Repository navigation
fix(agc): keep the guest's sample order where pixel (0,0)'s locations stand in for a 2x2 grid - #6683
Conversation
… stand in for a 2x2 grid Village's 2x checkerboard puts its two samples at x = +4/16 and -4/16 and swaps their indices on odd rows. On a device without a 2x2 sample location grid every pixel takes pixel (0,0)'s locations, so the odd rows hold the console's sample 1 in sample 0 and the reverse: a pass that reads the samples by index, as checkerboard reconstruction does, exchanges the two half-pixels of every odd row, and SampleID, sample masks and exported coverage name the wrong samples there. Such a pattern holds one set of positions in every pixel, so drawing with pixel (0,0)'s locations is exact up to the order of each pixel's samples. The draw now keeps the guest's order: the pixel shader reads SampleID, applies the sample mask and exports coverage through each pixel's order, and every render pass drawing with the stand-in puts the samples of its multisampled attachments in the stand-in's order before it and back in the guest's after it. Color targets do that through a storage view of their texels as unsigned integers, depth through a copy and a per-sample pass writing FragDepth, and stencil through VK_EXT_shader_stencil_export or one pass per bit. It needs shaderStorageImageMultisample with a storage view of the color format, sampleRateShading, and a depth format FragDepth writes back exactly (16-bit or 32-bit float); otherwise, and for patterns whose pixels hold different positions, the stand-in alone is used, and the log line says why. Devices with the grid are unchanged. Recompile requests carry the order as serialization version 32 (boykopovar#6470 takes 31), and the shader cache format becomes 40 (open pull requests take 37 and 39).
…t index The color swap (SampleOrder.comp) chose a pixel's order word with order.map[(at.x & 1u) | ((at.y & 1u) << 1u)], a push-constant vector indexed by a value that differs between the lanes of a wave, returned early for the pixels the order keeps, and gathered the held samples through a private array indexed per lane. On the AMD Windows driver (Radeon 0x1638, wave64) the 2x R8_UNORM round trip found sample 1 of pixel (0,0) in its sample 0, and the grid reference's exact path read sample index 1 in sample 0 of the same pixel, although the order keeps that pixel's samples. Only the invocation of pixel (0,0) stores to it, so that invocation ran the swap with another class's word. Each invocation now handles one 2x2 quad and takes every pixel class's word through a constant index, so the kept classes return uniformly, and picks the held samples through selects. The depth swap's fragment shader selects its word the same way. The planning test checks that no sample order shader indexes a vector or array through a value that varies between invocations, and a failed swap round trip counts its wrong samples per pixel class.
…round its reads On the 3070 the grid reference read the composite's and the 2x2 grid's depth at the standard 2x locations: sample 0 of pixel (14,0) held 0x3f00e5b5, the slope's depth at (14.75, 0.75), while the guest's sample 0 lies at (14.75, 0.5), whose depth 0x3f0153f8 the exact path held. All 3005 samples the slopes cover differed. The depth surface stays in the general layout for its life (DepthSurface.cpp, and the render passes in Pipeline.cpp and SampleOrder.cpp), so no layout transition ever names the sample locations it was drawn with, although the layout of an image created with SAMPLE_LOCATIONS_COMPATIBLE_DEPTH depends on them; the 3070 returned such depth at its standard locations when it was sampled or copied. The exact path's even rows came out right because its depth pass rewrites them at the stand-in's locations, but its odd rows came from vkCmdCopyImage, read at the standard locations and moved to the other sample; the 10 color mismatches, all in odd rows, are the shade triangle's depth test against those values. A pass that draws depth at custom sample locations now ends, after its samples are back in the guest's order, with a transition of the target to TRANSFER_SRC_OPTIMAL and back to the general layout that names the locations it drew with, and the depth swap copies its target between such transitions. The planning test checks both transition pairs, and that a swap without sample locations still copies in the general layout.
…x0 grid for a 2x2 one The 3070, whose vulkaninfo reports a maxSampleLocationGridSize of 1x1, ran the grid reference's native 2x2 render. vulkaninfo prints VkPhysicalDeviceSampleLocationsPropertiesEXT, the grid every supported sample count allows; the device setup reads each count's own VkMultisamplePropertiesEXT (VulkanDevice.cpp), which may be larger at low counts, and found an even grid at 2 samples there. The setup now logs each count's largest grid next to the one for every count and keeps it in the context, and the grid reference prints the one at 2 samples. The setup's test for a 2x2 grid also took a 0x0 grid, whose sides are even, for one. HostsSampleLocationGrid requires both sides to be nonzero and even, and the planning test checks it.
…ne reads back at the guest's locations The grid reference compared the exact path with a composite whose depth the 3070 had read at the standard 2x locations, so its 3005 depth mismatches said nothing about the exact path. It now places every sloped depth sample of each render from the slopes' plane equations: at the guest's sample location of its pixel and sample, or at the standard 2x location. When even the composite holds depth away from the guest's locations, the device reads depth drawn at custom sample locations back elsewhere despite the transitions that name them, no render can be compared with it bit for bit, and the test skips with the counts. A scene check that finds a wrong sample index now prints it, and where the device draws depth at custom sample locations the bench also times the swaps with the standard locations named at the depth copy's transitions.
The sample order planning test builds pipelines from graphics pipeline libraries on a mock device whose object count, handle counter and recorded sample masks are plain globals. With link-time optimization on, the Context default, each linked pipeline also queues an optimized link on the pipeline library worker thread. That link calls the mock's vkCreateGraphicsPipelines, and its vkDestroyPipeline when the pipeline was released first, while the test thread builds the next pipeline and destroys both. An increment or decrement of the object count can be lost, so the leak check fails now and then: on Windows, and on Linux in 8 of 20000 runs with eight runs at a time on four cores. No object is left alive: ClearPipelineLibraries waits for the worker before the check. Waiting with WaitForOptimizedPipelines after each pipeline does not close the overlap either, as the pipeline's constructor still destroys the shader modules a cached library part did not keep after it queues the link. The test now builds its library pipelines without the optimized link, as on a device without link-time optimization, so every mock call stays on the test thread.
|
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.
Some comparisons could not be completed because a pull request conflicts with the base branch. Review these shared files manually before concluding that there is no overlap.
|
…w recipe opens A pass that draws multisampled depth at custom sample locations ends with a transition to TRANSFER_SRC_OPTIMAL and back that names them, so the depth is not read back at other locations. The pass's end runs the work of the draw that opened it, and Draw sets the locations for it, but DrawWithRecipe built its RecordedDraw without them. Draw recipes are refused for multisampled color and for reordering pipelines, not for depth-only multisampled draws, so a recipe hit that opened a pass, on the native grid or with a uniform custom pattern, left its depth without the transition however many draws followed it. Draw and DrawWithRecipe now take the locations from passDepthLocations, on the recipe's pipeline for a replay. The recipe keeps its pipeline, whose key holds the custom locations, and Draw's caller passes the same depth target, so the helper sees what Draw saw for the recorded draw. The sample order tests' --recipe-depth-locations records a depth-only 2x draw with a uniform custom pattern and a recipe, reads every sample, clears the depth, replays the draw through DrawWithRecipe as the first draw of a new pass and reads again. It requires the replay to leave the recorded depth bit for bit, and skips without custom sample locations at 2 samples, or where even the recorded draw reads back away from the guest's locations.
…pth transitions and the sample mask throw The debt entry said the RTX 3070 Laptop GPU reports a 1x1 grid for every count. That is VkPhysicalDeviceSampleLocationsPropertiesEXT; the device setup reads each count's VkMultisamplePropertiesEXT, which gives an even grid at 2 samples, so the 3070 draws 2x patterns on its grid. The entry also gains the transition that ends a pass drawing depth at custom sample locations, and the throw for a draw with early depth or stencil tests whose pixel program writes memory when the order moves a partial sample mask into the pixel shader.
…y a moved sample mask throws The device setup logs each sample count's largest grid. On the RTX 3070 Laptop GPU (617.42) it is 2x4 at 2 samples, 2x2 at 4 and 1x2 at 8, while maxSampleLocationGridSize is 1x1 for every count; the AMD Radeon iGPU reports 2x2 both ways. So the 3070's 2x patterns take the native grid, and the stand-in plus the exact path serve its 8-sample patterns and devices without a grid. The throw for a uniform partial sample mask that the order moves stays. The order is fixed at decode, before compilation shows whether the pixel program writes memory, and falling back would lose exactness on draws the exact path gets right. The entry now says when the draw throws, what boykopovar#6451's stand-in did with it, and what a fix would take.
…y tests with memory writes The sample order checks validate the 2x checkerboard with a uniform mask of sample 0, early Z, a depth test and a pixel program that writes memory, on a device that reorders the checkerboard. The order moves the mask into the pixel shader, after the early tests, so the draw throws. The same draw validates when the pixel program writes no memory, and on a device with a 2x2 grid, where the mask stays static.
Brings boykopovar#5884's request field (output primitive size, read from serialization version 31). This branch's sample order stays at version 32, read after it, so a version-31 request reads as before.
jotitadev
left a comment
There was a problem hiding this comment.
A question about passes that share a depth target but take different paths, with a mock check, and a Linux run of the tests.
Machine: Linux, NVIDIA GeForce RTX 3070 (driver 595.99.02) and lavapipe (Mesa 26.0.3, LLVM 21.1.8). Ubuntu 26.04, i7-8700, GCC 15.2, Release. Head 418d5abb8 merged into main 66e290f1c (clean).
^agc_driver_sample_,agc_driver_graphics,request_serializer,agc_shader_memory(12 tests): pass 3/3 on the RTX 3070 and on lavapipe.agc_driver_sample_order_grid_referenceandagc_driver_sample_order_recipe_depth_locationsskip on both. On the RTX 3070 under Linux the recipe test gives the same counts as your Windows laptop:1 hold the slope's depth at the guest's sample locations and 3004 at the standard 2x locations, and the device logs2 samples 2x4, 4 samples 2x2, 8 samples 1x2.
Mixed passes on one depth target. SampleOrderRefusal is decided per render pass state, and nothing records which order a surface's samples are in between passes. On a device without shaderStorageImageMultisample (MoltenVK on Apple GPUs reports it as false, with a 1x1 grid at 2 and 4 samples), a depth-only pass and a colour+depth pass on the same target take different paths. A temporary print in agc_driver_sample_order_planning, using the test's village pattern and its noStorage context:
noStorage depth-only: grid 1x1 reorders=1 refusal='' steps=1
depth-only step attachment=0 method=1 toHost=1 toGuest=1
noStorage color+depth: grid 1x1 reorders=0 refusal='color format 97 has no storage view at 2 samples' steps=0
So a depth prepass stores the target in the guest's order (toGuest), and the colour pass that follows tests against it with no swap, in the stand-in's order. On odd rows each sample is then compared with the depth written at the other half-pixel's position. With #6451 alone both passes kept the stand-in's order and agreed. If that is intended, a note in the debt entry would help; otherwise refusing the whole surface once one pass is refused, or keeping the order per surface, would avoid it. I have not drawn this case on a GPU: the RTX 3070 and lavapipe both have multisampled storage images, so neither takes the refused path.
GPUs tested: NVIDIA GeForce RTX 3070 (595.99.02), lavapipe (Mesa 26.0.3, LLVM 21.1.8), Ubuntu 26.04
Written with AI assistance (Claude Code). I ran the builds and tests above on my machine.
…ampled storage images On such a device a pass with a multisampled color target is refused, because the color samples have no storage view to be reordered through, while a depth-only pass was still reordered. A depth target drawn by both then held its samples in the guest's order after the depth-only pass and was tested in the stand-in's order by the color pass, so on odd rows each sample met the depth of the other half-pixel's position. With boykopovar#6451 alone both passes kept the stand-in's order. Such a device now refuses the exact order for every pass, so each of its depth targets keeps one order. On a device with multisampled storage images, a color format without a storage view at its sample count still refuses only its own passes, which the debt entry now says.
|
@jotitadev thank you for the review, the Linux runs on the RTX 3070 and lavapipe, and the mock check. You're right: the refusal is decided per pass, and on a device without 583cca0 makes such a device refuse the exact order for every pass, depth-only passes included, so its depth targets keep the stand-in's order throughout, as with #6451 alone. A device that has multisampled storage images can still refuse a single colour format without a storage view at its sample count. A depth target shared by such a pass and a depth-only pass would then change order between them. The debt entry now says so; a full fix would decide the order per target rather than per pass, which also touches the shader's sample remap, so I've left it for a follow-up. |
…ple-location-grid-exact Takes boykopovar#6451's merge of main. Main's spanned-waves flag took request serialization version 32, so the sample order moves to version 33; a version 32 request keeps its spanned-waves flag and reads no sample order. Multisampled color targets now gain storage usage on their first storage binding; a target whose samples may be reordered still gets it at creation, and the recorder's storage-usage checks expect that.
…d exports in host order A per-sample shader under a non-uniform quad sample mask keeps only the invocations whose guest sample the mask names, since gl_SampleMaskIn is reordered before it gates them. The depth export is reordered back, so a depth probe at the mask's host samples runs exactly the guests the mask kept.
boykopovar#6503 took request serialization 36 for its float32 flush flag, so this branch's sample order moves to 37. The version relabels in ShaderMemory.cpp and RequestSerializerTests.cpp drop both trailing flags and the sample order.
main 7ce3b1d took disk-cache format 43 (boykopovar#8295) for its own layout, so this branch's format moves to 44. The request serializer stays at 42: main still writes 41.
|
@oneandonlydean, thanks. All three points are in, and the branch merges current
The three answers in my earlier comment now have a test each (9b7f8cd, 44e8786, ef6ec1e), and each fails with its fix line reverted:
On GitHub's runners (run) they and the sample-order, serializer and shader cache tests pass 5 runs in a row on Linux. On Windows the serializer and shader cache tests pass, and the GPU tests skip without a Vulkan device. At the merge before it (6d09797, |
|
@EagleBearerYS thanks, checked on |
|
@EagleBearerYS a heads-up after the merge. On an RTX 4070 Ti with the 595.99.02 Linux driver, The tests read the depth surface by binding its own view as a sampled image. A multisampled depth surface sampled through #7318's shadow image has no #9056 makes the tests read the same kind of copy, and then all 4 pass here. #9057 fixes a separate AI-assisted: yes (Claude Code) |
|
@milescoviello, thank you for running these on the RTX 4070 Ti, and for both fixes. Both are right, and both fix code #6683 added:
I've left a review comment on each. |
|
@EagleBearerYS @milescoviello: an AMD data point for Setup: Windows 11 Pro 26200, AMD Radeon 680M (RDNA 2 iGPU; Failure: in The Narrowed down with local early returns in
So it's the AI-assisted: yes |
|
@DavidSamir, thank you for the Radeon 680M data point and for bisecting it down to the |
|
Thanks @EagleBearerYS and @DavidSamir. If a fix for the 680M device loss comes out of this, I can run it on the RTX 4070 Ti under the layer, with #9056 and #9057, to check it changes nothing there. AI-assisted: yes (Claude Code) |
|
@DavidSamir, we've checked what we can here. We haven't found the cause of the Radeon 680M device loss, and there's a branch to try. What we checked (lavapipe, Mesa 25.2.8, validation layers 1.3.275):
The branch:
Could you run both trees and post the six logs? Use CONFIGURE="-G Ninja -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=ON -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache"
git clone https://github.com/boykopovar/AnyPS5 anyps5-main
cd anyps5-main && git checkout d099bc6cd8 && git submodule update --init --recursive
cmake -S . -B build $CONFIGURE -DANYPS5_AGC_EXECUTION_TESTS=SampleOrder
cmake --build build --target agc_driver_sample_order_tests agc_driver_graphics_tests
cd ..
git clone https://github.com/EagleBearerYS/AnyPS5 anyps5-branch
cd anyps5-branch && git checkout fix/agc-sample-order-copy-sampled-only && git submodule update --init --recursive
cmake -S . -B build $CONFIGURE -DANYPS5_AGC_EXECUTION_TESTS=SampleOrder
cmake --build build --target agc_driver_sample_order_tests agc_driver_graphics_tests
cd ..Two layer settings files. and Then, in each tree: ctest --test-dir build -R '^agc_driver_sample_order' -V > sample-order-plain.log 2>&1
export VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation
VK_LAYER_SETTINGS_PATH=C:/anyps5-vvl/sync/vk_layer_settings.txt ctest --test-dir build -R '^agc_driver_sample_order' -V > sample-order-sync.log 2>&1
VK_LAYER_SETTINGS_PATH=C:/anyps5-vvl/gpuav/vk_layer_settings.txt ctest --test-dir build -R '^agc_driver_sample_order' -V > sample-order-gpuav.log 2>&1
unset VK_INSTANCE_LAYERS
grep -c "was not found but was requested by env var VK_INSTANCE_LAYERS" sample-order-*.logThat last line prints one count per log; if any of them isn't 0, the layer didn't load. A device loss shows as @milescoviello, thanks for the offer. Could you run the branch on the RTX 4070 Ti under the layer, with #9056 on top, to check that it changes nothing there? It already carries #9057's change, and merging #9057 into it would conflict on that line. |
What
#6451 lets a draw whose MSAA sample locations vary between the pixels of the guest's 2x2 pattern run on a device without a 2x2 sample location grid: it draws pixel (0,0)'s locations in every pixel. Resident Evil Village's (PPSA01556) 2x checkerboard holds the same two positions in every pixel (x = +4/16 and -4/16) and swaps them on odd rows. So the stand-in draws every position exactly, and only the samples' order differs on odd rows. A pass that reads samples by index, as checkerboard reconstruction does, then exchanged the two half-pixels of those rows.
This keeps the guest's sample order where the stand-in holds the same set of positions:
SampleID, applies sample masks and exports coverage through each pixel's order.FragDepthpass;VK_EXT_shader_stencil_export, or one pass per bit.shaderStorageImageMultisample(with a storage view of the colour format),sampleRateShading, or a depth formatFragDepthwrites back exactly, and for patterns whose pixels hold different positions.VkSampleLocationsInfoEXT):VK_EXT_sample_locations leaves such depth undefined after a transition that omits them. The RTX 3070 then read it back at the standard 2x locations, which put odd rows' depth on the other sample.
uvec4and swapped pixel (0,0), whose order is kept. A planning check now refuses any sample-order shader that indexes a vector or array through a non-constant value.vkGetPhysicalDeviceMultisamplePropertiesEXT) and no longer takes a 0x0 grid for a 2x2 one.mainwrites 41): this PR's sample order is written aftermain's stencil operation value export flag and read atversion >= 42. Shader cacheFormatVersion44 (mainis at 43 since fix(shader): skip unreachable flat SRT loads under a known branch #8295). feat(shader): resolve nested image tables through runtime pointers #7223 and feat(shader): read samplers through nested and pointer-keyed descriptor tables #7395 (ours) move the format too, so whichever of them lands later takes the next free number.mainnow gives a multisampled colour target storage usage only at its first storage binding. On a device where this PR may reorder its samples, the target still gets storage usage and a mutable format when it is made, as before, and feat(agc): write a multisampled color target through a storage image #5881's recorder checks expect that there. Moving the swap's storage usage to its first reorder too is a possible follow-up; it needs the target swapped before the draw's framebuffer takes its view.SampleID.EmitSampleOffsetreadsSampleIdthroughEmitBuiltinU32, which returnsGuestSampleIndex, so host sample i reads guest sample order(i)'s location.#6451 is merged, and this branch merges current
main. The change is its six commits after #6451's, a review follow-up (a932bcc) and three review test commits (9b7f8cd, 44e8786, ef6ec1e).Cost
Two passes over each multisampled attachment per render pass that draws with the stand-in. On the RTX 3070 at 1920x2160, 2x, the median of 100 frames is 2.142 ms of GPU time per frame with one depth-only and one colour+depth pass swapped in and out; naming the sample locations at the depth copy's transitions makes it 2.132 ms.
Tested
Resident Evil Village (PPSA01556), Windows 11, RTX 3070 Laptop GPU (driver 617.42):
[gpu] driver failure: AGC graphics: sample locations varying between pixels require a 2x2 sample location grid for the draw's sample count.Windows 11, RTX 3070 Laptop GPU and AMD Radeon (integrated), Vulkan:
agc_driver_sample_orderfailed with "the 2x color format 9 put in the host's order: sample 0 of pixel (0, 0) holds 0x000000b1 0x00000000, expected 0x00000000 0x00000000 (sample 0)". 0xb1 is sample 1's fill. The grid reference failed with "the exact path: sample 0 of pixel (0, 0) does not hold its own sample index in color";agc_driver_sample_orderpasses (39 swap round trips, 6 shader remap checks, 3 scene checks) and the exact path holds the guest's depth at the guest's sample locations in 3005 of 3005 sloped samples. The composite reference reads its depth back at the standard locations on this device too (0 of 3005), so the bit-for-bit comparison skips with the counts.--repeat until-fail:5:agc_driver_sample_orderandagc_driver_sample_location_grid_fallbackpass every run;agc_driver_sample_order_planningpasses every run on the AMD iGPU. On the RTX 3070 machine it failed once in its first three runs with "sample order pipeline tests leaked Vulkan objects": nothing leaked, but each linked pipeline queued an optimized link on the pipeline-library worker, whose calls into the test's mock counters raced with the test thread's. The last commit turns link-time optimization off in that test (ThreadSanitizer on Linux: races in 11 of 11 runs before, none in 20 after; under load 13 of 40,000 runs failed before, none of 60,000 after). GitHub's Windows runner passes it 200 runs in a row.maxSampleLocationGridSize1x1 for every count); AMD Radeon, 2x2 at every count. With the per-count grid read, the RTX 3070 hosts a real grid at 2 samples, so Resident Evil Village draws its checkerboard there natively and does not take the stand-in; the stand-in and this PR's exact path serve devices without one.Linux, lavapipe (Mesa 25.2.8), CI's Linux configure:
agc_driver_sample_order_planning(mocks): orders and refusals on capable, gridded and refusing devices; plans per attachment and load/store op; render-pass and library pipelines; the cache key and serializer round trip.agc_driver_sample_order:SampleIDand exported coverage reach the guest's samples;agc_driver_sample_order_grid_referenceskips on lavapipe, which has no 2x colour and depth targets.agc_driver_sample_order_recipe_depth_locations(GPU) checks that a depth-only pass opened by a recipe hit still names its locations; a mock test pins the sample-mask throw and its message; the debt entry gives the per-count grids and the throw. On GitHub's runners (run) the sample-order tests andagc_driver_graphicspass 10 runs in a row on Linux, and the GPU tests skip on both runners. On the RTX 3070 and the AMD iGPU here the recipe test skipped, with the change and without it: both devices read depth drawn at custom sample locations back at the standard 2x locations even in a recorded draw with the named transitions ("of 3005 sloped depth samples, 1 hold the slope's depth at the guest's sample locations and 3004 at the standard 2x locations"), although the depth images carryVK_IMAGE_CREATE_SAMPLE_LOCATIONS_COMPATIBLE_DEPTH_BIT_EXT. So no device we have can show this change's before and after; it follows VK_EXT_sample_locations, which leaves such depth undefined after a transition that omits the locations. The other sample-order tests pass on the RTX 3070 at this head.agc_driver_sample_order_recipe_depth_locationscompares the recipe's replay with the recorded draw bit for bit instead of skipping.!pipeline->ReordersSamples()inDraw.cpp), so the test checks that the checkerboard through the exact path builds no recipe, and that pixel (0,0)'s locations, through the device's grid and without one, build a recipe whose replay matches the recorded draw.SampleIdreturning the host index instead ofGuestSampleIndex:agc_driver_pixel_sample_iterationfails with "2x: an iterated PERSP_SAMPLE on a reordered pattern varying across the 2x2 grid: the table index's low bits are not the order word's nibble at the shader's SampleId";|| pixel->ReordersSamples():agc_driver_pixel_sample_iterationfails with "2x: a pixel shader that only reorders its samples was not given the position input";ReorderedSampleBits:agc_driver_sample_orderfails with "4x a quad sample mask reached the pixel shader in the guest's order: guest sample 0 of pixel (3, 0) ran, expected guest mask 2".agc_driver_sample_order_grid_referenceskips with "skipped, the device does not keep depth drawn at custom sample locations …", whichtools/check_skips.py'sDEVICE_LIMITATIONaccepts.main7ce3b1d (8c9c8eb, the head; 6d09797 before it mergedmain1ff5c8a), on GitHub's runners (run):agc_driver_pixel_sample_iteration,agc_driver_graphics,agc_shader_memory,request_serializer,agc_shader_replay_requestsandagc_shader_disk_cache. On Windows, 67 of the 116 skip without Vulkan, the GPU tests among them, and the rest pass.guest_raise_in_system_call. This PR doesn't reach it, and it timed out on an unrelated branch the same night (run).^(agc|shader)tests pass: 859 tests, 0 failed, 59 skipped.ctest -R '^agc':agc_driver_preparation_scope_settle, a load flake that also fails onmainunder the same parallel load; alone it passes 20 of 20;main03c4cb5, 609 of 610 withrequest_serializer. The one failure is fix(agc): validate mesh index descriptors on cached draws #5791'sagc_driver_mesh_index_cache, which crashes llvmpipe's LLVM onmaintoo.mainf474fb7 (through fix(agc): fall back to pixel (0,0)'s sample locations where the device has no 2x2 grid #6451's merge), on GitHub's runners (run): the sample-order tests,request_serializer,agc_shader_memory,agc_driver_graphicsand feat(agc): write a multisampled color target through a storage image #5881's multisample tests pass 3 of 3 on Linux (64 tests) and Windows (67, of which 45 skip without Vulkan). The run shows as failed only because its Windows job listsguest_kqueue, a failure that runner has onmaintoo, without amaincomparison.main9b68377 (71de590, the head, with feat(agc,videoout): show an optional performance overlay with F10 #6012's overlay shaders), on GitHub's runners (run): the^agctests pass on Linux (717, 0 failed, 51 skipped), and the suites' only failure is libc'sprecise_waittiming test. On Windows, where 539 of the 717 skip without Vulkan, the only failures areagc_driver_pm4_replay_toolandagc_shader_replay_tool(exit code 0xc0000139), which fail the same way on that runner for an unrelated branch (run).--repeat until-fail:10.agc_driver_sample_order_planningfails on Linux and Windows with "a depth-only pass on a device without multisampled storage images was reordered"; with it, it passes 5 of 5 on both.maininto, merged ontomain12a71f3 (review): the 12 sample-order, sample-mask, serializer andagc_driver_graphicstests pass 3/3 on both, andagc_driver_sample_order_grid_referenceandagc_driver_sample_order_recipe_depth_locationsskip on both. With only 583cca0's new line inSampleOrderRefusalremoved,agc_driver_graphicsfails witha depth-only pass on a device without multisampled storage images was reordered.Checklist
main7ce3b1d, merged in (fix(agc): fall back to pixel (0,0)'s sample locations where the device has no 2x2 grid #6451 is merged). Overlaps, checked withgit merge-treeagainstmain5d9dcc4, each an adjacent edit where both sides are kept:Recompiler.hpp,ShaderStageInputInfo.hpp,DrawLookup.cpp,DrawRegisterKey.cpp), their serialization and tests, and SPIR-V helpers inSpirvModuleEmitter.cpp. See "With fix(recompiler): run a pixel shader the guest does not iterate once per pixel #6470" above.FormatVersionline inShaderDiskCache.hpp: perf(shader): select the record of a T# whose offset the CPU evaluates #6243, fix(agc): keep texture images inside their extent's mip chain #6280, fix(recompiler): defer the TYPE check of a guarded read-only static V# #6412, perf(agc): share one image table per heap and write epoch through capture, compare, resolution and descriptors #6454, perf(agc): stage raw buffer elements a dispatch sweeps #6486, feat(recompiler): run waterfall loops over per-lane T#s through image tables #6488 and feat(recompiler): add an uncached compile entry point and entry key helpers for offline tools #6296/feat(tools): add an offline shader archive tool that publishes prebuilt packs #6032 (offline shader tools). The version takes the next free number.DrawRegisterKey.cpp: feat(agc): draw radeonsi line and polygon smoothing (SAMPLE_COVERAGE, merged mixed samples) #6530 (line and polygon smoothing through SAMPLE_COVERAGE) adds to the same pixel-request comparison. Where both apply, coverage this PR maps through the pixel's sample order would include feat(agc): draw radeonsi line and polygon smoothing (SAMPLE_COVERAGE, merged mixed samples) #6530's.MultisampleTargetandDraw.cppnext to the swap's hooks, as does perf(agc): reuse address-based draw builds whose inputs are unchanged #6636 (ours, reused address-based draw builds) inDraw.cpp.Pipeline.hpp/.cpp.VulkanDevice.cpp,Pipeline.cppand the debt entry, and fix(agc): rasterize a single-sample scan into a multisampled depth target at the pixel center #5915 and fix(agc): compare a CB resolve's sample count with the rasterizer onl… #6571 (CB resolve sample counts) in the same debt entry. feat(agc): rasterize a multisampled draw into one-sample targets at sample 0's locations #5907 keeps the one-sample case this PR leaves to it.CMakeLists.txt: fix(agc): import guest memory through dma-buf before host pointer when host imports lose write tracking #2434, and feat(agc,videoout): show an optional performance overlay with F10 #6012 (merged): this branch's merge ofmain9b68377 (71de590) keeps feat(agc,videoout): show an optional performance overlay with F10 #6012's overlay shader loop after this PR's sample-order loop.NotImplemented_nid_no_patch); silent stubs are listed under Silent stubs in their library's technical debt file (none added).mdfiles or images added to the repository (attach them to this PR)