A domain's objects[32] only grew: CloseVirtualHandle returned without freeing anything, so a client that opens and
closes sub-objects (the applet proxy getters, about 17 at boot) would get IPC_R_UNKNOWN_COMMAND for its 33rd, which the
SDK aborts on. The handlers took the new object's id from nobjects, the table had no lock (two threads could race on
nobjects), and a sub-object reached through its own handle (CopyFromCurrentDomain) kept a root pointer that the
domain's last CloseHandle had freed.
The domain table now has a lock in ipc.c (g_domains), taken only for sessions in a domain and never across a handler
or a close callback. ipc_domain_add gives out the first free slot and returns the id the handlers write back; the
table holds one reference on each object and each object one on its domain (held_root), counted in the domain's subs.
CloseVirtualHandle clears the slot and drops the table's reference; it never closes the domain's own id. A request
takes a reference on its target object under the lock for its length, and a cleared id is answered with
IPC_R_BAD_HANDLE instead of being dereferenced; CopyFromCurrentDomain answers the same. When a domain's remaining
references are all its objects', its client has closed it: the table lets the objects go, each object nothing else
holds is freed and lets go of the domain, and the domain is freed with the last one. Domain objects now count in
ipc_sessions_live from the moment they are added, since their last reference counts them out.
Not reproduced before the change: no log here has TRACE=ipc, so the getters per return to the title are not counted.
ipc_session_check gains a domain section: appletOE converted to a domain, 100 rounds of a getter and its
CloseVirtualHandle each get id 3 with the table at 3 slots, a closed id gets a bad-handle result, the domain's own id
survives a CloseVirtualHandle, a proxy with a handle of its own keeps the closed domain until that handle closes and
then both are freed, and closing a domain frees its proxy and five getters. The compile check of every runtime file
passes with no new warnings.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Each file that contains copied code names its copyright holder and license and points at THIRD_PARTY_NOTICES.md; zlib code keeps its full notice and the mark that it was altered. Comments and probe text only.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Comments say what the code does and why, docs/maxwell.md keeps the Maxwell facts, and fetch_refs.sh clones only the checkout the build reads. Code is unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The NVN2 front end and the SM86 to Maxwell shader lowering (tools/xlate/AmpereLowering.cs, mesh and task stages,
bindless texture pools, BRX jump tables, the NVN2 compute c0 layout) with four translator patches (0017-0020) bring the
opening of the game to 58-60 fps on the Vulkan renderer.
This round fixes the haze: SM86 IPA is lowered as a plain Maxwell IPA.PASS (texture coordinates were corrected for
perspective twice); LDSM, TXD, both F2IP byte forms, HMMA, MOVM and HFMA2.RELU are lowered and spill mode has eight
uniform register groups; conditional rendering keeps the newest counter report per address and treats a report as
pending until its value is in guest memory, so occlusion tests and the depth clears around the depth copy behave; and
the upscaler stand-in decodes the post pass's sRGB picture before writing the linear target. Tensor-core programs keep
the stand-in unless NX2NAVI_NATIVE_TENSOR=1, because their lowering does not match the hardware yet.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>