Skip to content

fix(recompiler): run a pixel shader the guest does not iterate once per pixel - #6470

Merged
adriadam10 merged 10 commits into
boykopovar:mainfrom
EagleBearerYS:fix/recompiler-once-per-pixel-sample-inputs
Oct 19, 2026
Merged

adriadam10 merged 10 commits into
boykopovar:mainfrom
EagleBearerYS:fix/recompiler-once-per-pixel-sample-inputs

Conversation

@EagleBearerYS

@EagleBearerYS EagleBearerYS commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

What

A pixel shader that reads the ancillary input's sample number ran once per sample on every multisampled draw, even when the console runs it once per pixel.

The cause: the recompiler gave that field (bits 11:8) the SampleId builtin, and Vulkan enables sample shading for any fragment shader that uses SampleId (spec). That happened whatever PA_SC_MODE_CNTL_1.PS_ITER_SAMPLE said. So these shaders did N× the fragment work, and FragCoord, and with it POS_X_FLOAT and POS_Y_FLOAT, moved from the pixel centre to the sample.

With #5907 (merged):

Effect on open PRs:

Tested

Resident Evil Village (PPSA01556), Windows 11, RTX 3070 Laptop GPU (driver 617.42):

Linux, lavapipe (CI configuration):

  • New agc_driver_pixel_sample_iteration:
    • device draws at 4x and 1x: ten 4x cases, each red on main's code generation and green here (one invocation per pixel with sample number 0; POS at the centre; PERSP_SAMPLE and LINEAR_SAMPLE at sample 0; iterated invocations with their own sample numbers and inputs; PERSP_CENTER, POS_FLOAT_ULC, POS at sample 0, a partial quad sample mask), plus 1x unchanged;
    • module checks at 2x and 4x: no SampleId once per pixel; sample 0's offset; the guest location table when iterated, standard and per-pixel custom; no offsets without sampleRateShading.
  • Changed tests: pixel_ancillary (iterated and not), agc_driver_sample_mask_multisample (its per-sample pass sets perSampleShading, as a guest would), request_serializer (version 31 and its upgrades), agc_shader_memory (the request version) and agc_driver_graphics (the SPI_BARYC_CNTL decode, and feat(agc): rasterize a multisampled draw into one-sample targets at sample 0's locations #5907's three ANCILLARY with POS_X/Y cases, which now rasterize sample 0 alone instead of throwing).
  • At each commit: ctest -R '^(agc|shader|recompiler)' passes, 607 tests (608 with the new test). The one exception, agc_driver_preparation_scope_settle, is a load flake that also fails on main; it passed when rerun alone.
  • Repeats: the new and changed tests pass --repeat until-fail:10.
  • Cost on lavapipe, PPSA01556's input shape at 4x, PS_ITER_SAMPLE clear: 4 → 1 fragment invocations per pixel, 9.54 → 5.79 ms per 512×256 draw. Iterated shaders that read PERSP_SAMPLE or LINEAR_SAMPLE cost more for the explicit sample offsets: +17.6% per draw at the median of 9 runs (+11.6% to +32.1%), about 5 ns per sample invocation; iterated shaders that read only the centre pairs, and shaders run once per pixel, are within noise. The pixel stage's cache key grows by 34 words.

Windows (GitHub's runner, MinGW, no Vulkan device), at this head (run): request_serializer, pixel_ancillary, agc_shader_memory, agc_driver_graphics and the other 19 agc tests run with them pass 3 of 3; 4 device draws skip without Vulkan. Only these tests' targets were built: on main 0029e62 a whole-tree MinGW build stops at tests/execution/GpuIndirectArgumentsMisalignedWriterAhead.cpp (alignas(65536), from #5747), which this change does not touch. The libc and libkernel suites pass apart from guest_kqueue, which fails on main on that runner.

Merged with main b260d8d (bd09c49), on GitHub's runners (run): request_serializer, agc_shader_memory, agc_driver_graphics, pixel_ancillary, agc_driver_pixel_sample_iteration, agc_driver_sample_mask_multisample and #5907's state tests pass 3 of 3 on Linux and Windows. The run shows as failed because the Windows libkernel suite's guest_kqueue and the Linux timing test precise_wait fail on those runners with and without this PR (no main comparison was run).

  • The dropped refusal (3e802e4), on GitHub's runners (run): with the merge alone, agc_driver_graphics fails on Linux and Windows on the three cases; with the commit, it, pixel_ancillary and agc_driver_pixel_sample_iteration pass 3 of 3 on both.

Windows 11, RTX 3070 Laptop GPU (driver 617.42), native fragment-shader barycentrics: agc_driver_pixel_sample_iteration passes 5 of 5 (21 draws). With main's code generation (the fix commit's non-test files at d5cbfd1) it fails with "2x: a pixel shader the guest runs once per pixel reads SampleId". lavapipe runs the same draws through the emulated barycentrics.

Checklist

…quests

A pixel shader's request now says whether the guest iterates it per
sample (PA_SC_MODE_CNTL_1.PS_ITER_SAMPLE on a multisampled draw), where
SPI_BARYC_CNTL puts POS_X_FLOAT and POS_Y_FLOAT (POS_FLOAT_LOCATION,
bits 17:16, and POS_FLOAT_ULC, bit 20), and the guest's sample
locations for each pixel of the 2x2 quad when the shader reads
PERSP_SAMPLE, LINEAR_SAMPLE or a position at the sample: sample 0's
once per pixel, every sample's when iterated. The fields join the
shader cache key, the draw cache key and the request serialization
(version 31). A missing SPI_BARYC_CNTL reads as the pixel centre and
the reserved location 3 throws.

Devices with sampleRateShading now advertise the InterpolationFunction
capability, which the pixel shader validator accepts.
…er pixel

The ancillary input's sample number (bits 11:8) was the SampleId
builtin in every pixel shader. Vulkan enables sample shading for a
shader that uses SampleId, so a shader that reads the sample field or
the whole ancillary word ran once per sample on a multisampled draw
even when the guest runs it once per pixel (PS_ITER_SAMPLE clear), and
FragCoord, and with it POS_X_FLOAT and POS_Y_FLOAT, moved to the
sample. The sample number is now SampleId only when the request says
the guest iterates the shader, and otherwise 0, the iterated sample
number of a pixel the hardware does not iterate.

The other inputs that depend on the sample follow where the console
evaluates them:
- PERSP_SAMPLE and LINEAR_SAMPLE are interpolated with
  InterpolateAtOffset at sample 0's offset in a shader the guest does
  not iterate, and in an iterated one at the offset of the host's
  SampleId, read from a table of the guest's locations, because Vulkan
  leaves plain barycentrics under sample shading at an
  implementation-defined position (lavapipe uses the pixel centre).
- PERSP_CENTER and LINEAR_CENTER are interpolated at offset 0 in an
  iterated shader.
- POS_X_FLOAT and POS_Y_FLOAT follow SPI_BARYC_CNTL: the centre is
  floor(FragCoord) + 0.5 under sample shading, a sample position in a
  shader the guest does not iterate is the centre plus sample 0's
  offset, and POS_FLOAT_ULC gives the upper-left corner.

The offsets need InterpolationFunction (sampleRateShading) and the
fragment-shader barycentric path; devices without them keep the host's
default positions. The shader disk cache format goes to 39.
Draws a perspective triangle into a 4x target without attachments and
records, for every pixel and sample slot, how often the pixel shader
ran and what it read: the ancillary's sample number, POS_X_FLOAT and
POS_Y_FLOAT, and the PERSP_SAMPLE, LINEAR_SAMPLE or PERSP_CENTER
barycentrics, which are compared with the values at the expected
position. A shader the guest does not iterate must run once per pixel
and read sample 0's values and the centre, also with
POS_FLOAT_LOCATION at the sample, POS_FLOAT_ULC and a partial quad
sample mask; an iterated shader must run once per covered sample and
read that sample's values; a single-sample draw is unchanged. 2x draws
run where the device supports them. Module checks cover 2x and 4x
without a device: no SampleId in a non-iterated shader, sample 0's
offset, the guest's location table in an iterated shader (standard and
custom per-pixel locations), and no offsets without sampleRateShading.
@github-actions

github-actions Bot commented Oct 15, 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 4650 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp L3905, L4023, L4171-4172, L4177-4178, L4183-4184, L4189-4190
core/shader/recompiler/ControlFlow/src/RequestSerializer.cpp L781, L815
core/shader/recompiler/tests/RequestSerializerTests.cpp L209, L248, L273, L397, L410, L429, L431
PR 6503 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp L3905, L4023, L4171-4172, L4177-4178, L4183-4184, L4189-4190
core/shader/recompiler/ControlFlow/src/RequestSerializer.cpp L781, L815
core/shader/recompiler/tests/RequestSerializerTests.cpp L209, L248, L273, L397, L410, L429, L431
PR 6530 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Draw/DrawRegisterKey.cpp L264-265
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp L3173-3174
core/shader/recompiler/IntermediateRepresentation/include/IntermediateRepresentation/IrMetadata/StageIO.hpp L51
PR 6571 docs/dev/debt/libSceAgcDriver.md L133-134
PR 6639 core/libs/prx/libSceAgcDriver/Graphics/src/State.cpp L905
core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp L3905, L4023
core/shader/recompiler/ControlFlow/src/RequestSerializer.cpp L781, L815
core/shader/recompiler/tests/RequestSerializerTests.cpp L209, L248, L273, L397, L410, L429, L431
PR 6679 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp L3905, L4023
core/shader/recompiler/ControlFlow/src/RequestSerializer.cpp L781, L815
core/shader/recompiler/tests/RequestSerializerTests.cpp L209, L248, L273, L396-399, L410, L429, L431
PR 6762 core/libs/prx/libSceAgcDriver/Graphics/src/ShaderInputState.cpp L146-147, L174
core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp L3905, L4023, L4169, L4172, L4178, L4184, L4190
core/shader/recompiler/ControlFlow/src/RequestSerializer.cpp L345, L407, L781, L815
core/shader/recompiler/tests/RequestSerializerTests.cpp L49, L209, L248, L273, L397, L410, L429, L431
PR 6801 core/libs/prx/libSceAgcDriver/Graphics/src/State.cpp L905
core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp L3905, L4023
core/shader/recompiler/ControlFlow/src/RequestSerializer.cpp L781, L815
core/shader/recompiler/tests/RequestSerializerTests.cpp L209, L248, L273, L397, L410, L429, L431
PR 6858 core/shader/recompiler/ShaderDiskCache.hpp L16
PR 6924 core/shader/recompiler/ShaderDiskCache.hpp L16
PR 7410 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp L3905, L4023
core/shader/recompiler/ControlFlow/src/RequestSerializer.cpp L781, L815
core/shader/recompiler/tests/RequestSerializerTests.cpp L209, L248, L273, L397, L410, L429, L431

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/State.cpp
PR 1341 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
PR 1368 core/libs/prx/libSceAgcDriver/Graphics/include/State.hpp
PR 1395 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/State.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/State.cpp
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 2434 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
docs/dev/debt/libSceAgcDriver.md
PR 3247 core/shader/recompiler/Recompiler.cpp
core/shader/recompiler/Recompiler.hpp
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/src/ShaderValidation.cpp
core/shader/recompiler/Recompiler.cpp
core/shader/recompiler/Translation/include/Translation/InstructionTranslator.hpp
core/shader/recompiler/Translation/src/InstructionTranslator.cpp
PR 4448 docs/dev/debt/libSceAgcDriver.md
PR 4472 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 4891 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 5021 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/shader/recompiler/Optimization/src/ConstantFolder.cpp
core/shader/recompiler/Recompiler.cpp
docs/dev/debt/shader.md
PR 5058 docs/dev/debt/libSceAgcDriver.md
PR 5371 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
docs/dev/debt/shader.md
PR 5372 docs/dev/debt/libSceAgcDriver.md
PR 5426 docs/dev/debt/shader.md
PR 5431 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 5441 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 5499 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/State.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/State.cpp
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 5500 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Draw/DrawDecode.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/libs/tests/PixelAncillary.cpp
core/shader/recompiler/ControlFlow/src/RequestSerializer.cpp
core/shader/recompiler/IntermediateRepresentation/include/IntermediateRepresentation/IrMetadata/StageIO.hpp
core/shader/recompiler/Optimization/src/ConstantFolder.cpp
core/shader/recompiler/Optimization/src/ShaderInfoCollector.cpp
core/shader/recompiler/Recompiler.cpp
core/shader/recompiler/Recompiler.hpp
core/shader/recompiler/SpirvBackend/src/SpirvModuleEmitter.cpp
docs/dev/debt/shader.md
PR 5609 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Draw/DrawLookup.cpp
core/libs/prx/libSceAgcDriver/Execution/src/Driver/Draw/DrawRegisterKey.cpp
core/shader/recompiler/Recompiler.cpp
core/shader/recompiler/Recompiler.hpp
PR 5925 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
core/shader/recompiler/Recompiler.hpp
core/shader/recompiler/ShaderDiskCache.hpp
docs/dev/debt/libSceAgcDriver.md
PR 5941 docs/dev/debt/shader.md
PR 6009 docs/dev/debt/shader.md
PR 6044 core/libs/tests/PixelAncillary.cpp
PR 6177 core/libs/prx/libSceAgcDriver/Execution/src/ShaderDeviceProfile.cpp
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/CacheKey.hpp
core/shader/recompiler/ControlFlow/src/RequestSerializer.cpp
core/shader/recompiler/Recompiler.cpp
core/shader/recompiler/Recompiler.hpp
core/shader/recompiler/tests/RequestSerializerTests.cpp
PR 6188 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/State.cpp
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
core/shader/recompiler/Recompiler.hpp
PR 6194 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6202 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.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/ShaderValidation.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/Recompiler.hpp
core/shader/recompiler/SpirvBackend/src/SpirvModuleEmitter.cpp
core/shader/recompiler/Translation/src/ShaderInputInfoBuilder.cpp
core/shader/recompiler/tests/RequestSerializerTests.cpp
docs/dev/debt/shader.md
PR 6273 docs/dev/debt/libSceAgcDriver.md
PR 6280 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
core/shader/recompiler/ShaderDiskCache.hpp
docs/dev/debt/libSceAgcDriver.md
docs/dev/debt/shader.md
PR 6300 docs/dev/debt/libSceAgcDriver.md
PR 6360 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 6472 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6481 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6486 core/shader/recompiler/Recompiler.hpp
core/shader/recompiler/ShaderDiskCache.hpp
PR 6488 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/Recompiler.cpp
core/shader/recompiler/ShaderDiskCache.hpp
docs/dev/debt/shader.md
PR 6498 docs/dev/debt/libSceAgcDriver.md
PR 6505 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 6529 core/libs/prx/libSceAgcDriver/Graphics/include/State.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/State.cpp
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6535 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Draw/DrawDecode.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/State.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/State.cpp
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 6539 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Draw/DrawLookup.cpp
core/libs/prx/libSceAgcDriver/Execution/src/Driver/Draw/DrawRegisterKey.cpp
core/shader/recompiler/Recompiler.cpp
core/shader/recompiler/Recompiler.hpp
PR 6543 docs/dev/debt/libSceAgcDriver.md
PR 6548 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6549 docs/dev/debt/libSceAgcDriver.md
PR 6563 core/libs/prx/libSceAgcDriver/Graphics/src/State.cpp
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6612 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/ShaderValidation.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/IntermediateRepresentation/include/IntermediateRepresentation/IrMetadata/ProgramMetadata.hpp
core/shader/recompiler/IntermediateRepresentation/include/IntermediateRepresentation/IrMetadata/StageIO.hpp
core/shader/recompiler/Optimization/include/Optimization/ShaderStageInputInfo.hpp
core/shader/recompiler/Optimization/src/ShaderInfoCollector.cpp
core/shader/recompiler/Recompiler.cpp
core/shader/recompiler/Recompiler.hpp
core/shader/recompiler/SpirvBackend/src/SpirvModuleEmitter.cpp
core/shader/recompiler/Translation/src/InstructionTranslator.cpp
core/shader/recompiler/Translation/src/ShaderInputInfoBuilder.cpp
core/shader/recompiler/tests/RequestSerializerTests.cpp
docs/dev/debt/libSceAgcDriver.md
docs/dev/debt/shader.md
PR 6613 docs/dev/debt/shader.md
PR 6615 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 6645 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
PR 6718 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 6763 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 6786 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6788 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 6808 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6820 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 6867 docs/dev/debt/libSceAgcDriver.md
PR 6868 docs/dev/debt/libSceAgcDriver.md
PR 6879 core/shader/recompiler/CacheKey.hpp
core/shader/recompiler/Recompiler.cpp
core/shader/recompiler/Recompiler.hpp
PR 6941 core/libs/prx/libSceAgcDriver/Graphics/src/ShaderValidation.cpp
core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/CacheKey.hpp
core/shader/recompiler/ControlFlow/src/RequestSerializer.cpp
core/shader/recompiler/Recompiler.cpp
core/shader/recompiler/Recompiler.hpp
core/shader/recompiler/ShaderDiskCache.hpp
core/shader/recompiler/SpirvBackend/src/SpirvModuleEmitter.cpp
core/shader/recompiler/tests/RequestSerializerTests.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6946 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Draw/DrawLookup.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderInputState.cpp
core/shader/recompiler/Recompiler.cpp
core/shader/recompiler/Recompiler.hpp
docs/dev/debt/libSceAgcDriver.md
PR 6947 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Draw/DrawLookup.cpp
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderInputState.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderValidation.cpp
core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/CacheKey.hpp
core/shader/recompiler/IntermediateRepresentation/include/IntermediateRepresentation/IrMetadata/ProgramMetadata.hpp
core/shader/recompiler/Recompiler.cpp
core/shader/recompiler/Recompiler.hpp
core/shader/recompiler/ShaderDiskCache.hpp
core/shader/recompiler/SpirvBackend/src/SpirvModuleEmitter.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6960 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 6970 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
core/shader/recompiler/Recompiler.hpp
PR 6972 core/libs/prx/libSceAgcDriver/tests/Graphics.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/src/State.cpp
core/shader/recompiler/Recompiler.cpp
core/shader/recompiler/Translation/include/Translation/InstructionTranslator.hpp
core/shader/recompiler/Translation/src/InstructionTranslator.cpp
docs/dev/debt/libSceAgcDriver.md
docs/dev/debt/shader.md
PR 7008 docs/dev/debt/libSceAgcDriver.md
PR 7154 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
docs/dev/debt/libSceAgcDriver.md
PR 7201 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/shader/recompiler/CacheKey.hpp
core/shader/recompiler/IntermediateRepresentation/include/IntermediateRepresentation/IrMetadata/ProgramMetadata.hpp
core/shader/recompiler/Recompiler.cpp
core/shader/recompiler/Recompiler.hpp
core/shader/recompiler/SpirvBackend/src/SpirvModuleEmitter.cpp
PR 7223 core/shader/recompiler/Recompiler.cpp
core/shader/recompiler/ShaderDiskCache.hpp
docs/dev/debt/shader.md
PR 7233 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 7250 docs/dev/debt/libSceAgcDriver.md
PR 7254 core/libs/prx/libSceAgcDriver/Graphics/src/State.cpp
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 7256 core/libs/prx/libSceAgcDriver/Graphics/include/State.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/State.cpp
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 7258 docs/dev/debt/libSceAgcDriver.md
PR 7332 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Draw/DrawDecode.cpp
core/libs/prx/libSceAgcDriver/Execution/src/ShaderDeviceProfile.cpp
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/State.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderValidation.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/State.cpp
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/libs/prx/libSceAgcDriver/tests/execution/SampleMaskMultisample.cpp
core/shader/recompiler/CacheKey.hpp
core/shader/recompiler/ControlFlow/src/RequestSerializer.cpp
core/shader/recompiler/IntermediateRepresentation/include/IntermediateRepresentation/IrMetadata/ProgramMetadata.hpp
core/shader/recompiler/Optimization/src/HostInterpolationChecker.cpp
core/shader/recompiler/Optimization/src/ShaderInfoCollector.cpp
core/shader/recompiler/Recompiler.cpp
core/shader/recompiler/Recompiler.hpp
core/shader/recompiler/SpirvBackend/src/SpirvModuleEmitter.cpp
core/shader/recompiler/tests/RequestSerializerTests.cpp
docs/dev/debt/libSceAgcDriver.md
docs/dev/debt/shader.md
PR 7371 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 7388 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
docs/dev/debt/shader.md
PR 7390 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/shader/recompiler/Recompiler.cpp
core/shader/recompiler/Recompiler.hpp
core/shader/recompiler/ShaderDiskCache.hpp
core/shader/recompiler/SpirvBackend/src/SpirvModuleEmitter.cpp
docs/dev/debt/libSceAgcDriver.md
PR 7392 docs/dev/debt/shader.md
PR 7429 docs/dev/debt/shader.md
PR 7432 docs/dev/debt/libSceAgcDriver.md
PR 7505 docs/dev/debt/libSceAgcDriver.md
PR 7604 docs/dev/debt/libSceAgcDriver.md

EagleBearerYS added a commit to EagleBearerYS/AnyPS5 that referenced this pull request Oct 15, 2026
… 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).
EagleBearerYS added a commit to EagleBearerYS/AnyPS5 that referenced this pull request Oct 15, 2026
@github-actions github-actions Bot added shader core/shader docs agc libSceAgc* labels Oct 16, 2026
@simonbronk

Copy link
Copy Markdown
Contributor

@EagleBearerYS an overlap note with #5907 (sample-zero rasterization of a multisampled scan into one-sample targets), which adriadam10 plans to merge once main builds. The bot doesn't list it, but both touch State.cpp and the same debt entries, and they meet on the same draws:

The textual conflict is small: the debt lines in docs/dev/debt/libSceAgcDriver.md. Onimusha (PPSA27836) goes through #5907's path in its first scene load, so I can test this PR on the title once both are on main.

AI-assisted (Claude Code); I checked both diffs on main eb901bc.

@EagleBearerYS

Copy link
Copy Markdown
Contributor Author

Thanks, @simonbronk, that matches what I see.

An Onimusha (PPSA27836) run once both are on main would be very welcome.

@github-actions github-actions Bot added the needs rebase Conflicts with main, rebase needed label Oct 16, 2026
Main took request serialization versions 31 (output primitive size) and
32 (spanned waves), and boykopovar#6683 uses 33, so the pixel iteration fields move
to version 34. A version 32 request keeps its spanned-waves flag and reads
no pixel iteration.
A one-sample target drawn by a multisampled rasterizer refused a pixel
shader that reads ANCILLARY with POS_X_FLOAT or POS_Y_FLOAT, because the
sample index made the host shade per sample and moved FragCoord from the
pixel centre. A shader the guest does not iterate now runs once per pixel
with sample number 0, and on this path the rasterizer keeps one sample, so
those draws are no longer refused. Resident Evil Village's (PPSA01556)
2x depth-only pass with SPI_PS_INPUT_ENA 0x2301 was one of them.
@github-actions github-actions Bot removed the needs rebase Conflicts with main, rebase needed label Oct 16, 2026
EagleBearerYS added a commit to EagleBearerYS/AnyPS5 that referenced this pull request Oct 17, 2026
@github-actions github-actions Bot added the needs rebase Conflicts with main, rebase needed label Oct 17, 2026
main d7262bd adds the single-sample scan entry after the custom MSAA
sample locations entry in the AGC debt file. Keep it after this
branch's version of that entry.
@github-actions github-actions Bot removed the needs rebase Conflicts with main, rebase needed label Oct 17, 2026
@github-actions github-actions Bot added the needs rebase Conflicts with main, rebase needed label Oct 18, 2026
Main's EmitSetAttribute debt entry now says the generated rect-list and
barycentric tessellation stages forward the vertex shader's clip array.
It sits next to this branch's PERSP_SAMPLE and pixel position entries,
which main left as they were; keep main's entry and this branch's two.
@github-actions github-actions Bot removed the needs rebase Conflicts with main, rebase needed label Oct 18, 2026
@github-actions github-actions Bot added the needs rebase Conflicts with main, rebase needed label Oct 18, 2026
@github-actions github-actions Bot added unblocks title Names a title ID on the Unblocks line and removed needs rebase Conflicts with main, rebase needed labels Oct 18, 2026
Resolves the shader debt file bullet by bullet: main's EmitSetAttribute entry, and this branch's PERSP_SAMPLE/LINEAR_SAMPLE and pixel-position entries.
@github-actions github-actions Bot added needs rebase Conflicts with main, rebase needed and removed needs rebase Conflicts with main, rebase needed labels Oct 18, 2026
@klosixgaming-arch

Copy link
Copy Markdown
Contributor

Tested on Windows 11, MinGW-w64 GCC 15.2.0, NVIDIA GeForce RTX 5090 (driver 617.42), Ryzen 9 9950X3D. Head d13a90d01 (10 commits) merged onto current main (a373e85); the merge is clean and builds.

pixel_ancillary, agc_driver_pixel_sample_iteration, agc_driver_sample_mask_multisample, agc_driver_graphics, agc_shader_memory, agc_shader_bindless and request_serializer pass with the change (the agc_shader_* tests that I did not build were not run).

Not done: I did not run the new tests against main without the fix, did not run a title, and did not review the 32-file change (SPIR-V InterpolateAtOffset use, the new request fields and the sample-location handling). Because it changes the recompile request and ShaderDiskCache identity, a second reviewer who knows those paths would be useful. This is a test report only, not an approval.

AI-assisted: yes. Written with AI assistance and reviewed by me.

@adriadam10 adriadam10 self-assigned this Oct 19, 2026
@adriadam10
adriadam10 merged commit 00666ee into boykopovar:main Oct 19, 2026
10 checks passed
EagleBearerYS added a commit to EagleBearerYS/AnyPS5 that referenced this pull request Oct 19, 2026
Since boykopovar#6470, a draw decode sets the pixel stage's iteratesSamples from the per-sample shading state and its sample locations from the draw's state, and a pixel shader that does not iterate runs once per pixel with sample 0. The sample-order test built its pixel stage from the registers alone, so its per-sample passes ran once per pixel and SampleID read 0. It now sets both fields as DrawDecode does.
ycarogabriel-lgtm added a commit to ycarogabriel-lgtm/AnyPS5 that referenced this pull request Oct 19, 2026
…terates

This branch's Metal fix for uniform sample masks treated a pixel shader
that loads PERSP_SAMPLE and LINEAR_SAMPLE as running per sample: it
gave the shader its own gl_SampleID and kept only the current sample's
coverage bit. main now runs such a shader once per pixel unless the
guest iterates samples (boykopovar#6470's pixel sample iteration), and declaring
gl_SampleID makes every Vulkan driver run the shader per sample. The
own SampleId input and the per-sample masks now follow the guest's
sample iteration (pixelIteratesSamples, State::perSampleShading).
sample_mask_multisample and front_face_all_bits still pass on MoltenVK.

agc_driver_pixel_sample_iteration still fails its first case on
MoltenVK: an attachment-less 4x draw runs the fragment shader per
sample although the generated Metal function asks for no sample input.
That is recorded in the AGC debt file.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
oneandonlydean pushed a commit that referenced this pull request Oct 21, 2026
Combines this branch's sample order with #6470's once-per-pixel and once-per-sample inputs. The pixel request keeps both sides' fields: #6470's iteration, position location and sample locations are serialized at version 34, and the sample order after them at version 35. The serialization tests move the sample-order bytes after the iteration fields and drop both from older versions. The pixel info collector adds sample order to the SampleLocationsVary inputs, and the draw keys compare and hash both. EmitSampleOffset's iterated index already goes through GuestSampleIndex, since the SampleId builtin does. The shader cache stays at FormatVersion 40, and the sample-location debt entry takes #6470's sentence on the position inputs.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agc libSceAgc* 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.

4 participants