Skip to content

fix(agc): keep the guest's sample order where pixel (0,0)'s locations stand in for a 2x2 grid - #6683

Merged
oneandonlydean merged 39 commits into
boykopovar:mainfrom
EagleBearerYS:fix/agc-sample-location-grid-exact
Oct 21, 2026
Merged

oneandonlydean merged 39 commits into
boykopovar:mainfrom
EagleBearerYS:fix/agc-sample-location-grid-exact

Conversation

@EagleBearerYS

@EagleBearerYS EagleBearerYS commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

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:

  • In the shader: the pixel shader reads SampleID, applies sample masks and exports coverage through each pixel's order.
  • Around each render pass that draws with the stand-in: the pass puts its multisampled attachments' samples in the stand-in's order before it and back after it:
    • colour through a uint storage view;
    • depth through a copy and a per-sample FragDepth pass;
    • stencil through VK_EXT_shader_stencil_export, or one pass per bit.
  • The stand-in alone, with a log line saying why, when the device lacks shaderStorageImageMultisample (with a storage view of the colour format), sampleRateShading, or a depth format FragDepth writes back exactly, and for patterns whose pixels hold different positions.
  • A sample mask the order moves is applied in the shader. With early Z, a depth or stencil test and memory writes in the pixel program, that draw throws, where fix(agc): fall back to pixel (0,0)'s sample locations where the device has no 2x2 grid #6451's stand-in alone ran it with odd rows' sample indices swapped. The order is fixed when the draw is decoded, but whether the program writes memory is known only after it is compiled, so a fallback would have to choose the stand-in then. No title is known to hit it.
  • Depth drawn at custom sample locations is moved between layouts only by transitions that name those locations (VkSampleLocationsInfoEXT):
    • the swap's depth copy, between GENERAL and TRANSFER_SRC_OPTIMAL;
    • and, at the end of every draw pass with custom locations and depth, a transition pair naming the pipeline's own locations, including a pass a draw recipe opens: replays name the locations too (212c35f).
      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.
  • The colour swap shader picks each pixel class's order word through constant indices, one invocation per 2x2 quad. AMD's driver miscompiled the per-lane index into the push-constant uvec4 and 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.
  • Device setup logs each sample count's largest location grid (vkGetPhysicalDeviceMultisamplePropertiesEXT) and no longer takes a 0x0 grid for a 2x2 one.
  • Devices without multisampled storage images (583cca0, from jotitadev's review) take the stand-in alone for every pass, depth-only passes included, as fix(agc): fall back to pixel (0,0)'s sample locations where the device has no 2x2 grid #6451 alone does. Every pass with a multisampled colour target is refused there, so a depth-only pass that reordered would leave a shared depth target in a different order from the colour passes that test against it. On a device that has them, a colour format without a storage view at its sample count still refuses only its own passes; the debt entry says so.
  • Unchanged: devices with a 2x2 grid. One-sample targets under a varying pattern stay approximate (feat(agc): rasterize a multisampled draw into one-sample targets at sample 0's locations #5907's path).
  • Versions: request serialization 42 (main writes 41): this PR's sample order is written after main's stencil operation value export flag and read at version >= 42. Shader cache FormatVersion 44 (main is 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.
  • With feat(agc): write a multisampled color target through a storage image #5881 (merged): main now 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.
  • With fix(recompiler): run a pixel shader the guest does not iterate once per pixel #6470:

#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):

Windows 11, RTX 3070 Laptop GPU and AMD Radeon (integrated), Vulkan:

  • 3070, Resident Evil Village's 2x checkerboard against the reference (four uniform renders composed by pixel parity), every sample of colour and depth:
    • at the first commit (57ceb9e): "the exact path differs from the reference in 10 color and 3005 depth samples". All 3005 are the sloped depth samples, read back at the standard 2x locations;
    • with the commits after it, the depth this device reads back cannot be placed at the guest's locations for any render: even the composite of four uniform renders holds the guest's depth in 0 of 3005 sloped samples (all 3005 at the standard 2x locations), the device's own grid likewise, and the exact path in 1499, all of them on even rows (see the review commits below). The test reports those counts and skips, since no render can serve as a bit-for-bit reference here.
  • AMD Radeon (integrated):
    • at the first commit: agc_driver_sample_order failed 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";
    • with the commits after it, agc_driver_sample_order passes (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.
  • Both GPUs, --repeat until-fail:5: agc_driver_sample_order and agc_driver_sample_location_grid_fallback pass every run; agc_driver_sample_order_planning passes 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.
  • The devices' grids (logged by the third commit): RTX 3070, 2 samples 2x4, 4 samples 2x2, 8 samples 1x2 (maxSampleLocationGridSize 1x1 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:
    • every colour format through every alias size, and every depth/stencil method, round-trips bit for bit through both directions at each sample count;
    • SampleID and exported coverage reach the guest's samples;
    • the reference scene draws and reads back through the driver.
  • Red runs, each a temporary sabotage, reverted:
    • "putting the samples back in the guest's order did not restore every sample bit for bit";
    • "guest sample 0 of pixel (5, 0) ran, expected guest mask 10";
    • "guest sample 0 of pixel (1, 0) did not run, expected guest mask 1";
    • the swap shaders before the constant-index change: "sample order shader 0 picks a pixel's order word or a held sample through an access chain into %23 through the non-constant index %52";
    • the depth copy without the named transitions: "the depth swap did not copy its target between transitions that name the stand-in sample locations it was rendered with".
  • The grid reference now classifies every sloped depth sample of each render by the slope's plane equation: at the guest's location, or at the standard 2x location. If even the composite is not read back at the guest's locations, it skips with the counts, because then no render can be compared with it bit for bit.
  • agc_driver_sample_order_grid_reference skips on lavapipe, which has no 2x colour and depth targets.
  • The review follow-ups (212c35f, c3f947e, ee406d6, 3d2d8e5), from an after-the-fact completeness review: 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 and agc_driver_graphics pass 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 carry VK_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.
  • oneandonlydean's review on an RTX 4090 (comment) brought four test commits:
    • f90ffa8 splits each render's guest-location counts by even and odd rows. On the RTX 3070 the exact path's 1499 are all 1,499 even-row samples. None of the 1,506 odd-row ones, the pixels whose sample order changes and which the swap rewrites, match the guest's locations or the standard 2x ones. The AMD iGPU holds 1,499 of 1,499 and 1,506 of 1,506.
    • 0700f72: where the recorded draw's depth doesn't read back at the guest's locations, agc_driver_sample_order_recipe_depth_locations compares the recipe's replay with the recorded draw bit for bit instead of skipping.
    • aaffe03: a draw builds a recipe only when its pipeline doesn't reorder samples (!pipeline->ReordersSamples() in Draw.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.
    • 7f03326: the grid reference compares the device grid's depth with the composite only where the grid reads it back at the guest's locations, and otherwise compares its color alone.
    • At 7f03326, on the RTX 3070 and the AMD iGPU, the recipe test passes 3 of 3 (0 of 4,096 differences in each replay, and no recipe through the exact path). The grid reference skips on both, as before: the composite holds the guest's depth in 0 of 3,005 sloped samples. On GitHub's runners the sample-order tests and those tied to the changed files pass on Linux (68, 4 skipped) and Windows (71, 46 skipped) (run).
  • Tests for the three answers in this comment (9b7f8cd, 44e8786, ef6ec1e), Linux, CI's configuration. Each fails with its fix line reverted:
    • the location table's index, with SampleId returning the host index instead of GuestSampleIndex: agc_driver_pixel_sample_iteration fails 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";
    • the position input, without || pixel->ReordersSamples(): agc_driver_pixel_sample_iteration fails with "2x: a pixel shader that only reorders its samples was not given the position input";
    • the coverage order, without the input's ReorderedSampleBits: agc_driver_sample_order fails 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".
  • oneandonlydean's three small points (comment) are in a932bcc and the merges after it:
  • Merged with main 7ce3b1d (8c9c8eb, the head; 6d09797 before it merged main 1ff5c8a), on GitHub's runners (run):
    • These tests and the tests tied to the changed files pass 5 runs in a row on Linux (105 tests, 8 skipped): the sample-order tests, agc_driver_pixel_sample_iteration, agc_driver_graphics, agc_shader_memory, request_serializer, agc_shader_replay_requests and agc_shader_disk_cache. On Windows, 67 of the 116 skip without Vulkan, the GPU tests among them, and the rest pass.
    • The Windows libkernel suite timed out once, in guest_raise_in_system_call. This PR doesn't reach it, and it timed out on an unrelated branch the same night (run).
    • At 6d09797, on a cloud worker, the ^(agc|shader) tests pass: 859 tests, 0 failed, 59 skipped.
  • ctest -R '^agc':
    • at the head, 605 of 605 (42 skipped as expected); at e6068b7, 604 of 605. The one failure is agc_driver_preparation_scope_settle, a load flake that also fails on main under the same parallel load; alone it passes 20 of 20;
    • at the first commit, 605 of 605;
    • merged with main 03c4cb5, 609 of 610 with request_serializer. The one failure is fix(agc): validate mesh index descriptors on cached draws #5791's agc_driver_mesh_index_cache, which crashes llvmpipe's LLVM on main too.
  • Merged with main f474fb7 (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_graphics and 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 lists guest_kqueue, a failure that runner has on main too, without a main comparison.
  • Merged with main 9b68377 (71de590, the head, with feat(agc,videoout): show an optional performance overlay with F10 #6012's overlay shaders), on GitHub's runners (run): the ^agc tests pass on Linux (717, 0 failed, 51 skipped), and the suites' only failure is libc's precise_wait timing test. On Windows, where 539 of the 717 skip without Vulkan, the only failures are agc_driver_pm4_replay_tool and agc_shader_replay_tool (exit code 0xc0000139), which fail the same way on that runner for an unrelated branch (run).
  • Repeats: the new tests pass --repeat until-fail:10.
  • 583cca0 (devices without multisampled storage images), on GitHub's runners (run): without the change, agc_driver_sample_order_planning fails 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.
  • NVIDIA GeForce RTX 3070 (driver 595.99.02) and lavapipe (Mesa 26.0.3), Ubuntu 26.04 (GCC 15.2, Release), run by jotitadev at 3d42f60, which the current head only merges main into, merged onto main 12a71f3 (review): the 12 sample-order, sample-mask, serializer and agc_driver_graphics tests pass 3/3 on both, and agc_driver_sample_order_grid_reference and agc_driver_sample_order_recipe_depth_locations skip on both. With only 583cca0's new line in SampleOrderRefusal removed, agc_driver_graphics fails with a depth-only pass on a device without multisampled storage images was reordered.

Checklist

… 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.
@github-actions

github-actions Bot commented Oct 16, 2026 •

Copy link
Copy Markdown

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.

Pull request Conflicting files (lines on main) Same exports Same new files
PR 6628 core/libs/prx/libSceAgcDriver/Graphics/include/MultisampleTarget.hpp L5
PR 6639 core/shader/recompiler/tests/RequestSerializerTests.cpp L217, L257, L283, L413, L432, L455, L462
PR 6741 core/libs/prx/libSceAgcDriver/CMakeLists.txt L2909, L2913
PR 6801 core/shader/recompiler/tests/RequestSerializerTests.cpp L217, L257, L283, L413, L432, L455, L462
PR 6858 core/shader/recompiler/ShaderDiskCache.hpp L16
PR 6959 core/shader/recompiler/SpirvBackend/src/SpirvModuleEmitter.cpp L206-207
PR 6973 core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp L66
core/libs/prx/libSceAgcDriver/Graphics/src/MultisampleTarget.cpp L101, L287, L313, L465-466
PR 6987 core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp L66
core/libs/prx/libSceAgcDriver/Graphics/src/MultisampleTarget.cpp L101, L155-157, L287, L313, L465-466
PR 6989 core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp L66
core/libs/prx/libSceAgcDriver/Graphics/src/MultisampleTarget.cpp L101, L155-157, L287, L313, L465-466
PR 6995 core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp L66
core/libs/prx/libSceAgcDriver/Graphics/src/MultisampleTarget.cpp L101, L155-157, L287, L313, L465-466
PR 7002 core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp L66
core/libs/prx/libSceAgcDriver/Graphics/src/MultisampleTarget.cpp L101, L155-157, L287, L313, L465-466
PR 7659 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp L10479
PR 7803 core/libs/prx/libSceAgcDriver/CMakeLists.txt L174
PR 7888 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp L4852, L4970, L5126-5127, L5146-5147, L5149-5150, L5161-5162, L5170-5171, L5179-5180
core/shader/recompiler/tests/RequestSerializerTests.cpp L217, L257, L283, L413, L432, L455, L462
PR 8004 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp L4852, L4970, L5126-5127, L5146-5147, L5150, L5161-5162, L5170-5171, L5179-5180
core/shader/recompiler/tests/RequestSerializerTests.cpp L217, L257, L283, L413, L432, L455-456, L462
PR 8115 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Draw/DrawRegisterKey.cpp L265-266
docs/dev/debt/libSceAgcDriver.md L157-158
PR 8604 core/libs/prx/libSceAgcDriver/tests/execution/MultisampleRetirement.cpp L489-490
PR 8612 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp L4852, L4970, L5126-5127, L5146-5147, L5149-5150, L5161-5162, L5170-5171, L5179-5180
core/shader/recompiler/tests/RequestSerializerTests.cpp L217, L257, L283, L413, L432, L455, L462
PR 8658 core/shader/recompiler/CacheKey.hpp L219
PR 8847 core/libs/prx/libSceAgcDriver/Graphics/src/MultisampleTarget.cpp L466
core/libs/prx/libSceAgcDriver/tests/execution/MultisampleRetirement.cpp L489-490
PR 8992 core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp L2481
PR 9020 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Draw/DrawRegisterKey.cpp L265-266
core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp L4852, L4970, L5110-5111, L5147-5148
core/shader/recompiler/CacheKey.hpp L219
core/shader/recompiler/ControlFlow/src/RequestSerializer.cpp L357, L425, L830, L870
core/shader/recompiler/Optimization/include/Optimization/ShaderStageInputInfo.hpp L197
core/shader/recompiler/Recompiler.hpp L192
core/shader/recompiler/Translation/src/ShaderInputInfoBuilder.cpp L169
core/shader/recompiler/tests/RequestSerializerTests.cpp L57, L217, L257, L283, L413, L432, L455, L462, L507-508

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.

Pull request Shared files not compared
PR 1191 core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/State.cpp
PR 1368 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/include/DepthSurface.hpp
core/libs/prx/libSceAgcDriver/Graphics/include/State.hpp
core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/DepthSurface.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 1395 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Execution/include/VulkanDevice.hpp
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/DepthSurface.hpp
core/libs/prx/libSceAgcDriver/Graphics/include/State.hpp
core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/DepthSurface.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/State.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 2434 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Execution/include/VulkanDevice.hpp
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
docs/dev/debt/libSceAgcDriver.md
PR 4040 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 4072 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/Context.hpp
core/libs/prx/libSceAgcDriver/Graphics/include/Pipeline.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
PR 4448 core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
docs/dev/debt/libSceAgcDriver.md
PR 4449 docs/dev/debt/libSceAgcDriver.md
PR 4472 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/Context.hpp
PR 5021 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
core/shader/recompiler/SpirvBackend/include/SpirvBackend/SpirvEmitterState.hpp
PR 5058 docs/dev/debt/libSceAgcDriver.md
PR 5371 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
PR 5372 docs/dev/debt/libSceAgcDriver.md
PR 5431 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Execution/include/VulkanDevice.hpp
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
PR 5441 core/libs/prx/libSceAgcDriver/Execution/include/VulkanDevice.hpp
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 5499 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Execution/include/VulkanDevice.hpp
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/DepthSurface.hpp
core/libs/prx/libSceAgcDriver/Graphics/include/State.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/DepthSurface.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/State.cpp
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 5609 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Draw/DrawLookup.cpp
core/libs/prx/libSceAgcDriver/Execution/src/Driver/Draw/DrawRegisterKey.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/Pipeline.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Pipeline.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
core/shader/recompiler/Recompiler.hpp
PR 5925 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Execution/include/VulkanDevice.hpp
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/Pipeline.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Pipeline.cpp
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
core/shader/recompiler/Recompiler.hpp
core/shader/recompiler/ShaderDiskCache.hpp
docs/dev/debt/libSceAgcDriver.md
PR 6044 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6186 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 6187 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 6188 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Execution/include/VulkanDevice.hpp
core/libs/prx/libSceAgcDriver/Execution/src/Driver/Draw/DrawDecode.cpp
core/libs/prx/libSceAgcDriver/Execution/src/Driver/Draw/DrawLookup.cpp
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/State.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
core/shader/recompiler/Recompiler.hpp
PR 6192 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 6194 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6197 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 6202 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 6209 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 6223 docs/dev/debt/libSceAgcDriver.md
PR 6235 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Draw/DrawDecode.cpp
core/libs/prx/libSceAgcDriver/Execution/src/Driver/Draw/DrawLookup.cpp
core/libs/prx/libSceAgcDriver/Execution/src/Driver/Draw/DrawRegisterKey.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/State.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/State.cpp
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/CacheKey.hpp
core/shader/recompiler/ControlFlow/src/RequestSerializer.cpp
core/shader/recompiler/Optimization/include/Optimization/ShaderStageInputInfo.hpp
core/shader/recompiler/Recompiler.hpp
core/shader/recompiler/SpirvBackend/src/SpirvModuleEmitter.cpp
core/shader/recompiler/Translation/src/ShaderInputInfoBuilder.cpp
core/shader/recompiler/tests/RequestSerializerTests.cpp
PR 6280 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
core/shader/recompiler/ShaderDiskCache.hpp
docs/dev/debt/libSceAgcDriver.md
PR 6290 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
PR 6300 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/src/DepthSurface.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6412 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/Recompiler.hpp
core/shader/recompiler/ShaderDiskCache.hpp
docs/dev/debt/libSceAgcDriver.md
PR 6481 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/include/Context.hpp
core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6488 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/ShaderDiskCache.hpp
PR 6501 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6539 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Draw/DrawLookup.cpp
core/libs/prx/libSceAgcDriver/Execution/src/Driver/Draw/DrawRegisterKey.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/Pipeline.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Pipeline.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
core/shader/recompiler/Recompiler.hpp
PR 6548 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6604 core/shader/recompiler/Optimization/src/ShaderInfoCollector.cpp
core/shader/recompiler/SpirvBackend/src/SpirvModuleEmitter.cpp
PR 6645 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
PR 6747 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 6788 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 6808 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/src/DepthSurface.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/MultisampleTarget.cpp
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6867 docs/dev/debt/libSceAgcDriver.md
PR 6868 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6879 core/libs/prx/libSceAgcDriver/Graphics/include/DepthSurface.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/DepthSurface.cpp
core/shader/recompiler/CacheKey.hpp
core/shader/recompiler/Recompiler.hpp
PR 6924 core/shader/recompiler/ShaderDiskCache.hpp
PR 6946 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
core/shader/recompiler/Recompiler.hpp
docs/dev/debt/libSceAgcDriver.md
PR 6947 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Execution/include/VulkanDevice.hpp
core/libs/prx/libSceAgcDriver/Execution/src/Driver/Draw/DrawLookup.cpp
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/Pipeline.hpp
core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Pipeline.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/CacheKey.hpp
core/shader/recompiler/Recompiler.hpp
core/shader/recompiler/ShaderDiskCache.hpp
core/shader/recompiler/SpirvBackend/include/SpirvBackend/SpirvEmitterState.hpp
core/shader/recompiler/SpirvBackend/src/SpirvModuleEmitter.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6960 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 6971 core/libs/prx/libSceAgcDriver/Graphics/include/MultisampleTarget.hpp
core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/MultisampleTarget.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 6977 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Draw/DrawDecode.cpp
core/libs/prx/libSceAgcDriver/Execution/src/Driver/Draw/DrawRegisterKey.cpp
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/State.hpp
core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/DepthSurface.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/State.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
core/shader/recompiler/SpirvBackend/include/SpirvBackend/SpirvEmitterState.hpp
docs/dev/debt/libSceAgcDriver.md
PR 7048 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 7201 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Execution/include/VulkanDevice.hpp
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/DepthSurface.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/DepthSurface.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Pipeline.cpp
core/shader/recompiler/CacheKey.hpp
core/shader/recompiler/Recompiler.hpp
core/shader/recompiler/SpirvBackend/include/SpirvBackend/SpirvEmitterState.hpp
core/shader/recompiler/SpirvBackend/src/SpirvModuleEmitter.cpp
PR 7256 core/libs/prx/libSceAgcDriver/Graphics/include/State.hpp
core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/DepthSurface.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/State.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 7410 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Draw/DrawDecode.cpp
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/CacheKey.hpp
core/shader/recompiler/ControlFlow/src/RequestSerializer.cpp
core/shader/recompiler/Recompiler.hpp
core/shader/recompiler/tests/RequestSerializerTests.cpp
PR 7449 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/DepthSurface.hpp
core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/DepthSurface.cpp
docs/dev/debt/libSceAgcDriver.md
PR 7484 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/Context.hpp
core/shader/recompiler/CacheKey.hpp
core/shader/recompiler/Recompiler.hpp
core/shader/recompiler/SpirvBackend/include/SpirvBackend/SpirvEmitterState.hpp
PR 7505 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
docs/dev/debt/libSceAgcDriver.md
PR 7514 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 7550 core/shader/recompiler/ShaderDiskCache.hpp
PR 7604 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
docs/dev/debt/libSceAgcDriver.md
PR 7684 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/ShaderDiskCache.hpp
PR 7689 core/shader/recompiler/Recompiler.hpp
core/shader/recompiler/ShaderDiskCache.hpp
PR 7800 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/include/Context.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
docs/dev/debt/libSceAgcDriver.md
PR 7816 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
PR 7831 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
core/shader/recompiler/Optimization/src/ShaderInfoCollector.cpp
core/shader/recompiler/Recompiler.hpp
core/shader/recompiler/ShaderDiskCache.hpp
core/shader/recompiler/SpirvBackend/include/SpirvBackend/SpirvEmitterState.hpp
core/shader/recompiler/SpirvBackend/src/SpirvModuleEmitter.cpp
PR 8014 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Execution/include/VulkanDevice.hpp
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
docs/dev/debt/libSceAgcDriver.md
PR 8077 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
PR 8246 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 8278 core/libs/prx/libSceAgcDriver/Execution/include/VulkanDevice.hpp
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 8484 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 8489 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/shader/recompiler/CacheKey.hpp
core/shader/recompiler/Recompiler.hpp
core/shader/recompiler/SpirvBackend/include/SpirvBackend/SpirvEmitterState.hpp
PR 8552 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 8564 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Execution/src/Driver/Draw/DrawDecode.cpp
core/libs/prx/libSceAgcDriver/Execution/src/Driver/Draw/DrawLookup.cpp
core/libs/prx/libSceAgcDriver/Execution/src/Driver/Draw/DrawRegisterKey.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/Pipeline.hpp
core/libs/prx/libSceAgcDriver/Graphics/include/State.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Pipeline.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/State.cpp
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/CacheKey.hpp
core/shader/recompiler/ControlFlow/src/RequestSerializer.cpp
core/shader/recompiler/Optimization/include/Optimization/ShaderStageInputInfo.hpp
core/shader/recompiler/Optimization/src/ShaderInfoCollector.cpp
core/shader/recompiler/Recompiler.hpp
core/shader/recompiler/ShaderDiskCache.hpp
core/shader/recompiler/SpirvBackend/include/SpirvBackend/SpirvEmitterState.hpp
core/shader/recompiler/SpirvBackend/src/SpirvModuleEmitter.cpp
core/shader/recompiler/Translation/src/ShaderInputInfoBuilder.cpp
core/shader/recompiler/tests/RequestSerializerTests.cpp
docs/dev/debt/libSceAgcDriver.md
PR 8592 core/libs/prx/libSceAgcDriver/CMakeLists.txt
docs/dev/debt/libSceAgcDriver.md

…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.
@github-actions github-actions Bot removed the needs rebase Conflicts with main, rebase needed label Oct 16, 2026

@jotitadev jotitadev left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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_reference and agc_driver_sample_order_recipe_depth_locations skip 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 logs 2 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.
@EagleBearerYS

Copy link
Copy Markdown
Contributor Author

@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 shaderStorageImageMultisample a depth-only pass reordered the target while a colour+depth pass on it was refused, so the colour pass tested against samples in the other order.

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. agc_driver_sample_order_planning now checks your pair on the noStorage context: without the change it fails with "a depth-only pass on a device without multisampled storage images was reordered", and with it it passes on GitHub's Linux and Windows runners.

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.

@github-actions github-actions Bot added the needs rebase Conflicts with main, rebase needed label Oct 16, 2026
…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.
@EagleBearerYS

Copy link
Copy Markdown
Contributor Author

@oneandonlydean, thanks. All three points are in, and the branch merges current main (7ce3b1d); the head is 8c9c8eb.

The three answers in my earlier comment now have a test each (9b7f8cd, 44e8786, ef6ec1e), and each fails with its fix line reverted:

  • the location table's index: "the table index's low bits are not the order word's nibble at the shader's SampleId";
  • the position input: "a pixel shader that only reorders its samples was not given the position input";
  • the coverage order: "a quad sample mask reached the pixel shader in the guest's order".

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, main 1ff5c8a), the ^(agc|shader) tests pass on Linux, 0 of 859 failed. The description has the details.

@github-actions github-actions Bot removed the needs rebase Conflicts with main, rebase needed label Oct 21, 2026
@oneandonlydean

Copy link
Copy Markdown
Collaborator

@EagleBearerYS thanks, checked on 8c9c8eb5b5. The serializer writes 42 and the shader cache FormatVersion is 44, one above main's 41 and 43, and the branch merges main cleanly. HostSampleLocationsFor keeps main's fallback (pixel (0,0)'s locations on a 1x1 grid with the one-time warning) and adds the same-set sample order. The pipeline keys now include the device's sample-location caps. Next is a full CI run on this head.

@milescoviello

Copy link
Copy Markdown
Contributor

@EagleBearerYS a heads-up after the merge. On an RTX 4070 Ti with the 595.99.02 Linux driver, agc_driver_sample_order, agc_driver_sample_order_grid_reference and agc_driver_sample_order_recipe_depth_locations fail on main: they read back depth other than what was drawn.

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 SAMPLED usage, so the layer reports VUID-VkWriteDescriptorSet-descriptorType-00337, and this driver returns other depth. The reorder pass itself samples a copy, so the driver code is fine.

#9056 makes the tests read the same kind of copy, and then all 4 pass here. #9057 fixes a separate VUID-VkImageMemoryBarrier-image-03320 in the depth reorder's copy barrier for D32S8. Your review on either would be welcome.

AI-assisted: yes (Claude Code)

@EagleBearerYS

Copy link
Copy Markdown
Contributor Author

@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.

@DavidSamir

Copy link
Copy Markdown
Contributor

@EagleBearerYS @milescoviello: an AMD data point for agc_driver_sample_order_grid_reference. On the Radeon 680M it loses the device in the exact path's depth pass, and still does with #9056 and #9057.

Setup: Windows 11 Pro 26200, AMD Radeon 680M (RDNA 2 iGPU; shaderStorageImageMultisample true; largest sample location grid 2x2 at every count), AMD driver 32.0.21030.2001, main 27fabb6b7, alone and with #9056 + #9057 merged.

Failure: in RenderCheckerboard(device, emulated, ...) (the exact path, with sampleLocationGridSampleCounts forced to 0):

[device-fault] result 0: GPU fault
[device-fault] read invalid at 0x200000000 (precision 0x1000)
AGC graphics: vkQueueSubmit recorder: Vulkan result -4

The VUID-VkSubmitInfo-pSignalSemaphores-03242 that follows (a timeline at UINT64_MAX) is the aftermath of the lost device. The reference composite before it renders fine.

Narrowed down with local early returns in SampleOrders (not pushed):

  • skipping Storage() (the compute pass over the colour alias): still faults
  • skipping Depth(): no fault
  • returning after the layout barrier, after vkCmdCopyImage, or after vkUpdateDescriptorSets: no fault
  • no sample-locations chain on vkCmdBeginRenderPass: still faults
  • writing both sampled bindings (a depth-only target writes only 1): still faults
  • skipping only draw(pass.depth, 0u, 0xffu, 0u): no fault

So it's the pass.depth draw itself: the embedded fragment shader sampling the 2x depth copy, with sampleShadingEnable and minSampleShading 1.0. The copy image looks right (DEPTH_STENCIL_ATTACHMENT|TRANSFER_DST|SAMPLED, device-local, bound at offset 0). My suspect is a texelFetch sample index taken from DepthPush.map that is out of range at 2 samples: AMD's driver faults on that, while other drivers may clamp it. I haven't checked the shader source.

AI-assisted: yes

@EagleBearerYS

Copy link
Copy Markdown
Contributor Author

@DavidSamir, thank you for the Radeon 680M data point and for bisecting it down to the pass.depth draw, with and without #9056 and #9057. We're checking the depth pass's sample indices at 2 samples, starting with the map it reads from DepthPush, and will follow up here with a fix if the fault is in our code.

@milescoviello

Copy link
Copy Markdown
Contributor

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)

@EagleBearerYS

Copy link
Copy Markdown
Contributor Author

@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):

  • Sample indices. A new check applies the depth pass's map rule to 3,003 sample orders: the test's 2x, 4x and 8x orders and 3,000 random ones. Every map word reads only samples below the count, each sample once, in both directions. So an out-of-range sample index isn't it.
  • Validation (core, synchronization and GPU-assisted). lavapipe has no 2x and no VK_EXT_sample_locations, so it can't reach your located 2x D32_SFLOAT path. Over what it does reach (4x, unlocated), it found one error: the 03320 barrier that @milescoviello's fix(agc): give a depth stencil copy's layout barrier both aspects #9057 fixes. Your format has no stencil, so that doesn't explain your device loss. Nothing else came up.

The branch: EagleBearerYS/AnyPS5 fix/agc-sample-order-copy-sampled-only (4bdf36e), main d099bc6 plus three commits:

  • the index check;
  • fix(agc): give a depth stencil copy's layout barrier both aspects #9057's barrier fix, with a test;
  • two changes to the depth pass, each with a test that fails with it reverted:
    • The multisampled copy the pass samples is created with TRANSFER_DST | SAMPLED only, without DEPTH_STENCIL_ATTACHMENT. Where a device refuses that usage, it keeps the old usage and is sampled in DEPTH_STENCIL_READ_ONLY_OPTIMAL.
    • Binding 1 is now written for every method, with the depth view for the depth-only method. Before, it was left unwritten, which is valid since the shader doesn't read it there.

Could you run both trees and post the six logs? Use main d099bc6 rather than 27fabb6, so the trees differ only by those three commits. In Git Bash with CI's WinLibs GCC 15.2.0, CMake, Ninja, Python and the LunarG Vulkan SDK (drop the two *_LAUNCHER flags without ccache):

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. C:/anyps5-vvl/sync/vk_layer_settings.txt:

khronos_validation.debug_action = VK_DBG_LAYER_ACTION_LOG_MSG
khronos_validation.report_flags = error,warn,perf
khronos_validation.log_filename = stdout
khronos_validation.duplicate_message_limit = 0
khronos_validation.enables = VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXT

and C:/anyps5-vvl/gpuav/vk_layer_settings.txt, the same with VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT on the last line.

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-*.log

That last line prints one count per log; if any of them isn't 0, the layer didn't load. A device loss shows as Vulkan result -4. A Vulkan result 2 is CommandBatch::Wait's fixed 5 s fence wait, which GPU-assisted validation outlasted on lavapipe. If you hit it, raise 5'000'000'000ULL in core/libs/prx/libSceAgcDriver/Graphics/src/Resources.cpp and rebuild.

@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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agc libSceAgc* build docs shader core/shader unblocks title Names a title ID on the Unblocks line

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants