Repository navigation
Conversation
… depth prepass, 480 mesh draws 1.50 → 0.67-0.72 ms on an M1 A Metal mesh draw costs the M1 about 2.7 us however few triangles it has. Donkey Kong Bananza's 960x540 depth prepass draws 420-550 geometry-shader draws a frame as mesh draws (vertex f9c807930abd1234, culling kernel 5d537f7630ec3671, 15-350 triangles each): 1.0-2.0 ms of nearly idle GPU before the pass. dmsh_mesh.compose gives each mesh entry a run twin (dm_mesh_run, dm_mesh_run_z, ..._p16) that takes a table of draws at the draw slot: each draw's arguments, the running total of its threadgroups and the addresses bound at the vertex table's slots for it. A threadgroup finds its draw by halving and runs the same body with the draw's own numbers. The host (geo_mesh_take) lets a mesh draw that fits wait instead of dispatching, recording g_vt_addr after its arguments are bound, and draws the run as one dispatch before any operation but bindings, a program bind and draws (geo_mesh_keeps, from mtl_exec), before another draw (geo_mesh_draw, draw_), and before its pass ends (rp_end, defer_fallback). A run takes only draws whose result does not depend on their order: no colour writes, no stencil writes, an order-free depth test, no occlusion query counting, and a fragment shader with no resources. DM_NVN_GEO_MESH_RUN=0 turns runs off. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Landed as 84ec307 on main, unchanged apart from the rebase: the chain header regenerated ( Checked on main (M4 Pro): Thanks! |
What and why
A Metal mesh draw costs an M1 about 2.7 µs on the GPU however few triangles it draws. Donkey Kong Bananza draws its one geometry-shader pair (vertex
f9c807930abd1234, culling kernel5d537f7630ec3671) as mesh draws (geo_mesh.tsv), and its 960x540 depth prepass in the heavy areas has 420–550 of them a frame, 15–350 triangles each. InDM_NVN_GPUPROFthe pass showed an idle gap before it that grew with its draw count (about 2.3 µs a draw, 1.0–2.0 ms a frame), and the GPU counters showed that stretch at about 4 % occupancy.Fix:
dmsh_mesh.composegives each mesh entry a run twin (dm_mesh_run,dm_mesh_run_z,..._p16): it takes a table of draws at the draw slot (each draw's arguments, the running total of its threadgroups, and the addresses bound at the vertex table's slots for it), finds its draw by halving, and runs the same body with the draw's own threadgroup and primitive numbers.geo_mesh_takeinnvn_geometry.inc) lets a mesh draw that fits wait instead of dispatching, recordingg_vt_addrafter its arguments are bound. The run is drawn as one dispatch before any operation other than bindings, a program bind and draws (geo_mesh_keeps, frommtl_exec), before a draw of another pair, pass or kind, and before its pass ends (rp_end,defer_fallback). Bindings only change the replay state, so nothing else reaches the encoder between the draws of a run.DM_NVN_GEO_MESH_RUN=0turns runs off; the log'sgeometry mesh drawsline counts draws in runs and what ended them.Reference: Mesh geometry draws gathered into one dispatch.
Checked
main):make check_t_geometry_mesh(new: six geometry draws throughmtl_exec, each with its own uniform and storage counter, a scissor change in the middle; in runs, with runs off, and on the encoding thread; under Metal validation),check_t_geometry,check_t_geometry_hazards,check_t_geometry_feedback,t_nvn, alpha and logic replay;test_dmsh_geometry.py, includingmesh_primitive_id.m's new run cases (97 translated triangles as four draws, both depth modes, three index types) withDMSH_TEST_XLATEandDMSH_TEST_GPU=1;test_docs.py;lint_python.py(no new finding).040074A01BF12000v458752, handheld, the heaviest view of its heavy area, MetalFX upscaler (A game's own upscaler drawn by MetalFX, the player's choice in the launcher: Donkey Kong Bananza's NDSR network 3.5-5 ms → about 1 ms a frame on an M1 #1086) and the border-colour change (Pixel shaders without the border-colour correction in their main library: it spilled registers in every pixel where it never ran #1032) on. Correction: the first version of this PR refused runs while samples-passed counting was on, which stays on for the rest of the game after its first reset, so in Bananza no draw ever joined a run (0 of them in 0 runs); the 60 fps measured with A game's own upscaler drawn by MetalFX, the player's choice in the launcher: Donkey Kong Bananza's NDSR network 3.5-5 ms → about 1 ms a frame on an M1 #1086 did not include runs. The second commit allows runs while counting (a report ends a run and a pass keeps one query slot, so each query's interval holds whole runs and whether any sample passed does not depend on their order). With it: 142,000–155,000 mesh draws in 300 runs per 300 frames (one run of about 475 draws a frame), every mesh draw in a run. The view had fewer draws than the run before it (6,600 against 7,870 a frame), so its GPU time is not a like-for-like comparison.scripts/regress.py: not run. The chain changes (dmsh_mesh.py: new entries beside the existing ones, whose text is unchanged); the full Bananza build on this chain built all 23,638 shaders.geo_mesh.tsvpairs.Docs
docs/reference/shaders.mdand the game note,DM_NVN_GEO_MESH_RUNinenv_switches.tsv;python3 dm/tools/docs_symptoms.pywas rundmsh_chain.py --headerwas run anddm/gfx/nvn/dmsh_chain.his part of the change🤖 Generated with Claude Code