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:
1 parent
8a429d8b5f
commit
f5646efc47
21 files changed
+122818
-29
No files matched your search
@@ -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
@@ -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
|
||||
|
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
@@ -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
|
||||
|
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
+3
-2
@@ -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
@@ -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`.
|
||||
|
||||
|
||||
@@ -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(<, &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
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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()
|
||||
@@ -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)
|
||||
|
||||
@@ -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
@@ -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.
|
||||
|
||||
@@ -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})')
|
||||
|
||||
Reference in new issue
Block a user