Repository navigation
Partial texture re-uploads, one page check per submission - #2263
roandegraaf wants to merge 1 commit into
Conversation
|
Re-measured on ced3612 with its own shader libraries (chain bc8830d4ba5a). The body's results hold on this base, with two differences: the largest partial read of the array was 19.0 MB (14.2 MB in the body), and with Machine and settings: Apple M4 Pro (20-core GPU, 24 GB), macOS 27.2, profile
Notes on the table:
Pictures: one frame 44 s into each run ( Tests on the branch at ced3612, all 0 failed: Notes and what was not checked:
|
…s written, and a submission looks at a texture's pages once: the images (a layer's level) with a page written since the last upload are read from guest memory and the others copied on the GPU from the texture it replaces (pkg_written, up_copy_add; DM_NVN_PARTIAL_UPLOAD=0 reads whole), where one written page sent every layer and level through the upload again, at every use. A write another thread makes while the queue's thread replays a submission is found at the next submission's first look (nvn_dirty_touch then, so that generation caches do not keep the texture); writes by the replaying thread (nvn_dirty_own_writes) and looks outside a submission stay exact. Ocarina of Time's loader fills a 1800x1380x8 array of 38.5 MB piece by piece while the game draws with it: on the walk into Hyrule Castle Town 31-52 re-uploads a run, the array 16-17 times whole, frames of 30-64 ms; now 16-17 re-uploads, the array 7-9 times at 4.7-14.2 MB, frames of 25 ms at most (M4 Pro, on base 8db5dd4). A texture holding copied images is read whole once an upload batch was dropped (g_up_lost_gen), and the recovery of a dropped batch is no longer skipped for a texture with edge copies (pkg_edges_clean). The DM_NVN_REUPLOADS line names what was read, the time and the submission; t_partial_upload compares every image with a CPU reference after each write
213a281 to
d9247dd
Compare
…s written, and a submission looks at a texture's pages once: one written page sent every layer and level of the texture through the upload again, into another Metal texture, and the pages were asked at every use, so while the queue's thread replayed a submission each look found the few pages a loader thread had written since the last and uploaded again. Ocarina of Time (0400486024DEC000, v131072) fills a 1800x1380x8 array of 38.5 MB piece by piece while it draws with it: walking into Hyrule Castle Town, 11 to 19 whole reads of the array a run (424 to 732 MB) and frames of 49 to 90 ms with a re-upload. Now the images (a layer's level, or a 3D texture's level) with a page written since the last upload are read from guest memory and the others copied on the GPU from the texture it replaces (pkg_written, up_copy_add; DM_NVN_PARTIAL_UPLOAD=0 reads whole); sparse, linear and multisample textures are read whole as before. A write another thread makes during the replay races the GPU's run of that submission on the console, so it is found at the next submission's first look, as a sparse texture's already was (229fc22); nvn_dirty_touch at that mtl_sub_begin sends the caches that remember "nothing written since" by generation through their check again. Writes by the replaying thread (nvn_dirty_own_writes) and looks outside a submission stay exact. A texture holding copied images is read whole once an upload batch was dropped (g_up_lost_gen), and the recovery of a dropped batch is no longer skipped for a texture with edge copies (pkg_edges_clean kept the unwritten texture); t_direct_upload now waits for the report. The DM_NVN_REUPLOADS line names what was read, the time and the submission. The code, the diagnosis, the test and the measurements are PR #2263's; added here: the reference entry's open and not-checked lines. The author's runs (M4 Pro, headless, the recorded walk into the town, 70 s, baseline ced3612 and the branch interleaved, 8 and 3 runs): the array 7 to 9 reads of 4.7 to 19.0 MB (66 to 76 MB a run), the 3072x2096 BC5 texture 21-22 re-uploads to 2, the longest frame with a re-upload 20.5 to 23.6 ms, frame rate 57.96-60.12 and 58.42-58.91 fps. Checked here on 8b55ebb plus the change (M6): t_partial_upload 3,585 checks (every image against a CPU reference after each write; three re-uploads a submission of that array complete in 13.3 ms with one layer written, 68.5 ms read whole), t_direct_upload 26,384 and 26,388, t_cpu_tex, t_upload_slots, t_dirty_race, t_dirty_slots, test_docs. regress.py check, full routes, headless: Bastion PASS (59.5 to 59.1 fps, p99 17.55 to 17.61 ms) and The Binding of Isaac: Rebirth PASS (59.2 to 59.1 fps), no new red line; neither route makes a re-upload, nor does Ocarina's Kokiri Forest walk (run by hand on both hosts, 16.7 ms p50), so no game run here reached the partial read. Open: a single-image texture is still read whole, once a submission; DM_NVN_DIRTYCHECK=1 reports one dirty-page miss on the town route on the baseline, the branch's runs with the check did not reach the town, and those runs predate 1e69c18 (a write missed while opening shared pool pages), which may be that miss. Not run: the town route here (no save near it on this Mac), another game that re-uploads, the full gfx suite, lint_c.py, iOS. test_env_switches fails on main as here, for switches this does not touch (PR #2263) Co-authored-by: Roan de Graaf <36153028+roandegraaf@users.noreply.github.com>
|
Landed on main as d2556cf, with your code, test and measurements kept as they are and you as co-author. Thank you: the diagnosis (that fixing the whole read alone made the repeated looks worse) is what made this easy to judge. Checked here on main plus the change (M6): Left open in the reference entry:
|
What and why
Walking into Hyrule Castle Town in Ocarina of Time stutters for a few seconds: frames of 30–64 ms while the town's textures load, with no pipeline being built.
Cause. Two things in the host's look at a texture taken from guest memory (
tex_mtl_indm/gfx/nvn/nvn_mtl.m), which show where a game's loader thread fills a texture over several frames while the game already draws with it:submissionfield of theDM_NVN_REUPLOADSline: most of the re-uploads of one frame are inside one submission (5 of the array, 8 of a 3072x2096 BC5 texture).Fixing (1) alone made (2) worse, as a shorter upload lets more looks see a fresh write: 17–22 uploads in one submission and a frame of 148 ms.
Change. General, in the host:
pkg_written,up_copy_add,up_flush).DM_NVN_PARTIAL_UPLOAD=0reads whole.nvn_dirty_touchat thatmtl_sub_beginsends the caches that remember "nothing written since" by generation through their check again. Writes by the replaying thread itself (nvn_dirty_own_writes) and looks outside a submission stay exact.g_up_lost_gen).pkg_edges_cleanfound those bytes unchanged and kept the unwritten texture).t_direct_uploadpassed only because its recovery block ran when the report arrived before the test looked; it now waits for it.DM_NVN_REUPLOADSline names how much was read, the time, and the submission.Reference entry: A texture written while it is drawn read whole at every use (added here), with its lines in the game note.
Open:
DM_NVN_DIRTYCHECK=1reports onedirty-page misson the town route, with the old logic as well. Unexplained.Checked
make -C dm/gfx/tests GAME=0400486024DEC000 check_<name>:t_partial_upload3,585 checks, 0 failed;t_direct_upload26,384 + 26,388;t_cpu_tex98;t_alias_takeover28;t_cpu_storage135;t_sparse_tiles4,253;t_view_swizzle554;t_pool_chunks151;t_upload_slots305 ×2;t_nvn298;t_clear_msaa32 (the multisample zero fill of 01de04f, which shares the upload batch);t_readback218 cases;t_dirty_race,t_dirty_retire_race,t_dirty_slots; all 0 failed.make -C dm/host GAME=0400486024DEC000builds.python3 -m pytest -q dm/tools/tests/test_docs.py dm/tools/tests/test_env_switches.py: 7 passed.t_partial_upload(on base 8db5dd4): no copies of the unwritten images → 1,216 image mismatches; nonvn_dirty_touch→ 44 failed; no own-write condition → 88 failed; no in-submission condition → 22 failed.DM_FPS_HOLD=off, compared by theDM_NVN_REUPLOADSlines and the long-frame lines; 0 red lines. A default Hyrule Field route: 56.5–58.1 fps, 0 red lines, no re-uploads (with the old logic too). Not repeated in the game on ced3612: the change applied to it without conflicts, and the tests above ran on it.scripts/regress.py check --gamesreport: Ocarina of Time is the only game built on this Mac. Every NVN game with textures taken from guest memory passes through this path.In windowed play before the change: frames of 26–57 ms with 75.8–230 MB re-uploaded in each.
Docs
docs/reference/<subsystem>.mdentry, andpython3 dm/tools/docs_symptoms.pywas run (the symptom index)dmsh_chain.py --headerwas run anddm/gfx/nvn/dmsh_chain.his part of the change