WIP: fix(vk): a render target is not uploaded from memory for a GPU buffer write older than its drawing #332
No reviewers
Labels
No labels
area/accessibility
area/audio
area/input
area/install
area/menu
area/renderer
area/saves
area/upscaling
good first issue
gpu/amd
gpu/igpu
gpu/intel
gpu/nvidia
help wanted
kind
bug
kind
chore
kind
docs
kind
feature
kind
performance
kind
question
needs measurements
platform/linux
platform/steam-deck
platform/windows
preview
priority
critical
priority
high
priority
low
status
blocked
status
confirmed
status
duplicate
status
invalid
status
needs-info
status
wontfix
testing wanted
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
MagicBeanDev/Longshot!332
Loading…
Reference in a new issue
No description provided.
Delete branch "Amateurwizrd/Longshot:fix/drawn-target-upload"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Why
The first time the game samples a render target after finalizing it, the renderer asks what changed in the target's storage since. When a GPU buffer wrote that storage, it uploads the whole image from guest memory over what the pass drew. That buffer write was compared only with the last one the texture had seen, never with the drawing, so a target made over a buffer's old storage counted the older write as newer. In Hyrule Field on current
mainthat is 4 or 5 whole uploads of 1920x1080 targets a run in the two minutes after loading.mainalready fixes the other cause of the same uploads, a virtual-pool target drawn before it had a page map (#325, the port of Hookshot's 40955ed3). This PR started as our own version of that change and is now only the part #325 does not cover.What changed
texture_rendered(gpu/vk/vk_texture.cpp), which only a pass calls, now takes GPU buffer writes into the target's storage from earlier submissions as older than the drawing (gpu_wrote_seen), once a frame under the pass's lock. A write in the pass's own submission still counts, since which came first is not known there.tests/test_drawn_target.pycutstexture_written,texture_rendered,texture_released,texture_dirty,texture_gpu_wrote,gpu_wrote_intoand the check intexture_touchout of the source and checks the buffer-write cases with the switch off and on. Onmainits first case fails.docs/development.md, and the two measured builds as run files indocs/tested/.Flags and settings
RX_VK_NO_DRAWN_OVER_BUFFER_WRITE=1mainMeasurements
main:
98e2d95f(2026-11-14)this PR: fix/drawn-target-upload @
de3b4aabHardware: NVIDIA GeForce RTX 5070 Ti 16 GB, driver 621.01, AMD Ryzen 7 7800X3D, 32 GB, Windows 11 Pro 26200
Scene: Hyrule Field (child) by debug teleport from a copied save, standing; Output resolution 2560x1440 in a 1707x960 window, Render resolution 75%, the game's own upscaler, no frame generation, no frame cap, sound off, the serial replay, no VRAM allowance
Method: 3 rounds, the two builds alternating in each round. One game folder (
longshot v3.0.0-rc.3-27-gf516654c) with onlylongshot_vk.dllswapped (the host interface is unchanged since); both renderers built alone withRX_VK_ONLY=1and the same toolchain (v3.0.0-rc.3-57-g98e2d95fandv3.0.0-rc.3-58-gde3b4aab). Each run: teleport, 25 s standing, 5 s in the pause menu. Counts arevk: upload over a drawn imagelines; "for a buffer write" are those witha GPU buffer wrote it, each a whole image. Slow re-uploads areslow uploadlines markedagain(over 15 ms). Frame rate is the median of the log'sN presents, X fpslines from present 5040 on.How to reproduce: load a save, teleport to Hyrule Field (Debug tab), stand for 25 s, open and close the pause menu, and count the
upload over a drawn image ... a GPU buffer wrote itlines in the log.98e2d95fde3b4aabFrame rate by round, main / this PR: 118.4 / 114.7, 115.7 / 114.5, 114.4 / 114.2. Main ran first in each round here and was faster in each. In the earlier set on
514591a3(this PR's first version), this PR ran first in each round and was faster in each (118.6 / 114.2, 114.8 / 114.2, 115.3 / 114.7). The first run of a round is the faster one on this PC, so no frame rate change is claimed either way. The HUD labels were right in all six runs.The one left with this PR is a 1016 KB range of a 1920x1080 target, a page remapped or written after its finalize: another cause, not touched here.
main @
98e2d95f, round 1:On a build with 40955ed3 and
RX_VK_WATCH_TEX, the buffer writes behind these uploads were 1 to 3,221 frames older than the target's last drawing, in four of four.Testing
Tested:
python -I -B tests/run_all.pyon Windows 11 with llvm-mingw, atc42e9b1f: 517 passed, 5 failed, 34 skipped. All five fail the same way onmain98e2d95f(test_oot_state_tap,test_pad_layout,test_portable_builder_home,test_portable_builder_startup,test_tested_configurations; the last only in its Windows line-ending case, while its check of the repository's run files passes).tests/test_drawn_target.pypasses here; withmain'svk_texture.cpp(--source) its first case fails. In the game on the PC above: the 6 runs under Measurements, no device lost.Not tested:
RX_VK_PARALLEL=4. Zone changes on foot (the runs teleport once). Sessions longer than two minutes. Frame times (only the 5 s frame-rate readings). AMD and Intel GPUs. Linux. GCC for the new test. Whether the uploads onmainever show on screen.Needs other testers:
RX_VK_NO_DRAWN_OVER_BUFFER_WRITE=1, counting theupload over a drawn image ... a GPU buffer wrote itlines and watching the picture after each load (T-KUWQ)Screenshots
None: nothing differed on screen in these runs.
Risk and rollback
If a buffer write before the pass put texels into part of the target that the pass then does not cover, those texels are now missing from the image; on
mainthe whole drawing was missing instead.RX_VK_NO_DRAWN_OVER_BUFFER_WRITE=1givesmain's behavior without a rebuild; reverting the commit is enough.Reviewer notes
texture_rendered; it costs one compare and store per target per frame.texture_renderedis called only bybegin_pass, under theParLockthattexture_markeddecides, so the store needs no lock of its own.Issues
None found (the forge searched for "garbled", "rainbow" and "HUD", 2026-11-13).
Checklist
For everyone
type(scope): description).main.python -I -B tests/run_all.pyrun and passing (any failure that also fails onmainis named above).third_party/untouched (a new folder with aPROVENANCE.mdinstead).If applicable
Assisted-by:/Co-Authored-By:trailers.docs/tested-configurations.mdfor each measured run.mainand passing here.tests/that reads changed source updated in this PR, not weakened.Test request T-J359 is open (any GPU, with RX_VK_PARALLEL=4); the description names it and the Testing box is ticked. It can be claimed once a maintainer adds the testing wanted label.
210511373dc42e9b1f88WIP: fix(vk): render targets keep their drawing after the game finalizes themto WIP: fix(vk): a render target is not uploaded from memory for a GPU buffer write older than its drawingNarrowed and re-measured: #325 merged the drawn page map, so this PR is now only the buffer-write case it leaves (one commit,
de3b4aab, switch RX_VK_NO_DRAWN_OVER_BUFFER_WRITE). Force-pushed onto main98e2d95fand measured there: 4, 4 and 5 whole uploads for an older buffer write a run on main, none with this PR. T-J359 named the dropped switch and is closed; T-KUWQ replaces it.View command line instructions
Checkout
From your project repository, check out a new branch and test the changes.