Repository navigation
perf(agc): present resident displays without the 4K convert chain - #5311
Merged
oneandonlydean merged 1 commit intoOct 14, 2026
Merged
Conversation
A 10-bit resident display buffer (and an 8-bit one in the other channel order or an sRGB type) went through vkCmdCopyImageToBuffer, the color transfer's convert dispatch, vkCmdCopyBufferToImage into the scaler source and a blit, all at the display's resolution, plus a full clear of the swapchain image. PresentationPass now draws such an image straight into the swapchain image with one fragment pass: it reads the raw texels through an R32_UINT view, decodes them as the guest-memory path does (the display's channel order, the 10-bit variant truncated to 8 bits), scales with a bilinear filter of the decoded values and writes black outside the aspect-fit rectangle, so it needs neither intermediate buffer nor a clear. The swapchain stays B8G8R8A8_UNORM and now also allows color attachment use. A 16-bit float display buffer keeps the convert chain: its encode goes through the scanout threshold tables, and the pass refuses it. The blit paths clear only the letterbox bands (blits from a 1x1 black image) instead of the whole swapchain image, and the scaler source image is only used by the guest-memory, uniform and 16-bit float paths. GPU frame dumps of a drawn image are drawn by the same pass at the dump size, sampling every n-th texel, so they hold the same bytes as before. Test: agc_driver_presentation_pass compares the pass with the convert path for both 8-bit and both 10-bit channel orders (identical unscaled and letterboxed, within two levels of the blit filter scaled), checks that a 10-bit destination keeps every source bit, that dumps equal the subsampled guest-path frame, that the band clears equal a full clear, and that a 16-bit float display buffer is refused.
11 tasks done
|
Other open pull requests touch the same code. Merging one will break the other, or both implement the same thing. If this one builds on them, list them in Depends on.
|
This was referenced Oct 13, 2026
11 tasks done
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
A resident display buffer that can't be blitted as-is (10-bit, 8-bit in the other channel order, or an sRGB type) went through four full-resolution steps plus a full clear of the swapchain image:
vkCmdCopyImageToBuffer;vkCmdCopyBufferToImageinto the scaler source;The scaler source image and the color transfer's buffers are single objects, so before recording that chain each present also waited for every earlier present still in flight (
RetirePresents(0)behindSharedSlotInFlight).PresentationPassnow draws such an image straight into the swapchain image in one fragment pass. It reads the raw texels through anR32_UINTview and decodes them as the guest-memory path does (the display's channel order, the 10-bit variant truncated to 8 bits). It scales with a bilinear filter of the decoded values and writes black outside the aspect-fit rectangle, so there is no intermediate buffer and no clear. Its descriptor set is per present slot, so it doesn't wait for other presents. The swapchain staysB8G8R8A8_UNORMand also allows color-attachment use.PresentationPass::Bindthrows for such a buffer.Tested
Linux (CachyOS, kernel 7.2, GCC 16.2, RTX 4090, NVIDIA 610.57.04), Release,
BUILD_TESTING=ON, onmain0214069.agc_driver_presentation_pass(exit 77 without Vulkan). For both 8-bit and both 10-bit channel orders it compares the pass with the convert path: identical at 1:1 and letterboxed, within two levels when scaled; a 10-bit destination keeps every source bit. It also checks that dumps equal the subsampled guest-path frame, that the band clears equal a full clear, and that a 16-bit float display buffer is refused. The existing resident-present conversion tests (including 16-bit float) are unchanged and pass.ctest -R "agc|shader|video": 505 of 505. The presentation tests pass again merged ontomain30f9612.python3 tools/check_conventions.py --base origin/mainpasses.PPSA21564 scans out a 3840x2160 10-bit buffer.
main30f9612 against the same commit with this change merged, same build options, warm caches (one warm-up run each, not counted), runs alternated main, change, main, change. Title and menu are frames per second over fixed windows; the level is milliseconds per present over level frames 400 to 1200 (below 30 fps it advances a fixed step per frame, so frame indices compare like for like). A browser was open during all runs, on both sides. Onemainrun of the third pair is left out because its presses landed during the intro and it never reached the level; a fourth pair replaced it.main(n=3)With
APS5_PROFILE_DRAW=1 APS5_PROFILE_GPU=1(one run each),present-blitGPU time per present: 2.49 ms onmain, 0.11 ms with this, the same before the level and in it. The same runs: title 21.6 and 23.05 fps, menu 18.9 and 19.5 fps, first level 32.6 and 28.9 ms.Summary lines, captured as the Performance report form describes (no
APS5_PROFILE_*, caches warm), two runs each,mainfirst in each pair,APS5_TRACE_SECONDS=155:5(5 s in the first level).APS5_LOOP_GUARD,APS5_PAD_PRESSandAPS5_DUMP_FRAMESare set by my test harness on both sides; the other three variables it sets are not read bymain. The window starts at a fixed time, and the level starts 122 to 143 s into these runs, so the four windows cover different parts of the level; the frame-index numbers above are the like-for-like comparison. Over level frames 400 to 1200 these runs measured 35.9 and 30.6 ms onmain, 29.6 and 27.8 ms with this. The traces are not attached (the PR was edited from the command line); I can add them.{"commit":"30f961266ade","dirty":null,"env":{"APS5_DUMP_FRAMES":"6000","APS5_INEXACT_SINGLE_LANE":"500597a00","APS5_LOOP_GUARD":"2000","APS5_PAD_PRESS":"120:Return,130:Return","APS5_TOLERATE_DISPATCH_FAILURES":"1","APS5_TRACE_DIR":"<path>","APS5_TRACE_SECONDS":"155:5","APS5_TWO_LANE":"500597a00"},"gpu":"NVIDIA GeForce RTX 4090","driver":"NVIDIA 610.57.04","os":"Linux 7.2.3-1-cachyos","resolution":"3840x2160","window":{"spec":"seconds 155:5","first_present":3863,"ms":5029.966},"presents":146,"frame_ms":{"p50":31.314,"p90":37.484,"p99":91.894,"max":99.980},"gpu_busy_ms_per_present":17.465,"worker_busy_pct":{"queue worker 0x0":99.051,"queue worker 0x40":99.272,"queue worker 0x48":94.526,"queue worker 0x3a":0.000,"queue worker 0x46":4.046},"top_phases_ms_per_frame":{"Driver.Packet":101.903,"Driver.Packet.memory_wait":61.990,"Driver.Packet.draw":23.766,"Driver.Draw":23.708,"Driver.Draw.draw_and_resource_release":14.205,"Graphics.Draw":14.060,"Graphics.Draw.draw_and_resource_release":11.445,"Driver.Packet.prepare_memory":7.909},"trace_dropped":false,"trace":"aps5-trace-30f961266ade-1271581.json.gz"} {"commit":"f3d1e6bcd120","dirty":null,"env":{"APS5_DUMP_FRAMES":"6000","APS5_INEXACT_SINGLE_LANE":"500597a00","APS5_LOOP_GUARD":"2000","APS5_PAD_PRESS":"120:Return,130:Return","APS5_TOLERATE_DISPATCH_FAILURES":"1","APS5_TRACE_DIR":"<path>","APS5_TRACE_SECONDS":"155:5","APS5_TWO_LANE":"500597a00"},"gpu":"NVIDIA GeForce RTX 4090","driver":"NVIDIA 610.57.04","os":"Linux 7.2.3-1-cachyos","resolution":"3840x2160","window":{"spec":"seconds 155:5","first_present":3864,"ms":5010.792},"presents":171,"frame_ms":{"p50":29.288,"p90":31.893,"p99":33.766,"max":34.137},"gpu_busy_ms_per_present":20.436,"worker_busy_pct":{"queue worker 0x0":99.070,"queue worker 0x40":99.446,"queue worker 0x48":95.266,"queue worker 0x3a":0.000,"queue worker 0x46":3.074},"top_phases_ms_per_frame":{"Driver.Packet":86.742,"Driver.Packet.memory_wait":53.453,"Driver.Packet.draw":18.090,"Driver.Draw":18.044,"Driver.Draw.draw_and_resource_release":10.021,"Graphics.Draw":9.904,"Driver.Packet.prepare_memory":8.460,"Graphics.Draw.draw_and_resource_release":7.876},"trace_dropped":false,"trace":"aps5-trace-f3d1e6bcd120-1566760.json.gz"} {"commit":"30f961266ade","dirty":null,"env":{"APS5_DUMP_FRAMES":"6000","APS5_INEXACT_SINGLE_LANE":"500597a00","APS5_LOOP_GUARD":"2000","APS5_PAD_PRESS":"120:Return,130:Return","APS5_TOLERATE_DISPATCH_FAILURES":"1","APS5_TRACE_DIR":"<path>","APS5_TRACE_SECONDS":"155:5","APS5_TWO_LANE":"500597a00"},"gpu":"NVIDIA GeForce RTX 4090","driver":"NVIDIA 610.57.04","os":"Linux 7.2.3-1-cachyos","resolution":"3840x2160","window":{"spec":"seconds 155:5","first_present":3566,"ms":5028.586},"presents":146,"frame_ms":{"p50":33.608,"p90":37.784,"p99":39.506,"max":45.511},"gpu_busy_ms_per_present":16.351,"worker_busy_pct":{"queue worker 0x0":99.127,"queue worker 0x40":99.434,"queue worker 0x48":95.830,"queue worker 0x3a":0.000,"queue worker 0x46":2.772},"top_phases_ms_per_frame":{"Driver.Packet":102.058,"Driver.Packet.memory_wait":63.552,"Driver.Packet.draw":23.518,"Driver.Draw":23.466,"Driver.Draw.draw_and_resource_release":14.447,"Graphics.Draw":14.323,"Graphics.Draw.draw_and_resource_release":11.988,"Driver.Packet.prepare_memory":7.490},"trace_dropped":false,"trace":"aps5-trace-30f961266ade-1633952.json.gz"} {"commit":"f3d1e6bcd120","dirty":null,"env":{"APS5_DUMP_FRAMES":"6000","APS5_INEXACT_SINGLE_LANE":"500597a00","APS5_LOOP_GUARD":"2000","APS5_PAD_PRESS":"120:Return,130:Return","APS5_TOLERATE_DISPATCH_FAILURES":"1","APS5_TRACE_DIR":"<path>","APS5_TRACE_SECONDS":"155:5","APS5_TWO_LANE":"500597a00"},"gpu":"NVIDIA GeForce RTX 4090","driver":"NVIDIA 610.57.04","os":"Linux 7.2.3-1-cachyos","resolution":"3840x2160","window":{"spec":"seconds 155:5","first_present":3725,"ms":5006.581},"presents":144,"frame_ms":{"p50":33.515,"p90":39.173,"p99":45.262,"max":148.414},"gpu_busy_ms_per_present":17.311,"worker_busy_pct":{"queue worker 0x0":99.069,"queue worker 0x40":99.452,"queue worker 0x48":94.956,"queue worker 0x3a":0.000,"queue worker 0x46":3.843},"top_phases_ms_per_frame":{"Driver.Packet":103.133,"Driver.Packet.memory_wait":62.849,"Driver.Packet.draw":23.668,"Driver.Draw":23.607,"Driver.Draw.draw_and_resource_release":12.346,"Graphics.Draw":12.210,"Driver.Packet.prepare_memory":10.135,"Graphics.Draw.draw_and_resource_release":9.609},"trace_dropped":false,"trace":"aps5-trace-f3d1e6bcd120-1993370.json.gz"}Not tested: Windows, AMD, a title that presents an 8-bit display in the other channel order on a device.
Checklist
main; no other open PR implements the same functionsNotImplemented_nid_no_patch); silent stubs are listed under Silent stubs in their library's technical debt file.mdfiles or images added to the repository (attach them to this PR)