From 43b35a689e692290979a990c823efd695b4e75ee Mon Sep 17 00:00:00 2001 From: v0lumehi Date: Fri, 23 Oct 2026 21:19:28 +0200 Subject: [PATCH] Present: commit the residency set after resolving the presented texture, for every game. Super Smash Bros. Ultimate 13.0.5 presents its window texture in its first frames before drawing into it; the texture was made on that first resolution in the present path and joined the residency set (res_add), which only a submission commits, so the display command buffer sampled it outside the committed set: kIOGPUCommandBufferCallbackErrorPageFault at the first presents, after which macOS ignored every command buffer of the process (194 command buffer and 174 upload errors in the user's run) and the window stayed pink. Headless runs never present, which is why they looked right. res_commit is free when nothing changed. Smash windowed now: the opening movie, the DLC first-boot screens, the title, the main menu and a first match render right, no GPU error. Breath of the Wild windowed with only this change on the sync-lag branch its libraries match: its title, 60 fps, no GPU error. docs/agents/04-graphics.md says so --- dm/gfx/nvn/nvn_mtl.m | 5 +++++ docs/agents/04-graphics.md | 3 +++ 2 files changed, 8 insertions(+) diff --git a/dm/gfx/nvn/nvn_mtl.m b/dm/gfx/nvn/nvn_mtl.m index b471fee..77eba31 100644 --- a/dm/gfx/nvn/nvn_mtl.m +++ b/dm/gfx/nvn/nvn_mtl.m @@ -8088,6 +8088,11 @@ static int present_now(const tex_t *t, double period, uint64_t frame, uint64_t t PD("X ser=%llu", t->serial); id src = tex_mtl(t); if (!src) { RED_ONCE(8, "present texture could not get an MTLTexture"); return 0; } + // A texture made on first resolution joins the residency set (res_add), which a submission commits; a window texture presented before any submission has used it was still + // outside the committed set when the display command buffer sampled it. Super Smash Bros. Ultimate presents its window texture in its first frames before drawing into it: + // the display queue page-faulted (kIOGPUCommandBufferCallbackErrorPageFault) and macOS then ignored every later command buffer of the process, so the window stayed pink + // (headless runs never present, and every game before drew into a window texture before presenting it). A commit with nothing new costs nothing + res_commit(); // DM_NVN_REGLUM=x0,y0,x1,y1:file (normalized coordinates): read back this region on every present and record "present sequence number, present time ns, region mean luminance, subsampled grayscale thumbnail (hex)" (diagnostic: verify that animation speed is independent of frame rate). // A separate command buffer is queued after this frame's rendering (the same queue executes in submit order); does not wait for the GPU and does not disturb frame pacing static int rl = -1; static float rr[4]; static FILE *rlf; static pthread_mutex_t rlmu = PTHREAD_MUTEX_INITIALIZER; diff --git a/docs/agents/04-graphics.md b/docs/agents/04-graphics.md index 0663143..a806be6 100644 --- a/docs/agents/04-graphics.md +++ b/docs/agents/04-graphics.md @@ -439,3 +439,6 @@ Next Level Games' deferred renderer on SDK 7.3.2 (NVN 53): the scene draws into - **A depth texture drawn through a colour view** (the boot aborted in Metal's pipeline validation: `MTLPixelFormatDepth16Unorm is not color renderable`): a 1024×1024 D16 texture drawn through an R16 view. Metal has no colour view of a depth texture, so such a pass draws into a colour shadow of the same pixel size, copied in before and back after the pass through a buffer, as a compressed render target is (`shrt_block`; D16 and D32F, whose Metal pixel is the NVN pixel; not D24S8). - **Post-process passes with stale texture handles**: the game patches handles into recorded commands ([03](03-bringup.md)). - **Not done:** the tessellation stages (15 hull, 18 domain shaders; `primitive type 14 not implemented`, their patch draws are skipped) and 10 geometry shaders (one expands a box from two corners). Neither is drawn much. Two tessellated programs (vertex `28a39709d0adfcfa` / hull `51d2d156bb12c260` / domain `0b95742e863bec50`, and `d4d89931b5a9a514` / `8aa6feeb7d33e9f6` / `f254b4dce2d6c012`) draw twice a frame for about 30 frames, in the title scene behind the file select as it slides out before a new game. No draw used a geometry shader from the title through the opening cutscene to the lobby. A program whose geometry shader has no library used to draw silently without that stage, with the vertex shader's positions taken as clip coordinates; `draw with geometry shader … which has no library` now names it. SPIRV-Cross already writes the hull shaders as kernels and the domain shaders as post-tessellation vertex functions, but Metal 4's render encoder and pipelines have no tessellation (no `drawPatches`, no factor buffer), so the draws would need a tessellator in a compute kernel and domain shaders rewritten as plain vertex functions. The hull kernels also write quad factors (`MTLQuadTessellationFactorsHalf`) for triangle patches. The vertex shaders that feed a hull or geometry shader can be found from the shader headers (SPH): the generic attribute map at +0x18 of the consumer's header (inputs) equals the one at +0x36 of the vertex shader's (outputs). In LM3, 40 vertex shaders match a hull shader and 49 a geometry shader. A few pixel shaders declare a 3D texture in a slot the game fills with a 32×32 2D texture (`texture type mismatch`), on paths not seen taken. + +### Seen in Super Smash Bros. Ultimate +- **A pink window, every command buffer ignored, while headless runs looked right** (13.0.5, `DM_WINDOW=1`): the first presents failed on the display command buffer with `kIOGPUCommandBufferCallbackErrorPageFault`, and after a few of those macOS ignored every submission of the process ("Ignored (for causing prior/excessive GPU errors)"). The game presents its window texture in its first frames before drawing into it; the texture was made on that first resolution in the present path and added to the residency set (`res_add`), but only a submission commits the set, so the display command buffer sampled a texture outside the committed set. `present_now` now commits the residency set after resolving the presented texture (`res_commit`, free when nothing changed), for every game. Headless runs never present, which is why they looked right; Breath of the Wild windowed with the change: its title, 60 fps, no GPU error.