Repository navigation
The Legend of Zelda: Ocarina of Time (0400486024DEC000): renderer, shader and pipeline archive fixes through the Forest Temple - #1590
ksolenk38ze wants to merge 2 commits into
Conversation
|
Built this on a Mac mini (M4, 16 GB, macOS 27.2) from a v131072 NUP: 1. The NSP script stops at the shader table check
2.
It's not in the PR's test list. On If #1390 lands too
Tests on the whole stack: Not checked: the cause of the |
|
A note for this PR: e2b76d4 (from #1604) takes uncompressed textures from their storage unless the GPU wrote that storage, decided by address range rather than by pool. That covers Ocarina of Time's 260x260 and 68x68 terrain textures for any size and any game, so this PR's size rule for them is no longer needed. Please drop it when you rebase. |
4e6d541 to
d353679
Compare
|
Thank you for the detailed code review and for landing #1604! All three review items have been addressed, and the branch has been rebased onto
|
… attribute layout, pulling-base archive retention, image-view upgrades and retired alias safety through the Forest Temple Picture: - dmsh_meshstage.py lays out all v_blocks of 32 vertices before p_blocks of 32 per-primitive attributes in mesh stage memory (and honors sph[0x35] bit 3 PointSize and ctl[0x5f] point/line topologies), so the Forest Temple paintings (Poe Sisters and Phantom Ganon, rendered by ee4ef51a4fddc28e and 83c0dbc51c5481e3 with max_v = 128, max_p = 64 and per-primitive brush-stroke colors) read p0 from the primitive block instead of vertex block 1's screen-space positions. - fb_prepare ends the render pass when a draw samples R.rt.depth after an earlier draw in the same pass wrote depth (g_fb_dwrite): translucent geometry that reads the attached depth buffer for soft-depth fade (the Zora's Sapphire pedestal, Jabu-Jabu's interior walls) flickered black blocks on TBDR without a pass boundary. - image_prepare keeps NVN_TEXTURE_FLAGS_IMAGE on g_treg[tid].t.d.flags and upgrades R32Uint format views over RGBA8Unorm_sRGB before the pass (tex_upgrade_pfv), and tex_upgrade keeps an NvImageHeap owner and rebinds g_by_serial, g_ghost and g_alias views (tex_upgrade_alias_rebind) so agl_ndsr_vr does not leave blocky tiles on volcanic rocks or dynamic-resolution cutscenes. - bcrt_attach redirects renders into RGB_DXT1 (0x42) and RGTC1_UNORM (0x49) targets (flags 0x8) to an RGBA8Unorm / R8Unorm shadow texture and encodes them back on rp_end (bc_encode_bc1, bc_encode_bc4) for sky and water reflection baking. - mtk_pad_mesh_fn (nvn_geometry.inc) and var_pairs (shader_split.py) pad missing locnN outputs in mesh shaders (3a6340a04bf09797_b, a203347bb7bdbd03_b) with float4(0, 0, 0, 1) when paired with a fragment shader that reads them. Frame rate, pipeline archives and memory: - ArchEpoch separates vd == 0 (pulling base) and vd != 0 (vertex-layout base) flush periods (ep->kind) so pulling bases always serialize into p%05d.mtl4a instead of %05d.mtl4a and survive pso_compact_dir compaction (pso_prebuild also probes PRE_PROBE pairs against g_pull_arch4 before trusting prebuilt.tsv); pso4_init places compacted shards >= 256 MB at the head of g_arch4 outside g_compact_files and validates _MTL4Archive entry sizes (arch_entries_ok). - shader_prefetch_rest and pso_predict_rest_ copy the OP_CALL return stack (cur.ret) so lookahead continues across sub-command-buffer returns; hybrid_get_ex caches the reusable pulling base (vd == 0) on an uncached miss, and mtk_pso builds task/mesh pipelines on QOS_CLASS_USER_INITIATED. - treg_tex and tex_mtl_ skip re-creating or ghosting an unread retired GPU texture when a live alias already holds its (pool, off) range (alias_overlaps), and alias_take_over indexes g_by_serial by (pool, page) and marks retired g_treg slots over taken storage gone. - pool_gpu's patch scratch arrays (ids, ser_list, vals) are static under g_rmu instead of taking 1.96 MB on the 1 MB dm_bigstack. - Profile 0400486024DEC000: 16 GB mem_alias (0x400000000) for multi-dungeon virtual pool churn, v0 build entry, and updated README note. Checked: test_dmsh_meshstage 28, t_cpu_tex --metal 68, t_upgrade_alias 14, t_feedback 194, t_lookahead_bindless 22, t_pool_notes 81, dm/host/tests, test_docs, test_env_switches, test_game_profile, test_dmsh_pool_arrays, all 0 failed.
…nd Phantom Ganon (40,154 entries)
d353679 to
708f16e
Compare
…il cached view, on the test stack seedds#1604 uncompressed textures are taken from their storage unless the GPU wrote that storage, by address range, not their pool: the terrain no longer opens holes after walking a distance (streamed tiles came out zero once any texture in their pool had been a render target; the 260x260 tera_tile special case goes with it). Hand-merged with the stack's own ownership code: serial GPU writes (seedds#1558) and the BC render-target shadows (seedds#1590) stay; the image bind records the range through mtl_tex_gpu_written beside them; mtl_pool_gpu_written is gone with its last caller. seedds#1607 a texture ID with no texture drops its cached view: nil == nil kept a released texture valid on the pool tables' fast path, and the fast paths gave the shaders its resource ID after the host had released it (GPU page faults). The nil guard keeps the alias-view parent match. Tested in game on an M3 Max: a walk between areas holds the ground whole, no page faults, no regression of the earlier fixes (upscaler lines, load-time holes, stutters). Front-ends: host change only, chain unchanged (2027aa29b1b7).
…ck before the primitive blocks, with the point size ahead of the position and the topology from the control section: Ocarina of Time's Poe Sisters and Phantom Ganon paintings take their per-primitive colours again (chain 8900605baef9, from PR #1590) Symptom: a mesh shader's per-primitive outputs read as other values once it has more than 32 vertices. Ocarina of Time's Poe Sisters and Phantom Ganon paintings (ee4ef51a4fddc28e, 83c0dbc51c5481e3: 128 vertices, 64 primitives, a per-primitive colour) came out solid green or magenta (pull request #1590). A point mesh took its point size as its position's x. Cause: the wrapper read the attribute area as blocks of 32 vertices and 32 primitives side by side, each holding the vertex and then the primitive components. The guest writes all its vertex blocks first, then all its primitive blocks, each block only its own SPH's components: ee4ef51a4fddc28e (6 vertex components, 4 primitive) writes vertex v at (v / 32) * 768 + (v % 32) * 4 and primitive p at 3072 + (p / 32) * 512 + (p % 32) * 4. The SPH's point size (byte 0x35 bit 3) is a vertex block's first component: the point mesh 3a6340a04bf09797 writes the size at component 0 and the position at 1-4. Control +0x5f is a primitive's vertices (1 point, 2 line, 3 triangle); Ocarina's 5 mesh shaders with 1 are the 5 that write a point size, the other 495 have 3. Fix: dmsh_meshstage.memory and to_stage take ceil(max_v / 32) vertex blocks, then ceil(max_p / 32) primitive blocks; the point size goes to [[point_size]]; the topology and a primitive's index bytes follow +0x5f (another value stops the shader's build). The primitive index bytes stay reserved for every primitive block (PR #1575), +0x5f bytes a primitive instead of 3. The pull request's index area, +0x5f * max_p, would have undone #1575 and was not taken; nor were its other changes (reviewed on the pull request). Checks: test_dmsh_meshstage.py (30: the pull request's layout and point mesh tests, a point mesh memory test, the Metal compile of each case), test_docs.py, test_nsp_chain.py. The wrapper's reads checked against the guest's address arithmetic in the translated ee4ef51a4fddc28e and 3a6340a04bf09797. Regression: Ocarina of Time, its 500 mesh shaders translated and compiled on this chain (no other shader changes): 500 of 500 build, none refused, the largest stage memory 17,172 bytes (21,652 before). Mario Kart World, Splatoon Raiders and Yoshi not checked (no build here); the paintings not seen in the game; line topology not met. Ocarina's foliage point meshes (3a6340a04bf09797, a203347bb7bdbd03) still fail their pipelines on user(locn5), which their pixel shader reads as a texture coordinate (point sprite coordinate replacement suspected; open). Co-authored-by: ksolenk38ze <352968655+ksolenk38ze@users.noreply.github.com>
|
The mesh stage attribute layout from this PR landed as 3ccb7da (chain 8900605baef9), with you as co-author. Thank you. What I checked. The guest's own address arithmetic confirms it. In One difference. The index area keeps #1575's rule, reserved for every primitive block: The rest of this PR. It can't land as one change. The description and the code differ: the BC1/BC4 encoding, the alias rebinding in
|
… do not write, as (0,0,0,1) as a vertex shader does: Ocarina of Time's foliage point meshes build their pipelines again (chain 5616dbb62ec3, from PR #1590) Symptom: [RED] task / mesh pipeline: ... is not found in the output from the previous stage, and those mesh draws skipped. Ocarina of Time's foliage point meshes 3a6340a04bf09797 and a203347bb7bdbd03 write only a point size and a position; their pixel shaders 2a7c48d595feaaeb and cd609edc78b467d8 read generic attribute 5 (pull request #1590). Cause: a pixel shader input no stage wrote reads a default on the console and Metal refuses the pipeline; vs_pad covers vertex shaders, but mesh shaders had no pairs (shader_split.py var_pairs paired only vertex keys) and to_stage made only the outputs their SPHs enable. Not point sprite coordinate replacement: the pixel shaders' SPH input maps read generic attribute 5 (not a fixed-function texture coordinate, nor the point coordinate at 0x2e0), NVN has no point sprite function (only nvnCommandBufferSetPointSize), and the same file's triangle meshes leave locations 2, 8 and 9 unwritten that their pixel shaders read. Fix: var_pairs pairs a mesh key with its variation's pixel key; dmsh_build.py passes to_stage what the partners read (partner_inputs, shared with vs_pad), and the locations neither SPH enables become (0,0,0,1) vertex outputs. pso_offline.py plan and the host's pre_desc leave mesh pairs out (mesh pipelines are built at the draw). Ocarina's shader_pairs.tsv split again: 1,284 rows added, all with one of 491 mesh keys, none removed; its other tables split unchanged. test_dmsh_pairs.py gets an output() stand-in (two of its tests had failed since vs_pad read through the compile cache). The pull request's run-time padding on Metal's error text was not taken. Checks: test_dmsh_meshstage.py (31), test_dmsh_pairs.py (6, DM_GAME set), test_pso_offline.py, test_docs.py, test_nsp_chain.py, test_game_profile.py, the iOS compile check (261 files), lint_python (0 new). Ocarina's 500 mesh shaders and their 1,000 pixel partners built on the chain: 1,500 of 1,500, 19 mesh shaders padded. A Metal mesh pipeline built for each of the 1,284 mesh pairs: 1,283 build; the 31 that needed padding failed before. Open: 626fbf48041cb82b + c5eb985e769e317f (foliage, used by the game), 160 vertices of 14 outputs = 35,840 bytes past Metal's 32,768 mesh size, refused before for linkage and now for size. Regression: Ocarina only (no other mesh-shader game built here); the foliage not seen in the game; Yoshi, Mario Kart World and Splatoon Raiders have no mesh shaders in variations by their maps, not re-split. Co-authored-by: ksolenk38ze <352968655+ksolenk38ze@users.noreply.github.com>
|
A correction to my last comment: padding the missing mesh varyings is the right fix, and it landed as 5e344a8 (chain 5616dbb62ec3), with you as co-author. I was wrong to suggest point-sprite coordinate replacement:
So it's the same case as How it landed. Your Results. Of the 1,284 mesh pairs, 31 needed padding, and Metal now builds 1,283 of the pipelines. The one left is |
|
Follow-up: the last refused foliage pair ( Cause. Mesh outputs were declared as a full Fix. Each output is now declared only as wide as its paired pixel shaders can see: the components the mesh writes, plus a w they read but it doesn't write. On the GPU, Metal fills a narrower output's missing components with 0, which is the console's default for x, y and z, so the pixel shaders read the same values. That mesh comes to 28,160 bytes, and all 1,284 of Ocarina's mesh pairs build their pipelines. |
…s first write stays resident while any of them holds it: releasing one took it out of the residency set (GPU page faults, issue seedds#1326) The serials of one storage share one packaged texture (g_pkg_share). At the GPU's first write over that storage, cpu_unc_drop gives each of them the package's texture itself (tex_put), so they all hold one texture that was in no shared set. The first holder released (tex_put's ghost-ring eviction, serial_put or serial_del, through obj_drop or defer_obj_release), or the package's own release (NvPkg dealloc's res_remove), took it out of the residency set while the other serials still drew with it, and a command buffer reading it faulted. pkg_hand_over enters the handed-over texture in g_alias_set and in g_handed, a list by the package's sharing key, so releasing one holder only drops a reference (alias_has). The package's release and its re-upload's spare leave a handed-over texture resident, mtl_alias_drop_pool retires it with its pool, and tex_upgrade moves its entry. It does not enter g_alias, so a new texture object over the same storage still gets a texture of its own. DM_UNC_SHARE=0 gives back the old hand-over. Ocarina of Time v131072, Mac mini M4 16 GB, macOS 27.2, on main b2d46b8 with seedds#1590, seedds#1557, seedds#1556, seedds#1575, seedds#1522, seedds#1543 and seedds#1390: page faults at 44, 29, 24 and 15.5 minutes, with the missing textures named by DM_RES_CHECK and a diagnostic of where each left the residency set, before two of them, as 260x260 terrain tiles handed over this way and released by the ghost-ring eviction. One binary: with the change, 107 minutes and no fault (86 hand-overs); with DM_UNC_SHARE=0, a fault at 37 minutes with the same kind of tiles named. t_cpu_tex --metal handover_shared: 97 checks, 0 failed; with DM_UNC_SHARE=0, 2 failed. The other GPU suites are unchanged. (cherry picked from commit 8cbc330)
- Reconcile upstream PRs (seedds#1455, seedds#1447, seedds#1394, seedds#1439, seedds#1489, seedds#1590, seedds#1663) and commits (ffebfd5, e5f1ade) against local fork - Confirm PRs seedds#1455, seedds#1447, seedds#1394, and seedds#1439 are already implemented in ad99858 - Establish that host-only renderer optimizations require zero shader rebuilds and reuse the 42,854-entry b-dc815e0f38ca.img library - Establish that native subword stores (ffebfd5) affect only 515 shaders and leverage cas.db compilation caching - Rank candidates for base M3 Normal + Handheld (>=40 FPS target, ideal 60 FPS) and identify the top three candidates - Recommend the smallest independently verifiable first optimization (host-only PSO archive epoch separation from PR seedds#1590) - Update documentation index, plan, changelog, and known issues
…a, gmem commit repoint on the test stack seedds#1589 (carrying seedds#1391 + seedds#1482) the GPU memory guard reads the residency set's size and stops before macOS runs out of RAM; hand-merged with seedds#1590's ghost-active alias tables. seedds#1599 soft textures (gated, default off). seedds#1662's tip commit: the ocarina plays into the Mac's microphone (DM_MIC=1). seedds#1427 raw pool table words follow the pools at commit, as a candidate for seedds#1326's page faults (its window is skipped, not faulted: kept for the record). Full-map shader library (42,848), clearing the no-stamp and c1_full red lines. In-game: the GPU page fault at scene changes (seedds#1326) remains on this stack - one session lost the picture at frame 55,940 with the device revoked; the fault predates seedds#1585, which was excluded after the M2 Pro report but is not its cause. Front-ends: host change only, chain 2027aa29b1b7.
|
Thank you @seedds for landing the mesh stage attribute layout ( As requested, we have rebased onto current
Closing #1590 in favor of the split PRs above. |
…ck before the primitive blocks, with the point size ahead of the position and the topology from the control section: Ocarina of Time's Poe Sisters and Phantom Ganon paintings take their per-primitive colours again (chain 8900605baef9, from PR seedds#1590) Symptom: a mesh shader's per-primitive outputs read as other values once it has more than 32 vertices. Ocarina of Time's Poe Sisters and Phantom Ganon paintings (ee4ef51a4fddc28e, 83c0dbc51c5481e3: 128 vertices, 64 primitives, a per-primitive colour) came out solid green or magenta (pull request seedds#1590). A point mesh took its point size as its position's x. Cause: the wrapper read the attribute area as blocks of 32 vertices and 32 primitives side by side, each holding the vertex and then the primitive components. The guest writes all its vertex blocks first, then all its primitive blocks, each block only its own SPH's components: ee4ef51a4fddc28e (6 vertex components, 4 primitive) writes vertex v at (v / 32) * 768 + (v % 32) * 4 and primitive p at 3072 + (p / 32) * 512 + (p % 32) * 4. The SPH's point size (byte 0x35 bit 3) is a vertex block's first component: the point mesh 3a6340a04bf09797 writes the size at component 0 and the position at 1-4. Control +0x5f is a primitive's vertices (1 point, 2 line, 3 triangle); Ocarina's 5 mesh shaders with 1 are the 5 that write a point size, the other 495 have 3. Fix: dmsh_meshstage.memory and to_stage take ceil(max_v / 32) vertex blocks, then ceil(max_p / 32) primitive blocks; the point size goes to [[point_size]]; the topology and a primitive's index bytes follow +0x5f (another value stops the shader's build). The primitive index bytes stay reserved for every primitive block (PR seedds#1575), +0x5f bytes a primitive instead of 3. The pull request's index area, +0x5f * max_p, would have undone seedds#1575 and was not taken; nor were its other changes (reviewed on the pull request). Checks: test_dmsh_meshstage.py (30: the pull request's layout and point mesh tests, a point mesh memory test, the Metal compile of each case), test_docs.py, test_nsp_chain.py. The wrapper's reads checked against the guest's address arithmetic in the translated ee4ef51a4fddc28e and 3a6340a04bf09797. Regression: Ocarina of Time, its 500 mesh shaders translated and compiled on this chain (no other shader changes): 500 of 500 build, none refused, the largest stage memory 17,172 bytes (21,652 before). Mario Kart World, Splatoon Raiders and Yoshi not checked (no build here); the paintings not seen in the game; line topology not met. Ocarina's foliage point meshes (3a6340a04bf09797, a203347bb7bdbd03) still fail their pipelines on user(locn5), which their pixel shader reads as a texture coordinate (point sprite coordinate replacement suspected; open). Co-authored-by: ksolenk38ze <352968655+ksolenk38ze@users.noreply.github.com>
… do not write, as (0,0,0,1) as a vertex shader does: Ocarina of Time's foliage point meshes build their pipelines again (chain 5616dbb62ec3, from PR seedds#1590) Symptom: [RED] task / mesh pipeline: ... is not found in the output from the previous stage, and those mesh draws skipped. Ocarina of Time's foliage point meshes 3a6340a04bf09797 and a203347bb7bdbd03 write only a point size and a position; their pixel shaders 2a7c48d595feaaeb and cd609edc78b467d8 read generic attribute 5 (pull request seedds#1590). Cause: a pixel shader input no stage wrote reads a default on the console and Metal refuses the pipeline; vs_pad covers vertex shaders, but mesh shaders had no pairs (shader_split.py var_pairs paired only vertex keys) and to_stage made only the outputs their SPHs enable. Not point sprite coordinate replacement: the pixel shaders' SPH input maps read generic attribute 5 (not a fixed-function texture coordinate, nor the point coordinate at 0x2e0), NVN has no point sprite function (only nvnCommandBufferSetPointSize), and the same file's triangle meshes leave locations 2, 8 and 9 unwritten that their pixel shaders read. Fix: var_pairs pairs a mesh key with its variation's pixel key; dmsh_build.py passes to_stage what the partners read (partner_inputs, shared with vs_pad), and the locations neither SPH enables become (0,0,0,1) vertex outputs. pso_offline.py plan and the host's pre_desc leave mesh pairs out (mesh pipelines are built at the draw). Ocarina's shader_pairs.tsv split again: 1,284 rows added, all with one of 491 mesh keys, none removed; its other tables split unchanged. test_dmsh_pairs.py gets an output() stand-in (two of its tests had failed since vs_pad read through the compile cache). The pull request's run-time padding on Metal's error text was not taken. Checks: test_dmsh_meshstage.py (31), test_dmsh_pairs.py (6, DM_GAME set), test_pso_offline.py, test_docs.py, test_nsp_chain.py, test_game_profile.py, the iOS compile check (261 files), lint_python (0 new). Ocarina's 500 mesh shaders and their 1,000 pixel partners built on the chain: 1,500 of 1,500, 19 mesh shaders padded. A Metal mesh pipeline built for each of the 1,284 mesh pairs: 1,283 build; the 31 that needed padding failed before. Open: 626fbf48041cb82b + c5eb985e769e317f (foliage, used by the game), 160 vertices of 14 outputs = 35,840 bytes past Metal's 32,768 mesh size, refused before for linkage and now for size. Regression: Ocarina only (no other mesh-shader game built here); the foliage not seen in the game; Yoshi, Mario Kart World and Splatoon Raiders have no mesh shaders in variations by their maps, not re-split. Co-authored-by: ksolenk38ze <352968655+ksolenk38ze@users.noreply.github.com>
Follow-up to #1444, rebased cleanly onto
main(b2d46b86).Most of the early bring-up from #1444 (
EventFd,IAudioInManager,nn::ndvemovie networks, BNSH task/mesh shaders, float atomics,ATOMG.CAS,textureGatherOffsets, RGBA8 image atomics,mem_map_limit on,tex_flush_upload/tex_dirty_upload, and theshader_map.tsv/shader_seen.tsvprofiles) is now onmainthrough recent commits. This PR carries the remaining renderer fixes from #1444 together with the fixes found while playing The Legend of Zelda: Ocarina of Time (0400486024DEC000, Switch 2v131072) through all three child dungeons (Great Deku Tree, Dodongo's Cavern, Inside Jabu-Jabu's Belly), Hyrule Field, Market, Hyrule Castle, Kakariko Village, Death Mountain Trail, Zora's River / Domain / Fountain, the Temple of Time (adult timeline transition), the Graveyard, and completion of the first adult dungeon (Forest Temple, including the Poe Sisters and Phantom Ganon).Picture fixes
dm/gfx/tools/dmsh_meshstage.py,dm/gfx/nvn/dmsh_chain.h): Ampere mesh shaders store all vertex attribute blocks (v_blocks = ceil(max_v / 32)blocks of 32 vertices) first in stage memory, followed by all primitive attribute blocks (p_blocks = ceil(max_p / 32)blocks of 32 primitives).dmsh_meshstage.pypreviously interleaved one 32-vertex block and one 32-primitive block perblock = idx >> 5, so whenevermax_v > 32(v_blocks > 1), primitive attributes (attr >= p_first) read and wrote vertex block 1 (v[32..63]). In the Forest Temple, the Poe Sisters and Phantom Ganon painting shaders (ee4ef51a4fddc28eand83c0dbc51c5481e3,max_v = 128,max_p = 64) carry per-primitive brush-stroke colors inp0..p2; reading vertex block 1's screen-space positions asp0produced solid green/magenta paintings.dmsh_meshstage.pynow places allv_blocksbeforep_blocks, accounts forsph[0x35]bit 3 (PointSize) inv_slots, and handlesctl[0x5f]point (1) and line (2) topologies. Fixed and verified with unit tests (test_dmsh_meshstage.py, 28 tests) right after completing the Forest Temple; to be visually re-checked in the painting rooms on a revisit.dm/gfx/nvn/nvn_mtl.m): Infb_prepare, when a draw samples the currently attached depth target (R.rt.depth) in a fragment shader (prog_uses_tid) and an earlier draw in the same Metal render pass wrote depth (g_fb_dwrite), end the current pass before binding the draw. Without a pass boundary on Apple Silicon TBDR, translucent surfaces that sample scene depth for soft-depth fades (the Zora's Sapphire pedestal in Jabu-Jabu's Belly, translucent interior walls) read un-flushed tile depth and flickered with black blocks.NvImageHeapalias rebinding (dm/gfx/nvn/nvn_mtl.m):image_preparenow persistsNVN_TEXTURE_FLAGS_IMAGEong_treg[tid].t.d.flagswhen an image binding upgrades a texture and callstex_upgrade_pfvbefore the render pass starts when an image view binds a format view (R32UintoverRGBA8Unorm_sRGBinagl_ndsr_vr).tex_upgradealso preservesNvImageHeapownership on placement textures and rebinds matchingg_by_serial,g_ghost, andg_aliasviews (tex_upgrade_alias_rebind) so dynamic-resolution scaling and volcanic rock / lava shaders do not sample stale textures or leave blocky mosaic tiles.dm/gfx/nvn/nvn_mtl.m):aglbakes sky and water reflection cubemap faces by attachingRGB_DXT1(0x42) andRGTC1_UNORM(0x49) textures (flags 0x8 COMPRESSIBLE) as color targets. Since Metal cannot render directly into BC-compressed pixel formats,bcrt_attachredirects those attachments to anRGBA8Unorm/R8Unormshadow texture and encodes the rendered blocks back into the guest pool / BC texture onrp_end(bc_encode_bc1,bc_encode_bc4).dm/gfx/nvn/nvn_geometry.inc,dm/gfx/tools/shader_split.py): When a fragment shader reads alocnNinput that its paired mesh shader (3a6340a04bf09797_b,a203347bb7bdbd03_b) omits,mtk_pad_mesh_fnandvar_pairspad the missing varying withfloat4(0, 0, 0, 1)soMTL4Compilerdoes not abort pipeline compilation.dm/gfx/nvn/nvn_mtl.m):teraallocates260x260(256 + 2*2border) and68x68(64 + 2*2border)R16Unorm,RGBA8Unorm, andR8Unormterrain heightmap, normal, and blend-weight tiles in the same 2.43 GB pool as GPU render targets. Guardingattach()'sg_pool_gpumark withg_in_rt_attachand recognizing260x260/68x68bordered tiles intex_cpu_contentpreserves CPU terrain uploads across Kakariko Village and Death Mountain.Frame rate, pipeline archives, and memory
ArchEpochflush states for pulling vs vertex-layout bases (dm/gfx/nvn/nvn_mtl.m):pso_save_baseshared a singleg_base_epochbetween pulling bases (vd == 0, intended forp%05d.mtl4a) and vertex-layout bases (vd != 0,%05d.mtl4a). Whichever type hit the 32-pipeline batch threshold or 2-second timer flushed both into one file, so pulling bases landed in%05d.mtl4aand were discarded wheneverpso_compact_dircompacted%05d.mtl4awithinclude_pull = NO. Splittingg_base_epochandg_pull_epoch(ep->kind) keeps every pulling base inp%05d.mtl4a.pso_prebuildalso probes up to 8 entries fromprebuilt.tsvagainstg_pull_arch4(PRE_PROBE) so an olderpso_archivewhose pulling bases were compacted away automatically rebuilds them on launch.dm/gfx/nvn/nvn_mtl.m):pso4_initplaces compacted shards (>= 256 MB) at the head ofg_arch4and keeps them out ofg_compact_filesso they are checked first and not re-copied on every compaction pass, andarch_entries_okchecks_MTL4Archiveinternal entry offsets before loading an archive.OP_CALL) lookahead and pulling-base caching (dm/gfx/nvn/nvn_mtl.m):shader_prefetch_restandpso_predict_rest_now copy theOP_CALLreturn stack (cur.ret/cur.rdepth) when starting lookahead from inside a called sub-list so prefetch and PSO prediction continue across sub-list returns into the rest of the frame.hybrid_get_exalso caches the reusablevd == 0pulling base when compiling a specializedvd != 0pipeline on an uncached miss, andmtk_psobuilds task/mesh pipelines onQOS_CLASS_USER_INITIATED.dm/gfx/nvn/nvn_mtl.m,dm/gfx/nvn/nvn_dirty.h):treg_texandtex_mtl_skip materializing or ghosting an unread retired GPU texture when a live alias already owns its(pool, off)range (alias_overlaps), andalias_take_overindexesg_by_serialby(pool, page)and marks retiredg_tregslots over taken storage gone. This avoids a cascade ofpool_gpubindless table rebuilds andres_commitspikes in Hyrule Field, Market, and Kakariko Village.dm/gfx/nvn/nvn_mtl.m):pkg_upload_gathers sparse-pool textures (< 64 MB) into a batch-retainedMTLBufferfor the batched GPU deswizzle path instead of forcing synchronousup_flush()mid-cutscene, andup_big_srccaches up to four 16 MB (BIG_S) upload buffers ing_up_big_src.pool_gpupatch arrays (dm/gfx/nvn/nvn_mtl.m):pool_gpu's patch scratch arrays (ids,ser_list,vals, 1.96 MB total) are nowstaticunderg_rmuinstead of living on the 1 MBdm_bigstack.dm/games/0400486024DEC000/): Increasedmem_aliasto0x400000000(16 GB) for multi-dungeon virtual pool churn, added thev0base build entry ingame.tsv, bridgednn::hid::IsOunceVibrationDeviceMountedinhle_hid.c(called when playing Ocarina notes), and updatedpso_manifest.tsvto 40,154 observed(vs, fs, rt)triplets through the Forest Temple and Phantom Ganon.Upgrade / cache note for existing users
DMSH_CHAINis bumped to8b11d946d5b4for the mesh stage layout fix, so existing shader caches rebuild the 8 affected mesh shaders automatically.pso_archivedirectories do not need to be deleted manually:pso_prebuildnow probesprebuilt.tsvagainstg_pull_arch4(PRE_PROBE) and automatically regeneratesp*.mtl4aif an older compaction run had dropped the pulling bases.Open observations for follow-up
Verification
v131072) through Kokiri Forest, Great Deku Tree, Hyrule Field, Market, Hyrule Castle, Kakariko Village, Death Mountain Trail, Dodongo's Cavern, Zora's River / Domain / Fountain, Inside Jabu-Jabu's Belly, Temple of Time, Graveyard, and the Forest Temple (Poe Sisters & Phantom Ganon).lint_python.py --against origin/main(0 findings), all 30 test suites indm/gfx/tests/test_*.py(includingtest_dmsh_meshstage.py28/28),dm/tools/tests/test_*.py(test_docs.py,test_game_profile.py,test_env_switches.py,test_image_atomic_bounds.py,test_txq_type.py).make -C dm/host/tests GAME=010015100B514000 run,GAME=010015100B514000 python3 dm/ios/tools/compile_check.py(261 files, 0 failed), anddm/gfx/tests(t_nvn243,t_gfx_suspend,t_cpu_tex --metal68,t_upgrade_alias14,t_feedback194,t_lookahead_bindless22,t_pool_notes81,t_pso_pending52,t_pso_skey,t_refl43).