WIP: fix(vk): a direct quad draw's triangles grow the stream under RX_VK_STREAM_GROW_OFF too #853
No reviewers
Labels
No labels
area/accessibility
area/audio
area/input
area/install
area/menu
area/renderer
area/saves
area/tooling
area/upscaling
ci: approved
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/macos
platform/steam-deck
platform/windows
preview
priority
critical
priority
high
priority
low
regression
risk
high
risk
low
risk
medium
status
blocked
status
confirmed
status
duplicate
status
invalid
status
needs-info
status
wontfix
testing wanted
ci: approved
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
MagicBeanDev/Longshot!853
Loading…
Reference in a new issue
No description provided.
Delete branch "mooki/Longshot:fix/quad-stream-grow"
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?
Type: fix · Risk: low · Tested on: macOS 26.7.1, Apple M4 Max (arm64; x86_64 under Rosetta) · Needs: Windows and Linux, any GPU
Why
LS draws NVN's quads by writing each quad's two triangles into the recording's upload stream and drawing them as an indexed
triangle list. The testing switch
RX_VK_STREAM_GROW_OFF=1keeps that stream from growing when a recording needs more than itholds. With the switch on and the stream full, a direct quad draw found no room for its triangles and was left out of the frame,
on every platform and driver. The switch is there to try a fixed-size stream, not to drop geometry: what does not fit should be
refused only where nothing is drawn wrong because of it. This PR lets the stream grow for the triangles a quad draw cannot be
drawn without, under the switch too. Without the switch nothing changes. Found while the macOS port checked every draw that is
left out for want of stream room (its StreamRoom work). See #420.
How to reproduce
Seen on: every OS and GPU (the same code on every driver); shown on main by this PR's game-free test, on macOS 26.7.1, Apple M4 Max, arm64 and x86_64 under Rosetta
Settings and switches:
RX_VK_STREAM_GROW_OFF=1(with it the first stream is 24 MB;RX_VK_STREAM_MB=1makes it 1 MB, so it fills sooner)Steps: start the game with the switch and play until a recording's stream fills (
vk: the recording's stream is full (N MB)in longshot_log.txt) with a direct quad draw after it in the same recording. Game-free, from this branch:python -I -B tests/test_stream_needed.py --headers (the Vulkan-Headers include folder) --source (a checkout of main), case grow-off-fullExpected: the quad draw drawn, from a bigger stream made for its triangles (
vk: a recording needed more than its N MB stream: one of M MB made)Actual: the quad draw is left out: counted at the triangles'
stream_allocin thevk: skips a frame by vk_draw.cpp line:report; the test saysFAIL grow-off-full: the direct quad draw left out (1 skipped, 0 drawn of 1)What changed
The stream's allocation takes a
neededflag: what a draw cannot be drawn without. For a needed allocation the stream growsunder
RX_VK_STREAM_GROW_OFFtoo; every other use of the stream is refused under the switch as before. Only draw()'s directquad draw asks for its triangles as needed. The fix comes from the macOS port's stream work (its commit
bbfb465f), applied tomain's code by hand.
gpu/vk/vk_draw.cpp:stream_next(need, needed)makes the next stream under the switch whenneeded;stream_reserve(n, align, needed = false)andstream_alloc(n, align, needed = false)pass it along; draw()'s direct quad drawcalls
stream_alloc((uint64_t)quads * 6 * 4, 16, true). A quad draw is left out only when no buffer can be made at all. Theother callers (uniform data,
stream_copy,uniform_upload) are unchanged: under the switch an upload that does not fit stillreads the null buffer, as before, and no draw is left out for it. The comment above
stream_grow_off()says what the switchrefuses and what it does not.
tests/test_stream_needed.pywithtests/stream_needed_test.cpp(new):RecordingRes,stream_insert..stream_allocanddraw()'s direct quad draw cut out of
vk_draw.cpp(andDrawArgsout ofvk_draw.h), run on a model of a recording and ofthe GPU. Cases: grow-off-full (the switch on and the stream full: a quad draw from its first vertex and one indexed by the
game's 16-bit indices, each drawn from a stream made for its triangles, each quad as {v0, v1, v2, v0, v2, v3});
others-refused (an upload under the switch still refused, no stream made); grow-on (the default: drawn, uploads grow the stream
as before); room; no-memory (no buffer to be made: left out, the stream as it was). And a source check: the direct quad draw
alone asks as needed, and
stream_nextis reached fromstream_reservealone.--sourceruns it on another tree.Measurements
Nothing to measure: without
RX_VK_STREAM_GROW_OFFthe stream code takes main's path (it grows as before); with the switch the fix is whether a quad draw is drawn, which the new game-free test shows (failing on main, passing here, arm64 and x86_64).Flags and settings
One existing testing switch changes what it does:
RX_VK_STREAM_GROW_OFFno longer leaves a quad draw out.RX_VK_STREAM_GROW_OFF=1: a direct quad draw that finds the stream full is left out=1: uploads are refused as before, a direct quad draw's triangles grow the stream, so no quad draw is left outTesting
Tested: on macOS 26.7.1, Apple M4 Max, game-free, at this PR's head
d0df2ded:tests/test_stream_needed.pyon arm64 and on x86_64 under Rosetta (clang++ -arch x86_64): all five cases and the sourcecheck pass on both. The same test against main's
vk_draw.cpp(--source, mainaa95d35f): grow-off-full and the source checkfail on both arches, the other four cases pass (as they should: they are main's behaviour too).
vk_draw.cppor read them, on this head:test_draw_stream_visibility,test_recording_admission,test_fsr_uniform_ownershipandtest_draw_bindson arm64 and x86_64,test_mem_trimandtest_run_all_declarations: all pass. None needed a change.gpu/vk/vk_draw.cppcompiled whole for arm64 and x86_64 with nx2/build.py's own macOS commands: both exit 0. Main has no macOSbuild, so this PR's
vk_draw.cpp(byte for byte) was compiled in the macOS port's host tree (topic macos-host40c1c5f5,which leaves
vk_draw.cppas main has it and adds the macOS build and cache-file code main lacks); compiled in main's own treeit stops at
posix_fallocateinpipeline_cache_file.h(not in this PR), on both arches.unifdef -U__APPLE__of every changed C/C++ file, compared as tokens with main's):vk_draw.cpponly, and the difference is exactly this change (theneededparameter of the three stream functions, itspass-through,
stream_grow_off() && !needed, and the quad draw'strue); comments aside, nothing else.python -I -B tests/run_all.py --jobs 6) on this Mac against main's: 544 passed, 33 failed, 17 skipped (main: 543, 33, 17); by name the one difference istest_stream_needed, new and passing. The 33 failures are main's own on this Mac.78ec1c47), whose run E9a held play 1,197 swith every draw drawn (12 of 12 must-shows, a clean end, 0 skipped draws), without the switch: the default path is unchanged.
Not tested: Windows and Linux (no PC here); the game with
RX_VK_STREAM_GROW_OFF=1on any platform (the switch is fortesting; the model test covers the draw).
Must be tested:
d0df2ded) and main (aa95d35f) the same way and runpython -I -B tests/run_all.pyon each, then start each to the title, expectingtest_stream_neededto pass, no other check to change status against main, and the samevk:lines in longshot_log.txt as main's (Test Farm: @Beanstalk windows and linux: build unchanged, run_all, start to the title)Risks
What could break: only under
RX_VK_STREAM_GROW_OFF=1: a recording with direct quad draws after its stream fills now makesbigger streams (more memory) where before it left those draws out. Without the switch nothing changes: every caller takes
main's path.
Turning it off: revert the commit (the switch is the only path it changes).
Compatibility: Nothing changes: no cache, save,
longshot_options.inikey or vk ABI is touched.Issues
See #420
Checklist
Everyone
type(scope): description) of the status line's type.main.python -I -B tests/run_all.pypasses (any failure that also fails onmainis named).third_party/untouched (a new folder with aPROVENANCE.mdinstead).When it applies
Assisted-by:/Co-Authored-By:trailers.mainand passing here.View command line instructions
Checkout
From your project repository, check out a new branch and test the changes.