Uniform updates that cover part of what a draw reads no longer end the render pass; clears with no draw ride on the next pass

Outdoors in Breath of the Wild (the user's Great Plateau save, Mac M4 Pro) a frame had about 386
render passes and loaded and stored about 900 MB of attachments, which an iPhone at 60 fps can
hardly move (about 55 GB/s). 220 of those passes ended only because the game updates the first
64 bytes of a 64 KB vertex uniform block before each draw group (nvnCommandBufferUpdateUniformBuffer
inside the pass) while its shaders read up to 544 bytes of it. A deferred update that covers only
part of what a draw reads used to end the pass.

- Partly covered blocks (nvn_mtl.m ubp_get): the shadow starts from memory and takes every inline
  update queued in the submission, newest last, incrementally per range. It is refused, and the
  pass ends as before, when something else may have written the range by the time the pass runs:
  a copy, fill or feedback write queued in the submission, a storage buffer a shader may write or
  a texture->buffer copy over it (sbw, by 4 KB page), or a GPU write or counter report of an
  earlier submission still running (gw). A counter report of the same submission does not count:
  the host writes reports on the CPU after the whole submission completes (Fire Emblem Engage
  writes its reports into a uniform block's page). DM_NVN_UB_PARTIAL=0 turns it off;
  DM_NVN_UBP_CHECK=1 lands the updates, waits for the GPU and compares every shadow with memory.
- cb_extent.tsv (new tool dm/gfx/tools/cb_extent.py, c1_guard.py's interval arithmetic over the
  translated MSL): per shader, how far into each uniform slot it can read, and the storage slots
  it never writes. Like c1_full.tsv, the host loads it only for its chain version; build_ipa.sh
  copies it, the NSP script writes it for provisional profiles, and the chain procedure
  regenerates it. Without it bindings are copied whole (up to 64 KB). Ten profiles have one.
- Route B's reflection never says whether a storage buffer is written, so every one read as
  read-only and its writes went unnoticed: a storage buffer now counts as written unless
  SPIRV-Cross typed it const (nvn_refl.m sbuf_rw) or cb_extent.tsv proves the slot unwritten.
- Lazy clears (lc_*): a set of targets that gets only clears before the game sets other targets
  no longer opens a pass just to store them; the next pass that attaches the same texture level
  and layer through the same view clears it as its load action, and the rest land as before
  before anything else could see them. Breath of the Wild's four clear-only passes before the
  G-buffer fold into its first pass. Off in TBDR mode; DM_NVN_LAZY_CLEAR=0 turns it off.
- The residency set line counts shadows from memory, refusals by reason, and lazy clears.

On the Mac, old (DM_NVN_UB_PARTIAL=0 DM_NVN_LAZY_CLEAR=0) and new side by side on each game's
route; attachment loads + stores per frame:
- Fire Emblem Engage battles: about 1,850 -> 360 MB, 88 -> 38 passes.
- Tears of the Kingdom: about 1,100 -> 700 MB, 124 -> 116 passes.
- Breath of the Wild outdoors: 386 -> about 158 passes, GPU p50 about 9.3 -> 6.5 ms, submit
  5.7 -> 4.2-4.9 ms; where the old host fell to 30 or 20 fps under load, the new held 60.
- Link's Awakening, 13 Sentinels: about 15% less. Super Mario 3D World: 5% less (lazy clears).
- Odyssey, Three Houses: 2-8% less. Mario Wonder, Metroid Dread: unchanged.

No new red lines in any of them. The shadow check found every shadow equal to the GPU's memory
(BotW 346,000, Engage 284,000, TOTK 86,000), and t_nvn passes 68/68. Screenshots differ only by
timing. Tried and dropped: DM_NVN_TBDR=1 (it turns the deferred updates off), DM_NVN_BARRIER=game
(no gain), and same-target continuation outside TBDR mode (BotW's decals end the pass anyway).

What still splits BotW's big passes: the GPU particles' compute dispatches (about 190 MB a frame)
and decals that sample the G-buffer. Mac shader libraries were built for the current chain of
TOTK, Engage, Wonder, Dread, Odyssey, Link's Awakening, Three Houses and 13 Sentinels (c1_full.tsv
headers already matched). The IPA ZeldaBreathOfTheWild-2026-10-21-passes.ipa (an earlier state of
these changes plus the uncommitted frame-step probes) awaits an iPhone test.
This commit is contained in:
seedds committed 2026-10-21 12:57:48 +08:00
1 parent 8a429d8b5f
commit f5646efc47
21 files changed
+122818 -29

No files matched your search

+1 -1
View File
@@ -11,7 +11,7 @@
- After changing anything on the shader translation chain, run the chain procedure for each affected profile. The chain covers `dm/gfx/tools/dmsh_*`, `Program.cs`, the profile's `shader_map.tsv` / `shader_facts.tsv` / `shader_pairs.tsv`, and its `shader_*` keys. The procedure:
1. Run `dmsh_chain.py --header`, which writes the profile's `dmsh_chain.h`.
2. Rebuild the shaders (Mac and, with `IOSOUT`, iOS).
3. Regenerate the profile's `c1_full.tsv`.
3. Regenerate the profile's `c1_full.tsv` (`c1_guard.py`) and `cb_extent.tsv` (`cb_extent.py`).
4. Rebuild the host.
The host only loads libraries of its own chain version. The translator is `dm/gfx/tools/dmsh_xlate_bin`, which matches `dmsh_chain.lock`; a fresh `dotnet publish` does not.
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+640
View File
@@ -0,0 +1,640 @@
# chain b-601174f81d6a 2026-10-21T12:01:30+08:00
# shader key, then reg:bytes for each uniform slot whose reads stay inside its first bytes, and s<reg> for each storage slot it never writes (cb_extent.py)
0040f948baa144f4 0:1904
00870f86a49cf3b9 0:1904 12:64
0093b425acd3f401 2:16 4:144 13:288
00b73c6360ebc8a3 0:144 12:64
00f37717bf4bac4f 0:64 1:16 4:80
011944e3919d9086 0:320 13:288
0195aaa2774f7f94 13:368
01b67911b0eba290 0:96 1:16 4:112 13:368
01db2042ca1d750f 0:320
01f059409b9f67a6 0:112
01f5cb5257d9f97b 0:1904
0216f89788d5754b 0:304
0289d1c53871cfd8 13:288
02c1823e16d48275 0:192 12:64
02ca876f24e6ee00 0:336 13:368
034fd5775426fb0a 0:160
03fb9c7ed541610a 0:320 13:160
04b77059f98a3b78 0:64 1:16 3:80
051881873373d1da 1:80 13:368
05363af3087acda3 0:192
059b25011e019a1d 0:192
06481a7157e38253 0:112
06514574c231f3dc 0:1904 13:368
06e1ea4094189dba 0:160
0732be065f1ccb64 0:288 1:80 13:176
0803c807f16ba3d1 0:64 1:16 4:112
088b2410056cd167 1:32
08c29a91d2dec428 0:96 1:16
0972cb63d2599938 0:80
09792f3958306ae6 0:64 1:16 4:112
09d7ba33f95453a6 0:1904 12:64
0a2f043d53ce738a 2:16 4:192 13:2768
0a5a4fb79479e894 0:1904 1:80 13:160
0a6c03b820351de6 0:1904 12:64
0ac7bcd086662236 0:160
0bf3b0c8200753fc 13:288
0c07df41c7981b43 4:192 13:2768
0ca99e0593045cac 0:32
0d4d61c0a868f9a7 0:1904 13:368
0d6f1997de8db140 4:192 13:2768
0ddfcfcdcc3ddf9e 0:160
0e685e6294a6cbb9 0:1888 1:32
0e74ffd870215814 0:272
0ef727c7d38740c5 4:144 13:240
0f3f9e510179be23 0:112
0ffefa790db21654 13:368
1016abf3a39a6777 0:144
1037a2384ec6970c 0:48
10839897b2ae647d 0:64 1:16
1163a9f7c3d20076 2:16
1166cc27e685f802 13:144
11e0b14a9b1ac080 0:336 12:64
12f1b945891c5ccd 0:32
139b480e75a6c1ec 0:208
140accf5ff3960ce 4:192 13:2768
1420b58f7143823a 2:16 4:144 13:240
1459f681755b8ed1 2:16 4:192 13:2768
146a3716c4f9826b 0:288
14fa46d06cb79527 0:192 12:64
1549752359be9243 0:160
15f653b15298ad2d 2:16 13:288
16973133690146e6 0:160
16a74e9f2eb1e75e 4:144 13:288
1787a4f06b8a0102 1:80 13:368
17eca5cde94f7aa0 4:144 13:288
182310bcbaf83a29 13:288
1835add527114581 0:160
18890ab424a6d8b7 0:96
193839e199081fef 0:48
19a5120409cace01 0:240
1a28da408ff83ff4 0:96 1:16
1bf6bd9c542b5cd9 0:96
1c10ccd1d18c52ef 0:128 1:64 12:64
1d936fdedaeaec26 0:64 1:16 4:80
1da14272a93cd491 0:96
1e491ec218d183dc 0:240
1ed6df817c71028b 13:240
1f4a63b490f62a34 2:16 13:288
201b4d77416f979a 0:80 1:16 4:64 13:368
20a2ce4b867bf227 13:368
212650750751cbad 13:288
21448c3f9d89f216 4:144 13:288
2240a91ab3ac898b 1:80 13:176
22980b1ae5d2019e 0:272 1:64
23356e4eb828fb83 13:288
235b67cad9698821 4:192 13:2768
2432602e6a95c9b9 2:16 4:192 13:2768
2484e5994cef257c 1:80 13:176
25824022a2c6b470 2:16 4:192 13:2768
2668ed65546dee7e 0:32
26f78cd3aa4b8926 0:1904
26fa49ee946269b3 2:16 4:192 13:2768
27857033dddfde91 0:1904 1:80 13:160
2849e228f3a1df29 2:16 4:192 13:2768
285bd23319484bb0 1:80 13:160
28a54478ae1ca813 0:288 1:80 13:368
28f1d8f6fd56635e 0:96 1:16 4:112
28fd3e0769029b79 0:208
291d0488d9d84314 4:192 13:2768
2923044e32509c5d 13:288
29f2198cc62a4589 2:16
2a2ab3f137f2f816 0:320 13:288
2a7f04b0d3d60ce2 13:240
2b0757eb8ca43d70 0:96
2b4eee86e82db581 0:288 1:80 13:160
2bdf4c3fb6666f51 0:1904
2c5f640d1306cd67 0:1904 1:64
2cfe6de787c2a6bd 0:160
2d2533c0d817a29b 12:64
2d717589fd0904d6 0:1904
2de21173609569dd 0:80 1:16
2f64ecfbeb5ae4c2 0:192 12:64
2f763a93aae9ce99 0:80
30b45b0045b5b7a2 0:96
30de397838b07ff6 13:160
3100f6738db9f068 2:16 4:192 13:2768
318caf466b19bd3e 13:288
3195bdb152b7bb07 13:160
31d8cd9e425c28e7 0:1904 1:32
330a677ae5094609 0:80 1:16 13:368
339f73ba6e5b41f0 0:320 13:288
3490021606823f09 0:336 1:80 13:160
34d961561ff1327f 2:16
366a9a9aab88c22e 0:64 1:16 4:64
372bf5948213053f 0:192 12:64
3760c0afee65d856 0:320 13:288
3769521d23444ce4 0:192
377106c4d4c5ba1d 0:144
3771b9464681d485 0:336
378fc41a6fb740f9 0:48
37c8bcb74d398646 0:192
382ed7f5e7018312 0:64 1:16 4:112 13:368
383f8aabb836eb9d 4:192 13:2768
391de7f9e70f441c 0:48
3949ab9849265857 2:16 13:288
396ff9cf7f2a3801 0:320
3a19ad025b16f11d 0:1904 1:80 13:368
3a40f12f7ee5639d 0:112 1:64 12:64
3b73581d86c205fa 0:160
3c57cac8dab4f30d 13:288
3caec795d3d3bff1 0:288 1:64
3d38b9965c284bdc 0:32
3d4ac4ca90260022 0:1904 12:64
3d9cd4be9f3b5a2e 0:1904 1:64
3d9d2c26e744da49 0:1904 13:368
3dd8c00d3acc5ff6 0:272 12:64
3e8c65894c62edcf 0:80 1:16 4:112
3e9592ffd8ab389f 0:160
3f19991694c1b137 1:64
3f689fa3167ede95 0:64 1:16 4:112
3fc5f98e9bb2d280 0:320 13:240
3fd93343962695cd 4:192 13:2768
3ff941d5eece2395 0:1904
403a5758e49fbf9e 0:1904 1:64
4064c152d3890cac 2:16 4:144 13:240
40a0c914fd7f6675 0:320
40abd0c3805fded3 4:192 13:2768
40d75abc4deab1e5 0:336
40fc399fa393d3f2 2:16 4:192 13:2768
4194dcf325d08bbf 0:1904
41ad677d6e9b5780 0:160
420ed53c9f81b96b 0:96 1:16 4:112
4278d7860b7f1472 2:16 4:144 13:288
42c908bcacacab78 0:1904 1:80 13:368
43dce950e3ce9e00 0:1904 1:80 13:176
440d4449ff9ba011 0:1904
456f25b32b3251a5 1:80 13:368
4612a2438a1ae4d2 2:16 4:144
46780f757806d67d 13:368
4687812fcc097f4a 0:320 13:288
47629ffac9999ad4 0:192 12:64
499bee5c432ebce8 0:64 1:16 4:80
4a1794705ca53384 0:288 13:368
4a671745ba6531d9 0:96
4a7231ce50ac4458 0:288 1:80 13:368
4a75def0fc2737bc 0:1904
4abc7b9d65a714ad 4:192 13:2768
4b148d6596f3d23a 1:80 13:368
4b33aac14cc96596 0:288 1:80 13:160
4b7f451b92e9d9fa 0:80 1:16 4:112
4bf525a99134ebcf 0:1904
4c960fa2c25b109d 4:192 13:2768
4cfa0ce6a7fe1079 0:96 1:16 3:80
4d80a86e517151f5 0:160
4dd9c2e6a40c0394 0:96 1:16 4:64
4eac8f4c27d2c3e8 1:80 13:368
4ef43b090d4aa792 0:208
4f14b5d6cb6e8516 0:96
4f5acb13923bf8d0 0:1904
4f6927becce1f051 2:16 4:192 13:2768
4f914211462adb63 0:336 1:32
5020390f0855186a 13:368
50d5a361e2cbcf68 0:240
51ac57eb5f67fedc 0:1904 1:80 13:368
51c19c739e594d19 0:320 13:288
53b13bbb24694389 0:96
53bac653c73c418a 1:80 13:368
53d9cd70a28ee776 0:64 1:16 4:112
53f25eb27c4fe13c 0:1904
542af76c0f7f6331 0:240
5482dc93a27cf699 1:80 13:160
54b5c405d9816d26 13:288
553b071e8012918d 1:64
555d1d604a71abce 0:80 1:16 4:64
55afd0aca24c0419 0:64 1:16 3:80
55ea27cee5554264 0:320
5630fc0cbd15d4ed 13:288
5664a33faa83fd33 4:192 13:2768
568ff969a753e58c 2:16 4:144
56e5dbc3e071f016 0:320 13:288
573f306c6d82a2a7 13:288
57d4fd6e75bddc11 0:64 1:16 4:112 13:368
58258b4cece0dd8a 0:96 1:16 4:80
58915ad3486f4c58 0:1904 12:64
59439742561f60a1 0:320 13:288
59672edd5f258046 0:336
596d41d48b634aff 2:16 4:144 13:288
5a40c4889fe10994 0:1904 1:80 13:176
5a7902803b87d628 0:112
5aaf2555837387a2 0:64 1:16 4:112
5b5254fa605c9448 0:96
5b6a1b16861461f7 0:80 1:16 4:112 13:368
5b83ea06a6982c94 0:80 1:16 4:112
5bfd4ece6f0a0196 12:64
5c3c40c319b617fe 2:16 13:240
5c44c76019a7d1ec 0:336 1:64 13:368
5c7688eb040aa639 0:320 13:160
5d71ed0f2686224f 0:80 1:16 4:112
5d83bf515bb746c2 0:1904 13:368
5e8f30c04b6d74d8 0:1904
5f77b3888494b325 0:240
5fb685c49afc65d1 13:288
609279b3b1e48f3e 13:160
6098ad0051905c99 0:96 1:16 4:112
60d4c4ad76e48d5a 0:64
60d928216c2a1605 0:320
6119e2affa309a00 0:128 1:144 2:16
613211a136a1cf52 0:80 1:16
615cff6a5adcc5eb 13:160
6251be1afb429c0e 0:80 1:16 4:112 13:368
633e60fdef1e18ef 2:16 4:144 13:240
63fb8375bf0a966e 13:2688
6441a8afa1af6d3b 0:16
648171746e615511 0:320 13:160
64f095d6ad432cb6 2:16 13:288
654c7d071ded3f97 0:96
656da77697f3452e 0:224
65a051853eeba404 0:320 13:240
65d39061656b3ac6 12:64
67225779b9b79641 0:128
6745353ff6a61b06 13:240
67644fc5976390b9 0:1904 12:64
67a69e3417fb3354 0:96
67fa3164f2b2b54f 0:96
683bb6316a7ae2aa 0:80 1:16 4:112 13:368
688d2affa94b39e2 4:144
68c8cd907318f7d0 0:240
68cfd018dfcee1bc 0:320
697e3ab9dcf2464f 2:16 4:192 13:2768
69e6dcdb6d8d00e5 4:144 13:240
6a08c33a0239e639 0:320
6a24f57943c4ec67 0:96 1:16 4:112 13:368
6a502c6cd5bfabf4 0:1904 1:64 13:368
6a593450bb293e26 0:160
6add555f75b69aaf 4:192 13:2768
6b07b70e665775fd 0:1904 1:80 13:160
6b400d24e283fb89 0:96 1:16 4:80
6be5bba922b9b7dc 0:64 1:16 4:80
6c3b4678d1b4fbf0 0:320 13:288
6c477ce4fb255429 13:368
6c5a06abbf8385ac 13:368
6cf96e7eb288d0e5 0:1904
6d1106cc9e332d9a 0:336
6d7cf4c78dbabd40 0:96 1:16 4:112
6eef6583df6b6c50 0:336 1:80 13:368
6f120567ffd086a8 0:80 1:16 3:80
6f551ccdb24ec54a 0:320
6f867edbd352fa3f 0:320
6fed094f83ec834c 13:368
7018eeb2ade4406c 12:64
703cb25e0ea3ca8f 0:1904
706b36197ad381dd 4:144
70d126e8a37083f7 0:240
7115d177d5bead87 0:1904
713048c1a4d9c9b6 0:1904 1:80 13:368
717ddb7e3e3ca319 0:1904
71fd0ce3ce52829d 4:192 13:2768
7204b5c9cdf6a2d9 2:16 4:192 13:2768
72093b96f7b0c189 2:16 4:192 13:2768
72249a39fa56c6ae 0:144
7297cf79a8131e27 0:96
72aed5a33cd82126 0:64 1:16 4:112
732a18f5dee4bafb 0:160
73952b7e6005b452 2:16 4:192 13:2768
749e645455b4d6f9 0:96 1:16 4:112
7590b8fad1f79f5e 0:320 13:240
75f1ce743e36beb0 1:80 13:176
766b37a4dc8c15ec 0:336
777f203ce7bb39c2 0:320 13:240
77e107589a6aec66 0:320 13:240
77f37072c47af3bb 12:64
781fe6d04a9719bd 0:32
78878b5627402d1b 0:96 1:16 4:112
793af3323431348c 0:192
79da88ce1d76a5d2 13:288
7a537520dd53b0e4 0:96 1:16 4:112
7adec5f9978a5c86 4:192 13:2768
7b39574d6126ebab 2:16 13:288
7c073b91c37e838d 1:64 13:368
7c2a95f22a5e64c2 0:112
7d95d243aea2b2cc 2:16 4:192 13:2768
7de9d89c30323513 2:16 4:192 13:2768
7e051b2bd08543ee 0:336 1:80 13:160
7e97419919fa57f4 0:320 13:288
7eefb9d8881d27a4 13:288
7f16b8534971d61e 0:1904 1:80 13:176
7f2a6b38040a9d23 0:208
7fe488f38f8c555e 0:160
800a2ae29d353701 0:1904
800dd083bb92a94a 2:16 13:288
8038764dd5c8c75b 4:144 13:288
804bc47a5a52c682 0:192
80a7cc64abb3d449 4:192 13:2768
80b8c29864a6abee 0:80 1:16 4:80
80e0798b12b23163 0:224
8218d54372531eab 0:16
8229d319cca04b38 12:64
825ad973231b45a7 1:64 13:368
82b68976b8f3d729 0:1904 1:80 13:160
8378cc242b355150 2:16 4:192 13:2768
8393fa9fc9b1a637 0:80 1:16 4:80
83badef66a026c4e 1:80 13:160
83ee75623aa81e9a 13:160
84ec21ece3b5f93f 4:192 13:2768
862f4e924ef2931d 0:64 1:16 4:112
8682158094645e50 13:368
868b63cdf2e00113 2:16 4:192 13:2768
8698df5dfeb8d544 13:288
876c17d32e40fcc0 0:64 1:16 4:112
87812d8e3fea6240 13:240
87a0b64f386e2f48 1:64
88185a3d20c0b7b3 0:48
881f2b21dade164b 0:1904 1:80 13:368
88d767d663df8369 0:80 1:16 4:112
890671ec1c58d860 1:80 13:176
892ef45238e6139b 0:64 1:16 4:112 13:368
89891eabe54feb48 0:1904 1:80 13:160
8a4d27d1abc25239 4:192 13:2768
8b27c197c8a99d04 1:80 13:368
8b917f45ef866149 0:240
8b9ceaa3fd78f94d 0:208
8c3cdf4d7980c929 2:16 4:192 13:2768
8c7ecf1867ee7745 0:160
8d7b8aac7c3e458c 13:240
8e21cfdcc960fbcc 2:16 4:192 13:2768
8ec24135955a6184 0:320
9040dcd5171e3bea 0:128
90b21c4032406dcd 0:224
90db03a33353717d 12:64
910e1e3beb86a3e2 0:64 1:16 4:112
9137311b2d7c9ad7 0:192 12:64
91dfd159ac1467cb 0:320
9204295a3ffb0607 0:96
932b9fef87b605fb 0:192 12:64
94493455bc6c52af 13:288
9451af39e4a54358 0:96 1:16 4:112
946a7c2c6d2bc4f0 13:288
94a6dcc6311af787 0:208
952ecd6fcb3885d8 0:1904 1:80 13:368
95405b8f9257e987 0:1904 1:80 13:368
954f082c4e31acb4 13:368
955fecb9caa5c59a 1:80 13:160
95fc0eecb5d5694c 0:336 1:80 13:368
960299b97cb48b5e 1:32
9644447135c794af 2:16 4:144 13:288
964edbea4a852e35 0:272 1:64
9664bd8e4a677425 0:80 1:16 4:112
968c43b11286bb9f 0:96 1:16 4:112
96c1cc6962e78cec 13:240
96c36820dd97d0dd 13:288
96d29cfddd6730a5 12:64
97a9a455aef6ec80 0:160
97d0858d2861a5a3 2:16 4:192 13:2768
98bebb02dc6760d4 13:240
98d5b4f928be9df8 0:96 1:16 4:64 13:368
99ac30542b10a587 0:32
99cb04ae8d0485c3 0:80 1:16 4:112
9a1a3516b416471a 0:96 1:16 13:368
9a7fe795da700655 0:592
9a909735d9ba1aea 0:80 1:16 4:80
9a97bc2bc8da87b3 2:16
9b588c01a4a0552c 13:368
9c41dee31f9dd507 4:144 13:240
9d06a897896c4406 0:320 13:160
9d071ac8c1ad7fff 0:80
9d10049ad94a723c 0:96
9d4cb74596316043 1:80 13:368
9e52ae3fd8ce5931 0:1904
9e641b1a149809b0 13:160
9e8d0f978c50f5ec 0:64 1:16 13:368
9e9a4cbbce6b5989 1:80 13:160
9eec816e90054180 0:128
9fa9e192bf0d940c 1:80 13:176
9fbdb671c065b029 4:192 13:2768
a05e50da03818a3e 1:80 13:368
a0a7b4504253c250 13:288
a0b16dc3fd19ec28 0:1904 13:368
a0c08c3dcd1610e9 1:64
a10f747bf02dd679 4:192 13:2768
a161aa477f9b5ff4 13:240
a296958ec33de2c6 0:96 1:16 4:112
a2bff07f519914f0 13:240
a2d43f1cbc503e1f 0:64 1:16 4:112
a3ebc4e92e1c24fd 0:2064
a4ccb368846ce4c6 0:208
a5659569335af3b7 4:192 13:2768
a61d46af96db2e03 0:160
a621f8c9d891e2c7 0:80 1:16 4:112
a62f428b10a4dd40 1:80 13:160
a68ef2ae82efe989 4:192 13:2768
a6bafda23cdd2c01 0:320
a6c70a8b3bec32a8 2:16 4:144 13:288
a6cbedc8dae81d3b 0:64 1:16 4:112
a720c8bf0b1eb77d 0:160
a7d3eb68c93e77c7 0:160
a80161416ae4089d 13:288
a865b4f477c1d6b8 1:64 13:368
a890c3a180606eb8 0:96 1:16 4:80
a8e9b32f805036e5 0:336 1:64
a91aa1213a5aedba 2:16 4:192 13:2768
a9bf7470e2fad37c 0:112
aaddc37431adf19f 2:16 4:192 13:2768
abd2312f21636325 13:288
ac35a63615eb5fe6 0:1904 1:80 13:368
ac3ad93eccfd6081 0:240
ac6dea3227be07a9 2:16 4:144
ac87699e1f3ab8cf 0:112
acda869417b7a59c 2:16 4:192 13:2768
ad6eb2b7ea4f69b5 2:16 13:240
adc7a33f678ae433 0:320 13:288
ae1aeb9889c29fa4 0:320 13:288
aea4a1ec55b1f487 1:80 13:160
afb7a89e47c0c6af 0:1904 13:368
b10316f74f5492e2 0:336 1:80 13:176
b138aa31ff10b5f6 0:80 1:16 3:80
b148a2e31b0f9c7c 12:64
b18e57feacfd9f8d 12:64
b1fc882e248dd361 2:16 4:144 13:288
b336d3c4c49dcf3f 1:64 13:368
b348f28e7c5d1db4 0:320
b4836acd9a223438 4:192 13:2768
b4a331141ff0f388 0:96
b56e967305958a3c 0:1904 1:80 13:176
b5b3a75d5922471e 2:16
b5f13902c9ece469 13:288
b6407d8089c65b4a 2:16 13:288
b669d711c7213dfe 0:336 12:64
b6969c79fe2b954a 0:112
b69e1d39e335537b 0:96
b6af8657f766f967 0:320 13:288
b6f9a30612be37f9 0:192
b906d3a4a34ee750 1:80 13:368
b9357b88726f2f11 4:144
b94977a9fd877777 13:160
b97c703a0c8f34b7 0:1904 13:368
b983170ff0fbf0aa 0:80 1:16 4:112
b986067db0478ca1 13:160
b9a682c336cef810 0:1904 1:80 13:160
b9aef45ceed3a383 2:16 4:192 13:2768
ba335dc18c2f3e30 0:80 1:16 4:112
bbb3342e0b1b5359 0:320
bcbd9e943b56e0df 0:1904
bce015ea372217c5 0:128
bde9d97585eeecac 13:144
be370f06c37f487a 0:160
be66c83c7a8b1953 4:192 13:2768
be7228b37b341ece 1:80 13:160
be811c75cd4f797f 12:64
be9878db26b9f59f 0:160
beaafe2c6e95c93c 1:64 13:368
c0a082621ee59964 2:16 13:240
c0faef7c67715d4b 0:304
c10272c5fe59f478 0:288 13:368
c1b170b990c90ae3 0:1904
c1c5ec50ec09752f 0:1904
c1da6fb76bbb945a 0:320 13:240
c25d49635e691ab8 0:1904 1:80 13:368
c3bcdbfaff1f821e 0:240
c3cefa0ef6765996 13:144
c57463065d7fc12a 1:80 13:368
c5a1db84cc484193 2:16 4:144 13:288
c5c5150ac8e5ddc2 2:16
c684f5e2831c26f8 0:320
c6981da4a8a4231d 0:320
c6e74d5b96b2a9b9 0:96 1:16 4:112 13:368
c748e00e3f098ec3 2:16 13:240
c78266d47ce4a6e6 0:320
c7d10687f1fec5e6 0:1904 1:80 13:368
c7d5d9ba6c4c556d 1:32
c82c38faa5439f85 2:16 4:192 13:2768
c8ef856680691deb 1:64 13:368
c9491774a1fa7c0e 0:1904 1:80 13:160
c9ef0fcdc619f8a8 1:80 13:368
ca0ff630837275f6 13:240
ca1e8e4dc8ee46e8 0:64 1:16
ca41a02a5ff34d57 1:80 13:160
cac8c8837d11dc19 1:64
cacc367ed9b9b59f 2:16 4:192 13:2768
cb474a72243bae59 0:336
cb81f6d218f3babc 1:80 13:176
cce56c92e2006039 0:1904
cce69e11034510bb 4:192 13:2768
cd59bb7e15fe3be6 12:64
ce4adf04f3fce75d 0:176
cee7c1f5d45decbe 0:1904 1:80 13:368
cff7df07b8b7a949 4:192 13:2768
d030f91466a97a2b 0:288
d047388eb7a0d6c0 0:240
d062d8978d839eca 2:16 4:192 13:2768
d0747b5db7010662 0:96 1:16 4:112
d0fba5c88a6ad021 0:208
d1275371e06e539d 0:192
d147a874d995d079 0:96
d1bc0adc690b333a 4:192 13:2768
d28272643d6906ed 0:288 1:80 13:368
d38e714c1b376779 4:192 13:2768
d3988c83c2ed6522 0:320 13:240
d3af478e244d42d0 13:2688
d4369eedb6dbc67e 0:128 1:64 12:64
d485c105f171e9a9 2:16 4:192 13:2768
d49dbc75eb874280 4:192 13:2768
d4fb7b2f1bfaafeb 0:320 13:288
d50b237a8cd4b490 1:256
d5273f87dc2447cb 0:112 1:64 12:64
d547a708156058fd 0:1904 12:64
d555fca572db63c0 1:80 13:368
d5baa610ddf1d8dc 0:160
d623167f7aaff236 13:288
d66b2bf0ca4d8d99 1:80 13:368
d724f07bcc0b3ea2 0:1904
d773afc0b06d3334 0:320
d7e06ed10f6aeffa 4:144 13:288
d81999203ca8c2ba 13:288
d8672870ca5ec2d0 0:272
d99c2b313152b167 0:224
d9bd1d6903931958 2:16 4:192 13:2768
daa09ca1aefc87da 0:1904 13:368
dacb1a0303c7400b 4:192 13:2768
db30991486672cbe 0:2064
db30bc8dc757fc03 13:288
dbde49ce80239494 0:128
dbe59bbc08be74b0 0:80 1:16 4:112
dc1706074ee94ba0 0:96 1:16
dc1913b7423b2269 13:288
dc7e23921ede07a6 0:64 1:16 4:112 13:368
dcaca96d07536509 0:96 1:16 3:80
dd285934e902ecdd 0:80 1:64 12:64
dd63bff6133d182e 0:160
ddb159a9644f6486 0:320 13:240
de02569524ff804c 0:240
de674aadc76f9a4c 0:64 1:16 4:112
de82d5f529d3850f 0:1904 1:80 13:368
de9fdd1491f8f1af 1:80 13:368
ded22c2a18beaec3 4:144 13:288
dfb5058a40908e39 1:80 13:160
dfc13dee1219be5d 0:80 1:16 4:112
e163e64ffce467ca 0:304 12:64
e16db18046c16690 1:80 13:368
e1871737507bc29c 0:288
e1cb7c2d0d958dd2 1:80 13:160
e1cc9c2215442694 0:32
e1ce09cf71536ec0 0:1008
e1e9a5ddf3a54bfa 0:80 1:16 4:112 13:368
e22932bbf66f6aeb 0:1904 1:64
e2dbc95f27854c48 13:368
e34865342668e8c5 0:1904
e3a5a16c121eafd4 4:144 13:288
e3a8610ec4ba9fc6 0:1904
e45943977c868cbf 2:16 4:144 13:288
e45c4956a58b41c3 0:80 1:16
e4682699786919f3 0:336 13:368
e4ec47e63db966e8 0:1904 1:64 13:368
e5c827ed6dbac282 0:96 1:16 4:112
e7f38f5ff5f39bf7 0:2064
e80556c390d8a563 0:128
e8142918c4ee0963 0:320 13:288
e8d32c7319ab0540 0:32
e94a8606fdcc3cb8 13:288
e9a7e3179a9cd1fc 4:192 13:2768
e9d8fba810148eaa 0:1904 1:80 13:160
ea69c6fba6becbe8 4:144 13:240
ea7514a9dd3f5f62 1:32
ea8f896bd86a997d 0:320
eb6166b61a28b189 2:16 4:192 13:2768
ebbea3767437f264 0:320 13:288
ebcd512464db79f5 4:144
ebec8e0cf92da97c 0:1904 1:64 13:368
ebecb12e1a9163e0 0:64 1:16
ec503adf8210c554 0:80 1:16 4:80
ed092f9a172af2b6 1:64
ed9d0a999217d361 2:16 4:144
ee7ae7ef4ae4c028 0:48
ee98caab18503b7a 0:16
eefd20dad5a7b08a 0:112
ef300dd784340c34 4:144 13:288
ef323a6338db6c71 0:320
eff059cf1c0ae444 0:32
f09ee4f9c031897c 0:48
f1528b8c282af317 0:64 1:16 4:64 13:368
f1d399cb6802b1a4 0:96 1:16 4:80
f1f638d1d859cc61 0:160
f1fa64e81d7f9379 1:80 13:368
f2390a27574885bb 0:16
f2983b4ec002fac4 0:32
f2e3868276e465a7 0:144
f406c638e6ce73aa 0:1904 1:64 13:368
f5036d895bf95221 4:192 13:2768
f5650be1db2a97f9 13:240
f60f343439ab79b1 13:288
f62dfeb6dcdde0c2 0:96
f85664219babf3c7 2:16 4:192 13:2768
f86142aa00318401 2:16 13:288
f8cf171ceb721fe2 0:96 1:16 4:112 13:368
fa4c270c5660e4d8 0:288 1:64 13:368
fa918d47492767ec 1:80 13:368
fad8e21db86e0da6 1:80 13:160
fb9093bc49a5a108 0:144
fc18ecbf4168f637 0:336 1:80 13:368
fc1a4540d58457a7 0:192 12:64
fc4fb54243dc47f2 0:160
fcaf6e39b4f97c02 4:192 13:2768
fd2bd113912d8011 2:16 4:144 13:240
fd43d4110e9a4b93 0:2064
fe33a79e4e5cd5f9 0:128 1:64 12:64
feea3ea6b40dc9d9 2:16 4:192 13:2768
ffa69cca312c08b8 13:240
ffca0d0601277255 0:16
ffe1d3e915a20e65 0:1904 12:64
1 # chain b-601174f81d6a 2026-10-21T12:01:30+08:00
2 # shader key, then reg:bytes for each uniform slot whose reads stay inside its first bytes, and s<reg> for each storage slot it never writes (cb_extent.py)
3 0040f948baa144f4 0:1904
4 00870f86a49cf3b9 0:1904 12:64
5 0093b425acd3f401 2:16 4:144 13:288
6 00b73c6360ebc8a3 0:144 12:64
7 00f37717bf4bac4f 0:64 1:16 4:80
8 011944e3919d9086 0:320 13:288
9 0195aaa2774f7f94 13:368
10 01b67911b0eba290 0:96 1:16 4:112 13:368
11 01db2042ca1d750f 0:320
12 01f059409b9f67a6 0:112
13 01f5cb5257d9f97b 0:1904
14 0216f89788d5754b 0:304
15 0289d1c53871cfd8 13:288
16 02c1823e16d48275 0:192 12:64
17 02ca876f24e6ee00 0:336 13:368
18 034fd5775426fb0a 0:160
19 03fb9c7ed541610a 0:320 13:160
20 04b77059f98a3b78 0:64 1:16 3:80
21 051881873373d1da 1:80 13:368
22 05363af3087acda3 0:192
23 059b25011e019a1d 0:192
24 06481a7157e38253 0:112
25 06514574c231f3dc 0:1904 13:368
26 06e1ea4094189dba 0:160
27 0732be065f1ccb64 0:288 1:80 13:176
28 0803c807f16ba3d1 0:64 1:16 4:112
29 088b2410056cd167 1:32
30 08c29a91d2dec428 0:96 1:16
31 0972cb63d2599938 0:80
32 09792f3958306ae6 0:64 1:16 4:112
33 09d7ba33f95453a6 0:1904 12:64
34 0a2f043d53ce738a 2:16 4:192 13:2768
35 0a5a4fb79479e894 0:1904 1:80 13:160
36 0a6c03b820351de6 0:1904 12:64
37 0ac7bcd086662236 0:160
38 0bf3b0c8200753fc 13:288
39 0c07df41c7981b43 4:192 13:2768
40 0ca99e0593045cac 0:32
41 0d4d61c0a868f9a7 0:1904 13:368
42 0d6f1997de8db140 4:192 13:2768
43 0ddfcfcdcc3ddf9e 0:160
44 0e685e6294a6cbb9 0:1888 1:32
45 0e74ffd870215814 0:272
46 0ef727c7d38740c5 4:144 13:240
47 0f3f9e510179be23 0:112
48 0ffefa790db21654 13:368
49 1016abf3a39a6777 0:144
50 1037a2384ec6970c 0:48
51 10839897b2ae647d 0:64 1:16
52 1163a9f7c3d20076 2:16
53 1166cc27e685f802 13:144
54 11e0b14a9b1ac080 0:336 12:64
55 12f1b945891c5ccd 0:32
56 139b480e75a6c1ec 0:208
57 140accf5ff3960ce 4:192 13:2768
58 1420b58f7143823a 2:16 4:144 13:240
59 1459f681755b8ed1 2:16 4:192 13:2768
60 146a3716c4f9826b 0:288
61 14fa46d06cb79527 0:192 12:64
62 1549752359be9243 0:160
63 15f653b15298ad2d 2:16 13:288
64 16973133690146e6 0:160
65 16a74e9f2eb1e75e 4:144 13:288
66 1787a4f06b8a0102 1:80 13:368
67 17eca5cde94f7aa0 4:144 13:288
68 182310bcbaf83a29 13:288
69 1835add527114581 0:160
70 18890ab424a6d8b7 0:96
71 193839e199081fef 0:48
72 19a5120409cace01 0:240
73 1a28da408ff83ff4 0:96 1:16
74 1bf6bd9c542b5cd9 0:96
75 1c10ccd1d18c52ef 0:128 1:64 12:64
76 1d936fdedaeaec26 0:64 1:16 4:80
77 1da14272a93cd491 0:96
78 1e491ec218d183dc 0:240
79 1ed6df817c71028b 13:240
80 1f4a63b490f62a34 2:16 13:288
81 201b4d77416f979a 0:80 1:16 4:64 13:368
82 20a2ce4b867bf227 13:368
83 212650750751cbad 13:288
84 21448c3f9d89f216 4:144 13:288
85 2240a91ab3ac898b 1:80 13:176
86 22980b1ae5d2019e 0:272 1:64
87 23356e4eb828fb83 13:288
88 235b67cad9698821 4:192 13:2768
89 2432602e6a95c9b9 2:16 4:192 13:2768
90 2484e5994cef257c 1:80 13:176
91 25824022a2c6b470 2:16 4:192 13:2768
92 2668ed65546dee7e 0:32
93 26f78cd3aa4b8926 0:1904
94 26fa49ee946269b3 2:16 4:192 13:2768
95 27857033dddfde91 0:1904 1:80 13:160
96 2849e228f3a1df29 2:16 4:192 13:2768
97 285bd23319484bb0 1:80 13:160
98 28a54478ae1ca813 0:288 1:80 13:368
99 28f1d8f6fd56635e 0:96 1:16 4:112
100 28fd3e0769029b79 0:208
101 291d0488d9d84314 4:192 13:2768
102 2923044e32509c5d 13:288
103 29f2198cc62a4589 2:16
104 2a2ab3f137f2f816 0:320 13:288
105 2a7f04b0d3d60ce2 13:240
106 2b0757eb8ca43d70 0:96
107 2b4eee86e82db581 0:288 1:80 13:160
108 2bdf4c3fb6666f51 0:1904
109 2c5f640d1306cd67 0:1904 1:64
110 2cfe6de787c2a6bd 0:160
111 2d2533c0d817a29b 12:64
112 2d717589fd0904d6 0:1904
113 2de21173609569dd 0:80 1:16
114 2f64ecfbeb5ae4c2 0:192 12:64
115 2f763a93aae9ce99 0:80
116 30b45b0045b5b7a2 0:96
117 30de397838b07ff6 13:160
118 3100f6738db9f068 2:16 4:192 13:2768
119 318caf466b19bd3e 13:288
120 3195bdb152b7bb07 13:160
121 31d8cd9e425c28e7 0:1904 1:32
122 330a677ae5094609 0:80 1:16 13:368
123 339f73ba6e5b41f0 0:320 13:288
124 3490021606823f09 0:336 1:80 13:160
125 34d961561ff1327f 2:16
126 366a9a9aab88c22e 0:64 1:16 4:64
127 372bf5948213053f 0:192 12:64
128 3760c0afee65d856 0:320 13:288
129 3769521d23444ce4 0:192
130 377106c4d4c5ba1d 0:144
131 3771b9464681d485 0:336
132 378fc41a6fb740f9 0:48
133 37c8bcb74d398646 0:192
134 382ed7f5e7018312 0:64 1:16 4:112 13:368
135 383f8aabb836eb9d 4:192 13:2768
136 391de7f9e70f441c 0:48
137 3949ab9849265857 2:16 13:288
138 396ff9cf7f2a3801 0:320
139 3a19ad025b16f11d 0:1904 1:80 13:368
140 3a40f12f7ee5639d 0:112 1:64 12:64
141 3b73581d86c205fa 0:160
142 3c57cac8dab4f30d 13:288
143 3caec795d3d3bff1 0:288 1:64
144 3d38b9965c284bdc 0:32
145 3d4ac4ca90260022 0:1904 12:64
146 3d9cd4be9f3b5a2e 0:1904 1:64
147 3d9d2c26e744da49 0:1904 13:368
148 3dd8c00d3acc5ff6 0:272 12:64
149 3e8c65894c62edcf 0:80 1:16 4:112
150 3e9592ffd8ab389f 0:160
151 3f19991694c1b137 1:64
152 3f689fa3167ede95 0:64 1:16 4:112
153 3fc5f98e9bb2d280 0:320 13:240
154 3fd93343962695cd 4:192 13:2768
155 3ff941d5eece2395 0:1904
156 403a5758e49fbf9e 0:1904 1:64
157 4064c152d3890cac 2:16 4:144 13:240
158 40a0c914fd7f6675 0:320
159 40abd0c3805fded3 4:192 13:2768
160 40d75abc4deab1e5 0:336
161 40fc399fa393d3f2 2:16 4:192 13:2768
162 4194dcf325d08bbf 0:1904
163 41ad677d6e9b5780 0:160
164 420ed53c9f81b96b 0:96 1:16 4:112
165 4278d7860b7f1472 2:16 4:144 13:288
166 42c908bcacacab78 0:1904 1:80 13:368
167 43dce950e3ce9e00 0:1904 1:80 13:176
168 440d4449ff9ba011 0:1904
169 456f25b32b3251a5 1:80 13:368
170 4612a2438a1ae4d2 2:16 4:144
171 46780f757806d67d 13:368
172 4687812fcc097f4a 0:320 13:288
173 47629ffac9999ad4 0:192 12:64
174 499bee5c432ebce8 0:64 1:16 4:80
175 4a1794705ca53384 0:288 13:368
176 4a671745ba6531d9 0:96
177 4a7231ce50ac4458 0:288 1:80 13:368
178 4a75def0fc2737bc 0:1904
179 4abc7b9d65a714ad 4:192 13:2768
180 4b148d6596f3d23a 1:80 13:368
181 4b33aac14cc96596 0:288 1:80 13:160
182 4b7f451b92e9d9fa 0:80 1:16 4:112
183 4bf525a99134ebcf 0:1904
184 4c960fa2c25b109d 4:192 13:2768
185 4cfa0ce6a7fe1079 0:96 1:16 3:80
186 4d80a86e517151f5 0:160
187 4dd9c2e6a40c0394 0:96 1:16 4:64
188 4eac8f4c27d2c3e8 1:80 13:368
189 4ef43b090d4aa792 0:208
190 4f14b5d6cb6e8516 0:96
191 4f5acb13923bf8d0 0:1904
192 4f6927becce1f051 2:16 4:192 13:2768
193 4f914211462adb63 0:336 1:32
194 5020390f0855186a 13:368
195 50d5a361e2cbcf68 0:240
196 51ac57eb5f67fedc 0:1904 1:80 13:368
197 51c19c739e594d19 0:320 13:288
198 53b13bbb24694389 0:96
199 53bac653c73c418a 1:80 13:368
200 53d9cd70a28ee776 0:64 1:16 4:112
201 53f25eb27c4fe13c 0:1904
202 542af76c0f7f6331 0:240
203 5482dc93a27cf699 1:80 13:160
204 54b5c405d9816d26 13:288
205 553b071e8012918d 1:64
206 555d1d604a71abce 0:80 1:16 4:64
207 55afd0aca24c0419 0:64 1:16 3:80
208 55ea27cee5554264 0:320
209 5630fc0cbd15d4ed 13:288
210 5664a33faa83fd33 4:192 13:2768
211 568ff969a753e58c 2:16 4:144
212 56e5dbc3e071f016 0:320 13:288
213 573f306c6d82a2a7 13:288
214 57d4fd6e75bddc11 0:64 1:16 4:112 13:368
215 58258b4cece0dd8a 0:96 1:16 4:80
216 58915ad3486f4c58 0:1904 12:64
217 59439742561f60a1 0:320 13:288
218 59672edd5f258046 0:336
219 596d41d48b634aff 2:16 4:144 13:288
220 5a40c4889fe10994 0:1904 1:80 13:176
221 5a7902803b87d628 0:112
222 5aaf2555837387a2 0:64 1:16 4:112
223 5b5254fa605c9448 0:96
224 5b6a1b16861461f7 0:80 1:16 4:112 13:368
225 5b83ea06a6982c94 0:80 1:16 4:112
226 5bfd4ece6f0a0196 12:64
227 5c3c40c319b617fe 2:16 13:240
228 5c44c76019a7d1ec 0:336 1:64 13:368
229 5c7688eb040aa639 0:320 13:160
230 5d71ed0f2686224f 0:80 1:16 4:112
231 5d83bf515bb746c2 0:1904 13:368
232 5e8f30c04b6d74d8 0:1904
233 5f77b3888494b325 0:240
234 5fb685c49afc65d1 13:288
235 609279b3b1e48f3e 13:160
236 6098ad0051905c99 0:96 1:16 4:112
237 60d4c4ad76e48d5a 0:64
238 60d928216c2a1605 0:320
239 6119e2affa309a00 0:128 1:144 2:16
240 613211a136a1cf52 0:80 1:16
241 615cff6a5adcc5eb 13:160
242 6251be1afb429c0e 0:80 1:16 4:112 13:368
243 633e60fdef1e18ef 2:16 4:144 13:240
244 63fb8375bf0a966e 13:2688
245 6441a8afa1af6d3b 0:16
246 648171746e615511 0:320 13:160
247 64f095d6ad432cb6 2:16 13:288
248 654c7d071ded3f97 0:96
249 656da77697f3452e 0:224
250 65a051853eeba404 0:320 13:240
251 65d39061656b3ac6 12:64
252 67225779b9b79641 0:128
253 6745353ff6a61b06 13:240
254 67644fc5976390b9 0:1904 12:64
255 67a69e3417fb3354 0:96
256 67fa3164f2b2b54f 0:96
257 683bb6316a7ae2aa 0:80 1:16 4:112 13:368
258 688d2affa94b39e2 4:144
259 68c8cd907318f7d0 0:240
260 68cfd018dfcee1bc 0:320
261 697e3ab9dcf2464f 2:16 4:192 13:2768
262 69e6dcdb6d8d00e5 4:144 13:240
263 6a08c33a0239e639 0:320
264 6a24f57943c4ec67 0:96 1:16 4:112 13:368
265 6a502c6cd5bfabf4 0:1904 1:64 13:368
266 6a593450bb293e26 0:160
267 6add555f75b69aaf 4:192 13:2768
268 6b07b70e665775fd 0:1904 1:80 13:160
269 6b400d24e283fb89 0:96 1:16 4:80
270 6be5bba922b9b7dc 0:64 1:16 4:80
271 6c3b4678d1b4fbf0 0:320 13:288
272 6c477ce4fb255429 13:368
273 6c5a06abbf8385ac 13:368
274 6cf96e7eb288d0e5 0:1904
275 6d1106cc9e332d9a 0:336
276 6d7cf4c78dbabd40 0:96 1:16 4:112
277 6eef6583df6b6c50 0:336 1:80 13:368
278 6f120567ffd086a8 0:80 1:16 3:80
279 6f551ccdb24ec54a 0:320
280 6f867edbd352fa3f 0:320
281 6fed094f83ec834c 13:368
282 7018eeb2ade4406c 12:64
283 703cb25e0ea3ca8f 0:1904
284 706b36197ad381dd 4:144
285 70d126e8a37083f7 0:240
286 7115d177d5bead87 0:1904
287 713048c1a4d9c9b6 0:1904 1:80 13:368
288 717ddb7e3e3ca319 0:1904
289 71fd0ce3ce52829d 4:192 13:2768
290 7204b5c9cdf6a2d9 2:16 4:192 13:2768
291 72093b96f7b0c189 2:16 4:192 13:2768
292 72249a39fa56c6ae 0:144
293 7297cf79a8131e27 0:96
294 72aed5a33cd82126 0:64 1:16 4:112
295 732a18f5dee4bafb 0:160
296 73952b7e6005b452 2:16 4:192 13:2768
297 749e645455b4d6f9 0:96 1:16 4:112
298 7590b8fad1f79f5e 0:320 13:240
299 75f1ce743e36beb0 1:80 13:176
300 766b37a4dc8c15ec 0:336
301 777f203ce7bb39c2 0:320 13:240
302 77e107589a6aec66 0:320 13:240
303 77f37072c47af3bb 12:64
304 781fe6d04a9719bd 0:32
305 78878b5627402d1b 0:96 1:16 4:112
306 793af3323431348c 0:192
307 79da88ce1d76a5d2 13:288
308 7a537520dd53b0e4 0:96 1:16 4:112
309 7adec5f9978a5c86 4:192 13:2768
310 7b39574d6126ebab 2:16 13:288
311 7c073b91c37e838d 1:64 13:368
312 7c2a95f22a5e64c2 0:112
313 7d95d243aea2b2cc 2:16 4:192 13:2768
314 7de9d89c30323513 2:16 4:192 13:2768
315 7e051b2bd08543ee 0:336 1:80 13:160
316 7e97419919fa57f4 0:320 13:288
317 7eefb9d8881d27a4 13:288
318 7f16b8534971d61e 0:1904 1:80 13:176
319 7f2a6b38040a9d23 0:208
320 7fe488f38f8c555e 0:160
321 800a2ae29d353701 0:1904
322 800dd083bb92a94a 2:16 13:288
323 8038764dd5c8c75b 4:144 13:288
324 804bc47a5a52c682 0:192
325 80a7cc64abb3d449 4:192 13:2768
326 80b8c29864a6abee 0:80 1:16 4:80
327 80e0798b12b23163 0:224
328 8218d54372531eab 0:16
329 8229d319cca04b38 12:64
330 825ad973231b45a7 1:64 13:368
331 82b68976b8f3d729 0:1904 1:80 13:160
332 8378cc242b355150 2:16 4:192 13:2768
333 8393fa9fc9b1a637 0:80 1:16 4:80
334 83badef66a026c4e 1:80 13:160
335 83ee75623aa81e9a 13:160
336 84ec21ece3b5f93f 4:192 13:2768
337 862f4e924ef2931d 0:64 1:16 4:112
338 8682158094645e50 13:368
339 868b63cdf2e00113 2:16 4:192 13:2768
340 8698df5dfeb8d544 13:288
341 876c17d32e40fcc0 0:64 1:16 4:112
342 87812d8e3fea6240 13:240
343 87a0b64f386e2f48 1:64
344 88185a3d20c0b7b3 0:48
345 881f2b21dade164b 0:1904 1:80 13:368
346 88d767d663df8369 0:80 1:16 4:112
347 890671ec1c58d860 1:80 13:176
348 892ef45238e6139b 0:64 1:16 4:112 13:368
349 89891eabe54feb48 0:1904 1:80 13:160
350 8a4d27d1abc25239 4:192 13:2768
351 8b27c197c8a99d04 1:80 13:368
352 8b917f45ef866149 0:240
353 8b9ceaa3fd78f94d 0:208
354 8c3cdf4d7980c929 2:16 4:192 13:2768
355 8c7ecf1867ee7745 0:160
356 8d7b8aac7c3e458c 13:240
357 8e21cfdcc960fbcc 2:16 4:192 13:2768
358 8ec24135955a6184 0:320
359 9040dcd5171e3bea 0:128
360 90b21c4032406dcd 0:224
361 90db03a33353717d 12:64
362 910e1e3beb86a3e2 0:64 1:16 4:112
363 9137311b2d7c9ad7 0:192 12:64
364 91dfd159ac1467cb 0:320
365 9204295a3ffb0607 0:96
366 932b9fef87b605fb 0:192 12:64
367 94493455bc6c52af 13:288
368 9451af39e4a54358 0:96 1:16 4:112
369 946a7c2c6d2bc4f0 13:288
370 94a6dcc6311af787 0:208
371 952ecd6fcb3885d8 0:1904 1:80 13:368
372 95405b8f9257e987 0:1904 1:80 13:368
373 954f082c4e31acb4 13:368
374 955fecb9caa5c59a 1:80 13:160
375 95fc0eecb5d5694c 0:336 1:80 13:368
376 960299b97cb48b5e 1:32
377 9644447135c794af 2:16 4:144 13:288
378 964edbea4a852e35 0:272 1:64
379 9664bd8e4a677425 0:80 1:16 4:112
380 968c43b11286bb9f 0:96 1:16 4:112
381 96c1cc6962e78cec 13:240
382 96c36820dd97d0dd 13:288
383 96d29cfddd6730a5 12:64
384 97a9a455aef6ec80 0:160
385 97d0858d2861a5a3 2:16 4:192 13:2768
386 98bebb02dc6760d4 13:240
387 98d5b4f928be9df8 0:96 1:16 4:64 13:368
388 99ac30542b10a587 0:32
389 99cb04ae8d0485c3 0:80 1:16 4:112
390 9a1a3516b416471a 0:96 1:16 13:368
391 9a7fe795da700655 0:592
392 9a909735d9ba1aea 0:80 1:16 4:80
393 9a97bc2bc8da87b3 2:16
394 9b588c01a4a0552c 13:368
395 9c41dee31f9dd507 4:144 13:240
396 9d06a897896c4406 0:320 13:160
397 9d071ac8c1ad7fff 0:80
398 9d10049ad94a723c 0:96
399 9d4cb74596316043 1:80 13:368
400 9e52ae3fd8ce5931 0:1904
401 9e641b1a149809b0 13:160
402 9e8d0f978c50f5ec 0:64 1:16 13:368
403 9e9a4cbbce6b5989 1:80 13:160
404 9eec816e90054180 0:128
405 9fa9e192bf0d940c 1:80 13:176
406 9fbdb671c065b029 4:192 13:2768
407 a05e50da03818a3e 1:80 13:368
408 a0a7b4504253c250 13:288
409 a0b16dc3fd19ec28 0:1904 13:368
410 a0c08c3dcd1610e9 1:64
411 a10f747bf02dd679 4:192 13:2768
412 a161aa477f9b5ff4 13:240
413 a296958ec33de2c6 0:96 1:16 4:112
414 a2bff07f519914f0 13:240
415 a2d43f1cbc503e1f 0:64 1:16 4:112
416 a3ebc4e92e1c24fd 0:2064
417 a4ccb368846ce4c6 0:208
418 a5659569335af3b7 4:192 13:2768
419 a61d46af96db2e03 0:160
420 a621f8c9d891e2c7 0:80 1:16 4:112
421 a62f428b10a4dd40 1:80 13:160
422 a68ef2ae82efe989 4:192 13:2768
423 a6bafda23cdd2c01 0:320
424 a6c70a8b3bec32a8 2:16 4:144 13:288
425 a6cbedc8dae81d3b 0:64 1:16 4:112
426 a720c8bf0b1eb77d 0:160
427 a7d3eb68c93e77c7 0:160
428 a80161416ae4089d 13:288
429 a865b4f477c1d6b8 1:64 13:368
430 a890c3a180606eb8 0:96 1:16 4:80
431 a8e9b32f805036e5 0:336 1:64
432 a91aa1213a5aedba 2:16 4:192 13:2768
433 a9bf7470e2fad37c 0:112
434 aaddc37431adf19f 2:16 4:192 13:2768
435 abd2312f21636325 13:288
436 ac35a63615eb5fe6 0:1904 1:80 13:368
437 ac3ad93eccfd6081 0:240
438 ac6dea3227be07a9 2:16 4:144
439 ac87699e1f3ab8cf 0:112
440 acda869417b7a59c 2:16 4:192 13:2768
441 ad6eb2b7ea4f69b5 2:16 13:240
442 adc7a33f678ae433 0:320 13:288
443 ae1aeb9889c29fa4 0:320 13:288
444 aea4a1ec55b1f487 1:80 13:160
445 afb7a89e47c0c6af 0:1904 13:368
446 b10316f74f5492e2 0:336 1:80 13:176
447 b138aa31ff10b5f6 0:80 1:16 3:80
448 b148a2e31b0f9c7c 12:64
449 b18e57feacfd9f8d 12:64
450 b1fc882e248dd361 2:16 4:144 13:288
451 b336d3c4c49dcf3f 1:64 13:368
452 b348f28e7c5d1db4 0:320
453 b4836acd9a223438 4:192 13:2768
454 b4a331141ff0f388 0:96
455 b56e967305958a3c 0:1904 1:80 13:176
456 b5b3a75d5922471e 2:16
457 b5f13902c9ece469 13:288
458 b6407d8089c65b4a 2:16 13:288
459 b669d711c7213dfe 0:336 12:64
460 b6969c79fe2b954a 0:112
461 b69e1d39e335537b 0:96
462 b6af8657f766f967 0:320 13:288
463 b6f9a30612be37f9 0:192
464 b906d3a4a34ee750 1:80 13:368
465 b9357b88726f2f11 4:144
466 b94977a9fd877777 13:160
467 b97c703a0c8f34b7 0:1904 13:368
468 b983170ff0fbf0aa 0:80 1:16 4:112
469 b986067db0478ca1 13:160
470 b9a682c336cef810 0:1904 1:80 13:160
471 b9aef45ceed3a383 2:16 4:192 13:2768
472 ba335dc18c2f3e30 0:80 1:16 4:112
473 bbb3342e0b1b5359 0:320
474 bcbd9e943b56e0df 0:1904
475 bce015ea372217c5 0:128
476 bde9d97585eeecac 13:144
477 be370f06c37f487a 0:160
478 be66c83c7a8b1953 4:192 13:2768
479 be7228b37b341ece 1:80 13:160
480 be811c75cd4f797f 12:64
481 be9878db26b9f59f 0:160
482 beaafe2c6e95c93c 1:64 13:368
483 c0a082621ee59964 2:16 13:240
484 c0faef7c67715d4b 0:304
485 c10272c5fe59f478 0:288 13:368
486 c1b170b990c90ae3 0:1904
487 c1c5ec50ec09752f 0:1904
488 c1da6fb76bbb945a 0:320 13:240
489 c25d49635e691ab8 0:1904 1:80 13:368
490 c3bcdbfaff1f821e 0:240
491 c3cefa0ef6765996 13:144
492 c57463065d7fc12a 1:80 13:368
493 c5a1db84cc484193 2:16 4:144 13:288
494 c5c5150ac8e5ddc2 2:16
495 c684f5e2831c26f8 0:320
496 c6981da4a8a4231d 0:320
497 c6e74d5b96b2a9b9 0:96 1:16 4:112 13:368
498 c748e00e3f098ec3 2:16 13:240
499 c78266d47ce4a6e6 0:320
500 c7d10687f1fec5e6 0:1904 1:80 13:368
501 c7d5d9ba6c4c556d 1:32
502 c82c38faa5439f85 2:16 4:192 13:2768
503 c8ef856680691deb 1:64 13:368
504 c9491774a1fa7c0e 0:1904 1:80 13:160
505 c9ef0fcdc619f8a8 1:80 13:368
506 ca0ff630837275f6 13:240
507 ca1e8e4dc8ee46e8 0:64 1:16
508 ca41a02a5ff34d57 1:80 13:160
509 cac8c8837d11dc19 1:64
510 cacc367ed9b9b59f 2:16 4:192 13:2768
511 cb474a72243bae59 0:336
512 cb81f6d218f3babc 1:80 13:176
513 cce56c92e2006039 0:1904
514 cce69e11034510bb 4:192 13:2768
515 cd59bb7e15fe3be6 12:64
516 ce4adf04f3fce75d 0:176
517 cee7c1f5d45decbe 0:1904 1:80 13:368
518 cff7df07b8b7a949 4:192 13:2768
519 d030f91466a97a2b 0:288
520 d047388eb7a0d6c0 0:240
521 d062d8978d839eca 2:16 4:192 13:2768
522 d0747b5db7010662 0:96 1:16 4:112
523 d0fba5c88a6ad021 0:208
524 d1275371e06e539d 0:192
525 d147a874d995d079 0:96
526 d1bc0adc690b333a 4:192 13:2768
527 d28272643d6906ed 0:288 1:80 13:368
528 d38e714c1b376779 4:192 13:2768
529 d3988c83c2ed6522 0:320 13:240
530 d3af478e244d42d0 13:2688
531 d4369eedb6dbc67e 0:128 1:64 12:64
532 d485c105f171e9a9 2:16 4:192 13:2768
533 d49dbc75eb874280 4:192 13:2768
534 d4fb7b2f1bfaafeb 0:320 13:288
535 d50b237a8cd4b490 1:256
536 d5273f87dc2447cb 0:112 1:64 12:64
537 d547a708156058fd 0:1904 12:64
538 d555fca572db63c0 1:80 13:368
539 d5baa610ddf1d8dc 0:160
540 d623167f7aaff236 13:288
541 d66b2bf0ca4d8d99 1:80 13:368
542 d724f07bcc0b3ea2 0:1904
543 d773afc0b06d3334 0:320
544 d7e06ed10f6aeffa 4:144 13:288
545 d81999203ca8c2ba 13:288
546 d8672870ca5ec2d0 0:272
547 d99c2b313152b167 0:224
548 d9bd1d6903931958 2:16 4:192 13:2768
549 daa09ca1aefc87da 0:1904 13:368
550 dacb1a0303c7400b 4:192 13:2768
551 db30991486672cbe 0:2064
552 db30bc8dc757fc03 13:288
553 dbde49ce80239494 0:128
554 dbe59bbc08be74b0 0:80 1:16 4:112
555 dc1706074ee94ba0 0:96 1:16
556 dc1913b7423b2269 13:288
557 dc7e23921ede07a6 0:64 1:16 4:112 13:368
558 dcaca96d07536509 0:96 1:16 3:80
559 dd285934e902ecdd 0:80 1:64 12:64
560 dd63bff6133d182e 0:160
561 ddb159a9644f6486 0:320 13:240
562 de02569524ff804c 0:240
563 de674aadc76f9a4c 0:64 1:16 4:112
564 de82d5f529d3850f 0:1904 1:80 13:368
565 de9fdd1491f8f1af 1:80 13:368
566 ded22c2a18beaec3 4:144 13:288
567 dfb5058a40908e39 1:80 13:160
568 dfc13dee1219be5d 0:80 1:16 4:112
569 e163e64ffce467ca 0:304 12:64
570 e16db18046c16690 1:80 13:368
571 e1871737507bc29c 0:288
572 e1cb7c2d0d958dd2 1:80 13:160
573 e1cc9c2215442694 0:32
574 e1ce09cf71536ec0 0:1008
575 e1e9a5ddf3a54bfa 0:80 1:16 4:112 13:368
576 e22932bbf66f6aeb 0:1904 1:64
577 e2dbc95f27854c48 13:368
578 e34865342668e8c5 0:1904
579 e3a5a16c121eafd4 4:144 13:288
580 e3a8610ec4ba9fc6 0:1904
581 e45943977c868cbf 2:16 4:144 13:288
582 e45c4956a58b41c3 0:80 1:16
583 e4682699786919f3 0:336 13:368
584 e4ec47e63db966e8 0:1904 1:64 13:368
585 e5c827ed6dbac282 0:96 1:16 4:112
586 e7f38f5ff5f39bf7 0:2064
587 e80556c390d8a563 0:128
588 e8142918c4ee0963 0:320 13:288
589 e8d32c7319ab0540 0:32
590 e94a8606fdcc3cb8 13:288
591 e9a7e3179a9cd1fc 4:192 13:2768
592 e9d8fba810148eaa 0:1904 1:80 13:160
593 ea69c6fba6becbe8 4:144 13:240
594 ea7514a9dd3f5f62 1:32
595 ea8f896bd86a997d 0:320
596 eb6166b61a28b189 2:16 4:192 13:2768
597 ebbea3767437f264 0:320 13:288
598 ebcd512464db79f5 4:144
599 ebec8e0cf92da97c 0:1904 1:64 13:368
600 ebecb12e1a9163e0 0:64 1:16
601 ec503adf8210c554 0:80 1:16 4:80
602 ed092f9a172af2b6 1:64
603 ed9d0a999217d361 2:16 4:144
604 ee7ae7ef4ae4c028 0:48
605 ee98caab18503b7a 0:16
606 eefd20dad5a7b08a 0:112
607 ef300dd784340c34 4:144 13:288
608 ef323a6338db6c71 0:320
609 eff059cf1c0ae444 0:32
610 f09ee4f9c031897c 0:48
611 f1528b8c282af317 0:64 1:16 4:64 13:368
612 f1d399cb6802b1a4 0:96 1:16 4:80
613 f1f638d1d859cc61 0:160
614 f1fa64e81d7f9379 1:80 13:368
615 f2390a27574885bb 0:16
616 f2983b4ec002fac4 0:32
617 f2e3868276e465a7 0:144
618 f406c638e6ce73aa 0:1904 1:64 13:368
619 f5036d895bf95221 4:192 13:2768
620 f5650be1db2a97f9 13:240
621 f60f343439ab79b1 13:288
622 f62dfeb6dcdde0c2 0:96
623 f85664219babf3c7 2:16 4:192 13:2768
624 f86142aa00318401 2:16 13:288
625 f8cf171ceb721fe2 0:96 1:16 4:112 13:368
626 fa4c270c5660e4d8 0:288 1:64 13:368
627 fa918d47492767ec 1:80 13:368
628 fad8e21db86e0da6 1:80 13:160
629 fb9093bc49a5a108 0:144
630 fc18ecbf4168f637 0:336 1:80 13:368
631 fc1a4540d58457a7 0:192 12:64
632 fc4fb54243dc47f2 0:160
633 fcaf6e39b4f97c02 4:192 13:2768
634 fd2bd113912d8011 2:16 4:144 13:240
635 fd43d4110e9a4b93 0:2064
636 fe33a79e4e5cd5f9 0:128 1:64 12:64
637 feea3ea6b40dc9d9 2:16 4:192 13:2768
638 ffa69cca312c08b8 13:240
639 ffca0d0601277255 0:16
640 ffe1d3e915a20e65 0:1904 12:64
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+997
View File
@@ -0,0 +1,997 @@
# chain b-ef65926816d8 2026-10-21T12:01:11+08:00
# shader key, then reg:bytes for each uniform slot whose reads stay inside its first bytes, and s<reg> for each storage slot it never writes (cb_extent.py)
003b38fe9b3627ba 0:192 2:64
00500b94cf88443d 0:1168
00516aa1e784d9e0 0:576
0076e7956282bfc5 0:208 2:64
0094ff5d3f9cc5d8 0:1168
0095d8689baf5ec7 0:464
00c32c2411fbbe03 0:112
00e1833e9ac78892 0:1152
00e453d026d2fc05 0:528
00fe118ffda2ee0c 0:192 2:96
01055d415502eaa6 0:1264
012068e325b0b4c3 0:432
01a48390c89957a4 0:656
01bb2e2343daaa92 0:1184
01c79a49c01ab882 0:512
02295512bae1fd1b 0:512
024d83528f550fbe 0:112 1:256 2:128 3:64
02503a8189808d47 0:592
02a939263d583ed5 0:208 2:64
035e6a2b6d644d19 0:192 2:64 3:32 4:32
0365c6f2bc598f38 0:192 2:96 3:32
0366b4fb9baa6bf0 0:192 2:64 3:16
03d7e7a2efac8a2f 0:464
03f12c555d184617 0:480
0459b351d841fc2b 0:544
045a54bb20e3750f 0:864
051c001a5ba37928 0:480
05251d2037611165 0:208 2:96 3:16 4:16
0558bceeac0c3e90 0:192 2:64
05d7c93d306ce7b0 0:592
0664bf4cf905428d 0:1168
0665288c892231e9 0:1184
069b1843c4a4bb52 0:192 2:16 3:80 4:32
070e1d7aaac06775 0:544
07c8fcc6d480f88f 0:512
080f05eeb6d4ac45 0:448
08163380d49d7720 0:192 2:16
08330cc9f09f4749 0:1264
08ee2b1ba6ea5b4a 0:448
09457a6ed8ef5d96 0:128 1:256 2:128 3:64
094c296cbfc656d5 0:208 2:64 3:32 4:16
095fe9b06dd8a7ae 0:208 2:64 3:80 4:16
0a403f6b9ebe470f 0:448
0b102b779013d112 0:464
0b75021f6c2322c1 0:208 2:16 3:64 4:16
0b974083af053985 0:1152
0bb91b311d5d5eda 0:112 1:256 2:128 3:64
0bfb16c2a111868c 0:192 2:64
0c2665b73acdc30a 0:1152
0c41eeee4a5854d6 0:192 2:16
0d3958f2ada85e8a 0:1248
0d52e6465405bdc4 0:208 2:64
0d67b375c8c9aff7 0:528
0dcdec77cec91e17 0:192 2:64
0de7e38975573b0f 0:1184
0e41205fbc497a08 0:48
0e7ef57fa0c54855 0:80
0ed3a9552a557ba0 0:528
0ef46c960dd2115d 0:592
0f571d1e58930bfe 0:192 2:64
0f600befccd3f827 0:448
1001e21246f626fe 0:1168
101dded719fcb9ca 0:208 2:64 3:32 4:16
1053586ba2440c56 0:192 2:64 3:16
1078cfc1b36b5a5c 0:496
10985418584072e1 0:400
10a1a81f8e80d54a 0:208 2:64 3:16 4:16
10c0666c52203a43 0:1200
10ddd89f8f885f85 0:208 2:64
10f5730dc1545780 0:480
112d8391b4a78890 0:128 1:256 2:128 3:64 4:64
1150d5d28be3ac67 0:192 2:64
11ecba96b9b277d1 0:208 2:16
12459b0fd95239d8 0:208 2:64
127ecd713e1c3ddf 0:208 2:64 3:32 4:16
12814fde4abb727d 0:1232
12b0ba3856f9ffdb 0:512
12e44e9ceb25155e 0:1264
131f31c5cdeb4423 0:1264
13b3ce7083269906 0:1232
13ea95cc4d0d7b10 0:1216
1469448cdce0e18d 0:592
1497a509b3e92394 0:512
14c5beb649a944c9 0:1184
14e7e37bfa93b6c7 0:208 2:64 3:48 4:16
1595632bdcedf218 0:496
15acb74d525be21d 0:192 2:64
162fcd8fb03b4054 0:192 2:64
165f62a9bbaf9cc3 0:528
1660c5f8f510f559 0:608
1662ef4aa0380b63 0:528
16785a240276ff55 0:208 2:16
1704eece77a4d2f5 0:192 2:96 3:80 4:32
181de1508dda74e0 0:528
189e26dc3b0012f2 0:496
18c802f27e644ef3 0:432
1a453e95678d140c 0:496
1ab913acba0f8698 0:1200
1af54ac857775e4e 0:496
1afd338e220f30dc 0:560
1bb807d790e7d27a 0:512
1c964ca95773b64b 0:1168
1cb0c3bae54a58de 0:192
1cc713a86aa7139f 0:480
1cde87f3c5223512 0:192 2:64
1cfcd3c2f0b78130 0:208 2:16
1d3612b6a2602722 0:464
1d58747aebc18d8f 0:192 2:16
1dc3e13c16f61a8a 0:400
1dead970396c0191 0:464
1e1f880fbdedc76d 0:208 2:64
1e2d2e2c80828aad 0:1168
1e377f4acd9f7393 0:208 2:16
1e7cc5e42b776b8f 0:192 2:64
1ea4b2af5ab33987 0:1152
1ecfb702217db62d 0:800
1f28ef4492e54f2d 0:1264
1f3f2e3949a3c47d 0:1232
1f6ba53e9c2536c6 0:480
1f9a00f83e3802e8 0:192 2:64
1ffb268e982f32cd 0:528
204a23a3dc28b378 0:304
213d958a59c7d065 0:208 2:64
2167d71ea19b9058 0:592
220caf1e0b940346 0:208 2:64 3:16 4:16
2264d9a055b86750 0:192 2:96 3:80 4:32
22eacc2235befd8d 0:528
22f0b85b580053cf 0:1232
22fbc2f8ad586e60 0:592
2304bd067704251a 0:1152
2307bab6e11d6ca4 0:480
230d810c58a5fcf4 0:96
231cd7e544d26f65 0:496
231f987c2add65a7 0:448
235c1dd4ecd02dce 0:464
23b3c7dd957c8632 0:1200
2417eee0219abdea 0:576
24596ad96cdfc268 0:448
245b7bce27997afb 0:464
247cf1f1dc95d691 0:784
24cb3fc88280af15 0:112 1:256 2:128 3:64
24ece705db8a781c 0:1248
256622a5b64d2098 0:208 2:64 3:16 4:16
25b6fb9d1f20875e 0:192 2:64 3:48 4:32
25eb204602f5be51 0:208 2:64 3:16
25f77c6ba0ec8295 0:512
25fa5ba6c60c199c 0:800
261dc6cae8a0d7b1 0:544
262dc000f3349e00 0:256
26577edc5675379f 0:208 2:64 3:16 4:16
268dade08b3e726c 0:1152
269f3ed401c155d8 0:1184
26b2a36b5680e959 0:448
26b8bd86580e3270 0:1168
27e40fa36dec84a9 0:192 2:16 3:96 4:32
2850fc54dffd4108 0:192 2:64
2851fc507359a21b 0:208 2:64 3:16
2856edf0f52b0419 0:1200
28613b62bb1ef308 0:208 2:96 3:64 4:16
287e7705325f5303 0:1232
28995d282b955899 0:1200
28bad575151ef721 0:592
28da3486bb8ed432 0:192 2:64 3:144 4:32
290101b2578ae6d2 0:208 2:64
2919566fbd54eab7 0:208 2:16 3:64 4:16
29babf3d9ce5de24 0:528
2a30f4df98604d2a 0:208 2:64
2a4a49116f52dbce 0:208 2:64
2a4d294aa05bad0f 0:208 2:64
2a9eb2bccda4f423 0:1152
2ac0460dcfead30f 0:192 2:16 3:96 4:32
2ae4cf047ba58f85 0:512
2b051de5cddce7c1 0:480
2b19d7bb67e00d50 0:80 1:256 2:128
2b3b688f619c8966 0:1232
2bd85efd2691eb6e 0:400
2c2736740611bfc8 0:208 2:64
2d0dcfc6e3be3fb1 0:192 2:16
2d2b40d01da208c4 0:192 2:96 3:32
2d517e0124d944d2 0:192 2:96 3:64 4:32
2d53ce7ac44372e9 0:208 2:64 3:16 4:16
2dc9d4b1f56f379a 0:208 2:16
2e185900917f606c 0:208 2:16 3:32 4:16
2ed56b2d1555131b 0:480
2eeddb2e6689a650 0:208 2:16
2f39398d19b37151 0:1264
2f800d95bf716ac0 0:624
2ff18bebd5c4f8a9 0:208 2:64
306ed34b0f6fb2f9 0:208 2:64
30c4659e2d5d060d 0:400
30f7411bfa6d533c 0:192 2:64
30fe33bf65df7390 0:208 2:64
31297697572dcb6b 0:192 2:16 3:32
31715dc852392279 0:592
33b954292864ebd5 0:208 2:64
33c8135008748347 0:464
34388df8dfdc1310 0:192 2:16
35294b44e8850b68 0:1168
353f48d7ac006fc2 0:464
3564ed1b55346d1c 0:544
3566a7febe9aaf69 0:528
35826c17c45a8233 0:192 2:64
358c65dbdcc9bf4b 0:448
359179047c54ab6a 0:208 2:16
35c6656939defe10 0:528
35dfcc9f26812196 0:528
35ffa4b26138cc5c 0:1328
364e8b47058223f6 0:464
36598bd7ee5eb050 0:208 2:64
3659fef557b0ef7f 0:1248
37110d689802476f 0:192 2:64
3741f56ef3481f65 0:480
37944f7cf5a3ecc9 0:496
37f802c38c01fc47 0:208 2:16
386c5042f82b2a16 0:1168
3891d01a7b0a9206 0:528
38e0b2442ddfa8c5 0:1200
39162c78afb0fd6e 0:528
3922eb98d8191b6a 0:192 2:96
39f2d7189c0841fb 0:192 2:16
39fd4958fb3959b5 0:1248
3a0ffe970e2a3d35 0:192 2:64
3a366f1c92e74949 0:1216
3a4728dffa05259d 0:1248
3b71f34c64339f7e 0:1200
3bc5f3dd1c0a3c17 0:608
3bc606b31493d8d4 0:1248
3c7fff3a699f1052 0:544
3cc872702f77cc07 0:1184
3cf35cb9b34cddd4 0:192 2:16 3:16
3cfcd51c2c8cd36d 0:608
3d1a5e53ec2d679c 0:496
3d48809101022a4d 0:1168
3da87a93a8f9b236 0:576
3e2d388d6f915dce 0:208 2:64
3e348fa5650023ec 0:192 2:64
3eb12a4f23c09c41 0:208 2:64
3f103f005885994f 0:192 2:96 3:80 4:32
3f41b972176e242f 0:208 2:64
40288ae9363ef277 0:208 2:64
402c4196c5998bc6 0:432
409b745e966fed89 0:448
40e3812dce5e0185 0:1200
413da19d1e25356b 0:192 2:64
42e1ccc71b18442f 0:592
42e486c09fcccc07 0:208 2:64
43ad6c7c431e1b0c 0:32
43bfc11f1f3d55f7 0:1152
43c7e5c266125d57 0:192 2:16
4406298b845a3773 0:512
44173a3a3f049ce7 0:208 2:64
4449939ff05e42f7 0:208 2:16 3:48 4:16
4467d56e6592a3c1 0:448
446e26a167ccc2fb 0:208 2:96 3:64 4:16
446e27fbda0c678c 0:528
4501d34633dd2b4b 0:192 2:16
45066194a2e4bac4 0:208 2:64
452fd9681da7d8aa 0:1184
455d1d2f1a12f495 0:1184
4584a1f8f055dacc 0:208 2:16
459614e6566470a7 0:192 2:64
45a9f0d7ae592881 0:528
45b1a54935ceb2c3 0:48
45e96bef912ad310 0:208 2:16 3:64 4:16
460775513b16e335 0:1184
46163e5ef930f3b3 0:192 2:64
46f0c14e38986d84 0:1168
473d71e1f053748d 0:544
47a6f465106a8587 0:800
48163fad9263ed89 0:208 2:64
48a3e32fb70e711f 0:544
49689cfb9bce7463 0:464
4a25baca5a170ec6 0:208 2:64
4a5f8a1a29d1629b 0:1232
4a745ca5af81e2a1 0:512
4aa4baef97a82ec2 0:208 2:64
4ab570ca0816d510 0:208 2:64
4aef3b7d38a5eee4 0:208 2:96 3:16
4b13c1a85b5459e2 0:1200
4b5ad2f60e79990e 0:1200
4bbf98d3631a0d1a 0:784
4bf4acd4f3bba426 0:208 2:16 3:32 4:16
4c0624731bf19b5d 0:528
4c11452c5abce0b5 0:512
4c9d2e35d6d58dd3 0:192 2:64
4cb3eb4a9ee9e0af 0:192
4cb4b3b6177bc6ec 0:1168
4cea0257728b2574 0:1312
4d2ed23be38fe357 0:1216
4d9b38377404ef5b 0:528
4da44afa7db29e5f 0:208 2:64 3:64 4:16
4dd76d7031529a0b 0:512
4de3f38a50643f2d 0:512
4e7bffde2b238d62 0:560
4ebb315d245d941d 0:192 2:16 3:16 4:32
4ee7ba569bf78515 0:464
4f71d95d00e2e48c 0:496
4f96152ddbaca4fb 0:192 2:16 3:64 4:32
4fadeb6187682b76 0:192 2:64 3:32
4fc710ed808de18a 0:208 2:64 3:16 4:16
4fe465f4cb8d2e2b 0:1200
4fed4e0ecf59b4a3 0:208 2:16 3:64 4:16
4fefa68e6ba6e968 0:208 2:64 3:16
4ff7ea7045a2b74b 0:208 2:16
5045e3e810972a29 0:480
50eab34d17a496d7 0:480
51064c3ec6c8d736 0:192 1:16 2:48
517016b0c656918a 0:528
527938518f6f6561 0:80
52bdbf8404ae9145 0:1152
52d3123fffa92d4c 0:352
52e8d662822c47ba 0:1232
53444b1e81ddf54f 0:208 2:64
536e4bf65732bcc6 0:192 2:16 3:16 4:32
537e630b9823140e 0:208 2:96 3:64 4:16
53801d1f08daa292 0:208 2:96 3:16
5386e2a839c554ff 0:208 2:64
540b931e24ef7d1a 0:528
544a5c3051722647 0:192 2:64 3:112 4:32
545e9a73a015002f 0:1200
54778e89446411c3 0:208 2:64
548644cd8e3fa9d3 0:208 2:16
54d1bfc288cb5dff 0:208 2:32 3:32
54e2b58576b63a5c 0:400
55a299770c03c6be 0:192 2:16
55a73554e9c3296d 0:1184
567a7239836fcab9 0:1168
5693abdc10b396e0 0:528
56a5775ac9bf092e 0:208 2:64 3:80 4:16
56cc4f4a37f388c7 0:512
56dd42fb2f849dc3 0:656
56ec357dd266fd6b 0:496
5747a5ebd7afb442 0:144
574e33d2767ea13a 0:1200
57d709037a27e467 0:496
57eb9f0bae677756 0:576
585fde3223d3e2ce 0:528
589f301f398d4a69 0:1184
58b018066dc1aa37 0:192 2:96 3:80 4:32
595879360574ad7e 0:1152
59686d553f1fc825 0:192 2:64
5973606589357a47 0:208 2:64
59892f7b55a94b8a 0:592
59b33e2e4022d755 0:512
5a3401c28ed940a6 0:208 2:16
5a44ffbe60ec8eb7 0:1248
5b97500cd901af07 0:208 2:64
5bfe1be69008db55 0:1216
5c08b3005c958359 0:240
5c1a9632193fd9a3 0:1248
5c3ac632f0b041b5 0:208 2:64
5ca1c399088012ae 0:1184
5db8588e4c10b7c3 0:528
5df5426088cfdc80 0:480
5ebd93d976f32021 0:208 2:64 3:16 4:16
5ebee0fb86bab763 0:192 2:64
5ed5b0f68a3be9bf 0:208 2:64
5ee902ca16c494f0 0:192 2:96
5f063a7c5b7a4737 0:128 1:256 2:128 3:64 4:64
5f3d107483cdb5a2 0:1200
5f6a4bab9c4d8d94 0:208 2:16
5f7c712e4cb64b45 0:528
5f7f2a41ae11ca80 0:16
5ff1e55d8725a319 0:528
605082369f2bf104 0:208 2:64 3:64 4:16
60974d8687fada32 0:736
609d08739c5788ea 0:192 2:64 3:48 4:32
611cc45090cb1f99 0:528
61226ca69fc9ac7b 0:464
61c97c44da9d8afd 0:1216
61c998477745b90e 0:464
61ee121ba416e72c 0:208 2:64 3:16
6215dcf816c3b535 0:1248
625493dcbf6ccd54 0:192 2:64
62a5c6fdac93384a 0:480
62e4f3be796a24cf 0:192 2:64
62e7dd4607fa9396 0:560
63043ed8a95a008b 0:208 2:64
635959377ca1c1e7 0:1184
6374ff927aa191e3 0:528
63a873e28f295d74 0:1184
63f83fb1afaa14fc 0:592
643e349a7fa54af3 0:1200
644ebe432e7f2ffe 0:1168
6466ccc66322b178 0:448
648307fd2d1d0f6b 0:464
64d5783666006cf1 0:208 2:64 3:16 4:16
64fe98cab672d2ea 0:1200
655a88152b9f0898 0:80 1:256 2:128
65ac96e1470122cf 0:528
65cbffc60015759a 0:32
65e3bc772bff7590 0:1168
660992a99a3befb5 0:496
6635b105e0ec217d 0:592
66b625ef10d6bbc2 0:192 2:16 3:32 4:32
66e280642d7a6710 0:1264
66f0e023464e3001 0:496
66f2a59f66e98b59 0:192 2:16 3:32
675eeaf49b44b28f 0:192 2:16 3:32 4:32
678ddb5490fb5c08 0:496
67dc5f84ac6fbd5f 0:208 2:64 3:16 4:16
67ffe6dd06e39b24 0:464
6805a2145f46019b 0:208 2:16 3:64 4:16
6827963f46253124 0:1184
682c656ad19017ac 0:544
687b3775ceda1da1 0:1200
688892bb5017b36c 0:528
68d491fd03e715bb 0:1184
68ddccc6fb6acf4b 0:528
6917f5c2ad8e9ee6 0:112
696de079c9bd18eb 0:208 2:96 3:64 4:16
697f239e9c9f35dd 0:192 2:16 3:64
69998cc359854bb1 0:1168
6a0143486947af9a 0:496
6a52feae5b9cb58d 0:464
6a849c4394084afe 0:1200
6a92c50cd83ab97b 0:448
6b1871742afff7c4 0:192 2:64 3:112 4:32
6b7035d155e17030 0:192 2:64 3:32 4:32
6bb501b4d5cb43ea 0:512
6c1623278f10e38b 0:464
6c23bbcc17ecc9c3 0:528
6c66c6f06e1bed24 0:1248
6c8032ea54265a5a 0:16
6ce939515d9bc070 0:64
6d622d39e924d58a 0:1184
6e0ab5ac33578a43 0:592
6e4686d46ac46a71 0:464
6e50a7ec29679a47 0:208 2:64
6e5726691e94e1c3 0:464
6e71588b624826e3 0:528
6ea5555f0fad5d3d 0:480
6ed2a6583f5b1831 0:1184
6ee84a40a1128a8b 0:192 2:64 3:16 4:32
6f44ca79edffe6cc 0:592
6f80d16b55406f55 0:192 2:16
7027a7f207f0fd6c 0:1168
709f19d5ba01f6d3 0:192 2:64
70b2843f4e977fdb 0:1264
70f943134590d9fe 0:192 2:16
7167e3f85e5f2444 0:400
716f7d03325acee6 0:864
7184314ce6e70db7 0:1152
718fe4f11868377e 0:208 2:96
72819fa5a9fd08d6 0:208 2:80
72b5bce0c8256361 0:528
7314b420d3346547 0:192 2:16
7320b5755e1ffdd9 0:192 2:96 3:16 4:32
732f93ede2aa79ba 0:544
7341259ffbc22506 0:1184
73692e62e8226b02 0:560
73c223f06e1aab66 0:192 2:64
7400f35f4da6929a 0:496
7411c3e2cc7e0a94 0:592
742c3a773a8f0ae9 0:432
745da253f6892e04 0:192 2:64
74ab3bd004f79fa4 0:464
74ff5c53b5fb2347 0:464
7574e2533fd31332 0:464
758bf3768cb023d3 0:192
75b2300b991bd4c0 0:640
75cb4e487e34a232 0:592
7636729ea37f67b4 0:1264
76603f778fd57d10 0:448
770ee33d19b3b845 0:1152
77117455bcf5568c 0:208 2:64
7740409d6a974e50 0:208 2:64
77c6e939de2ef98d 0:416
77d4c4e80b5b72a2 0:208 2:64
77dcc8352daeec2d 0:1232
781f4b9fcc4d3772 0:560
78485403b8b73a8f 0:192 2:64
785d755ef0ee47f2 0:208 2:96 3:48 4:16
78b3f6b626aeb812 0:1152
78f4adf82303c990 0:480
78f87b399904ae28 0:464
7902a648c56e7b7f 0:400
790d30f6f432e325 0:208 2:16
7a0c72875a585df1 0:208 2:96
7a1e2727350c3b8d 0:592
7a779ef059afcb67 0:592
7a9f384c513787e8 0:592
7abdc0dacf340544 0:1216
7aecd1d0a2dc9fa2 0:1184
7b741e480d3e98f4 0:528
7bd6d4d30ce672a5 0:512
7c69c9c67234c96e 0:208 2:16
7d37b62275d06824 0:512
7de4f2f2ee4919c2 0:528
7e030ce90774dd83 0:496
7e5b6de4a9f76aca 0:464
7e88880eff483ace 0:1264
7e96e7379ce709ee 0:208 2:16
7e99e5710af25b9a 0:496
7eb6f3c8a5e1f9f3 0:192 2:64
7ecffedf1eee3bb2 0:560
7f212cf7905652f9 0:208 2:16
7f6cd11d97596427 0:1168
7f9cb173d93da9b4 0:192 2:96
7faa98edafbf8135 0:1216
7fb80dbb61c913ae 0:1168
7fc0b0b0007d760f 0:592
80689f71d4f7c741 0:512
816ebf680bed5bef 0:208 2:64
81a0bf7aa31debd6 0:448
81e823c97cb21bb1 0:208 2:64
822cb9fd05ab0907 0:1168
822f00337477980d 0:192 2:16
8252bf0ca730ce90 0:208 2:64 3:32 4:16
82c6c4a0d90eec41 0:480
82cfc5f415335c95 0:208 2:16
82da5c17ef5997a8 0:192 2:64
82e274e6a3127f30 0:528
82e653b3fa51dcce 0:80
831a6f33a80978c0 0:1232
835a1dae93272ed3 0:480
838d01df115b29a7 0:464
83c6c5ca6d8349b6 0:528
83cab67e5d4b8dd4 0:528
844468d613651334 0:464
84d577aa4ed5550d 0:192 2:16 3:112 4:32
84f6b38693136738 0:192 2:64 3:48 4:32
8506547be3983b26 0:1248
859faca9533a193d 0:192 2:64 3:16
861c1d4ecec13867 0:208 2:16 3:64 4:16
863ca276f8260416 0:192 2:64
866fbc503e77a0e7 0:192 2:64
86c7db14355e59c3 0:464
86d47c3b5e18c878 0:1152
86f91d4c7bdcc4a2 0:192 2:64
8706768352dea538 0:1168
876f5eb6e1f1a81d 0:464
87d03e98e5709fa5 0:112 1:256 2:128 3:64
8831169cdd60ccbb 0:1248
8837a45f035664b1 0:1184
886497cebb33306d 0:528
88fa765ab7ac0852 0:192 2:16
89405f3b226b9df4 0:1168
896a4646ce982ce2 0:528
89aeb839833d6a08 0:192 2:96
89cc64dd4084887b 0:528
89d815d8c2ce381e 0:192 2:96
8ae29b8cbc478adc 0:448
8af70f7ca64d873f 0:48
8b26f1dd2d620f24 0:208 2:64
8b4f7aad9ad65d5f 0:1264
8bc82a8d6f11b5d9 0:544
8bf0c62d350e30ee 0:400
8bfaa882b7dcd0fc 0:544
8c3bdd2d11286815 0:208 2:96
8c3e4adea4e3517b 0:464
8c510dcb60cabb24 0:208 2:64
8cf2c91be8b954ea 0:208 2:64
8cf582b137cb33c7 0:448
8cfb5649bc82a517 0:192 2:64
8d11a3c302e169a8 0:1264
8d1ced293b413257 0:192 2:96 3:80 4:32
8d58714986811eff 0:1216
8d5fb93120a78f56 0:192 2:64 3:64 4:32
8d6e001aaf877360 0:208 2:16 3:96 4:16
8d6e52fead65a464 0:1168
8e46e46c246eb256 0:208 2:16 3:64 4:16
8e544452e34cc4bb 0:208 2:16 3:64 4:16
8eb3388626ca59f6 0:528
8f28587560d29439 0:208 2:16
8f2fa8f65c48ff16 0:784
8fcd3a61b34d3fbd 0:528
901b1aa492d63dd5 0:192 2:16
9032b774f74493fb 0:1264
90dcca4efc518101 0:192 2:64 3:16 4:32
9125415f789df81b 0:1152
91329e8e026e7853 0:1168
913fea846027d43c 0:1152
91af6ae142f930a4 0:208 2:64 3:16
91fc7e6b7322ffde 0:208 2:64
92afeef02edc2e5d 0:528
92babd83d6e080cf 0:208 2:64
92ea41ac31ac84ea 0:208 2:16
933354857016d925 0:464
933b62107007fe6d 0:464
934f95f84e221a95 0:208 2:64 3:16 4:16
941bf816aa50e01d 0:528
9441ea587bda3d8e 0:1168
94a5695671dc298b 0:464
9531d4ba58afdb02 0:544
955ece1e8ddb3956 0:448
9561d9abcc7fe61e 0:208 2:64 3:32 4:16
958550eba5319747 0:544
95a16c24d9064390 0:1360
95de928183c8086c 0:464
95e3e6db38052743 0:192 2:64 3:48 4:32
95ec7d9bfc408f08 0:400
9613f24c29827a94 0:448
963bd6fe203f4d20 0:1168
96d81152277e6188 0:80
971b6f7d9d327218 0:544
97f8dab29dce5012 0:192 2:64
985458a944f9f170 0:592
98b25235aaef2fe5 0:208 2:96 3:64 4:16
98bbcfb9d832b0f5 0:192 2:16
98bf391aa0e67449 0:528
98cbca7a4d4724f4 0:448
9a06bcd0ab84e644 0:528
9a61ac18d9c75733 0:1216
9a7ad8b14fb31e24 0:528
9a7b26ed2fab9615 0:1264
9a84efe6f01cd73f 0:112 1:256 2:128
9ae52c66b0faec14 0:608
9bdcfb3b3b54602e 0:736
9befee0e8c9c4927 0:544
9c0f034b987c7751 0:528
9c5b321b46b25570 0:192 2:16
9c6d1f06fd864412 0:688
9cdad29d947cc0c4 0:1280
9ce66165b6f30935 0:208 2:64 3:16
9cfe01a18deca01d 0:592
9d124705b08333df 0:192 2:64 3:16
9d9eaef02864f136 0:1216
9e69638daed6b381 0:1168
9f22a3d3c70a4801 0:416
9f9f47bcc7b3195a 0:448
9fc6597ba76dc705 0:208 2:16
9fe954ccfabf1160 0:192 2:16 3:16
a05f9d7b331e2876 0:464
a0992be934d44874 0:208 2:64 3:16
a09a5306816b9004 0:400
a0bad0342bd595dd 0:1232
a12a4169b7c164bc 0:1280
a14aad935ffb7470 0:192 2:64 3:16 4:32
a1640081386f2e66 0:208 2:64 3:16 4:16
a1cbb29c982a3e60 0:528
a20de470dbd2eb4b 0:208 2:16
a210c344462d78b8 0:544
a280140f655ee935 0:480
a30786c95a76c53e 0:432
a32678d25472822d 0:192 2:64
a36f488cfd82f6b5 0:496
a3ccd8f0e442d8f7 0:208 2:16
a3efc18daab22509 0:1152
a410763a3a798eee 0:448
a41728dc2407ee9a 0:1312
a44395086ff087a9 0:192 2:96
a4b87dcff13f7b0f 0:192 2:64 3:16 4:32
a553f143aaf98769 0:496
a5e9290b220a7773 0:208 2:96
a626b4a678133eb9 0:208 2:96
a6a4e82f2cdf33b2 0:528
a6ec6e93725105da 0:192 2:64
a7274f8eaf7250b1 0:192 2:16
a732a93a74cd76c4 0:480
a76bdce7a156d80b 0:1184
a786cb63d76555d2 0:208 2:64
a7a9b39af5c96d21 0:80
a7da670a58459aa5 0:208 2:16 3:64 4:16
a827b657befaf9ae 0:208 2:64
a828270905ed9d3b 0:528
a8ccff62f3ffda8e 0:448
a90886f6b308c31f 0:560
a908e733565a79e7 0:208 2:64
a96e1f61f417abf7 0:528
a97c91ce0536b332 0:192 2:64 3:16 4:32
a9aa5ef0461fb5e1 0:1184
aa5764bb57838f4f 0:192 2:64
aa90fe76eeb8a845 0:1248
aae14b048a1796c8 0:208 2:16 3:96 4:16
ab059fd4b22c4ad3 0:512
ab7761bae4d49b7b 0:544
abb01305ec2aa3e8 0:208 2:64 3:16 4:16
abd5727f1ff718bb 0:448
ac44c282a2805b12 0:208 2:64 3:48 4:16
ac471f459daa97cc 0:544
ac7b09f708a78fe4 0:192 2:16
acb7d5c564d73ce4 0:464
ad18d54baad8ad46 0:192 2:64 3:16 4:32
ad6c796c2322274b 0:448
ae243c8e877fde07 0:192 2:64
ae24d7227bec6488 0:192 2:96 3:16
ae3ceb9a28c88ee0 0:192 2:16
aeef39cc613852fd 0:1232
af1e522c49491e98 0:1264
af3062070920c929 0:592
af6772a753a31e13 0:208 2:96 3:16 4:16
afc555a481ea1de5 0:400
afc601ce1ead8d3b 0:448
afd2209d3c272d0c 0:592
b04d08256112da23 0:192 2:64
b0bbde5bfe7b67ae 0:1248
b15e2e252b5337ed 0:192 2:96
b25951e9dc31546e 0:112 1:256 2:128
b31f397cedf8567c 0:496
b333a7c9ff076d6f 0:192 2:64
b347b0c4498ffc1d 0:1200
b395b955b4826514 0:448
b3f4a51f54de75e1 0:592
b3fbbd14979825a5 0:528
b407597ede6be1e4 0:496
b40e8fe71f3407e3 0:432
b4fbff6d0ddd8b42 0:192 2:64
b52e21ef0e18f720 0:208 2:96 3:64 4:16
b59f236cb6b8b5e4 0:192 2:64
b5bf81b57551c213 0:1152
b64bbed3300cbbb9 0:208 2:16 3:64 4:16
b682f507eef5f6be 0:432
b6a0e8fcd17d5f88 0:192 2:64
b6eed402da843ec1 0:496
b6f0c9892178bf5a 0:128
b7304eaa0d07241c 0:512
b781d83e79fad241 0:528
b84680c71f88ae7c 0:480
b84d9cd8248c7623 0:192 2:64 3:16 4:32
b858d6dfe05a97c8 0:592
b873e523e8facb66 0:192 2:16
b8d3458ec0dc178a 0:448
b92dd53682242df5 0:432
b98f6dae553d5ff5 0:528
b9d1bcc25bfca06d 0:208 2:64
b9ef417381310c88 0:544
b9f6877db8668668 0:192 2:16
ba08836dabf5801e 0:464
ba58aaff1ee9531b 0:208 2:64
ba8e34c7fc612783 0:192 2:16
bae8c8b0e58a587f 0:48
bb0cbd5ac10f04fb 0:464
bb3dce3a02e8843d 0:112 1:256 2:128
bb5924e15cd4315b 0:192 2:96
bb5bed02c1638244 0:192 2:16
bb9a2b9bacd59ba0 0:1216
bbb5b0ed7e681362 0:592
bbe70fc18588aca3 0:48
bc468827ff2f3b50 0:528
bca7605eba5a4c80 0:544
bcafcb418bc346d7 0:192 2:64
bcec454f95b64436 0:1232
bcedfe12546a35b8 0:432
bd5028f8e14dae2d 0:464
bd80064be800c382 0:208 2:64
bd84c3cbaa259d2e 0:528
bda8618c2611835a 0:1232
bead1e6e158e7de3 0:208 2:96 3:48 4:16
bf1a45588aebc762 0:112
bff24c45c555fc31 0:544
c01a293c7b3703ef 0:464
c0fc767548a5c9e1 0:592
c0fde9561d5c5151 0:480
c1017ce2b48113cb 0:192 2:96
c1f18b2833678922 0:592
c278c2d2c0387ae5 0:464
c2bd22921d7a7a09 0:208 2:64
c301e6962c288a26 0:496
c341e35528812cf4 0:1168
c360ba56937ce7ce 0:464
c36399e4e6acdde2 0:448
c3fdbeb58935c082 0:192 2:64
c3fdd18088f8733d 0:192 2:16 3:64 4:32
c405bc420ad6a050 0:192 2:96
c41fe4dcf9c937cc 0:528
c4a09fc85fc26129 0:1200
c4c3f2b5a927662b 0:544
c4f6bf1dcd96904f 0:608
c55795062e95790c 0:208 2:96
c577b6ba3d77fa86 0:480
c5910693e0d562e2 0:192 1:1008
c59ff46edc6f8fa6 0:48
c5f9c582741821be 0:208 2:64 3:16 4:16
c63326013ebf35e9 0:528
c6db0e51afb5abf8 0:464
c737b928574cf9ad 0:1168
c77cbbcbb032741c 0:208 2:64
c7835882cf62088e 0:192 2:64
c85c1dfe14f56fba 0:208 2:64
c8baef0558872e4c 0:1312
c94c5953c973d6fa 0:592
c96e863a8b9c583a 0:544
c99bd3ba69b5e0f2 0:432
c99d8b2b90177d79 0:208 2:64 3:16
c9d8010ed9dcea74 0:1328
ca517cadf1ef811a 0:208 2:16
ca5eff94c0f04ecc 0:416
ca78c1fbf996d764 0:496
ca7f3463080a1dbe 0:464
cad9220e876e92b9 0:192 2:64
cae8f1d55cf78304 0:528
cb55db1eff5516f2 0:1168
cb5b73f3de96fdfe 0:496
cb8d4026fa1524df 0:208 2:16 3:32 4:16
cbcb384c18cbf4be 0:1200
cc0450bafa36cc95 0:192 2:16
cc561305cc2dfbfa 0:464
cc8b1dd2195237a8 0:192 2:64
ccbf5de61419aed0 0:448
ccf32a372045005a 0:592
ccfb6fa1aa81030d 0:192 2:64
cd42e2fa635b2ca0 0:1232
cd717acb78537d5e 0:544
cd7b535c64685673 0:560
cda978100923d1f9 0:592
cdb50cb5b0828103 0:192 2:64 3:16 4:32
cdcf84461201462f 0:464
cde8027493f803f8 0:224 2:16
cf32cd6dc1f72bfa 0:448
cf3d275b207a69ca 0:208 2:64 3:32 4:16
cf5f34b0c1af8365 0:208 2:64 3:32 4:16
cf68a638da698af4 0:192 2:16
cf6e2c83dddcad7a 0:464
cf87d5f3cc891bc8 0:1168
cf8f489717ed15ae 0:208 2:64
d025695a5566cca0 0:528
d07b492ad22e2df8 0:464
d14823342bef41ed 0:192 2:64 3:32
d1f5c6df4ae2219b 0:192 2:16
d204f21692e053ff 0:1216
d22f583ec3826ab0 0:208 2:64 3:16
d23bc0f264c475b9 0:1216
d30570448de42896 0:496
d30acad2d9b9bc43 0:528
d31a3183db64e0e8 0:1200
d36e5715f125f4dd 0:608
d3a66c4920653135 0:1168
d416b9aca97312a6 0:192 2:64
d43b2274abd88032 0:512
d482b3669b471ca5 0:208 2:64 3:16 4:16
d4d35c53ef0eb5bd 0:304
d4edcad6035f18c0 0:592
d519a462cf425560 0:464
d57cd67cce36761d 0:496
d59e91af3eee964e 0:496
d622ffd0746fb0d5 0:208 2:16
d6746698b6d80f79 0:192 2:64
d675b527562414b0 0:192 2:16
d677a206a8953fbd 0:512
d6b26908dab29f90 0:208 2:16
d723b4e348929c5d 0:480
d7262203afc69a04 0:192 2:64
d7850c91ca03badb 0:1152
d8604fcaccee09e3 0:1184
d861fd7ab21e0db1 0:592
d8818274c76aba5d 0:576
d89ace4f0ca24729 0:208 2:96 3:16
d8c7761f49b123d9 0:592
d8d69e1d5331e497 0:1184
d8f36d6cd852aded 0:528
d8f69f92af8e18f2 0:512
d8f8c1b46dfb7123 0:48
d9b2cdd1dd232007 0:1168
d9b49de3db5b572b 0:544
da1deba2a03bcfc6 0:592
db1f225b63c988aa 0:192 2:16 3:80 4:32
db3e3e14f48d03e1 0:1280
db404d0fc9580f0b 0:512
db6c25bb6b954bf8 0:208 2:64 3:16 4:16
db7d66f85e032b97 0:432
dbbc092887bdd0ea 0:1248
dc689ba359f0b368 0:496
dd43b024931f0093 0:592
ddc8abd795a1d0c7 0:448
de3d71c0869adc36 0:192 2:16
df27f7def45498cd 0:1200
df2cfe75ab01dcab 0:1200
df8dbb9862f3a058 0:528
dfb282ec0bb39448 0:544
dfdf8fbb1c8c18b1 0:512
e0008c01e6066dac 0:208 2:80
e079b0132b309178 0:464
e07c1fdd14da3b08 0:192 2:16 3:96 4:32
e0fea43c24726d0e 0:448
e1b5d46b45f96b9c 0:1200
e1b89e09a307a3ea 0:208 2:16
e1c39914a4c3857e 0:480
e21b68db4ac70c6a 0:528
e226c1dc0f1150f7 0:448
e271fee63eaa0da8 0:512
e27f19141815d125 0:1152
e2c187c6a2e2e414 0:208 2:64
e2e3e51468b16894 0:192 2:64
e38e10c676070c47 0:192 2:64 3:16 4:32
e3cd43337031cc8b 0:1184
e3dd41b33751ec7d 0:432
e3f0bc2e8d4e4d01 0:192 2:64 3:16
e3fb91550b67114f 0:496
e401a1a2ec9c30cc 0:80
e40e53e5b7125f33 0:1184
e47ad056df2c2a3d 0:1168
e48825cdc7119225 0:1216
e4d32f54b3729f1f 0:176
e4db543505579a99 0:208 2:64
e506ce03486acbde 0:1184
e63de66413b44081 0:1200
e675470eb45f4b42 0:1168
e68dd6c0731b5f29 0:208 2:64 3:16 4:16
e6b3b9bbccd7e6e3 0:448
e6c956b8fee60aed 0:192 2:64
e6d1e77c66edf899 0:208 2:16 3:48 4:16
e6f150a366bf08cd 0:800
e71c3c1c1c20a804 0:400
e724108d5072402c 0:208 2:16 3:32 4:16
e81a8b7736dd8501 0:432
e82f9bda6415ad3f 0:1232
e85685d1535d8f83 0:192 2:16
e8a019034500be81 0:480
e8a325a1f064cc10 0:208 2:64
e8d6a5f59a363efb 0:208 2:64 3:16
e8f5b73417fc21e7 0:1168
e90929433e4ee59c 0:640
e93ab2c1e13c3ee8 0:1248
e95d4d4a94af1cc9 0:1248
ea7af5dc3727a6ec 0:1184
ead0f03e7ba90095 0:208 2:64
eb8b222f4690b108 0:208 2:16 3:64 4:16
ebcb4d55c3ab2462 0:208 2:16
ec30dbb9070217fe 0:496
ec3e328e16b652c0 0:1264
ec51312631c2dcb0 0:544
ed58f8b79a4c5d9f 0:528
eda7d956ec545ed8 0:1168
edad9c00bca23a7b 0:192 2:64 3:48 4:32
edb0aafdda50e9db 0:192 2:96 3:16 4:32
edbfa86039cac6d8 0:512
edc21380fc66486c 0:496
edcc77ab7f338866 0:1152
ee270de1f09c9ba2 0:192 2:16 3:16
ee5ca4fcd176cd6f 0:32
ee8044f0a4342a10 0:512
ee85b78bd36690a5 0:1152
eee1790176db5307 0:528
ef47d534616d4472 0:512
ef7b66c0c00244f7 0:208 2:64
ef856164f73e2368 0:208 2:64
f0628d4bb33771b2 0:496
f08d8f8c69d32fa5 0:208 2:64
f0bea8670c0b05ef 0:1264
f0f22f9493294d06 0:480
f0faad4f3f8b6b1b 0:1232
f11ea123b6ed7853 0:160
f12091d5bf9470d1 0:1168
f122ec10981114e3 0:1184
f13ff42b17bcb8ad 0:528
f198cc7a8d8c0e49 0:528
f203f913e66532ef 0:528
f221aa2df3b4fcba 0:528
f249285c00b3a9d2 0:528
f252f8bedf0aa606 0:128 1:256 2:128 3:64
f275374609bbe536 0:208 2:64 3:32 4:16
f2b347ee8ae57e01 0:208 2:64
f351721b8c6764dc 0:528
f37c7e79260afe79 0:800
f39c6b4ac55f892c 0:464
f3b6b038640f5519 0:464
f3c871a629010d87 0:192 2:64 3:160 4:32
f3d7a9b76f723b33 0:80 1:256 2:128
f4200d5b98bca00a 0:1280
f424e68100171725 0:208 2:64
f4a66d24d39a4ee6 0:1168
f4e1a5f0b4be960e 0:400
f51aa565930e5354 0:800
f52f55248284851d 0:512
f55cf0b300cb88df 0:400
f576e164768043af 0:1216
f596244c670b82ba 0:1232
f6669ed1d4e877cb 0:128
f6d47fcac91d417d 0:208 2:64
f700f0b9f3ce0a7f 0:1232
f70f558fdff37b62 0:496
f720642ffcefa61a 0:1168
f72ffe6b715001ec 0:192 2:64
f74c00e45881019b 0:464
f826f2b59cfa39a8 0:576
f89a6b4b5fd3355a 0:1152
f8b826aec94f1c15 0:464
f8e86ea53fdd1479 0:496
f8ec95d23fe6bae6 0:64
f8f7c54fabd23d07 0:208 2:64
f99781c61846b4f9 0:208 2:64
f99ea1392887bbd7 0:512
f9a3a92a90dee9a0 0:512
fa1ffaed7eefa476 0:464
fa6464f7942ef4b9 0:1232
faf59ecce1662eb6 0:208 2:16 3:64 4:16
fb1645bccb830255 0:112 1:256 2:128 3:64
fb3d2f49371dabc5 0:208 2:64
fb3d68e98aa0ff81 0:544
fb73a1c82d9939d5 0:64
fcb0d2c1c0a73902 0:208 2:64
fcb86e7811c11425 0:208 2:96 3:16
fd1165c2de978f87 0:1168
fd2b13f97cfb0508 0:192 2:64 3:16
fdb444c7f0c947d2 0:784
fdf3efae5e94691f 0:512
fe18f03e74364843 0:1184
fe1e825f5ba68e67 0:480
fe4a97973adb94f6 0:208 2:64
fe911827664c56ce 0:1248
ff30022fc3965465 0:512
ff3e559d88724492 0:192 2:16
ffc89e780ac33776 0:432
ffcfb49e7f03fde9 0:1152
1 # chain b-ef65926816d8 2026-10-21T12:01:11+08:00
2 # shader key, then reg:bytes for each uniform slot whose reads stay inside its first bytes, and s<reg> for each storage slot it never writes (cb_extent.py)
3 003b38fe9b3627ba 0:192 2:64
4 00500b94cf88443d 0:1168
5 00516aa1e784d9e0 0:576
6 0076e7956282bfc5 0:208 2:64
7 0094ff5d3f9cc5d8 0:1168
8 0095d8689baf5ec7 0:464
9 00c32c2411fbbe03 0:112
10 00e1833e9ac78892 0:1152
11 00e453d026d2fc05 0:528
12 00fe118ffda2ee0c 0:192 2:96
13 01055d415502eaa6 0:1264
14 012068e325b0b4c3 0:432
15 01a48390c89957a4 0:656
16 01bb2e2343daaa92 0:1184
17 01c79a49c01ab882 0:512
18 02295512bae1fd1b 0:512
19 024d83528f550fbe 0:112 1:256 2:128 3:64
20 02503a8189808d47 0:592
21 02a939263d583ed5 0:208 2:64
22 035e6a2b6d644d19 0:192 2:64 3:32 4:32
23 0365c6f2bc598f38 0:192 2:96 3:32
24 0366b4fb9baa6bf0 0:192 2:64 3:16
25 03d7e7a2efac8a2f 0:464
26 03f12c555d184617 0:480
27 0459b351d841fc2b 0:544
28 045a54bb20e3750f 0:864
29 051c001a5ba37928 0:480
30 05251d2037611165 0:208 2:96 3:16 4:16
31 0558bceeac0c3e90 0:192 2:64
32 05d7c93d306ce7b0 0:592
33 0664bf4cf905428d 0:1168
34 0665288c892231e9 0:1184
35 069b1843c4a4bb52 0:192 2:16 3:80 4:32
36 070e1d7aaac06775 0:544
37 07c8fcc6d480f88f 0:512
38 080f05eeb6d4ac45 0:448
39 08163380d49d7720 0:192 2:16
40 08330cc9f09f4749 0:1264
41 08ee2b1ba6ea5b4a 0:448
42 09457a6ed8ef5d96 0:128 1:256 2:128 3:64
43 094c296cbfc656d5 0:208 2:64 3:32 4:16
44 095fe9b06dd8a7ae 0:208 2:64 3:80 4:16
45 0a403f6b9ebe470f 0:448
46 0b102b779013d112 0:464
47 0b75021f6c2322c1 0:208 2:16 3:64 4:16
48 0b974083af053985 0:1152
49 0bb91b311d5d5eda 0:112 1:256 2:128 3:64
50 0bfb16c2a111868c 0:192 2:64
51 0c2665b73acdc30a 0:1152
52 0c41eeee4a5854d6 0:192 2:16
53 0d3958f2ada85e8a 0:1248
54 0d52e6465405bdc4 0:208 2:64
55 0d67b375c8c9aff7 0:528
56 0dcdec77cec91e17 0:192 2:64
57 0de7e38975573b0f 0:1184
58 0e41205fbc497a08 0:48
59 0e7ef57fa0c54855 0:80
60 0ed3a9552a557ba0 0:528
61 0ef46c960dd2115d 0:592
62 0f571d1e58930bfe 0:192 2:64
63 0f600befccd3f827 0:448
64 1001e21246f626fe 0:1168
65 101dded719fcb9ca 0:208 2:64 3:32 4:16
66 1053586ba2440c56 0:192 2:64 3:16
67 1078cfc1b36b5a5c 0:496
68 10985418584072e1 0:400
69 10a1a81f8e80d54a 0:208 2:64 3:16 4:16
70 10c0666c52203a43 0:1200
71 10ddd89f8f885f85 0:208 2:64
72 10f5730dc1545780 0:480
73 112d8391b4a78890 0:128 1:256 2:128 3:64 4:64
74 1150d5d28be3ac67 0:192 2:64
75 11ecba96b9b277d1 0:208 2:16
76 12459b0fd95239d8 0:208 2:64
77 127ecd713e1c3ddf 0:208 2:64 3:32 4:16
78 12814fde4abb727d 0:1232
79 12b0ba3856f9ffdb 0:512
80 12e44e9ceb25155e 0:1264
81 131f31c5cdeb4423 0:1264
82 13b3ce7083269906 0:1232
83 13ea95cc4d0d7b10 0:1216
84 1469448cdce0e18d 0:592
85 1497a509b3e92394 0:512
86 14c5beb649a944c9 0:1184
87 14e7e37bfa93b6c7 0:208 2:64 3:48 4:16
88 1595632bdcedf218 0:496
89 15acb74d525be21d 0:192 2:64
90 162fcd8fb03b4054 0:192 2:64
91 165f62a9bbaf9cc3 0:528
92 1660c5f8f510f559 0:608
93 1662ef4aa0380b63 0:528
94 16785a240276ff55 0:208 2:16
95 1704eece77a4d2f5 0:192 2:96 3:80 4:32
96 181de1508dda74e0 0:528
97 189e26dc3b0012f2 0:496
98 18c802f27e644ef3 0:432
99 1a453e95678d140c 0:496
100 1ab913acba0f8698 0:1200
101 1af54ac857775e4e 0:496
102 1afd338e220f30dc 0:560
103 1bb807d790e7d27a 0:512
104 1c964ca95773b64b 0:1168
105 1cb0c3bae54a58de 0:192
106 1cc713a86aa7139f 0:480
107 1cde87f3c5223512 0:192 2:64
108 1cfcd3c2f0b78130 0:208 2:16
109 1d3612b6a2602722 0:464
110 1d58747aebc18d8f 0:192 2:16
111 1dc3e13c16f61a8a 0:400
112 1dead970396c0191 0:464
113 1e1f880fbdedc76d 0:208 2:64
114 1e2d2e2c80828aad 0:1168
115 1e377f4acd9f7393 0:208 2:16
116 1e7cc5e42b776b8f 0:192 2:64
117 1ea4b2af5ab33987 0:1152
118 1ecfb702217db62d 0:800
119 1f28ef4492e54f2d 0:1264
120 1f3f2e3949a3c47d 0:1232
121 1f6ba53e9c2536c6 0:480
122 1f9a00f83e3802e8 0:192 2:64
123 1ffb268e982f32cd 0:528
124 204a23a3dc28b378 0:304
125 213d958a59c7d065 0:208 2:64
126 2167d71ea19b9058 0:592
127 220caf1e0b940346 0:208 2:64 3:16 4:16
128 2264d9a055b86750 0:192 2:96 3:80 4:32
129 22eacc2235befd8d 0:528
130 22f0b85b580053cf 0:1232
131 22fbc2f8ad586e60 0:592
132 2304bd067704251a 0:1152
133 2307bab6e11d6ca4 0:480
134 230d810c58a5fcf4 0:96
135 231cd7e544d26f65 0:496
136 231f987c2add65a7 0:448
137 235c1dd4ecd02dce 0:464
138 23b3c7dd957c8632 0:1200
139 2417eee0219abdea 0:576
140 24596ad96cdfc268 0:448
141 245b7bce27997afb 0:464
142 247cf1f1dc95d691 0:784
143 24cb3fc88280af15 0:112 1:256 2:128 3:64
144 24ece705db8a781c 0:1248
145 256622a5b64d2098 0:208 2:64 3:16 4:16
146 25b6fb9d1f20875e 0:192 2:64 3:48 4:32
147 25eb204602f5be51 0:208 2:64 3:16
148 25f77c6ba0ec8295 0:512
149 25fa5ba6c60c199c 0:800
150 261dc6cae8a0d7b1 0:544
151 262dc000f3349e00 0:256
152 26577edc5675379f 0:208 2:64 3:16 4:16
153 268dade08b3e726c 0:1152
154 269f3ed401c155d8 0:1184
155 26b2a36b5680e959 0:448
156 26b8bd86580e3270 0:1168
157 27e40fa36dec84a9 0:192 2:16 3:96 4:32
158 2850fc54dffd4108 0:192 2:64
159 2851fc507359a21b 0:208 2:64 3:16
160 2856edf0f52b0419 0:1200
161 28613b62bb1ef308 0:208 2:96 3:64 4:16
162 287e7705325f5303 0:1232
163 28995d282b955899 0:1200
164 28bad575151ef721 0:592
165 28da3486bb8ed432 0:192 2:64 3:144 4:32
166 290101b2578ae6d2 0:208 2:64
167 2919566fbd54eab7 0:208 2:16 3:64 4:16
168 29babf3d9ce5de24 0:528
169 2a30f4df98604d2a 0:208 2:64
170 2a4a49116f52dbce 0:208 2:64
171 2a4d294aa05bad0f 0:208 2:64
172 2a9eb2bccda4f423 0:1152
173 2ac0460dcfead30f 0:192 2:16 3:96 4:32
174 2ae4cf047ba58f85 0:512
175 2b051de5cddce7c1 0:480
176 2b19d7bb67e00d50 0:80 1:256 2:128
177 2b3b688f619c8966 0:1232
178 2bd85efd2691eb6e 0:400
179 2c2736740611bfc8 0:208 2:64
180 2d0dcfc6e3be3fb1 0:192 2:16
181 2d2b40d01da208c4 0:192 2:96 3:32
182 2d517e0124d944d2 0:192 2:96 3:64 4:32
183 2d53ce7ac44372e9 0:208 2:64 3:16 4:16
184 2dc9d4b1f56f379a 0:208 2:16
185 2e185900917f606c 0:208 2:16 3:32 4:16
186 2ed56b2d1555131b 0:480
187 2eeddb2e6689a650 0:208 2:16
188 2f39398d19b37151 0:1264
189 2f800d95bf716ac0 0:624
190 2ff18bebd5c4f8a9 0:208 2:64
191 306ed34b0f6fb2f9 0:208 2:64
192 30c4659e2d5d060d 0:400
193 30f7411bfa6d533c 0:192 2:64
194 30fe33bf65df7390 0:208 2:64
195 31297697572dcb6b 0:192 2:16 3:32
196 31715dc852392279 0:592
197 33b954292864ebd5 0:208 2:64
198 33c8135008748347 0:464
199 34388df8dfdc1310 0:192 2:16
200 35294b44e8850b68 0:1168
201 353f48d7ac006fc2 0:464
202 3564ed1b55346d1c 0:544
203 3566a7febe9aaf69 0:528
204 35826c17c45a8233 0:192 2:64
205 358c65dbdcc9bf4b 0:448
206 359179047c54ab6a 0:208 2:16
207 35c6656939defe10 0:528
208 35dfcc9f26812196 0:528
209 35ffa4b26138cc5c 0:1328
210 364e8b47058223f6 0:464
211 36598bd7ee5eb050 0:208 2:64
212 3659fef557b0ef7f 0:1248
213 37110d689802476f 0:192 2:64
214 3741f56ef3481f65 0:480
215 37944f7cf5a3ecc9 0:496
216 37f802c38c01fc47 0:208 2:16
217 386c5042f82b2a16 0:1168
218 3891d01a7b0a9206 0:528
219 38e0b2442ddfa8c5 0:1200
220 39162c78afb0fd6e 0:528
221 3922eb98d8191b6a 0:192 2:96
222 39f2d7189c0841fb 0:192 2:16
223 39fd4958fb3959b5 0:1248
224 3a0ffe970e2a3d35 0:192 2:64
225 3a366f1c92e74949 0:1216
226 3a4728dffa05259d 0:1248
227 3b71f34c64339f7e 0:1200
228 3bc5f3dd1c0a3c17 0:608
229 3bc606b31493d8d4 0:1248
230 3c7fff3a699f1052 0:544
231 3cc872702f77cc07 0:1184
232 3cf35cb9b34cddd4 0:192 2:16 3:16
233 3cfcd51c2c8cd36d 0:608
234 3d1a5e53ec2d679c 0:496
235 3d48809101022a4d 0:1168
236 3da87a93a8f9b236 0:576
237 3e2d388d6f915dce 0:208 2:64
238 3e348fa5650023ec 0:192 2:64
239 3eb12a4f23c09c41 0:208 2:64
240 3f103f005885994f 0:192 2:96 3:80 4:32
241 3f41b972176e242f 0:208 2:64
242 40288ae9363ef277 0:208 2:64
243 402c4196c5998bc6 0:432
244 409b745e966fed89 0:448
245 40e3812dce5e0185 0:1200
246 413da19d1e25356b 0:192 2:64
247 42e1ccc71b18442f 0:592
248 42e486c09fcccc07 0:208 2:64
249 43ad6c7c431e1b0c 0:32
250 43bfc11f1f3d55f7 0:1152
251 43c7e5c266125d57 0:192 2:16
252 4406298b845a3773 0:512
253 44173a3a3f049ce7 0:208 2:64
254 4449939ff05e42f7 0:208 2:16 3:48 4:16
255 4467d56e6592a3c1 0:448
256 446e26a167ccc2fb 0:208 2:96 3:64 4:16
257 446e27fbda0c678c 0:528
258 4501d34633dd2b4b 0:192 2:16
259 45066194a2e4bac4 0:208 2:64
260 452fd9681da7d8aa 0:1184
261 455d1d2f1a12f495 0:1184
262 4584a1f8f055dacc 0:208 2:16
263 459614e6566470a7 0:192 2:64
264 45a9f0d7ae592881 0:528
265 45b1a54935ceb2c3 0:48
266 45e96bef912ad310 0:208 2:16 3:64 4:16
267 460775513b16e335 0:1184
268 46163e5ef930f3b3 0:192 2:64
269 46f0c14e38986d84 0:1168
270 473d71e1f053748d 0:544
271 47a6f465106a8587 0:800
272 48163fad9263ed89 0:208 2:64
273 48a3e32fb70e711f 0:544
274 49689cfb9bce7463 0:464
275 4a25baca5a170ec6 0:208 2:64
276 4a5f8a1a29d1629b 0:1232
277 4a745ca5af81e2a1 0:512
278 4aa4baef97a82ec2 0:208 2:64
279 4ab570ca0816d510 0:208 2:64
280 4aef3b7d38a5eee4 0:208 2:96 3:16
281 4b13c1a85b5459e2 0:1200
282 4b5ad2f60e79990e 0:1200
283 4bbf98d3631a0d1a 0:784
284 4bf4acd4f3bba426 0:208 2:16 3:32 4:16
285 4c0624731bf19b5d 0:528
286 4c11452c5abce0b5 0:512
287 4c9d2e35d6d58dd3 0:192 2:64
288 4cb3eb4a9ee9e0af 0:192
289 4cb4b3b6177bc6ec 0:1168
290 4cea0257728b2574 0:1312
291 4d2ed23be38fe357 0:1216
292 4d9b38377404ef5b 0:528
293 4da44afa7db29e5f 0:208 2:64 3:64 4:16
294 4dd76d7031529a0b 0:512
295 4de3f38a50643f2d 0:512
296 4e7bffde2b238d62 0:560
297 4ebb315d245d941d 0:192 2:16 3:16 4:32
298 4ee7ba569bf78515 0:464
299 4f71d95d00e2e48c 0:496
300 4f96152ddbaca4fb 0:192 2:16 3:64 4:32
301 4fadeb6187682b76 0:192 2:64 3:32
302 4fc710ed808de18a 0:208 2:64 3:16 4:16
303 4fe465f4cb8d2e2b 0:1200
304 4fed4e0ecf59b4a3 0:208 2:16 3:64 4:16
305 4fefa68e6ba6e968 0:208 2:64 3:16
306 4ff7ea7045a2b74b 0:208 2:16
307 5045e3e810972a29 0:480
308 50eab34d17a496d7 0:480
309 51064c3ec6c8d736 0:192 1:16 2:48
310 517016b0c656918a 0:528
311 527938518f6f6561 0:80
312 52bdbf8404ae9145 0:1152
313 52d3123fffa92d4c 0:352
314 52e8d662822c47ba 0:1232
315 53444b1e81ddf54f 0:208 2:64
316 536e4bf65732bcc6 0:192 2:16 3:16 4:32
317 537e630b9823140e 0:208 2:96 3:64 4:16
318 53801d1f08daa292 0:208 2:96 3:16
319 5386e2a839c554ff 0:208 2:64
320 540b931e24ef7d1a 0:528
321 544a5c3051722647 0:192 2:64 3:112 4:32
322 545e9a73a015002f 0:1200
323 54778e89446411c3 0:208 2:64
324 548644cd8e3fa9d3 0:208 2:16
325 54d1bfc288cb5dff 0:208 2:32 3:32
326 54e2b58576b63a5c 0:400
327 55a299770c03c6be 0:192 2:16
328 55a73554e9c3296d 0:1184
329 567a7239836fcab9 0:1168
330 5693abdc10b396e0 0:528
331 56a5775ac9bf092e 0:208 2:64 3:80 4:16
332 56cc4f4a37f388c7 0:512
333 56dd42fb2f849dc3 0:656
334 56ec357dd266fd6b 0:496
335 5747a5ebd7afb442 0:144
336 574e33d2767ea13a 0:1200
337 57d709037a27e467 0:496
338 57eb9f0bae677756 0:576
339 585fde3223d3e2ce 0:528
340 589f301f398d4a69 0:1184
341 58b018066dc1aa37 0:192 2:96 3:80 4:32
342 595879360574ad7e 0:1152
343 59686d553f1fc825 0:192 2:64
344 5973606589357a47 0:208 2:64
345 59892f7b55a94b8a 0:592
346 59b33e2e4022d755 0:512
347 5a3401c28ed940a6 0:208 2:16
348 5a44ffbe60ec8eb7 0:1248
349 5b97500cd901af07 0:208 2:64
350 5bfe1be69008db55 0:1216
351 5c08b3005c958359 0:240
352 5c1a9632193fd9a3 0:1248
353 5c3ac632f0b041b5 0:208 2:64
354 5ca1c399088012ae 0:1184
355 5db8588e4c10b7c3 0:528
356 5df5426088cfdc80 0:480
357 5ebd93d976f32021 0:208 2:64 3:16 4:16
358 5ebee0fb86bab763 0:192 2:64
359 5ed5b0f68a3be9bf 0:208 2:64
360 5ee902ca16c494f0 0:192 2:96
361 5f063a7c5b7a4737 0:128 1:256 2:128 3:64 4:64
362 5f3d107483cdb5a2 0:1200
363 5f6a4bab9c4d8d94 0:208 2:16
364 5f7c712e4cb64b45 0:528
365 5f7f2a41ae11ca80 0:16
366 5ff1e55d8725a319 0:528
367 605082369f2bf104 0:208 2:64 3:64 4:16
368 60974d8687fada32 0:736
369 609d08739c5788ea 0:192 2:64 3:48 4:32
370 611cc45090cb1f99 0:528
371 61226ca69fc9ac7b 0:464
372 61c97c44da9d8afd 0:1216
373 61c998477745b90e 0:464
374 61ee121ba416e72c 0:208 2:64 3:16
375 6215dcf816c3b535 0:1248
376 625493dcbf6ccd54 0:192 2:64
377 62a5c6fdac93384a 0:480
378 62e4f3be796a24cf 0:192 2:64
379 62e7dd4607fa9396 0:560
380 63043ed8a95a008b 0:208 2:64
381 635959377ca1c1e7 0:1184
382 6374ff927aa191e3 0:528
383 63a873e28f295d74 0:1184
384 63f83fb1afaa14fc 0:592
385 643e349a7fa54af3 0:1200
386 644ebe432e7f2ffe 0:1168
387 6466ccc66322b178 0:448
388 648307fd2d1d0f6b 0:464
389 64d5783666006cf1 0:208 2:64 3:16 4:16
390 64fe98cab672d2ea 0:1200
391 655a88152b9f0898 0:80 1:256 2:128
392 65ac96e1470122cf 0:528
393 65cbffc60015759a 0:32
394 65e3bc772bff7590 0:1168
395 660992a99a3befb5 0:496
396 6635b105e0ec217d 0:592
397 66b625ef10d6bbc2 0:192 2:16 3:32 4:32
398 66e280642d7a6710 0:1264
399 66f0e023464e3001 0:496
400 66f2a59f66e98b59 0:192 2:16 3:32
401 675eeaf49b44b28f 0:192 2:16 3:32 4:32
402 678ddb5490fb5c08 0:496
403 67dc5f84ac6fbd5f 0:208 2:64 3:16 4:16
404 67ffe6dd06e39b24 0:464
405 6805a2145f46019b 0:208 2:16 3:64 4:16
406 6827963f46253124 0:1184
407 682c656ad19017ac 0:544
408 687b3775ceda1da1 0:1200
409 688892bb5017b36c 0:528
410 68d491fd03e715bb 0:1184
411 68ddccc6fb6acf4b 0:528
412 6917f5c2ad8e9ee6 0:112
413 696de079c9bd18eb 0:208 2:96 3:64 4:16
414 697f239e9c9f35dd 0:192 2:16 3:64
415 69998cc359854bb1 0:1168
416 6a0143486947af9a 0:496
417 6a52feae5b9cb58d 0:464
418 6a849c4394084afe 0:1200
419 6a92c50cd83ab97b 0:448
420 6b1871742afff7c4 0:192 2:64 3:112 4:32
421 6b7035d155e17030 0:192 2:64 3:32 4:32
422 6bb501b4d5cb43ea 0:512
423 6c1623278f10e38b 0:464
424 6c23bbcc17ecc9c3 0:528
425 6c66c6f06e1bed24 0:1248
426 6c8032ea54265a5a 0:16
427 6ce939515d9bc070 0:64
428 6d622d39e924d58a 0:1184
429 6e0ab5ac33578a43 0:592
430 6e4686d46ac46a71 0:464
431 6e50a7ec29679a47 0:208 2:64
432 6e5726691e94e1c3 0:464
433 6e71588b624826e3 0:528
434 6ea5555f0fad5d3d 0:480
435 6ed2a6583f5b1831 0:1184
436 6ee84a40a1128a8b 0:192 2:64 3:16 4:32
437 6f44ca79edffe6cc 0:592
438 6f80d16b55406f55 0:192 2:16
439 7027a7f207f0fd6c 0:1168
440 709f19d5ba01f6d3 0:192 2:64
441 70b2843f4e977fdb 0:1264
442 70f943134590d9fe 0:192 2:16
443 7167e3f85e5f2444 0:400
444 716f7d03325acee6 0:864
445 7184314ce6e70db7 0:1152
446 718fe4f11868377e 0:208 2:96
447 72819fa5a9fd08d6 0:208 2:80
448 72b5bce0c8256361 0:528
449 7314b420d3346547 0:192 2:16
450 7320b5755e1ffdd9 0:192 2:96 3:16 4:32
451 732f93ede2aa79ba 0:544
452 7341259ffbc22506 0:1184
453 73692e62e8226b02 0:560
454 73c223f06e1aab66 0:192 2:64
455 7400f35f4da6929a 0:496
456 7411c3e2cc7e0a94 0:592
457 742c3a773a8f0ae9 0:432
458 745da253f6892e04 0:192 2:64
459 74ab3bd004f79fa4 0:464
460 74ff5c53b5fb2347 0:464
461 7574e2533fd31332 0:464
462 758bf3768cb023d3 0:192
463 75b2300b991bd4c0 0:640
464 75cb4e487e34a232 0:592
465 7636729ea37f67b4 0:1264
466 76603f778fd57d10 0:448
467 770ee33d19b3b845 0:1152
468 77117455bcf5568c 0:208 2:64
469 7740409d6a974e50 0:208 2:64
470 77c6e939de2ef98d 0:416
471 77d4c4e80b5b72a2 0:208 2:64
472 77dcc8352daeec2d 0:1232
473 781f4b9fcc4d3772 0:560
474 78485403b8b73a8f 0:192 2:64
475 785d755ef0ee47f2 0:208 2:96 3:48 4:16
476 78b3f6b626aeb812 0:1152
477 78f4adf82303c990 0:480
478 78f87b399904ae28 0:464
479 7902a648c56e7b7f 0:400
480 790d30f6f432e325 0:208 2:16
481 7a0c72875a585df1 0:208 2:96
482 7a1e2727350c3b8d 0:592
483 7a779ef059afcb67 0:592
484 7a9f384c513787e8 0:592
485 7abdc0dacf340544 0:1216
486 7aecd1d0a2dc9fa2 0:1184
487 7b741e480d3e98f4 0:528
488 7bd6d4d30ce672a5 0:512
489 7c69c9c67234c96e 0:208 2:16
490 7d37b62275d06824 0:512
491 7de4f2f2ee4919c2 0:528
492 7e030ce90774dd83 0:496
493 7e5b6de4a9f76aca 0:464
494 7e88880eff483ace 0:1264
495 7e96e7379ce709ee 0:208 2:16
496 7e99e5710af25b9a 0:496
497 7eb6f3c8a5e1f9f3 0:192 2:64
498 7ecffedf1eee3bb2 0:560
499 7f212cf7905652f9 0:208 2:16
500 7f6cd11d97596427 0:1168
501 7f9cb173d93da9b4 0:192 2:96
502 7faa98edafbf8135 0:1216
503 7fb80dbb61c913ae 0:1168
504 7fc0b0b0007d760f 0:592
505 80689f71d4f7c741 0:512
506 816ebf680bed5bef 0:208 2:64
507 81a0bf7aa31debd6 0:448
508 81e823c97cb21bb1 0:208 2:64
509 822cb9fd05ab0907 0:1168
510 822f00337477980d 0:192 2:16
511 8252bf0ca730ce90 0:208 2:64 3:32 4:16
512 82c6c4a0d90eec41 0:480
513 82cfc5f415335c95 0:208 2:16
514 82da5c17ef5997a8 0:192 2:64
515 82e274e6a3127f30 0:528
516 82e653b3fa51dcce 0:80
517 831a6f33a80978c0 0:1232
518 835a1dae93272ed3 0:480
519 838d01df115b29a7 0:464
520 83c6c5ca6d8349b6 0:528
521 83cab67e5d4b8dd4 0:528
522 844468d613651334 0:464
523 84d577aa4ed5550d 0:192 2:16 3:112 4:32
524 84f6b38693136738 0:192 2:64 3:48 4:32
525 8506547be3983b26 0:1248
526 859faca9533a193d 0:192 2:64 3:16
527 861c1d4ecec13867 0:208 2:16 3:64 4:16
528 863ca276f8260416 0:192 2:64
529 866fbc503e77a0e7 0:192 2:64
530 86c7db14355e59c3 0:464
531 86d47c3b5e18c878 0:1152
532 86f91d4c7bdcc4a2 0:192 2:64
533 8706768352dea538 0:1168
534 876f5eb6e1f1a81d 0:464
535 87d03e98e5709fa5 0:112 1:256 2:128 3:64
536 8831169cdd60ccbb 0:1248
537 8837a45f035664b1 0:1184
538 886497cebb33306d 0:528
539 88fa765ab7ac0852 0:192 2:16
540 89405f3b226b9df4 0:1168
541 896a4646ce982ce2 0:528
542 89aeb839833d6a08 0:192 2:96
543 89cc64dd4084887b 0:528
544 89d815d8c2ce381e 0:192 2:96
545 8ae29b8cbc478adc 0:448
546 8af70f7ca64d873f 0:48
547 8b26f1dd2d620f24 0:208 2:64
548 8b4f7aad9ad65d5f 0:1264
549 8bc82a8d6f11b5d9 0:544
550 8bf0c62d350e30ee 0:400
551 8bfaa882b7dcd0fc 0:544
552 8c3bdd2d11286815 0:208 2:96
553 8c3e4adea4e3517b 0:464
554 8c510dcb60cabb24 0:208 2:64
555 8cf2c91be8b954ea 0:208 2:64
556 8cf582b137cb33c7 0:448
557 8cfb5649bc82a517 0:192 2:64
558 8d11a3c302e169a8 0:1264
559 8d1ced293b413257 0:192 2:96 3:80 4:32
560 8d58714986811eff 0:1216
561 8d5fb93120a78f56 0:192 2:64 3:64 4:32
562 8d6e001aaf877360 0:208 2:16 3:96 4:16
563 8d6e52fead65a464 0:1168
564 8e46e46c246eb256 0:208 2:16 3:64 4:16
565 8e544452e34cc4bb 0:208 2:16 3:64 4:16
566 8eb3388626ca59f6 0:528
567 8f28587560d29439 0:208 2:16
568 8f2fa8f65c48ff16 0:784
569 8fcd3a61b34d3fbd 0:528
570 901b1aa492d63dd5 0:192 2:16
571 9032b774f74493fb 0:1264
572 90dcca4efc518101 0:192 2:64 3:16 4:32
573 9125415f789df81b 0:1152
574 91329e8e026e7853 0:1168
575 913fea846027d43c 0:1152
576 91af6ae142f930a4 0:208 2:64 3:16
577 91fc7e6b7322ffde 0:208 2:64
578 92afeef02edc2e5d 0:528
579 92babd83d6e080cf 0:208 2:64
580 92ea41ac31ac84ea 0:208 2:16
581 933354857016d925 0:464
582 933b62107007fe6d 0:464
583 934f95f84e221a95 0:208 2:64 3:16 4:16
584 941bf816aa50e01d 0:528
585 9441ea587bda3d8e 0:1168
586 94a5695671dc298b 0:464
587 9531d4ba58afdb02 0:544
588 955ece1e8ddb3956 0:448
589 9561d9abcc7fe61e 0:208 2:64 3:32 4:16
590 958550eba5319747 0:544
591 95a16c24d9064390 0:1360
592 95de928183c8086c 0:464
593 95e3e6db38052743 0:192 2:64 3:48 4:32
594 95ec7d9bfc408f08 0:400
595 9613f24c29827a94 0:448
596 963bd6fe203f4d20 0:1168
597 96d81152277e6188 0:80
598 971b6f7d9d327218 0:544
599 97f8dab29dce5012 0:192 2:64
600 985458a944f9f170 0:592
601 98b25235aaef2fe5 0:208 2:96 3:64 4:16
602 98bbcfb9d832b0f5 0:192 2:16
603 98bf391aa0e67449 0:528
604 98cbca7a4d4724f4 0:448
605 9a06bcd0ab84e644 0:528
606 9a61ac18d9c75733 0:1216
607 9a7ad8b14fb31e24 0:528
608 9a7b26ed2fab9615 0:1264
609 9a84efe6f01cd73f 0:112 1:256 2:128
610 9ae52c66b0faec14 0:608
611 9bdcfb3b3b54602e 0:736
612 9befee0e8c9c4927 0:544
613 9c0f034b987c7751 0:528
614 9c5b321b46b25570 0:192 2:16
615 9c6d1f06fd864412 0:688
616 9cdad29d947cc0c4 0:1280
617 9ce66165b6f30935 0:208 2:64 3:16
618 9cfe01a18deca01d 0:592
619 9d124705b08333df 0:192 2:64 3:16
620 9d9eaef02864f136 0:1216
621 9e69638daed6b381 0:1168
622 9f22a3d3c70a4801 0:416
623 9f9f47bcc7b3195a 0:448
624 9fc6597ba76dc705 0:208 2:16
625 9fe954ccfabf1160 0:192 2:16 3:16
626 a05f9d7b331e2876 0:464
627 a0992be934d44874 0:208 2:64 3:16
628 a09a5306816b9004 0:400
629 a0bad0342bd595dd 0:1232
630 a12a4169b7c164bc 0:1280
631 a14aad935ffb7470 0:192 2:64 3:16 4:32
632 a1640081386f2e66 0:208 2:64 3:16 4:16
633 a1cbb29c982a3e60 0:528
634 a20de470dbd2eb4b 0:208 2:16
635 a210c344462d78b8 0:544
636 a280140f655ee935 0:480
637 a30786c95a76c53e 0:432
638 a32678d25472822d 0:192 2:64
639 a36f488cfd82f6b5 0:496
640 a3ccd8f0e442d8f7 0:208 2:16
641 a3efc18daab22509 0:1152
642 a410763a3a798eee 0:448
643 a41728dc2407ee9a 0:1312
644 a44395086ff087a9 0:192 2:96
645 a4b87dcff13f7b0f 0:192 2:64 3:16 4:32
646 a553f143aaf98769 0:496
647 a5e9290b220a7773 0:208 2:96
648 a626b4a678133eb9 0:208 2:96
649 a6a4e82f2cdf33b2 0:528
650 a6ec6e93725105da 0:192 2:64
651 a7274f8eaf7250b1 0:192 2:16
652 a732a93a74cd76c4 0:480
653 a76bdce7a156d80b 0:1184
654 a786cb63d76555d2 0:208 2:64
655 a7a9b39af5c96d21 0:80
656 a7da670a58459aa5 0:208 2:16 3:64 4:16
657 a827b657befaf9ae 0:208 2:64
658 a828270905ed9d3b 0:528
659 a8ccff62f3ffda8e 0:448
660 a90886f6b308c31f 0:560
661 a908e733565a79e7 0:208 2:64
662 a96e1f61f417abf7 0:528
663 a97c91ce0536b332 0:192 2:64 3:16 4:32
664 a9aa5ef0461fb5e1 0:1184
665 aa5764bb57838f4f 0:192 2:64
666 aa90fe76eeb8a845 0:1248
667 aae14b048a1796c8 0:208 2:16 3:96 4:16
668 ab059fd4b22c4ad3 0:512
669 ab7761bae4d49b7b 0:544
670 abb01305ec2aa3e8 0:208 2:64 3:16 4:16
671 abd5727f1ff718bb 0:448
672 ac44c282a2805b12 0:208 2:64 3:48 4:16
673 ac471f459daa97cc 0:544
674 ac7b09f708a78fe4 0:192 2:16
675 acb7d5c564d73ce4 0:464
676 ad18d54baad8ad46 0:192 2:64 3:16 4:32
677 ad6c796c2322274b 0:448
678 ae243c8e877fde07 0:192 2:64
679 ae24d7227bec6488 0:192 2:96 3:16
680 ae3ceb9a28c88ee0 0:192 2:16
681 aeef39cc613852fd 0:1232
682 af1e522c49491e98 0:1264
683 af3062070920c929 0:592
684 af6772a753a31e13 0:208 2:96 3:16 4:16
685 afc555a481ea1de5 0:400
686 afc601ce1ead8d3b 0:448
687 afd2209d3c272d0c 0:592
688 b04d08256112da23 0:192 2:64
689 b0bbde5bfe7b67ae 0:1248
690 b15e2e252b5337ed 0:192 2:96
691 b25951e9dc31546e 0:112 1:256 2:128
692 b31f397cedf8567c 0:496
693 b333a7c9ff076d6f 0:192 2:64
694 b347b0c4498ffc1d 0:1200
695 b395b955b4826514 0:448
696 b3f4a51f54de75e1 0:592
697 b3fbbd14979825a5 0:528
698 b407597ede6be1e4 0:496
699 b40e8fe71f3407e3 0:432
700 b4fbff6d0ddd8b42 0:192 2:64
701 b52e21ef0e18f720 0:208 2:96 3:64 4:16
702 b59f236cb6b8b5e4 0:192 2:64
703 b5bf81b57551c213 0:1152
704 b64bbed3300cbbb9 0:208 2:16 3:64 4:16
705 b682f507eef5f6be 0:432
706 b6a0e8fcd17d5f88 0:192 2:64
707 b6eed402da843ec1 0:496
708 b6f0c9892178bf5a 0:128
709 b7304eaa0d07241c 0:512
710 b781d83e79fad241 0:528
711 b84680c71f88ae7c 0:480
712 b84d9cd8248c7623 0:192 2:64 3:16 4:32
713 b858d6dfe05a97c8 0:592
714 b873e523e8facb66 0:192 2:16
715 b8d3458ec0dc178a 0:448
716 b92dd53682242df5 0:432
717 b98f6dae553d5ff5 0:528
718 b9d1bcc25bfca06d 0:208 2:64
719 b9ef417381310c88 0:544
720 b9f6877db8668668 0:192 2:16
721 ba08836dabf5801e 0:464
722 ba58aaff1ee9531b 0:208 2:64
723 ba8e34c7fc612783 0:192 2:16
724 bae8c8b0e58a587f 0:48
725 bb0cbd5ac10f04fb 0:464
726 bb3dce3a02e8843d 0:112 1:256 2:128
727 bb5924e15cd4315b 0:192 2:96
728 bb5bed02c1638244 0:192 2:16
729 bb9a2b9bacd59ba0 0:1216
730 bbb5b0ed7e681362 0:592
731 bbe70fc18588aca3 0:48
732 bc468827ff2f3b50 0:528
733 bca7605eba5a4c80 0:544
734 bcafcb418bc346d7 0:192 2:64
735 bcec454f95b64436 0:1232
736 bcedfe12546a35b8 0:432
737 bd5028f8e14dae2d 0:464
738 bd80064be800c382 0:208 2:64
739 bd84c3cbaa259d2e 0:528
740 bda8618c2611835a 0:1232
741 bead1e6e158e7de3 0:208 2:96 3:48 4:16
742 bf1a45588aebc762 0:112
743 bff24c45c555fc31 0:544
744 c01a293c7b3703ef 0:464
745 c0fc767548a5c9e1 0:592
746 c0fde9561d5c5151 0:480
747 c1017ce2b48113cb 0:192 2:96
748 c1f18b2833678922 0:592
749 c278c2d2c0387ae5 0:464
750 c2bd22921d7a7a09 0:208 2:64
751 c301e6962c288a26 0:496
752 c341e35528812cf4 0:1168
753 c360ba56937ce7ce 0:464
754 c36399e4e6acdde2 0:448
755 c3fdbeb58935c082 0:192 2:64
756 c3fdd18088f8733d 0:192 2:16 3:64 4:32
757 c405bc420ad6a050 0:192 2:96
758 c41fe4dcf9c937cc 0:528
759 c4a09fc85fc26129 0:1200
760 c4c3f2b5a927662b 0:544
761 c4f6bf1dcd96904f 0:608
762 c55795062e95790c 0:208 2:96
763 c577b6ba3d77fa86 0:480
764 c5910693e0d562e2 0:192 1:1008
765 c59ff46edc6f8fa6 0:48
766 c5f9c582741821be 0:208 2:64 3:16 4:16
767 c63326013ebf35e9 0:528
768 c6db0e51afb5abf8 0:464
769 c737b928574cf9ad 0:1168
770 c77cbbcbb032741c 0:208 2:64
771 c7835882cf62088e 0:192 2:64
772 c85c1dfe14f56fba 0:208 2:64
773 c8baef0558872e4c 0:1312
774 c94c5953c973d6fa 0:592
775 c96e863a8b9c583a 0:544
776 c99bd3ba69b5e0f2 0:432
777 c99d8b2b90177d79 0:208 2:64 3:16
778 c9d8010ed9dcea74 0:1328
779 ca517cadf1ef811a 0:208 2:16
780 ca5eff94c0f04ecc 0:416
781 ca78c1fbf996d764 0:496
782 ca7f3463080a1dbe 0:464
783 cad9220e876e92b9 0:192 2:64
784 cae8f1d55cf78304 0:528
785 cb55db1eff5516f2 0:1168
786 cb5b73f3de96fdfe 0:496
787 cb8d4026fa1524df 0:208 2:16 3:32 4:16
788 cbcb384c18cbf4be 0:1200
789 cc0450bafa36cc95 0:192 2:16
790 cc561305cc2dfbfa 0:464
791 cc8b1dd2195237a8 0:192 2:64
792 ccbf5de61419aed0 0:448
793 ccf32a372045005a 0:592
794 ccfb6fa1aa81030d 0:192 2:64
795 cd42e2fa635b2ca0 0:1232
796 cd717acb78537d5e 0:544
797 cd7b535c64685673 0:560
798 cda978100923d1f9 0:592
799 cdb50cb5b0828103 0:192 2:64 3:16 4:32
800 cdcf84461201462f 0:464
801 cde8027493f803f8 0:224 2:16
802 cf32cd6dc1f72bfa 0:448
803 cf3d275b207a69ca 0:208 2:64 3:32 4:16
804 cf5f34b0c1af8365 0:208 2:64 3:32 4:16
805 cf68a638da698af4 0:192 2:16
806 cf6e2c83dddcad7a 0:464
807 cf87d5f3cc891bc8 0:1168
808 cf8f489717ed15ae 0:208 2:64
809 d025695a5566cca0 0:528
810 d07b492ad22e2df8 0:464
811 d14823342bef41ed 0:192 2:64 3:32
812 d1f5c6df4ae2219b 0:192 2:16
813 d204f21692e053ff 0:1216
814 d22f583ec3826ab0 0:208 2:64 3:16
815 d23bc0f264c475b9 0:1216
816 d30570448de42896 0:496
817 d30acad2d9b9bc43 0:528
818 d31a3183db64e0e8 0:1200
819 d36e5715f125f4dd 0:608
820 d3a66c4920653135 0:1168
821 d416b9aca97312a6 0:192 2:64
822 d43b2274abd88032 0:512
823 d482b3669b471ca5 0:208 2:64 3:16 4:16
824 d4d35c53ef0eb5bd 0:304
825 d4edcad6035f18c0 0:592
826 d519a462cf425560 0:464
827 d57cd67cce36761d 0:496
828 d59e91af3eee964e 0:496
829 d622ffd0746fb0d5 0:208 2:16
830 d6746698b6d80f79 0:192 2:64
831 d675b527562414b0 0:192 2:16
832 d677a206a8953fbd 0:512
833 d6b26908dab29f90 0:208 2:16
834 d723b4e348929c5d 0:480
835 d7262203afc69a04 0:192 2:64
836 d7850c91ca03badb 0:1152
837 d8604fcaccee09e3 0:1184
838 d861fd7ab21e0db1 0:592
839 d8818274c76aba5d 0:576
840 d89ace4f0ca24729 0:208 2:96 3:16
841 d8c7761f49b123d9 0:592
842 d8d69e1d5331e497 0:1184
843 d8f36d6cd852aded 0:528
844 d8f69f92af8e18f2 0:512
845 d8f8c1b46dfb7123 0:48
846 d9b2cdd1dd232007 0:1168
847 d9b49de3db5b572b 0:544
848 da1deba2a03bcfc6 0:592
849 db1f225b63c988aa 0:192 2:16 3:80 4:32
850 db3e3e14f48d03e1 0:1280
851 db404d0fc9580f0b 0:512
852 db6c25bb6b954bf8 0:208 2:64 3:16 4:16
853 db7d66f85e032b97 0:432
854 dbbc092887bdd0ea 0:1248
855 dc689ba359f0b368 0:496
856 dd43b024931f0093 0:592
857 ddc8abd795a1d0c7 0:448
858 de3d71c0869adc36 0:192 2:16
859 df27f7def45498cd 0:1200
860 df2cfe75ab01dcab 0:1200
861 df8dbb9862f3a058 0:528
862 dfb282ec0bb39448 0:544
863 dfdf8fbb1c8c18b1 0:512
864 e0008c01e6066dac 0:208 2:80
865 e079b0132b309178 0:464
866 e07c1fdd14da3b08 0:192 2:16 3:96 4:32
867 e0fea43c24726d0e 0:448
868 e1b5d46b45f96b9c 0:1200
869 e1b89e09a307a3ea 0:208 2:16
870 e1c39914a4c3857e 0:480
871 e21b68db4ac70c6a 0:528
872 e226c1dc0f1150f7 0:448
873 e271fee63eaa0da8 0:512
874 e27f19141815d125 0:1152
875 e2c187c6a2e2e414 0:208 2:64
876 e2e3e51468b16894 0:192 2:64
877 e38e10c676070c47 0:192 2:64 3:16 4:32
878 e3cd43337031cc8b 0:1184
879 e3dd41b33751ec7d 0:432
880 e3f0bc2e8d4e4d01 0:192 2:64 3:16
881 e3fb91550b67114f 0:496
882 e401a1a2ec9c30cc 0:80
883 e40e53e5b7125f33 0:1184
884 e47ad056df2c2a3d 0:1168
885 e48825cdc7119225 0:1216
886 e4d32f54b3729f1f 0:176
887 e4db543505579a99 0:208 2:64
888 e506ce03486acbde 0:1184
889 e63de66413b44081 0:1200
890 e675470eb45f4b42 0:1168
891 e68dd6c0731b5f29 0:208 2:64 3:16 4:16
892 e6b3b9bbccd7e6e3 0:448
893 e6c956b8fee60aed 0:192 2:64
894 e6d1e77c66edf899 0:208 2:16 3:48 4:16
895 e6f150a366bf08cd 0:800
896 e71c3c1c1c20a804 0:400
897 e724108d5072402c 0:208 2:16 3:32 4:16
898 e81a8b7736dd8501 0:432
899 e82f9bda6415ad3f 0:1232
900 e85685d1535d8f83 0:192 2:16
901 e8a019034500be81 0:480
902 e8a325a1f064cc10 0:208 2:64
903 e8d6a5f59a363efb 0:208 2:64 3:16
904 e8f5b73417fc21e7 0:1168
905 e90929433e4ee59c 0:640
906 e93ab2c1e13c3ee8 0:1248
907 e95d4d4a94af1cc9 0:1248
908 ea7af5dc3727a6ec 0:1184
909 ead0f03e7ba90095 0:208 2:64
910 eb8b222f4690b108 0:208 2:16 3:64 4:16
911 ebcb4d55c3ab2462 0:208 2:16
912 ec30dbb9070217fe 0:496
913 ec3e328e16b652c0 0:1264
914 ec51312631c2dcb0 0:544
915 ed58f8b79a4c5d9f 0:528
916 eda7d956ec545ed8 0:1168
917 edad9c00bca23a7b 0:192 2:64 3:48 4:32
918 edb0aafdda50e9db 0:192 2:96 3:16 4:32
919 edbfa86039cac6d8 0:512
920 edc21380fc66486c 0:496
921 edcc77ab7f338866 0:1152
922 ee270de1f09c9ba2 0:192 2:16 3:16
923 ee5ca4fcd176cd6f 0:32
924 ee8044f0a4342a10 0:512
925 ee85b78bd36690a5 0:1152
926 eee1790176db5307 0:528
927 ef47d534616d4472 0:512
928 ef7b66c0c00244f7 0:208 2:64
929 ef856164f73e2368 0:208 2:64
930 f0628d4bb33771b2 0:496
931 f08d8f8c69d32fa5 0:208 2:64
932 f0bea8670c0b05ef 0:1264
933 f0f22f9493294d06 0:480
934 f0faad4f3f8b6b1b 0:1232
935 f11ea123b6ed7853 0:160
936 f12091d5bf9470d1 0:1168
937 f122ec10981114e3 0:1184
938 f13ff42b17bcb8ad 0:528
939 f198cc7a8d8c0e49 0:528
940 f203f913e66532ef 0:528
941 f221aa2df3b4fcba 0:528
942 f249285c00b3a9d2 0:528
943 f252f8bedf0aa606 0:128 1:256 2:128 3:64
944 f275374609bbe536 0:208 2:64 3:32 4:16
945 f2b347ee8ae57e01 0:208 2:64
946 f351721b8c6764dc 0:528
947 f37c7e79260afe79 0:800
948 f39c6b4ac55f892c 0:464
949 f3b6b038640f5519 0:464
950 f3c871a629010d87 0:192 2:64 3:160 4:32
951 f3d7a9b76f723b33 0:80 1:256 2:128
952 f4200d5b98bca00a 0:1280
953 f424e68100171725 0:208 2:64
954 f4a66d24d39a4ee6 0:1168
955 f4e1a5f0b4be960e 0:400
956 f51aa565930e5354 0:800
957 f52f55248284851d 0:512
958 f55cf0b300cb88df 0:400
959 f576e164768043af 0:1216
960 f596244c670b82ba 0:1232
961 f6669ed1d4e877cb 0:128
962 f6d47fcac91d417d 0:208 2:64
963 f700f0b9f3ce0a7f 0:1232
964 f70f558fdff37b62 0:496
965 f720642ffcefa61a 0:1168
966 f72ffe6b715001ec 0:192 2:64
967 f74c00e45881019b 0:464
968 f826f2b59cfa39a8 0:576
969 f89a6b4b5fd3355a 0:1152
970 f8b826aec94f1c15 0:464
971 f8e86ea53fdd1479 0:496
972 f8ec95d23fe6bae6 0:64
973 f8f7c54fabd23d07 0:208 2:64
974 f99781c61846b4f9 0:208 2:64
975 f99ea1392887bbd7 0:512
976 f9a3a92a90dee9a0 0:512
977 fa1ffaed7eefa476 0:464
978 fa6464f7942ef4b9 0:1232
979 faf59ecce1662eb6 0:208 2:16 3:64 4:16
980 fb1645bccb830255 0:112 1:256 2:128 3:64
981 fb3d2f49371dabc5 0:208 2:64
982 fb3d68e98aa0ff81 0:544
983 fb73a1c82d9939d5 0:64
984 fcb0d2c1c0a73902 0:208 2:64
985 fcb86e7811c11425 0:208 2:96 3:16
986 fd1165c2de978f87 0:1168
987 fd2b13f97cfb0508 0:192 2:64 3:16
988 fdb444c7f0c947d2 0:784
989 fdf3efae5e94691f 0:512
990 fe18f03e74364843 0:1184
991 fe1e825f5ba68e67 0:480
992 fe4a97973adb94f6 0:208 2:64
993 fe911827664c56ce 0:1248
994 ff30022fc3965465 0:512
995 ff3e559d88724492 0:192 2:16
996 ffc89e780ac33776 0:432
997 ffcfb49e7f03fde9 0:1152
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+3 -2
View File
@@ -6,6 +6,7 @@ Each game the port knows has a folder `dm/games/<id>/`, named after the base gam
- **The shader tables** that `shader_split.py` writes: `shader_map.tsv` (+ `.conflicts.tsv`), `shader_facts.tsv`, `shader_pairs.tsv`.
- **`shader_facts_manual.tsv`** (optional): hand-written translation facts in `shader_facts.tsv`'s row format, for what the machine code cannot tell (Link's Awakening: a vertex input the integer-input guess gets wrong; Breath of the Wild and Tears of the Kingdom: integer fragment outputs, which a game without a PC version has no other source for). `shader_split.py` merges it over the generated rows; since the table is on the chain, changing it changes only that profile's chain version.
- **`c1_full.tsv`**: regenerated by `c1_guard.py` after each shader build.
- **`cb_extent.tsv`**: how far into each uniform slot every shader can read; regenerated by `cb_extent.py` after each shader build (optional: without it a uniform block the game updates in part inside a render pass is copied whole).
- **`pso_manifest.tsv`**: the prewarm seed list.
- **`vk_capture.tsv`** (a Vulkan game that generates its shaders at run time, Super Mario Galaxy): the keys of the SPIR-V modules it generates.
- **`bf_want.tsv`**.
@@ -88,12 +89,12 @@ These are not profile keys: the tools read them from the game files each time, b
No short run decides `render_cond`, `tex_flush_upload`, `tex_dirty_upload`, `core_preempt`, `gpu_timestamps`, `feedback_snap`, `alpha_from_red`, `vconv_range` or `present_interval`, nor `op_mode` / `pad_layout` outside the presets: they keep their defaults for a developer. A minute's boot without input counted Wonder's clears under render conditions (65,536 or more; it needs no `render_cond`) as readily as Tears of the Kingdom's, saw Breath of the Wild flush 32 CPU-filled textures with data (it needs no `tex_flush_upload`) and Age of Calamity none (its movie frames come later), and Metroid Dread's movie crash shows in about half the runs. On the iPhone, `Documents/env.txt` can still set `DM_OPMODE`, `DM_NVN_GPU_TS` and `DM_NVN_FB_SNAP`, and the pad layout switches in game.
The shader tables, `dmsh_chain.h` and `c1_full.tsv` are written into the same folder. A second run reuses that `game.tsv` (delete it to survey again), so it can be edited by hand. `--provisional` builds from a provisional profile even for a game that has one in `dm/games`, to test the guesses: `DM_GAMES_FIRST=1` makes every tool search `DM_GAMES_DIR` first, and the IPA gets `-provisional` in its name. Tools find profiles outside `dm/games` through `DM_GAMES_DIR` (folders separated by `:`, searched after `dm/games`); `make -C dm/host` reaches such a profile through the symlink `dm/host/gen/<id>/profile`. To keep a game, move the folder into `dm/games/` and bring it up as below.
The shader tables, `dmsh_chain.h`, `c1_full.tsv` and `cb_extent.tsv` are written into the same folder. A second run reuses that `game.tsv` (delete it to survey again), so it can be edited by hand. `--provisional` builds from a provisional profile even for a game that has one in `dm/games`, to test the guesses: `DM_GAMES_FIRST=1` makes every tool search `DM_GAMES_DIR` first, and the IPA gets `-provisional` in its name. Tools find profiles outside `dm/games` through `DM_GAMES_DIR` (folders separated by `:`, searched after `dm/games`); `make -C dm/host` reaches such a profile through the symlink `dm/host/gen/<id>/profile`. To keep a game, move the folder into `dm/games/` and bring it up as below.
2. **Profile.** Copy `010015100B514000/game.tsv` (or the provisional profile) to `dm/games/<title ID>/game.tsv` (the base game's title ID, as the folder name) and fill in the identity, `build` rows and `modules`. Leave the memory values as Mario's until the bring-up measures them ([docs/agents](../../docs/agents/README.md)).
3. **Shader tables.** Run `DM_GAME=<id> shader_split.py … dm/games/<id>/shader_map.tsv dm/games/<id>/shader_facts.tsv dm/games/<id>/shader_pairs.tsv`. Add an empty `shader_map.tsv.conflicts.tsv`, `bf_want.tsv` and `pso_manifest.tsv` (copy Mario's headers).
4. **Chain.**
1. `DM_GAME=<id> dmsh_chain.py --header`
2. `DM_GAME=<id> [IOSOUT=…] dmsh_build.py <pkg> <cache>`
3. `c1_guard.py <cache>/b-<V> dm/games/<id>/c1_full.tsv`
3. `c1_guard.py <cache>/b-<V> dm/games/<id>/c1_full.tsv` and `cb_extent.py <cache>/b-<V> dm/games/<id>/cb_extent.tsv`
5. **Host bring-up.** Run `make -C dm/host GAME=<id>`, then work through the bring-up loop in docs/agents. Code that only fits one game is gated by its build ID (`dm_main_build()`), never left to run on every game.
6. **IPA.** Use `GAME=<id> dm/ios/tools/build_ipa.sh`, or the NSP script, which now finds the profile.
+3 -1
View File
@@ -49,6 +49,7 @@ The whole chain is driven by `tools/dmsh_build.py`, and `setup.sh` runs it for y
- `dmsh_chain.py --header`: rewrites `dm/games/<id>/dmsh_chain.h`.
- It is normal for the local Xcode or spirv-cross version to differ from the one registered in the repository; `setup.sh` automatically re-registers according to the local tools.
- **`dm/games/<id>/c1_full.tsv`**: the index list for the shaders' built-in constant section (c1), generated by `tools/c1_guard.py` scanning the translated MSL; it lists the shader keys whose "run-time index could not be proven bounded". An index counts as proven only when interval arithmetic over the whole expression (every variable followed to its single definition; literals, `& K`, `% K`, shifts, `min`, `max`, `clamp` and casts bound it) keeps it non-negative and inside the span a shared bank gives that shader: its c1 data rounded up to 256 bytes plus the 256-byte zero gap. Every stage counts (`vp_`, `fp_`, `cp_` …). Its first line records the `b-<V>` it corresponds to. For the shaders on the list the replay layer allocates a separate whole 64 KiB buffer for c1; when the list is missing or its version does not match, it reports red and conservatively treats all shaders this way.
- **`dm/games/<id>/cb_extent.tsv`**: how far into each uniform slot (cbuf binding) every shader can read, generated by `tools/cb_extent.py` from the translated MSL with `c1_guard.py`'s interval arithmetic: per shader key, `reg:bytes` for each slot whose reads are all proven to stay inside its first bytes, and `s<reg>` for each storage slot the shader never writes (SPIRV-Cross types every storage buffer Ryujinx emits as writable, so the host counts the others as written). When the game updates part of a bound uniform block inside a render pass, the replay layer copies only that much of the binding to give the draws after the update their data without ending the pass (`nvn_mtl.m` `ubp_get`; Breath of the Wild binds a 64 KiB block and its vertex shaders read at most 544 bytes of it). Its first line records the `b-<V>` it corresponds to; when it is missing or stale, bindings are copied whole (up to 64 KiB).
- **`dm/games/<id>/shader_pairs.tsv`**: the (vertex key, pixel key) of every BNSH variation (Unity: of every program), written by `tools/shader_split.py`. Metal only builds a pipeline when every pixel shader input is a vertex shader output, while Maxwell gives an unwritten attribute a default; `dmsh_build.py` therefore adds the outputs a vertex shader's partners read but it doesn't write, set to (0, 0, 0, 1) (`vs_pad`). The table is part of the translation chain version.
- **Several game versions**: `shader_split.py` takes comma-separated RomFS and `main` lists (base game first) and writes the union; the map, facts and pairs tables currently cover Mario v0 and 1.2.1.
- **`dm/games/<id>/pso_manifest.tsv`**: the warm-up seed manifest bundled with the app: shaders (`S`), render pipelines (`R`, the hex of `pso_skey` in `nvn/nvn_pso_skey.h`) and compute pipelines (`C`) to pre-build at startup. The row order is the pre-build order (first use); do not sort it. Its companion is `pso_user.tsv`, which the host appends next to the save directory whenever it has to build something on the spot, and which is pre-built after the seed at the next launch. Both name shaders by key and describe pipeline settings only, so a list recorded on one device works on any other; lines a build cannot use are skipped. Recorded lines can be appended to the seed below its header (currently empty).
@@ -92,6 +93,7 @@ The scripts in `tools/`; usage is written in each file's header:
| `dmsh_facts.py` | Reads the answer table `shader_facts.tsv` (which `shader_split.py` writes) |
| `dmsh_fetch.py` | Generates the "readable tile" versions of fragment shaders |
| `c1_guard.py` | Generates `c1_full.tsv` |
| `cb_extent.py` | Generates `cb_extent.tsv` |
| `dmsh_dryrun.py` | Dry-run conversion of the whole library, measuring only "can it be converted" |
| `gen_protos.py` | Generates `nvn_protos.h` / the thunks |
| `tbdr_budget.py`, `tbdr_load_dead.py`, `tbdr_store_dead.py`, `tbdr_pass_merge.py` | Read the `DM_NVN_PASSDUMP` log and analyze the load / store volume of each render pass's attachments per frame |
@@ -106,7 +108,7 @@ The shader libraries are generated by `setup.sh`:
- the Mac version is in `$DM_ROOT/build/cache/metal_shader_cache/b-<V>/`;
- the iOS version is in `$DM_ROOT/build/ios/dmsh_b/b-<V>/`.
After changing a file on the translation chain, the order for rebuilding manually is the same as in `setup.sh`: `dmsh_chain.py --header` → `dmsh_build.py` → `c1_guard.py` → recompile the host.
After changing a file on the translation chain, the order for rebuilding manually is the same as in `setup.sh`: `dmsh_chain.py --header` → `dmsh_build.py` → `c1_guard.py` and `cb_extent.py` → recompile the host.
The per-shader cache key in `dmsh_build.py` (`shader_key`) covers the profile's `shader_*` rows and the shader's pairs, and a paired vertex shader's key also takes its pixel shaders' keys (`pair_keyed`), since `vs_pad` reads their MSL. Before, these were only in the chain version, so a build after changing only them hit the old per-shader entries and filed them under the new version. `$DM_ROOT` defaults to `~/dm-work`.
+6 -3
View File
@@ -1242,11 +1242,14 @@ static void power_line(uint64_t frame) {
(e - pe) / 1e9 / s, (e - pe) / 1e6 / nf, nf / s, (cpu - pcpu) / 1e7 / s, cpu > pcpu ? 100.0 * (double)(p - pp) / (double)(cpu - pcpu) : 0, (iw - piw) / s, (idw - ppw) / s, (g - pg) / 1e6 / s, dm_thermal_now(), yt);
char rs[400]; mtl_res_stats(rs, sizeof rs); static uint64_t pbs, pbf; uint64_t bs, bf; mtl_barrier_stats(&bs, &bf);
uint64_t mtl_cut_count(void), mtl_blit_splits(void); void mtl_ubd_stats(uint64_t *, uint64_t *); static uint64_t pcut, pbsp, pud, puc; uint64_t cut = mtl_cut_count(), bsp = mtl_blit_splits(), ud, uc; mtl_ubd_stats(&ud, &uc);
void mtl_ubp_stats(uint64_t *, uint64_t *, uint64_t *); static uint64_t ppm, ppr, ppf; uint64_t pm, pr, pf_; mtl_ubp_stats(&pm, &pr, &pf_);
void mtl_lc_stats(uint64_t *, uint64_t *); static uint64_t plt, pll; uint64_t lt, ll; mtl_lc_stats(&lt, &ll);
void mtl_ubp_why(uint64_t w[5]); static uint64_t pw5[5]; uint64_t w5[5]; mtl_ubp_why(w5);
uint64_t ld, st, fu, udc = mtl_udc_saved_bytes(); mtl_bw(&ld, &st, &fu);
LOG("[nvn] residency set up to frame %llu: %s; draw-pass entry barriers full %llu / saved %llu; split submits %llu; passes broken by copies / buffer updates %llu; in-pass uniform updates deferred %llu, passes ended to land them for a read %llu; "
LOG("[nvn] residency set up to frame %llu: %s; draw-pass entry barriers full %llu / saved %llu; split submits %llu; passes broken by copies / buffer updates %llu; in-pass uniform updates deferred %llu, passes ended to land them for a read %llu, partly covered blocks read from memory %llu (cached %llu, refused %llu: other GPU writes %llu, earlier submission running %llu, copy or fill queued %llu, size %llu, unreadable %llu); waiting clears taken by a later pass %llu, landed in passes of their own %llu; "
"attachments per frame load %.0f MB / store %.0f MB, load-all store-all passes %.0f, saved by not storing unwritten attachments %.1f MB", frame, rs, (unsigned long long)(bf - pbf), (unsigned long long)(bs - pbs),
(unsigned long long)(cut - pcut), (unsigned long long)(bsp - pbsp), (unsigned long long)(ud - pud), (unsigned long long)(uc - puc),
(ld - pld) / 1048576.0 / nf, (st - pst) / 1048576.0 / nf, (fu - pfu) / nf, (udc - pudc) / 1048576.0 / nf); pbs = bs; pbf = bf; pcut = cut; pbsp = bsp; pud = ud; puc = uc;
(unsigned long long)(cut - pcut), (unsigned long long)(bsp - pbsp), (unsigned long long)(ud - pud), (unsigned long long)(uc - puc), (unsigned long long)(pm - ppm), (unsigned long long)(pr - ppr), (unsigned long long)(pf_ - ppf), (unsigned long long)(w5[1] - pw5[1]), (unsigned long long)(w5[2] - pw5[2]), (unsigned long long)(w5[3] - pw5[3]), (unsigned long long)(w5[0] - pw5[0]), (unsigned long long)(w5[4] - pw5[4]), (unsigned long long)(lt - plt), (unsigned long long)(ll - pll),
(ld - pld) / 1048576.0 / nf, (st - pst) / 1048576.0 / nf, (fu - pfu) / nf, (udc - pudc) / 1048576.0 / nf); pbs = bs; pbf = bf; pcut = cut; pbsp = bsp; pud = ud; puc = uc; ppm = pm; ppr = pr; ppf = pf_; memcpy(pw5, w5, sizeof pw5); plt = lt; pll = ll;
char tc[400]; dm_thread_cpu(tc, sizeof tc, s);
LOG("[nvn] threads up to frame %llu: CPU %s", frame, tc); }
else { char yt[192], rs[400], tc[400]; dm_yield_top(yt, sizeof yt); mtl_res_stats(rs, sizeof rs); dm_thread_cpu(tc, sizeof tc, 1); } // the first call only takes the baselines
+262 -16
View File
@@ -237,6 +237,7 @@ static size_t g_c1_bank_off, g_c1_alloc_bytes, g_c1_data_bytes;
static uint64_t g_c1_count, g_c1_exclusive;
static NSMutableSet<NSString *> *g_c1_full;
static int g_c1_full_valid;
static NSDictionary<NSString *, NSString *> *g_cb_ext; // cb_extent.tsv: shader key → "reg:bytes ..." (how far into each uniform slot the shader can read); nil when stale or missing
static os_unfair_lock g_c1_lock = OS_UNFAIR_LOCK_INIT;
// DM_UDC_SELFTEST=1 (diagnostic, checks DontCare behavior on a real A19 device): private-storage Depth32Float_Stencil8 / RGBA8 (1952x900) are first cleared to write known values,
@@ -521,8 +522,29 @@ static struct { int32_t e, next; } g_pend_node[PEND_NODES]; static int g_npnode;
static int32_t g_pend_wide[PEND_WIDE]; static int g_nwide;
typedef struct { uint64_t lo; size_t off; __unsafe_unretained id<MTLBuffer> buf; } upd_ent; // the ring block lives until this submission completes (mtl_sub_update)
static upd_ent g_upd[PEND_MAX]; static int g_nupd;
// Other writes to guest memory in this submission, which the pend list does not hold: writable storage buffers bound to a shader, texture→buffer copies, counter reports (ubp_get).
// Kept by 4 KB page (Breath of the Wild's particle dispatches bind about ten storage buffers each, hundreds a frame): a set of pages tagged with the submission (g_pend_gen) and with what
// wrote them. A counter report does not count against this submission's shadows: the host writes reports on the CPU when the whole submission has completed, so no draw of it reads one
// (Fire Emblem Engage writes its query reports into the page of a uniform block); it counts for later submissions while this one runs (gw_commit)
enum { SBW_N = 16384, SBW_PAGES = 4096 };
static struct { uint64_t page; uint32_t gen; uint8_t src; } g_sbwp[SBW_N]; static int g_nsbw, g_sbw_over; // src: SBW_* bits; pages in the set this submission; over: a write could not be kept (too large, set full, size not known)
static int sbw_slot(uint64_t pg, int add) { // open addressing; −1 = not there (or no room to add)
unsigned h = (unsigned)((pg * 0x9E3779B97F4A7C15ull) >> 50) & (SBW_N - 1);
for (int i = 0; i < 64; i++, h = (h + 1) & (SBW_N - 1)) {
if (g_sbwp[h].gen != g_pend_gen) { if (!add) return -1; g_sbwp[h].page = pg; g_sbwp[h].gen = g_pend_gen; g_sbwp[h].src = 0; g_nsbw++; return (int)h; }
if (g_sbwp[h].page == pg) return (int)h; }
return -1;
}
enum { SBW_GPU = 1, SBW_REPORT = 2 };
static uint32_t g_sbw_gen; // bumped by every write noted that this submission's shadows must respect (a cached shadow made before it is checked again)
static void sbw_note(uint64_t lo, uint64_t n, int src) {
if (src == SBW_GPU) g_sbw_gen++;
if (!n || n > (uint64_t)SBW_PAGES << 12) { if (src == SBW_GPU) g_sbw_over = 1; return; } // a report too large to keep cannot happen (16 bytes)
for (uint64_t pg = lo >> 12; pg <= (lo + n - 1) >> 12; pg++) { int k = sbw_slot(pg, 1); if (k < 0) { g_sbw_over = 1; return; } g_sbwp[k].src |= (uint8_t)src; }
}
static int sbw_hits(uint64_t lo, uint64_t hi) { if (!g_nsbw) return 0; for (uint64_t pg = lo >> 12; pg <= (hi - 1) >> 12; pg++) { int k = sbw_slot(pg, 0); if (k >= 0 && (g_sbwp[k].src & SBW_GPU)) return 1; } return 0; }
static inline unsigned pend_bucket(uint64_t page) { return (unsigned)((page * 0x9E3779B97F4A7C15ull) >> 53) & (PEND_HB - 1); }
static void pend_reset(void) { g_npend = g_pend_over = g_nupd = g_npnode = g_nwide = 0; if (!++g_pend_gen) { memset(g_pend_hgen, 0, sizeof g_pend_hgen); g_pend_gen = 1; } }
static void pend_reset(void) { g_npend = g_pend_over = g_nupd = g_npnode = g_nwide = g_nsbw = g_sbw_over = 0; if (!++g_pend_gen) { memset(g_pend_hgen, 0, sizeof g_pend_hgen); memset(g_sbwp, 0, sizeof g_sbwp); g_pend_gen = 1; } }
static void vc_gpu_write(uint64_t dst, uint64_t n); // kept index ranges under the written range are not trusted again (ix_range)
static int pend_add(uint64_t dst, uint64_t n, int kind) {
vc_gpu_write(dst, n);
@@ -750,10 +772,10 @@ void mtl_sub_copy(uint64_t src, uint64_t dst, uint64_t n) {
static id<MTLBuffer> g_ubs_buf; static size_t g_ubs_off, g_ubs_size;
// Inline updates inside an open render pass are deferred instead of ending the pass. Metal cannot copy into a buffer inside a render pass, so each update used to end it: all attachments stored,
// reloaded by the next pass, new encoders (Metroid Dread about 246 times a frame, Tears of the Kingdom about 50). NVN applies the update in command order, so the draws after it in the pass must
// read the new data: a draw whose uniform binding overlaps a deferred update reads a shadow made only of the updates deferred in this pass, latest first per byte, and only when they cover the
// whole bound range (then the shadow is exactly what the GPU would read, whatever earlier frames still have in flight). The real copies are encoded in order when the pass ends (rp_end), so later
// passes and the CPU see them as before. The pass still ends before a draw that would need more: a binding the deferred updates cover only in part, or a read of the deferred data through a vertex,
// index, indirect or storage buffer (ubd_conflict). Off in TBDR mode (it reorders passes). DM_NVN_UB_DEFER=0 turns it off
// read the new data: a draw whose uniform binding overlaps a deferred update reads a shadow. When the updates deferred in this pass cover all of the binding the shader can read, the shadow is
// made of them alone, latest first per byte (exactly what the GPU would read, whatever earlier frames still have in flight); when they cover only part of it, the rest comes from memory (ubp_get).
// The real copies are encoded in order when the pass ends (rp_end), so later passes and the CPU see them as before. The pass still ends before a draw that would need more: a partly covered binding
// whose rest memory cannot give, or a read of the deferred data through a vertex, index, indirect or storage buffer (ubd_conflict). Off in TBDR mode (it reorders passes). DM_NVN_UB_DEFER=0 turns it off
static size_t arena_alloc(size_t n, id<MTLBuffer> *buf); static inline void args_dirty_all(void);
typedef struct { uint64_t lo, hi, gpu; size_t off; __unsafe_unretained id<MTLBuffer> buf; } ubd_ent; // data at buf + off (the ubs ring; a ring block replaced meanwhile lives until this submission completes)
enum { UBD_MAX = 512 };
@@ -791,6 +813,99 @@ static void ubd_read(uint64_t lo, size_t n, void *out) {
for (int i = 0; i < g_nubd; i++) { const ubd_ent *e = &g_ubd[i]; uint64_t a = e->lo > lo ? e->lo : lo, b = e->hi < lo + n ? e->hi : lo + n;
if (a < b) memcpy((uint8_t *)out + (a - lo), (const uint8_t *)e->buf.contents + e->off + (a - e->lo), (size_t)(b - a)); }
}
// Bindings the deferred updates cover only in part. The rest of the binding is what memory holds when the pass runs on the GPU. The shadow then starts from memory as the CPU sees it at encode
// time and lays over it every inline update queued in this submission that overlaps it, in queue order (earlier passes' updates, encoded but not yet run, and this pass's deferred ones): exactly
// what the GPU would read. It is made only when nothing else can have written the range by then: no copy, fill or feedback write queued in this submission (pend kinds 2–4), no writable storage
// buffer, texture→buffer copy or counter report over it in this submission (sbw), and no GPU write of an earlier submission still running (gw, by 4 KB page). Otherwise the pass ends as before.
// Breath of the Wild updates part of a bound block about 226 times a frame outdoors and ended a pass for nearly every one (about 900 MB of attachment loads and stores a frame on an iPhone).
// DM_NVN_UB_PARTIAL=0 turns it off
static int ub_partial_on(void) { static int v = -1; if (v < 0) { const char *e = getenv("DM_NVN_UB_PARTIAL"); v = !(e && !strcmp(e, "0")); if (!v) MLOG("DM_NVN_UB_PARTIAL=0: a binding the deferred uniform updates cover only in part ends the pass as before"); } return v; }
enum { GW_N = 4096, GW_PAGES = 4096 };
static struct { uint64_t page, fence; } g_gw[GW_N]; // page ~0: two live pages met in the slot, so any page there counts as written until fence completes
static uint64_t g_gw_all; // every page counts as written until this fence completes (a submission whose writes could not all be listed)
static uint64_t g_ubp_made, g_ubp_reused, g_ubp_refused; // partial shadows made / taken from the cache / refused (the pass ended), for the residency set line
static uint64_t g_ubp_why[5]; // why ubp_get refused: 0 too large or off, 1 other GPU writes in this submission (sbw), 2 GPU writes of an earlier submission still running, 3 a copy, fill or feedback write queued, 4 unreadable or too many writes
static inline unsigned gw_slot(uint64_t pg) { return (unsigned)((pg * 0x9E3779B97F4A7C15ull) >> 52) & (GW_N - 1); }
static void gw_put(uint64_t lo, uint64_t hi, uint64_t fence, uint64_t done) {
if (hi <= lo) return;
uint64_t p0 = lo >> 12, p1 = (hi - 1) >> 12;
if (p1 - p0 >= GW_PAGES) { if (fence > g_gw_all) g_gw_all = fence; return; }
for (uint64_t pg = p0; pg <= p1; pg++) { unsigned s = gw_slot(pg);
g_gw[s].page = g_gw[s].page == pg || g_gw[s].fence <= done ? pg : ~0ull;
if (fence > g_gw[s].fence) g_gw[s].fence = fence; }
}
static int gw_live(uint64_t lo, uint64_t hi) {
uint64_t done = g_done; // read without the lock as elsewhere: a stale value only refuses more
if (g_gw_all > done) return 1;
for (uint64_t pg = lo >> 12; pg <= (hi - 1) >> 12; pg++) { unsigned s = gw_slot(pg); if ((g_gw[s].page == pg || g_gw[s].page == ~0ull) && g_gw[s].fence > done) return 1; }
return 0;
}
// The submission's GPU writes go into the page table with its fence (mtl_sub_commit)
static void gw_commit(uint64_t fence) {
uint64_t done = g_done;
if ((g_pend_over || g_sbw_over) && fence > g_gw_all) g_gw_all = fence;
for (int e = 0; e < g_npend; e++) gw_put(g_pend_lo[e], g_pend_hi[e], fence, done);
if (g_nsbw) for (int i = 0; i < SBW_N; i++) if (g_sbwp[i].gen == g_pend_gen) gw_put(g_sbwp[i].page << 12, (g_sbwp[i].page + 1) << 12, fence, done);
}
// The writes queued in this submission from index since on that overlap [a, b), newest first, into out (room for every entry a lookup can meet); -1 when they cannot all be told
static int pend_since(uint64_t a, uint64_t b, int since, int *out) {
if (g_pend_over) return -1;
int n = 0; uint64_t p0 = a >> 12, p1 = (b - 1) >> 12;
if (p1 - p0 >= PEND_SPAN) { for (int e = g_npend - 1; e >= since; e--) if (a < g_pend_hi[e] && g_pend_lo[e] < b) out[n++] = e; return n; } // every entry, newest first
for (int i = 0; i < g_nwide; i++) { int e = g_pend_wide[i]; if (e >= since && a < g_pend_hi[e] && g_pend_lo[e] < b) out[n++] = e; }
for (uint64_t pg = p0; pg <= p1; pg++) { unsigned bk = pend_bucket(pg); if (g_pend_hgen[bk] != g_pend_gen) continue;
for (int k = g_pend_head[bk]; k >= 0 && g_pend_node[k].e >= since; k = g_pend_node[k].next) { int e = g_pend_node[k].e; if (a < g_pend_hi[e] && g_pend_lo[e] < b) out[n++] = e; } } // chains run newest first
if (n > 1 && (g_nwide || p1 > p0)) { // several lists: newest first, each once
for (int i = 1; i < n; i++) { int v = out[i], j = i; while (j > 0 && out[j - 1] < v) { out[j] = out[j - 1]; j--; } out[j] = v; }
int m = 1; for (int i = 1; i < n; i++) if (out[i] != out[m - 1]) out[m++] = out[i];
n = m; }
return n;
}
int nvn_host_readable(uint64_t a, uint64_t n); // hle_nvn.c: guest memory and sparse pools
// Shadows made from memory, per range. One is kept while no write is queued after it (the draws after an update bind the same block again and again); the next one for the same range starts
// from it and lays over only the writes queued since (the game rewrites one block hundreds of times a submission). A range read whole from memory once is not read from memory again in the submission
enum { UBP_CACHE = 16, UBP_MAX_BYTES = 65536 };
static int g_ubp_idx[PEND_MAX + PEND_WIDE]; // every entry a lookup can meet: the chains of the range's pages hold each entry at most once after dedup, the wide list at most PEND_WIDE
typedef struct { uint64_t lo, hi, gpu; uint8_t *cpu; int npend; uint32_t gen, sbw; } ubp_ent; // sbw: g_sbw_gen when the other writes were last checked
static ubp_ent g_ubpc[UBP_CACHE]; static unsigned g_ubpc_i;
// The bytes [lo, hi) as the GPU will read them at this point of the submission (see above): 1 with the shadow's GPU and CPU addresses, 0 when they cannot be known (the pass ends instead)
static int ubp_get(uint64_t lo, uint64_t hi, uint64_t *gpu, const uint8_t **cpu) {
if (!ub_partial_on() || hi <= lo || hi - lo > UBP_MAX_BYTES) { g_ubp_why[0]++; return 0; }
ubp_ent *c = NULL;
for (int i = 0; i < UBP_CACHE; i++) if (g_ubpc[i].lo == lo && g_ubpc[i].hi == hi && g_ubpc[i].gen == g_pend_gen) { c = &g_ubpc[i]; break; }
if (!c || c->sbw != g_sbw_gen) { if (g_sbw_over || sbw_hits(lo, hi)) { g_ubp_why[1]++; return 0; } if (c) c->sbw = g_sbw_gen; }
if (c && c->npend == g_npend) { g_ubp_reused++; *gpu = c->gpu; *cpu = c->cpu; return 1; }
int since = c ? c->npend : 0;
if (!c && gw_live(lo, hi)) { g_ubp_why[2]++; return 0; }
if (!c && !nvn_host_readable(lo, hi - lo)) { g_ubp_why[4]++; return 0; }
int n = pend_since(lo, hi, since, g_ubp_idx); if (n < 0) { g_ubp_why[4]++; return 0; }
// Newest first, keep the writes that still show through somewhere (a write only newer ones cover is never read, whatever wrote it); stop once they cover the range
enum { COVN = 64 }; uint64_t cl[COVN], ch[COVN]; int nc = 0, nk = 0, exact = 1; // covered intervals, sorted and disjoint; exact = 0 once they no longer fit
for (int i = 0; i < n; i++) { int e = g_ubp_idx[i];
uint64_t x = g_pend_lo[e] > lo ? g_pend_lo[e] : lo, y = g_pend_hi[e] < hi ? g_pend_hi[e] : hi;
int j = 0; while (j < nc && ch[j] < y) j++;
if (exact && j < nc && cl[j] <= x && y <= ch[j]) continue; // newer writes cover all of it
if (g_pend_kind[e] != 1 || !g_pend_upd[e]) { g_ubp_why[3]++; return 0; } // a copy, fill or feedback write the CPU cannot see
g_ubp_idx[nk++] = e;
if (exact) { // add [x, y) and merge neighbours
int k = 0; while (k < nc && ch[k] < x) k++;
int m = k; uint64_t nl = x, nh = y; while (m < nc && cl[m] <= y) { nl = MIN(nl, cl[m]); nh = MAX(nh, ch[m]); m++; }
if (nc - (m - k) + 1 > COVN) exact = 0;
else { memmove(&cl[k + 1], &cl[m], (nc - m) * sizeof *cl); memmove(&ch[k + 1], &ch[m], (nc - m) * sizeof *ch); nc = nc - (m - k) + 1; cl[k] = nl; ch[k] = nh;
if (nc == 1 && cl[0] == lo && ch[0] == hi) break; } } }
uint64_t len = hi - lo;
id<MTLBuffer> ab; size_t o = arena_alloc((size_t)len, &ab); uint8_t *d = (uint8_t *)ab.contents + o;
memcpy(d, c ? c->cpu : (const uint8_t *)(uintptr_t)lo, (size_t)len);
for (int i = nk - 1; i >= 0; i--) { int e = g_ubp_idx[i]; const upd_ent *u = &g_upd[g_pend_upd[e] - 1]; // oldest first: each byte ends with the newest write
uint64_t x = g_pend_lo[e] > lo ? g_pend_lo[e] : lo, y = g_pend_hi[e] < hi ? g_pend_hi[e] : hi;
memcpy(d + (x - lo), (const uint8_t *)u->buf.contents + u->off + (x - u->lo), (size_t)(y - x)); }
g_ubp_made++;
if (!c) c = &g_ubpc[g_ubpc_i++ % UBP_CACHE];
*c = (ubp_ent){lo, hi, ab.gpuAddress + o, d, g_npend, g_pend_gen, g_sbw_gen};
*gpu = c->gpu; *cpu = d; return 1;
}
void mtl_ubp_stats(uint64_t *made, uint64_t *reused, uint64_t *refused) { *made = g_ubp_made; *reused = g_ubp_reused; *refused = g_ubp_refused; }
void mtl_ubp_why(uint64_t w[5]) { memcpy(w, g_ubp_why, sizeof g_ubp_why); }
void mtl_sub_update(const void *data, uint64_t dst, uint64_t n) {
if (!n) return;
int pi = pend_add(dst, n, 1);
@@ -831,7 +946,7 @@ static void post(post_op o) {
g_post[g_npost++] = o;
}
void mtl_sub_event(volatile uint32_t *val, uint32_t mode, uint32_t v) { post((post_op){1, val, mode, v, 0, 0, NULL}); }
void mtl_sub_counter(uint64_t addr, uint32_t type) { post((post_op){2, NULL, 0, 0, addr, type, NULL, g_seg}); }
void mtl_sub_counter(uint64_t addr, uint32_t type) { sbw_note(addr, 16, SBW_REPORT); post((post_op){2, NULL, 0, 0, addr, type, NULL, g_seg}); }
void mtl_counter_stats(uint64_t rep[32], uint64_t rst[32]) { memcpy(rep, g_cnt_report, sizeof g_cnt_report); memcpy(rst, g_cnt_reset, sizeof g_cnt_reset); }
// Counter timestamps (19.2 MHz) are taken from the guest clock (hle_os.c guest_ns, the same source as svc GetSystemTick / cntpct): on hardware GPU timestamps and the CPU counter share one timebase, and games compare them.
@@ -955,12 +1070,15 @@ int mtl_gpu_span(uint64_t f, uint64_t *t0, uint64_t *t1) {
}
static void rp_flush(void);
static const char *cctx_snap(void); // What is in this submission (printed into the failure line on error; defined before mtl_exec)
static void lc_land(void);
uint64_t mtl_sub_commit(void) {
lc_land(); // clears still waiting (the command list ends with them)
defer_fallback(); // Deferred merged pass: at the end of the submission there are still P draws not replayed (the normal path never gets here)
rp_flush();
if (g_blit) { enc_b_end(g_blit); g_blit = nil; }
up_flush();
uint64_t fence = ++g_fence;
gw_commit(fence);
if (g_vis_ring_i >= 0) g_vis_ring[g_vis_ring_i].fence = fence;
// CPU-visible effects after completion: copy the op table into the callback
int n = g_npost; post_op *ops = n ? malloc(n * sizeof *ops) : NULL;
@@ -2433,11 +2551,21 @@ static void shmap_load(void) {
g_c1_full_valid = 1; g_c1_full = [NSMutableSet set];
for (NSString *line in [ct componentsSeparatedByString:@"\n"]) if (line.length && ![line hasPrefix:@"#"]) [g_c1_full addObject:[line stringByTrimmingCharactersInSet:NSCharacterSet.whitespaceAndNewlineCharacterSet]];
}
{ // cb_extent.tsv (tools/cb_extent.py), beside c1_full.tsv: without it a uniform block updated in part inside a pass is copied whole, up to 64 KB (ubp_get)
NSString *xp = [[path stringByDeletingLastPathComponent] stringByAppendingPathComponent:@"cb_extent.tsv"];
NSString *xt = [NSString stringWithContentsOfFile:xp encoding:NSUTF8StringEncoding error:nil];
NSString *xh = xt ? [[xt componentsSeparatedByString:@"\n"] firstObject] : nil;
if (!xh || ![xh hasPrefix:want]) MLOG("cb_extent.tsv is stale or missing: uniform reads are taken to reach the whole binding");
else { NSMutableDictionary *d = [NSMutableDictionary dictionary];
for (NSString *line in [xt componentsSeparatedByString:@"\n"]) { if (!line.length || [line hasPrefix:@"#"]) continue;
NSRange t = [line rangeOfString:@"\t"]; if (t.location != NSNotFound) d[[line substringToIndex:t.location]] = [line substringFromIndex:t.location + 1]; }
g_cb_ext = d; MLOG("uniform read extents: %lu shaders (cb_extent.tsv)", (unsigned long)d.count); }
}
MLOG("shader route B (translated Switch originals): shader map %lu entries (%s), metallib directory %s", (unsigned long)g_shmap.count, path.UTF8String, g_msl_dir.UTF8String);
warm_start();
}
@interface NvShader : NSObject { @public id<MTLFunction> fn, tf_fn; uint16_t tf_stride[4]; nvn_refl rf; id<MTLArgumentEncoder> ae; NSUInteger arg_len; int stage, range_ro, afr, layer_out; const char *builtin; uint64_t logged; char key[24]; id<MTLBuffer> c1buf; uint64_t c1_gpu; size_t c1off;
@interface NvShader : NSObject { @public id<MTLFunction> fn, tf_fn; uint16_t tf_stride[4]; uint32_t cb_ext[16], sb_ro; nvn_refl rf; id<MTLArgumentEncoder> ae; NSUInteger arg_len; int stage, range_ro, afr, layer_out; const char *builtin; uint64_t logged; char key[24]; id<MTLBuffer> c1buf; uint64_t c1_gpu; size_t c1off;
// The argument buffer encoded last time
id<MTLBuffer> ab_buf; uint64_t ab_gpu; size_t ab_off; uint64_t ab_pass; uint32_t ab_binst; // ab_pass: serial of the render pass that encoded this argument block - reused only within the same pass (the arena holding a block from another pass / another submission may already have been reclaimed and rewritten)
id<MTLLibrary> bflib; int bflib_tried; NSMutableDictionary<NSString *, id<MTLFunction>> *bffn; } @end // bflib: readable-tile version <key>_bf (merge B step 2)
@@ -2606,8 +2734,14 @@ static NvShader *shader_load(NSString *pc, int stage) {
MDIE("shader %s has an unexpected argument buffer layout: encodedLength=%lu maxAid=%d", o->key, (unsigned long)o->arg_len, max_aid);
}
if (o->rf.has_c1) c1_store(o);
NSString *ext = g_cb_ext[[pc hasSuffix:@"_b"] ? [pc substringToIndex:pc.length - 2] : pc]; // bytes each uniform slot can read (cb_len), storage slots never written (sb_ro)
for (NSString *f in [ext componentsSeparatedByString:@" "]) { int r = 0, n = 0;
if (sscanf(f.UTF8String, "%d:%d", &r, &n) == 2 && r >= 0 && r < 16 && n > 0) o->cb_ext[r] = (uint32_t)n;
else if (sscanf(f.UTF8String, "s%d", &r) == 1 && r >= 0 && r < 32) o->sb_ro |= 1u << r; }
return o;
}
// The part of uniform slot reg's binding the shader can read: its first cb_ext bytes when cb_extent.tsv bounds them, else the whole binding
static inline uint64_t cb_len(NvShader *sh, int reg, uint64_t size) { uint32_t e = sh && reg >= 0 && reg < 16 ? sh->cb_ext[reg] : 0; return e && e < size ? e : size; }
static int stage_of(NSString *stage) {
if ([stage isEqualToString:@"vertex"]) return 0; if ([stage isEqualToString:@"pixel"]) return 1; if ([stage isEqualToString:@"compute"]) return 5;
@@ -3697,6 +3831,7 @@ static void ubo_read(int stage, int reg, int off, size_t n, void *out) {
const p_bind_buf *u = &S.ubo[stage][reg];
if (!u->addr || (uint64_t)off + n > u->size) return;
if (g_nubd && ubd_hits(u->addr + off, u->addr + off + n) && ubd_covers(u->addr + off, u->addr + off + n)) { ubd_read(u->addr + off, n, out); return; } // written by an inline update deferred in this pass
{ uint64_t g; const uint8_t *c; if (pend_hits(u->addr + off, n) && ubp_get(u->addr + off, u->addr + off + n, &g, &c)) { memcpy(out, c, n); return; } } // memory and the inline updates queued over it
if (pend_hits(u->addr + off, n)) { int kind; if (pend_read(u->addr + off, n, out, &kind)) return; // written by an inline update queued in this submission: its data
RED_ONCE(47, "the uniform buffer holding bindless handles (stage %d slot %d +%#x) has GPU-side writes in this submission (%s): the current value is read", stage, reg, off,
kind == 2 ? "a buffer copy" : kind == 3 ? "a fill" : kind == 1 ? "an inline update covering part of it" : "more writes than the host tracks"); }
@@ -3733,8 +3868,10 @@ static int encode_args_(id<MTLCommandEncoder> en, NvShader *sh, int nvn_stage, i
const p_bind_buf *u = reg < 16 ? &S.ubo[nvn_stage][reg] : NULL;
void *mb; uint64_t mo, gpu;
if (!u || !u->addr || !mtl_gpu_addr(u->addr, 1, &mb, &mo, &gpu)) { RED_ONCE(16, "stage %d cb%d has no uniform buffer bound", nvn_stage, reg); continue; }
if (g_nubd && ubd_hits(u->addr, u->addr + u->size)) { // inline updates deferred in this pass (see mtl_sub_update); ubd_conflict made sure they cover the binding
if (ubd_covers(u->addr, u->addr + u->size)) gpu = ubd_shadow(u->addr, u->addr + u->size);
uint64_t ul = cb_len(sh, reg, u->size); // what the shader can read of it
if (g_nubd && ubd_hits(u->addr, u->addr + ul)) { // inline updates deferred in this pass (see mtl_sub_update); ubd_conflict made sure they cover the binding or the rest can be read from memory
uint64_t g; const uint8_t *c; if (ubd_covers(u->addr, u->addr + ul)) gpu = ubd_shadow(u->addr, u->addr + ul);
else if (ubp_get(u->addr, u->addr + ul, &g, &c)) gpu = g;
else RED_ONCE(92, "a uniform update deferred inside the pass covers only part of the binding (stage %d cb%d): the content before the update is read", nvn_stage, reg); }
if (bl) {
PD("B %llu st%d cb reg%d addr=%#llx size=%llu pool=%#llx+%#llx f=%g,%g,%g,%g", g_stat_pass, nvn_stage, reg, (unsigned long long)u->addr, (unsigned long long)u->size,
@@ -3832,13 +3969,13 @@ static int encode_args_(id<MTLCommandEncoder> en, NvShader *sh, int nvn_stage, i
} else if (b->kind == NVN_RB_SBUFP || b->kind == NVN_RB_UBOP) { // B: storage buffers / compute-stage uniforms are device pointers; the address is taken by NVN slot
const p_bind_buf *u = reg < 16 ? (b->kind == NVN_RB_UBOP ? &S.ubo[nvn_stage][reg] : &S.ssbo[nvn_stage][reg]) : NULL;
void *mb; uint64_t mo, gpu;
if (u && u->addr && mtl_gpu_addr(u->addr, u->size ? u->size : 1, &mb, &mo, &gpu)) { slots[aid] = gpu; USE((__bridge id<MTLBuffer>)mb, b->rw ? MTLResourceUsageRead | MTLResourceUsageWrite : MTLResourceUsageRead); }
if (u && u->addr && mtl_gpu_addr(u->addr, u->size ? u->size : 1, &mb, &mo, &gpu)) { slots[aid] = gpu; USE((__bridge id<MTLBuffer>)mb, b->rw ? MTLResourceUsageRead | MTLResourceUsageWrite : MTLResourceUsageRead); if (b->rw && b->kind == NVN_RB_SBUFP && !(reg < 32 && (sh->sb_ro >> reg & 1))) sbw_note(u->addr, u->size, SBW_GPU); } // cb_extent.tsv: slots the shader never writes
else { slots[aid] = dummy_buf_gpu(); USE(dummy_buf(), MTLResourceUsageRead); }
if (bl) PD("B %llu st%d sbufp reg%d %s addr=%#llx size=%llu %s", g_stat_pass, nvn_stage, reg, u && u->addr ? "real" : "dummy", u ? (unsigned long long)u->addr : 0ull, u ? (unsigned long long)u->size : 0ull, b->rw ? "rw" : "ro");
} else if (b->kind == NVN_RB_SBUFU) { // B: a storage buffer whose GPU address the game keeps in its own uniform buffer (Monster Hunter Rise's compute shaders: c3 + 0x38); read like a bindless handle
uint64_t addr; ubo_read(nvn_stage, reg, b->off, 8, &addr);
void *mb; uint64_t mo, gpu;
if (addr && mtl_gpu_addr(addr, 1, &mb, &mo, &gpu)) { slots[aid] = gpu; USE((__bridge id<MTLBuffer>)mb, b->rw ? MTLResourceUsageRead | MTLResourceUsageWrite : MTLResourceUsageRead); }
if (addr && mtl_gpu_addr(addr, 1, &mb, &mo, &gpu)) { slots[aid] = gpu; USE((__bridge id<MTLBuffer>)mb, b->rw ? MTLResourceUsageRead | MTLResourceUsageWrite : MTLResourceUsageRead); if (b->rw) sbw_note(addr, 0, SBW_GPU); } // size not known
else { slots[aid] = dummy_buf_gpu(); USE(dummy_buf(), MTLResourceUsageRead); }
if (bl) PD("B %llu st%d sbufu reg%d+%#x addr=%#llx %s", g_stat_pass, nvn_stage, reg, b->off, (unsigned long long)addr, b->rw ? "rw" : "ro");
} else if (b->kind == NVN_RB_C1) { // B: the shader's own constant segment, built when the shader is fetched
@@ -5546,8 +5683,25 @@ static void wide_run(const p_draw_idx *di) {
if (!g_wide_runs++) MLOG("8-bit index GPU expansion: first time, %d draws (the indices have GPU-side writes in this submission; a compute pass expands them to 16 bits before the render pass)", n);
else if (g_wide_runs % 3600 == 0) MLOG("8-bit index GPU expansion: %llu times, %llu draws, render pass split %llu times", (unsigned long long)g_wide_runs, (unsigned long long)g_wide_draws, (unsigned long long)g_wide_splits);
}
// Whether this draw needs more from the inline updates deferred in the open pass than the uniform shadows give (see mtl_sub_update): a uniform binding they cover only in part, a bindless
// handle in such a part, or their data read as vertices, indices, indirect arguments or a storage buffer. Then the pass ends first and the updates land before the draw, as before
// Diagnostic DM_NVN_UBP_CHECK=1: each shadow made from memory (ubp_get) is checked against the GPU. The pass ends, the deferred updates land, the replay waits for the GPU (as an indirect-count
// multi-draw does), and the bytes the draw would have read from the shadow are compared with memory, which now holds exactly what the GPU reads. The draw then goes on as without the shadows
static void mdi_wait(void);
static uint64_t g_ubpk_same, g_ubpk_diff;
static int ubp_check_on(void) { static int v = -1; if (v < 0) { v = getenv("DM_NVN_UBP_CHECK") != NULL; if (v) MLOG("DM_NVN_UBP_CHECK: every uniform shadow made from memory is compared with the GPU's memory after the updates land (slow)"); } return v; }
static void ubp_check(uint64_t lo, uint64_t hi, const uint8_t *sh) {
size_t n = (size_t)(hi - lo); uint8_t *tmp = malloc(n); memcpy(tmp, sh, n);
mdi_wait();
const uint8_t *m = (const uint8_t *)(uintptr_t)lo; size_t bad = 0, first = 0;
for (size_t i = 0; i < n; i++) if (tmp[i] != m[i]) { if (!bad++) first = i; }
if (bad) { g_ubpk_diff++; if (g_ubpk_diff <= 10) MLOG("[RED] uniform shadow check: [%#llx +%zu] differs from the GPU's memory in %zu bytes, first at +%zu (shadow %02x, memory %02x) frame %llu pass %llu",
(unsigned long long)lo, n, bad, first, tmp[first], m[first], (unsigned long long)atomic_load(&g_cur_frame), g_stat_pass); }
else g_ubpk_same++;
if ((g_ubpk_same + g_ubpk_diff) % 2000 == 0) MLOG("uniform shadow check: %llu equal, %llu different", (unsigned long long)g_ubpk_same, (unsigned long long)g_ubpk_diff);
free(tmp);
}
// Whether this draw needs more from the inline updates deferred in the open pass than the uniform shadows give (see mtl_sub_update): a uniform binding they cover only in part whose rest
// cannot be read from memory (ubp_get; a binding counts only as far as the shader can read it, cb_len), a bindless handle in such a part, or their data read as vertices, indices, indirect
// arguments or a storage buffer. Then the pass ends first and the updates land before the draw, as before
static int ubd_conflict(NvProg *pr, const p_draw *dw, const p_draw_idx *di) {
for (int s_ = 0; s_ < 16; s_++) if (S.vbuf[s_].address && ubd_hits(S.vbuf[s_].address, S.vbuf[s_].address + S.vbuf[s_].size)) return 1;
if (di && di->ibuf && ubd_hits(di->ibuf, di->ibuf + (uint64_t)di->count * 4)) return 1;
@@ -5556,8 +5710,11 @@ static int ubd_conflict(NvProg *pr, const p_draw *dw, const p_draw_idx *di) {
for (int i = 0; i < sh->rf.nb; i++) { const nvn_rbind *b = &sh->rf.b[i]; if (b->reg >= 16) continue;
const p_bind_buf *u = b->kind == NVN_RB_SBUFP ? &S.ssbo[st][b->reg] : &S.ubo[st][b->reg];
if (!u->addr) continue;
if (b->kind == NVN_RB_CBUF) { if (ubd_hits(u->addr, u->addr + u->size) && !ubd_covers(u->addr, u->addr + u->size)) return 1; }
else if (b->kind == NVN_RB_TEXU || b->kind == NVN_RB_SAMPU || b->kind == NVN_RB_SBUFU) { uint64_t h = u->addr + b->off, n = b->kind == NVN_RB_SBUFU ? 8 : 4; if (ubd_hits(h, h + n) && !ubd_covers(h, h + n)) return 1; }
if (b->kind == NVN_RB_CBUF) { uint64_t g, ul = cb_len(sh, b->reg, u->size); const uint8_t *c;
if (ubd_hits(u->addr, u->addr + ul) && !ubd_covers(u->addr, u->addr + ul)) {
if (!ubp_get(u->addr, u->addr + ul, &g, &c)) { g_ubp_refused++; return 1; }
if (ubp_check_on()) { ubp_check(u->addr, u->addr + ul, c); return 1; } } }
else if (b->kind == NVN_RB_TEXU || b->kind == NVN_RB_SAMPU || b->kind == NVN_RB_SBUFU) { uint64_t h = u->addr + b->off, n = b->kind == NVN_RB_SBUFU ? 8 : 4; uint64_t g; const uint8_t *c; if (ubd_hits(h, h + n) && !ubd_covers(h, h + n) && !ubp_get(h, h + n, &g, &c)) { g_ubp_refused++; return 1; } }
else if (b->kind == NVN_RB_SBUFP || b->kind == NVN_RB_UBOP) { if (ubd_hits(u->addr, u->addr + (u->size ? u->size : 1))) return 1; } } }
return 0;
}
@@ -5642,6 +5799,91 @@ static void tf_draw(NvProg *pr, const p_draw *dw, const p_draw_idx *di) {
(unsigned long long)S.tf_off[0], (unsigned long long)S.tf_off[1], (unsigned long long)S.tf_off[2], (unsigned long long)S.tf_off[3]);
}
// Lazy clears. A set of targets that gets only clears before the game sets other targets used to open a pass just to land them (rp_flush), storing the cleared attachments, and the next
// pass that attached them loaded them back. Breath of the Wild clears its G-buffer one target at a time (depth with the lighting target, then albedo, normals, the fourth), then attaches all
// five: four passes stored 27 MB of cleared memory at 1600x900 and the G-buffer pass loaded it again. Such clears now wait (g_lc): the next pass that attaches the same texture level and
// layer through the same view takes the clear as its load action. The rest land as before, in order, each in a pass of its own (lc_land), before anything else could see their textures: a
// draw whose program samples one, the pass of a draw that does not attach it (before that pass opens), and any operation other than targets, clears, state, uniform updates and buffer
// copies or fills, and the end of a command list (not of a sub-list it calls). A newer clear of the same subresource replaces an older one. Off in TBDR mode (its hoisting moves clear-only passes its own way).
// DM_NVN_LAZY_CLEAR=0 turns it off
typedef struct { p_set_rt rt; uint8_t clear_c[8]; MTLClearColor cc[8]; uint8_t clear_d, clear_s; double cd; uint32_t cs; } lc_group;
enum { LC_MAX = 8 };
static lc_group g_lc[LC_MAX]; static int g_nlc;
static uint64_t g_lc_taken, g_lc_landed; // clears a later pass took as its load action / clear-only passes still opened for them (the residency set line)
void mtl_lc_stats(uint64_t *taken, uint64_t *landed) { *taken = g_lc_taken; *landed = g_lc_landed; }
static int lc_on(void) { static int v = -1; if (v < 0) { const char *e = getenv("DM_NVN_LAZY_CLEAR"); v = !(e && !strcmp(e, "0")); if (!v) MLOG("DM_NVN_LAZY_CLEAR=0: clears with no draw open a pass of their own as before"); } return v && !tbdr_on(); }
static int lc_same(const p_set_rt *a, int ka, const p_set_rt *b, int kb) { // the same subresource through the same view (k = 8: depth / stencil)
uint64_t s1, s2; int l1, l2, x1, x2; rt_sub(a, ka, &s1, &l1, &x1); rt_sub(b, kb, &s2, &l2, &x2);
if (!s1 || s1 != s2 || l1 != l2 || x1 != x2) return 0;
int h1 = ka == 8 ? a->has_dview : a->has_cview[ka], h2 = kb == 8 ? b->has_dview : b->has_cview[kb];
return h1 == h2 && (!h1 || !memcmp(ka == 8 ? &a->dview : &a->cview[ka], kb == 8 ? &b->dview : &b->cview[kb], sizeof(view_t)));
}
// Land every waiting clear, oldest first, each group in a pass of its own (rp_flush's way)
static void lc_land(void) {
if (!g_nlc) return;
if (g_enc) rp_end();
int n = g_nlc; g_nlc = 0;
typeof(R) save = R;
for (int gi = 0; gi < n; gi++) { const lc_group *g = &g_lc[gi]; int any = g->clear_d || g->clear_s; for (int i = 0; i < 8; i++) any |= g->clear_c[i];
if (!any || !g_cb) continue;
R.rt = g->rt; R.has_rt = 1; memcpy(R.clear_c, g->clear_c, sizeof R.clear_c); memcpy(R.cc, g->cc, sizeof R.cc);
R.clear_d = g->clear_d; R.clear_s = g->clear_s; R.cd = g->cd; R.cs = g->cs;
rp_begin_ex(1); rp_end(); g_lc_landed++; }
R = save;
}
// SetRenderTargets with clears pending and no draw since: the clears wait instead of opening a pass
static void lc_push(void) {
if (g_nlc == LC_MAX) lc_land();
lc_group *g = &g_lc[g_nlc];
g->rt = R.rt; memcpy(g->clear_c, R.clear_c, sizeof g->clear_c); memcpy(g->cc, R.cc, sizeof g->cc); g->clear_d = R.clear_d; g->clear_s = R.clear_s; g->cd = R.cd; g->cs = R.cs;
for (int gi = 0; gi < g_nlc; gi++) { lc_group *o = &g_lc[gi]; // older clears of the same subresources are overwritten
for (int i = 0; i < 8; i++) if (o->clear_c[i]) for (int j = 0; j < 8; j++) if (g->clear_c[j]) { uint64_t s1, s2; int l1, l2, x1, x2; rt_sub(&o->rt, i, &s1, &l1, &x1); rt_sub(&g->rt, j, &s2, &l2, &x2);
if (s1 && s1 == s2 && l1 == l2 && x1 == x2) { o->clear_c[i] = 0; break; } }
if ((o->clear_d || o->clear_s) && (g->clear_d || g->clear_s)) { uint64_t s1, s2; int l1, l2, x1, x2; rt_sub(&o->rt, 8, &s1, &l1, &x1); rt_sub(&g->rt, 8, &s2, &l2, &x2);
if (s1 && s1 == s2 && l1 == l2 && x1 == x2) { if (g->clear_d) o->clear_d = 0; if (g->clear_s) o->clear_s = 0; } } }
g_nlc++;
memset(R.clear_c, 0, sizeof R.clear_c); R.clear_d = R.clear_s = 0;
}
// Whether the program samples a texture with a waiting clear (a program with bindless or dynamic handles counts as sampling)
static int lc_sampled(NvProg *pr) {
if (!pr) return 1;
for (int st = 0; st < 5; st++) { __unsafe_unretained NvShader *sh = pr->sh[st]; if (!sh || sh->stage >= 6) continue;
if (sh->rf.bindless || sh->rf.dyn) return 1;
for (int i = 0; i < sh->rf.nb; i++) { const nvn_rbind *b = &sh->rf.b[i]; uint64_t h;
if (b->kind == NVN_RB_IMG) h = b->reg < 32 ? S.img[sh->stage][b->reg] : 0; else if (b->kind == NVN_RB_TEX || b->kind == NVN_RB_TBUF) h = b->reg < NTEX ? S.tex[sh->stage][b->reg] : 0; else continue;
uint64_t ser = h ? h_ser(h) : 0; if (!ser) continue;
for (int gi = 0; gi < g_nlc; gi++) { const lc_group *g = &g_lc[gi];
for (int k = 0; k < 8; k++) if (g->clear_c[k] && g->rt.color[k] && g->rt.color[k]->serial == ser) return 1;
if ((g->clear_d || g->clear_s) && g->rt.depth && g->rt.depth->serial == ser) return 1; } } }
return 0;
}
// The draw about to open a pass: its attachments take the waiting clears of the same subresources (the newest one; the pass's own pending clear is newer still), the rest land first
static void lc_take(NvProg *pr) {
if (lc_sampled(pr)) { lc_land(); return; }
for (int gi = g_nlc - 1; gi >= 0; gi--) { lc_group *g = &g_lc[gi];
for (int i = 0; i < 8; i++) if (g->clear_c[i])
for (int j = 0; j < R.rt.n && j < 8; j++) if (R.rt.color[j] && !rt_dup_slot(&R.rt, j) && !nvn_fmt_bc(R.rt.color[j]->d.format) && lc_same(&g->rt, i, &R.rt, j)) {
if (!R.clear_c[j]) { R.clear_c[j] = 1; R.cc[j] = g->cc[i]; }
g->clear_c[i] = 0; g_lc_taken++; break; }
if ((g->clear_d || g->clear_s) && R.rt.depth && lc_same(&g->rt, 8, &R.rt, 8)) {
if (g->clear_d) { if (!R.clear_d) { R.clear_d = 1; R.cd = g->cd; } g->clear_d = 0; }
if (g->clear_s) { if (!R.clear_s) { R.clear_s = 1; R.cs = g->cs; } g->clear_s = 0; }
g_lc_taken++; } }
lc_land();
}
// The operations a waiting clear can wait across: they neither read nor write textures
static int lc_keeps(uint32_t op) {
switch (op) {
case OP_SET_RT: case OP_CLEAR_COLOR: case OP_CLEAR_DS: case OP_DRAW: case OP_DRAW_IDX: case OP_BEGIN: case OP_JUMP: case OP_CALL:
case OP_SCISSOR: case OP_BIND_PROGRAM: case OP_BIND_STATE: case OP_BIND_VATTR: case OP_BIND_VSTREAM: case OP_BIND_VBUF:
case OP_BIND_UBO: case OP_BIND_SSBO: case OP_BIND_TEX: case OP_BIND_SAMP: case OP_BIND_IMG: case OP_STENCIL:
case OP_POLY_OFFSET: case OP_VIEWPORTS: case OP_DEPTH_RANGE: case OP_DEPTH_CLAMP: case OP_BLEND_COLOR: case OP_COPY_STRIDE:
case OP_TF_BIND: case OP_TF_STATE: case OP_RAST_DISCARD: case OP_BARRIER: case OP_SET_TEX_POOL: case OP_SET_SAMP_POOL: case OP_RENDER_COND:
case OP_UPDATE_UB: case OP_COPY_B2B: case OP_CLEAR_BUF: return 1;
default: return 0;
}
}
static void draw(const p_draw *dw, const p_draw_idx *di) {
g_draw_binst = (uint32_t)(dw ? dw->base_instance : di ? di->base_instance : 0); // c0 + 0x644 of the stages that read the driver segment (encode_args)
if ((di && di->mdi_cnt && !mdi_live(di->mdi_cnt, di->mdi_i)) || (dw && dw->mdi_cnt && !mdi_live(dw->mdi_cnt, dw->mdi_i))) return; // past the multi-draw's count
@@ -5652,6 +5894,7 @@ static void draw(const p_draw *dw, const p_draw_idx *di) {
if (zskip_can_draw(pr)) { // Zero-source skip: the output is always 0, writing 0 over 0, so this draw changes no result (see zskip_can_draw)
g_zskip_count++; { static int once; if (!once++) MLOG("zero-source skip: first case pass %llu", g_stat_pass + 1); }
PD("N %llu zero-source draw skipped", g_stat_pass + 1); return; }
if (g_nlc && !g_enc) lc_take(pr); // waiting clears: this pass's load actions, or landed before it (see lc_take)
if (ixc_wanted(dw, di) && !ixc_find(dw, di)) ixc_run(dw, di); // indirect quads / fans / 8-bit indices: converted on the GPU before the render pass, at their own place in the replay (see ixc_run)
if (di && wide_wanted(di) && !wide_find(di)) wide_run(di); // 8-bit indices written earlier in this submission: widened on the GPU before the render pass (see wide_run)
if (!g_defer_replaying) {
@@ -5988,6 +6231,7 @@ static void copy_t2b(const p_copy_b2t *c) {
int is3d = c->tex->d.target == 2, nz = c->r.depth ? c->r.depth : 1;
void *mb; uint64_t mo;
if (!mtl_addr(c->src, img * nz, &mb, &mo)) { RED_ONCE(31, "texture→buffer copy destination is in no memory pool"); return; }
sbw_note(c->src, img * nz, SBW_GPU);
id<MTL4ComputeCommandEncoder> b = blit();
if (is3d)
enc_b_copy_texture_buffer(b, t, 0, level, MTLOriginMake(c->r.xoffset, c->r.yoffset, c->r.zoffset), MTLSizeMake(c->r.width, c->r.height, nz), (__bridge id<MTLBuffer>)mb, mo, row, img);
@@ -6447,6 +6691,7 @@ void mtl_exec(const uint8_t *p) {
if (g_allocprof) { static uint64_t last; static int prev = -1; uint64_t now = g_dev.currentAllocatedSize; if (prev >= 0 && prev < 64 && now > last) g_ap_bytes[prev] += now - last; last = now; prev = h.op; }
if (g_hoist_n && hoist_take(p)) { if (g_fz.active && p == g_fz.rt2_op) { g_fz.phase = 2; g_rt_merged = 0; PD("F %llu merged pass enters the later pass's draws", g_stat_pass); } p += h.size; continue; } // A pure-clear render pass already executed early / the start of a later pass already merged in // Entering the later pass: the same-target continuation of the earlier pass ends here; the later pass reading the earlier pass's attachment is proven to be same-pixel by fz_p2_draw, and is no longer split by the continuation rule
const void *a = p + 8;
if (g_nlc && !lc_keeps(h.op) && !(h.op == OP_END && g_ret_n)) lc_land(); // see lc_keeps (a sub-list's end returns to its caller)
switch (h.op) {
case OP_END: g_exec_cur = NULL;
if (g_hoist_n && !g_ret_n && !g_nrest) {
@@ -6501,7 +6746,8 @@ void mtl_exec(const uint8_t *p) {
g_rt_merged = 1; if (!g_rt_merge_n++) MLOG("same-target continuation: first case pass %llu", g_stat_pass); PD("M %llu same-target continuation pass", g_stat_pass); break; }
// Do not continue a render pass opened only for a clear; one with fewer depth / stencil attachments can be continued (check the planes before drawing)
if (g_enc && g_enc_mode != 1 && !pend && R.has_rt && tbdr_on() && rt_same(&R.rt, r)) { g_rt_merged = 1; if (!g_rt_merge_n++) MLOG("same-target continuation: first case pass %llu", g_stat_pass); PD("M %llu same-target continuation pass", g_stat_pass); R.rt = *r; break; }
rp_flush(); sub_cut(); R.rt = *r; R.has_rt = 1; break;
if (pend && !g_enc && g_cb && lc_on()) lc_push(); else rp_flush(); // clears with no draw wait for the next pass that attaches their targets (lc_push)
sub_cut(); R.rt = *r; R.has_rt = 1; break;
}
case OP_CLEAR_COLOR: {
const p_clear_color *c = a;
+4 -2
View File
@@ -17,6 +17,8 @@ static void dummy_kind(NSString *t, uint8_t *tt, uint8_t *pf) {
*pf = [t hasPrefix:@"depth"] ? NVN_DPF_DEPTH : [t containsString:@"<uint"] ? NVN_DPF_UINT : [t containsString:@"<int"] ? NVN_DPF_SINT : NVN_DPF_FLOAT;
}
// Whether a storage buffer binding may be written: route A's reflection says so ("rw"); route B's does not, and there SPIRV-Cross types a buffer the shader never writes as const device
static int sbuf_rw(NSDictionary *b) { id rw = b[@"rw"]; if (rw) return [rw boolValue]; id ty = b[@"msl_type"]; return !([ty isKindOfClass:[NSString class]] && [ty hasPrefix:@"const "]); }
int nvn_refl_from_json(NSDictionary *j, nvn_refl *o, char *err, int errlen) {
memset(o, 0, sizeof *o);
#define FAIL(...) do { free(o->c1); o->c1 = NULL; snprintf(err, errlen, __VA_ARGS__); return 1; } while (0)
@@ -58,9 +60,9 @@ int nvn_refl_from_json(NSDictionary *j, nvn_refl *o, char *err, int errlen) {
else if ([k isEqualToString:@"samp_id"]) r->kind = NVN_RB_SAMPI;
else if ([k isEqualToString:@"img"]) { r->kind = NVN_RB_IMG; dummy_kind(b[@"msl_type"], &r->dtt, &r->dpf); }
else if ([k isEqualToString:@"tbuf"]) { r->kind = NVN_RB_TBUF; uint8_t tt; dummy_kind(b[@"msl_type"], &tt, &r->dpf); }
else if ([k isEqualToString:@"sbuf"]) { r->kind = NVN_RB_SBUFP; r->rw = [b[@"rw"] boolValue]; }
else if ([k isEqualToString:@"sbuf"]) { r->kind = NVN_RB_SBUFP; r->rw = sbuf_rw(b); }
else if ([k isEqualToString:@"ubo_ptr"]) r->kind = NVN_RB_UBOP;
else if ([k isEqualToString:@"sbuf_ubo"]) { r->kind = NVN_RB_SBUFU; r->rw = [b[@"rw"] boolValue]; r->off = (uint16_t)[b[@"off"] intValue]; }
else if ([k isEqualToString:@"sbuf_ubo"]) { r->kind = NVN_RB_SBUFU; r->rw = sbuf_rw(b); r->off = (uint16_t)[b[@"off"] intValue]; }
else if ([k isEqualToString:@"support"]) r->kind = NVN_RB_SUPPORT;
else if ([k isEqualToString:@"c1"]) r->kind = NVN_RB_C1;
else if ([k isEqualToString:@"drvcb"]) r->kind = [b[@"bank"] intValue] == 2 ? NVN_RB_DRV2 : NVN_RB_DRV0;
+99
View File
@@ -0,0 +1,99 @@
#!/usr/bin/env python3
# cb_extent.py <dmsh_b version dir> <output tsv>: how far into each uniform slot (cbuf binding) a shader can read, from the translated MSL. A line lists, per shader key, the slots whose
# reads are all proven to stay inside the first <bytes> bytes: `<key>\t<reg>:<bytes> ...` (reg as in the reflection json, bytes a multiple of 16). A slot left out may be read anywhere in its
# binding. Indices are bounded with c1_guard.py's interval arithmetic; any other use of the binding's name (a pointer handed on, a member other than _m0) leaves the slot out.
# `s<reg>` marks a storage slot the shader never writes (unwritten); the host notes GPU writes for every other storage binding (nvn_mtl.m sbw_note).
# The host (nvn_mtl.m cb_ext) reads only that much of a binding when it has to copy one: a uniform block the game updates in part inside a render pass (ubp_get). Breath of the Wild binds
# a 64 KiB block to the vertex stage and updates its first 64 bytes 221 times a frame, while its vertex shaders read at most 544 bytes of it.
# The host loads the table only when its header names its chain version (like c1_full.tsv); regenerate it after each shader build
import datetime
import json
import multiprocessing
import os
import re
import sys
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from c1_guard import Interval, definitions_of, known # noqa: E402
MAX = 65536
def extents(source, bindings):
"""{reg: bytes} for the cbuf bindings whose every read is a proven index into _m0"""
out, definitions = {}, None
for b in bindings:
if b.get("kind") != "cbuf" or "reg" not in b: continue
name = b["msl_name"]
uses = len(re.findall(r"\b" + re.escape(name) + r"\b", source))
reads = re.findall(r"\(\*spvDescriptorSet0\." + re.escape(name) + r"\)\._m0\[([^\]]+)\]", source)
declared = len(re.findall(r"\b" + re.escape(name) + r"\s*\[\[id\(", source)) # the argument buffer member
if uses != len(reads) + declared: continue
high = -1
for index in set(reads):
if definitions is None: definitions = definitions_of(source)
low, top = Interval(definitions).expression(index)
if not known(low, top) or low < 0: high = None; break
high = max(high, top)
if high is None or 16 * (high + 1) >= MAX: continue
out[b["reg"]] = 16 * (high + 1)
return out
WRITE = re.compile(r"\s*(?:=(?!=)|[-+*/%&|^]=|<<=|>>=|\+\+|--)")
def unwritten(source, bindings):
"""The storage slots (sbuf bindings) the shader never writes: every use of the name is (*<set>.<name>)._m0[...] read as a value. A use followed by an assignment, after
an address-of (atomics take &...), or of any other form (the pointer handed to a function) counts as a write. SPIRV-Cross types every storage buffer Ryujinx emits as
writable (device, not const device), so the host takes a binding as written unless the table lists it"""
out = []
for b in bindings:
if b.get("kind") != "sbuf" or "reg" not in b: continue
name = "spvDescriptorSet0." + b["msl_name"]; ok = True
for m in re.finditer(r"\(\*" + re.escape(name) + r"\b", source):
j = m.end()
if source[m.start() - 1:m.start()] == "&" or not source.startswith(")._m0[", j): ok = False; break
j += len(")._m0"); depth = 0
while j < len(source): # the index and any further [..] or .member
c = source[j]
if c == "[": depth += 1
elif c == "]": depth -= 1
elif depth == 0 and not (c == "." or c.isalnum() or c == "_"): break
j += 1
if WRITE.match(source, j): ok = False; break
if ok and len(re.findall(re.escape(name) + r"\b", source)) == len(re.findall(r"\(\*" + re.escape(name) + r"\b", source)):
out.append(b["reg"])
return sorted(set(out))
def row(path):
"""The table line for one shader's reflection json, or None"""
try:
with open(path, encoding="utf-8") as stream: bindings = json.load(stream).get("bindings") or []
if not any(b.get("kind") in ("cbuf", "sbuf") for b in bindings): return None
with open(path[:-5] + ".metal", encoding="utf-8") as stream: source = stream.read()
except (OSError, ValueError):
return None
toks = [f"{r}:{n}" for r, n in sorted(extents(source, bindings).items())] + [f"s{r}" for r in unwritten(source, bindings)]
return os.path.basename(path)[:-len("_b.json")] + "\t" + " ".join(toks) if toks else None
def main():
if len(sys.argv) != 3:
raise SystemExit(f"usage: {sys.argv[0]} <dmsh_b version dir> <output tsv>")
version_dir, output = map(os.path.abspath, sys.argv[1:])
paths = [os.path.join(version_dir, n) for n in sorted(os.listdir(version_dir)) if n.endswith("_b.json")]
with multiprocessing.Pool() as pool: rows = [r for r in pool.map(row, paths, chunksize=64) if r]
slots, ro = sum(r.count(":") for r in rows), sum(len(re.findall(r"\bs\d+", r.split("\t", 1)[1])) for r in rows)
os.makedirs(os.path.dirname(output), exist_ok=True)
with open(output, "w", encoding="utf-8", newline="") as stream:
stamp = datetime.datetime.now().astimezone().isoformat(timespec="seconds")
stream.write(f"# chain {os.path.basename(version_dir)} {stamp}\n")
stream.write("# shader key, then reg:bytes for each uniform slot whose reads stay inside its first bytes, and s<reg> for each storage slot it never writes (cb_extent.py)\n")
for line in rows: stream.write(line + "\n")
print(f"bounded uniform reads: {slots} slots; storage slots never written: {ro}; {len(rows)} shaders")
if __name__ == "__main__":
main()
+2 -1
View File
@@ -44,7 +44,8 @@ F=$(python3 tools/gen_embed.py "$PATCHED" Gen/embed.S $MODS) || die "gen_embed"
echo "OTHER_LDFLAGS = \$(inherited) \$(DM_FRAMEWORKS) $F" >> Gen/dm.xcconfig
cp "$PATCHED"/*.fixups.tsv "$PATCHED"/*.gates.tsv "$PATCHED"/*.cuts.tsv "$PATCHED"/*.obs.tsv Gen/dm/ || die "copy rewriter tables"
if [ "$GFXAPI" = vulkan ]; then cp "$GD/shader_map.tsv" "$GD/pso_manifest.tsv" Gen/dm/ || die "copy shader tables" # empty NVN tables: the NVN layer is never used
else cp "$GD/shader_map.tsv" "$GD/pso_manifest.tsv" "$GD/c1_full.tsv" Gen/dm/ || die "copy shader tables"; fi
else cp "$GD/shader_map.tsv" "$GD/pso_manifest.tsv" "$GD/c1_full.tsv" Gen/dm/ || die "copy shader tables"
if [ -f "$GD/cb_extent.tsv" ]; then cp "$GD/cb_extent.tsv" Gen/dm/ || die "copy cb_extent.tsv"; fi; fi # optional: without it the host copies whole uniform bindings
# Diagnostic build: DM_ENV_FILE=file → dm/env.txt in the bundle (main.m sets one environment variable per line at boot)
if [ -n "${DM_ENV_FILE:-}" ]; then cp "$DM_ENV_FILE" Gen/dm/env.txt || die "copy DM_ENV_FILE"; t "env: $(grep -v '^#' "$DM_ENV_FILE" | tr '\n' ' ')"; fi
# The shader libraries go into the archive as DmIOS.app/msl/<folder> (main.m sets DM_MSL_DIR to it)
+5 -1
View File
@@ -148,6 +148,7 @@ So the translator leaves z alone (`QueryGraphicsState` depth mode false in `Prog
- **Fixed: the iPhone app was killed for memory in the first shrine (GitHub issue #9, iPhone 16 Pro Max, handheld).** An 8 GB iPhone gives this app about 3.4 GB (resident plus `headroom to the system memory limit` stayed at 3,375 MB). Resident memory grew about 0.2 MB a frame from 2.6 GB at the shrine load until the kill, while the residency set and the texture counts stayed flat. The cause was the deferred-release drain running on the guest submit thread with no autorelease pool, the Metroid Dread leak (`defer_drain` now has its own `@autoreleasepool`): on the Mac a host without that pool grew 1 MB a frame in the shrine (GPU 3.0 → 4.4 GB in 2,400 frames); with it the shrine stays at 2.7–2.9 GB resident and 1.5–1.7 GB GPU, idle or walking (vmmap at 2.8 GB: about 1.6 GB guest memory, 0.75 GB private textures, 0.17 GB IOAccelerator). Found on the way: (1) about 10 serial-table entries a frame were never deleted: the game records its transient render targets (the HUD captures, the 640×360 buffers) and finalizes them before it submits, and replay put the dead serials back into `g_by_serial` (276,000 after 25,000 frames). Dead serials now go to a 512-entry table (`tex_put`, `g_ghost`; the memory line's `finalized textures still referenced`). (2) The memory-pool tracking table had a fixed 4,096 slots and the phone reached 4,006 pools; a pool past the end would have its textures re-uploaded at every use. It now grows in blocks of 1,024 (`nvn_dirty.c`, up to 262,144).
- **Address → memory pool lookups**: BotW keeps about 1,760 memory pools alive, and `mtl_addr` / `mtl_gpu_addr` scanned them all for every buffer binding of every draw: a CPU sample of the submit thread had about 1,000 of its samples under those scans (vertex buffers in `draw`, uniform buffers in `encode_args`). They now try the last hit, then a binary search over pools sorted by start address (`pool_find`, rebuilt when pools are added or removed). Host submit time in the shrine went from 21 ms to 7 ms per frame (p50), the median frame from 38 ms to 21 ms.
- **Submissions handed to the GPU in segments.** The game does not submit frame N+1 until frame N's GPU work is done: a stack sample in the shrine had the main thread in `nvnSyncWait` (the fence of the frame just submitted) for 59% of the time and the render thread in `nvnQueueSubmitCommands` for 40%. On the Switch that submit costs nothing; here it is the host's translation (about 3,600 draws and 347 passes, 7 ms), so per frame the GPU ran 13–14 ms and then sat idle 7.7 ms (`DM_NVN_TSV` rows `@gpu_beg_ms` / `@gpu_end_ms` against `@call_ms`). The replay now commits the command buffer encoded so far every 64 draws, between two passes (`sub_cut` in `nvn_mtl.m`, called after `rp_flush` in `OP_SET_RT`; `DM_NVN_CUT=<draws>`, 0 = off). It cuts only with no open encoder and nothing deferred, merged or hoisted, commits the pending upload batch first, and continues on the same command allocator. The fence signal, the completion work (`post` ops, `g_done`) and the allocator's fence stay on the last segment: the queue runs command buffers in commit order, and every encoder starts with a queue barrier. GPU idle per frame went from 7.7 to 3.8 ms; most of the rest is the game's own work between its fence wait and the next submit (about 2.5 ms). The other five games' frame times were unchanged (Dread's p95 dropped from 19.6 to 16.9 ms).
- **Outdoor frames: passes, not shading (2026-10-21, the user's Great Plateau save, Mac M4 Pro).** A frame had about 386 render passes and loaded and stored about 900 MB of attachments (on an iPhone at 60 fps about 55 GB/s, near the memory's bandwidth); the GPU waits for each pass to finish before the next. 220 of the passes ended only because the game updates the first 64 bytes of a 64 KB vertex uniform block (`0x70c38c0000`) before each draw group while its shaders read up to 544 bytes of it (the terrain pixel shader `eb0afe555b86da79`, which indexes the block with an integer made from an interpolated value, the whole block). The shadows read from memory (`ubp_get`, `DM_NVN_UB_PARTIAL`) and the per-shader read extents of `cb_extent.tsv` keep those passes open: 386 → about 165 passes, GPU p50 about 9.3 → 6.5 ms, submit 5.7 → 4.9 ms; `DM_NVN_UBP_CHECK=1` found every shadow equal to the GPU's memory (968,000 checked). Lazy clears (`DM_NVN_LAZY_CLEAR`) fold the four clear-only passes before the G-buffer into its first pass (about 30 MB less loaded and stored a frame at 1600x900). What still splits the big passes (a `DM_NVN_PASSDUMP` frame dump): the NintendoWare VFX GPU particles run one compute dispatch per emitter between draws (ten 800x450 half-resolution passes and two G-buffer passes, about 190 MB a frame; the G-buffer ones read the depth being drawn, so they cannot move ahead of the pass), and decals that sample the G-buffer right after the game sets it again. The decals sample targets of their own pass (Metal leaves that undefined; the Mac reads the stored content); `DM_NVN_FB_SNAP=all` would snapshot them at a large cost. Tried and dropped: `DM_NVN_TBDR=1` (10–15% fewer stores, more CPU, red ledger lines, and it turns the deferred uniform updates off), `DM_NVN_BARRIER=game` (no gain), same-target continuation outside TBDR mode (the decals end the pass anyway)
- **Frame rate in the Shrine of Resurrection on the Mac (M4 Pro)**, after the above: docked (1600×900) GPU about 13 ms, frame p50 16.7 ms (60 fps; p90 17.6 ms), was 20.8 ms before segmenting; handheld (`DM_OPMODE=0`, 1280×720) GPU p50 9.3 ms and a steady 60. Host translation is 8 ms per frame (22,000 instructions per draw), spread over Metal's encoder creation and draw calls, argument encoding, Objective-C retain / release and pool lookups. The per-pass GPU timer (`DM_NVN_PASSGPU`) is switched off under Metal 4 (`pg_render` returns at once), so GPU time cannot yet be attributed to passes. The frame loads 376 MB and stores 432 MB of render-target data (`@rt_load_mb` / `@rt_store_mb`; 325 of 347 passes load and store everything), which is the next thing to look at.
- **Fixed: dark boxes and cream cloud rectangles behind HUD prompts, a black stamina wheel and a black System menu background (layout captures; GitHub PR #6).** Panes tagged `CaptureOn` (about 140 layouts, e.g. `PaGuideKeySmoke_00`; user data `A8`, `CaptureScale` 0.5, `MultiFilter`) are drawn into a target, blurred at half size and copied into a capture texture that the layout's materials sample in place of the placeholder `FBLayout_00`. The game creates that texture with its per-format default mapping (one call site, `main+0xecb0bc`: R8 → (R, 0, 0, 1), RG8 → (R, G, 0, 1), and so on), then rebuilds it on the same storage with the capture's own mapping: `main+0xf597dc` picks (1, 1, 1, R) for an `A8` capture (the material colour kept, the mask as alpha) and alpha 1 when the pane says `CaptureOutputAlpha` 255 (read at `main+0xf58e98`; an RGB10A2 capture then reads (R, G, B, 1)); `main+0xecacf0` stores the mapping and rebuilds the texture (`main+0xecabe8`), and `main+0xec33f0` replaces the registered descriptor only if `nvnTextureCompare` reports the two textures different. The host compared the description and the storage but not the mapping, so every rebuild was dropped and the captures kept (R, 0, 0, 1), whose alpha is always 1: hard-edged dark boxes behind every prompt (the shadow pane `e6a88e12dbae9743`: black, alpha = capture alpha × vertex alpha 180/255) and rectangles filled with cream cloud (the glow `aa209f57b133e862`: alpha = min(cloud alpha, capture alpha)). Before the cause was known, the profile key `alpha_from_red` listed all 26 pixel-shader variants of the layout library (`main`'s BNSH at 0x1d83000) and bound such render targets through a view mapped (R, 0, 0, R) (`tex_alpha_red` in `nvn_mtl.m`). That fixed the alpha but zeroed green and blue, so tinted panes such as the stamina wheel came out black, and the System menu background (a capture with alpha forced to 1) stayed black. `nvnTextureCompare` now compares the mapping too, an unset mapping counting as (R, G, B, A), and BotW's profile no longer lists `alpha_from_red`. Checked on the Mac by the PR's author (M4 Pro, unchanged shader libraries): green stamina, the purple noise meter and the game's own blurred System menu background. `t_nvn` covers the comparison.
- **BC textures are never attached or viewed raw (GitHub issue #4, reported from an iPhone 14 Pro / A16).** The game encodes one 32×32 BC4 texture on the GPU, drawing its blocks through an RGBA16UI view (one texel = one 8-byte block). Metal can neither attach a compressed texture nor make an uncompressed view of one, so a pass that draws into it uses an uncompressed shadow (above), and `attach`, the pipeline prediction and the sampling views go by the NVN format. The A16 has no BC formats; the host used to store BC textures decompressed on such GPUs (about 3.9 GB instead of 2.8 GB for this game, over iOS's limit on a 6 GB iPhone), and that path has since been removed: only GPUs with BC are supported.
@@ -236,7 +237,10 @@ Game Freak's Trinity engine on SDK 19 (NVN 55); every shader comes from the Oodl
| `DM_NVN_FB_SNAP=0` / `all` / `<keys>` | Which fragment shaders get the snapshot for same-pass feedback sampling (a draw sampling a colour attachment of its own render pass reads a copy taken just before it): none, every shader (slow, see BotW above), or a comma-separated key list instead of the profile's `feedback_snap` |
| `DM_NVN_ALPHA_RED=0` / `<keys>` | Which fragment shaders read single-channel render targets mapped (R, 0, 0, 1) with alpha = red: none, or a comma-separated key list instead of the profile's `alpha_from_red` (Odyssey's layout shaders; BotW no longer needs it since the `nvnTextureCompare` fix, see above) |
| `DM_NVN_CUT=<draws>` | Commit the replay's command buffer every that many draws, between passes (default 64; 0 = one command buffer per submission). Growing segments (64, 128, 256 … draws) were tried for fewer commits: Breath of the Wild fell from 60 to 30 fps in the same scene (GPU idle while the long last segments were encoded), and the commits cost little once the residency set stopped churning |
| `DM_NVN_UB_DEFER=0` | End the render pass at every inline uniform update (`nvnCommandBufferUpdateUniformBuffer`), as before. By default an update inside an open pass is deferred to the pass end; the draws after it read a shadow made of the deferred updates when they cover the whole bound range, and the pass still ends first for a draw that needs more (partial cover, the data read as vertices, indices, indirect arguments or a storage buffer). The `residency set` line counts deferred updates and such early ends |
| `DM_NVN_UB_DEFER=0` | End the render pass at every inline uniform update (`nvnCommandBufferUpdateUniformBuffer`), as before. By default an update inside an open pass is deferred to the pass end; the draws after it read a shadow made of the deferred updates when they cover all the shader can read of the binding (`cb_extent.tsv`), or of memory and the updates queued in the submission when they cover part of it (`DM_NVN_UB_PARTIAL`), and the pass still ends first for a draw that needs more (the data read as vertices, indices, indirect arguments or a storage buffer, or a partly covered block memory cannot give). The `residency set` line counts deferred updates, shadows read from memory and early ends |
| `DM_NVN_UB_PARTIAL=0` | A uniform block the deferred updates cover only in part ends the pass, as before. By default its shadow starts from memory and takes every inline update queued in the submission, newest last, when nothing else can have written the range by the time the pass runs: no copy, fill or transform-feedback write queued in the submission, no storage buffer a shader may write (every one but the slots `cb_extent.tsv` proves unwritten) and no texture→buffer copy over it in the submission, and no GPU write or counter report of an earlier submission still running (by 4 KB page). A counter report of the same submission does not count: the host writes reports on the CPU after the whole submission completes. The `residency set` line splits the refusals by reason |
| `DM_NVN_UBP_CHECK=1` | Check every uniform shadow read from memory: the pass ends, the updates land, the replay waits for the GPU and compares (`uniform shadow check: N equal, M different`; a difference is a red line). Breath of the Wild outdoors: 388,000 equal, 0 different |
| `DM_NVN_LAZY_CLEAR=0` | Clears with no draw after them open a pass of their own when the game sets other targets, as before. By default they wait: the next pass that attaches the same texture level and layer through the same view clears it as its load action, and the rest land in passes of their own before anything else could see their textures (a draw sampling one, a pass not attaching it, any operation other than targets, clears, state, uniform updates and buffer copies or fills, the end of the command list). Off in TBDR mode. The `residency set` line counts clears taken by a later pass and those landed alone |
| `DM_NVN_BARRIER=game` / `full` | How draw passes are ordered. `full` (default): every pass waits for all earlier GPU work. `game`: a pass waits only for the previous pass's fragment stage, so its vertex work overlaps the previous pass's fragments, unless the game called `nvnCommandBufferBarrier` in between or a compute / copy / upload ran (those keep full barriers). Only vertex-stage reads of the previous pass's output without a game barrier change order |
| `DM_NVN_GPU_TS=segment` / `submission` | What timestamp reports record, instead of the profile's `gpu_timestamps`: the GPU start / end of the segment holding each report, or one time for the whole submission |
| `MTL_DEBUG_LAYER=1 MTL_DEBUG_LAYER_ERROR_MODE=nslog` | Metal validation without aborting |
+4 -2
View File
@@ -75,7 +75,7 @@ On the device, environment switches go in `Documents/env.txt` (one `KEY=VALUE` p
Each game has a profile in `dm/games/<id>/`:
- `game.tsv` holds the title ID, known builds, code modules, RomFS marker, memory split, app name and bundle ID;
- the shader tables: `shader_map.tsv`, `shader_facts.tsv`, `shader_pairs.tsv`, `c1_full.tsv`, `pso_manifest.tsv`;
- the shader tables: `shader_map.tsv`, `shader_facts.tsv`, `shader_pairs.tsv`, `c1_full.tsv`, `cb_extent.tsv`, `pso_manifest.tsv`;
- `dmsh_chain.h` holds the chain version.
The shader tools pick a profile with `DM_GAME=<id>`; `make -C dm/host` and `build_ipa.sh` pick it with `GAME=<id>`. Profiles are named after the base game's title ID. There is no default game: without `GAME` / `DM_GAME` the tools stop and list the profiles. `python3 dm/games/game.py list` lists the profiles. Host code that relies on one build's fixed addresses checks that build's ID.
@@ -105,6 +105,7 @@ DM_GAME=$G python3 dm/gfx/tools/shader_split.py $W/data/v0/RomFS,$W/data/$VER/Ro
DM_GAME=$G python3 dm/gfx/tools/dmsh_chain.py --header
DM_GAME=$G python3 dm/gfx/tools/dmsh_build.py $W/shader/pkg $W/build/cache/metal_shader_cache
python3 dm/gfx/tools/c1_guard.py $W/build/cache/metal_shader_cache/b-<chain version> dm/games/$G/c1_full.tsv
python3 dm/gfx/tools/cb_extent.py $W/build/cache/metal_shader_cache/b-<chain version> dm/games/$G/cb_extent.tsv
# 4. the host, and the button-icon font for the Nintendo-extension shared font
make -C dm/host GAME=$G dmhost
python3 dm/tools/make_ext_font.py $W/build/font/nintendo_ext.ttf
@@ -149,7 +150,7 @@ The game's own work and its frame rate stay as they are; the host avoids work of
- **Thread classes.** Every guest thread runs at QoS user-interactive, whatever its Switch priority. `DM_QOS_MAP=1` (off by default, for a phone A/B) maps priority ≤ 44 to user-interactive, 45–59 to user-initiated and the rest to utility (`DM_QOS_EDGES=44,59` moves the edges). `SetThreadPriority` moves a thread's class too, and a thread waiting on a lock lends its class to the owner until the lock is handed over. Host helper threads then set their own class (audio notify, silent sink and vsync user-interactive, movie decode user-initiated) instead of inheriting it from the guest thread that made them.
- **Replay CPU.** Memory-pool addresses are cached per thread; per-encoder draw state is sent only when it changes; texture IDs of GPU-only textures stay cached when the game writes other memory; upload staging blocks are reused (Breath of the Wild used to allocate, make resident and free a 32 MB block for each re-upload of a small CPU-written texture, about 3 GB/s) and the residency set is committed only when it changed.
- **Vertex bindings.** Normal and transform-feedback draws reuse resolved stream addresses until the guest address or memory-pool generation changes. The vertex argument table skips unchanged addresses, including slot 30's zero buffer; converted streams and shader-argument writes update the same table cache. `DM_NVN_VBUF_CACHE=0` restores repeated lookups and table writes for an A/B run. Every 300 frames, `vertex bindings` reports per-frame lookups/reuse and table writes/skips (the table counts include vertex shader arguments). Compare the existing submit CPU/instruction and onscreen interval logs as well: fewer binding calls alone do not establish a frame-rate gain. `make -C dm/gfx/tests GAME=<id> t_vbuf` builds the GPU-readback regression; run it with `MTL_DEBUG_LAYER=1`, both with the cache enabled and with `DM_NVN_VBUF_CACHE=0`.
- **GPU.** An inline uniform update inside a render pass no longer ends the pass (Metroid Dread ended about 246 passes a frame this way, each one storing and reloading its attachments): the update lands when the pass ends, and the draws after it read a copy of the updated data (`DM_NVN_UB_DEFER=0` restores the old behaviour). A format-changing texture copy that covers the whole destination level does not load it first. `DM_NVN_BARRIER=game` lets a pass's vertex work overlap the previous pass ([04](agents/04-graphics.md) section 7); it is off by default, as the games issue their own barriers before most passes anyway.
- **GPU.** An inline uniform update inside a render pass no longer ends the pass (Metroid Dread ended about 246 passes a frame this way, each one storing and reloading its attachments): the update lands when the pass ends, and the draws after it read a copy of the updated data (`DM_NVN_UB_DEFER=0` restores the old behaviour). When the update covers only part of what a draw's shader reads of the block, the rest of the copy comes from memory and the other inline updates queued in the submission, unless a copy, fill, storage write or an earlier submission still running may have written it (`DM_NVN_UB_PARTIAL=0` ends the pass instead; `DM_NVN_UBP_CHECK=1` checks every such copy against the GPU's memory). Attachment loads and stores per frame on the Mac, old → new: Fire Emblem Engage's battles about 1,850 → 360 MB (88 → 38 passes), Tears of the Kingdom 1,100 → 700 MB, Link's Awakening and 13 Sentinels about 15% less, Super Mario 3D World 5%; Breath of the Wild 386 → 158 passes; Mario Wonder and Metroid Dread unchanged (their updates already covered what the draws read). Clears with no draw after them no longer open a pass of their own when the game sets other targets: the next pass that attaches the same target clears it as its load action (`DM_NVN_LAZY_CLEAR=0` restores the old behaviour). A format-changing texture copy that covers the whole destination level does not load it first. `DM_NVN_BARRIER=game` lets a pass's vertex work overlap the previous pass ([04](agents/04-graphics.md) section 7); it is off by default, as the games issue their own barriers before most passes anyway.
## Game notes
@@ -173,6 +174,7 @@ The game's own work and its frame rate stay as they are; the host avoids work of
- Scenes that fix the game's step themselves (the VFR's override: 2 at `main+0xc3b588` / `+0xc5ebf8`, 1 at `main+0xc609d8`) keep it, and the host holds frames that long (log line `the game fixes its own step`; not reached on the Mac yet).
- Mac (M4 Pro), from the title into the save's scene: 1.000 of real time at 60; with 12 ms added to every frame (`DM_TEST_PRESENT_LAG=1,12`) it drops to 30 and stays at 1.000. `DM_FPS_TARGET=30` holds 30 (saves power).
- **The game's own interval controller** (at `DM_FPS_TARGET=0`, and the interval the framework keeps while the VFR override holds): patches to it lift its floor from 2 to 1. The game's time step follows its frame interval, so the speed is right at a steady 60, 30 or 20. The game picks the interval from the frame's CPU time and its GPU time, which it reads from two GPU timestamps around the frame; the host gives each timestamp the GPU time of the work around it (profile key `gpu_timestamps`, which its dynamic resolution needs too). Before that it saw only the main thread's CPU time (about 3 ms a frame in the first shrine) and stayed at 60 in slow motion: at 40 fps, about two thirds of the normal speed (an iPhone 16 Pro Max in handheld mode, GitHub issue #9; [04](agents/04-graphics.md)). Under load it still ran at 0.93–0.98 of real time.
- **Outdoors on the Mac (M4 Pro, the Great Plateau):** about 165 render passes a frame instead of 386 and GPU p50 about 6.5 ms instead of 9.3 since a partly updated uniform block no longer ends the pass (the game updates 64 bytes of a 64 KB block before each draw group), and the G-buffer clears ride on its first pass ([04](agents/04-graphics.md)). The frame still loads and stores about 800 MB of attachments, most of it where compute dispatches of the GPU particles split passes.
- **Render scale:** `DM_RENDER_SCALE=0.5`–`1.0` (also from `Documents/env.txt`) fixes the 3D views at that fraction of 1600×900 docked (1280×720 handheld) and turns the game's own dynamic resolution off; 1.0, the default, keeps it. A stub sets the scale where the game applies its own (`main+0x1266880`), so every scene pass, the shader's resolution ratio and the LOD check follow it: at 0.5 the 1600×900 passes become 800×450 and the 800×450, 400×225, 200×112 and 100×56 chains halve too, while the shadow maps and the 1920×1080 output keep their size and the HUD stays sharp. It holds in handheld mode too (960×540 at 0.75). On the Mac (M4 Pro) the GPU time does not change (about 13 ms in the first shrine at 1.0 and at 0.5): a frame has about 650 passes, most of them tiny, whose fixed cost outweighs their pixels there. Whether it helps an iPhone, whose GPU loads and stores each pass's attachments, is what the setting is for.
- **Open: an intermittent crash at the world load on the Mac.** About 3 s after Start, a task worker's `operator new[]` (`main+0x155a79c`) gets null from a game heap and writes through it (`main+0x155a7a4`). It happened with the earlier, elapsed-time frame step too (1 of 8 runs), so the frame step does not cause it, though it may make it likelier: 12 of 33 runs across the variants tried (each stub alone, no pay-back, the game's interval as a floor), solo or beside other runs. None of the about 95 earlier logs (up to 2026-10-19) has it. PR #27 traced it to the resource heap of `Model/Obj_TreeConiferous.bfres`: while the game sets the model up, a 0x78-byte allocation finds 0x70 free in the heap its resource size table entry sizes (0x29e520 for the 0x19b010-byte file). Raising the model entries through `DM_ROMFS_OVERLAY` (the PR's overlay: +64 KB each, +512 KB for this model) avoided it in 0 of 8 runs, against 3 of 9 on 89b608d (2026-10-21, 110 s runs, four at a time). A Switch runs with the original table, so the host makes the setup take more of that heap than the hardware does; that difference is still to be found, and the overlay is not in the repository.
- **Memory:** about 2.8 GB in the first shrine in handheld mode, idle or walking (Mac measurement), against the 3.4 GB an 8 GB iPhone gives the app.
+2
View File
@@ -1023,6 +1023,8 @@ def build_shaders(py, repo, sh, xlate, env, logs, g, provisional=False, split_ke
if provisional:
PROG.set(step='c1 guard')
run([py, repo / 'dm/gfx/tools/c1_guard.py', sh / 'cache' / f'b-{chain}', g.table('c1_full.tsv')], logs / 'c1_guard.log', env=env) # shaders whose c1 reads are not proven bounded
PROG.set(step='uniform read extents')
run([py, repo / 'dm/gfx/tools/cb_extent.py', sh / 'cache' / f'b-{chain}', g.table('c1_full.tsv').with_name('cb_extent.tsv')], logs / 'cb_extent.log', env=env) # how far each shader reads into its uniform blocks
n = sum(1 for _ in libs.glob('*_b.metallib')) if libs.is_dir() else 0
if n == 0: raise BuildError(f'no iOS shader libraries in {libs}')
say(f'{n} iOS shader libraries ({libs})')