Skip to content

fix(shader_recompiler): pack format 11_11_10 float image stores in shader - #8898

Open
camezaro-intc wants to merge 2 commits into
boykopovar:mainfrom
camezaro-intc:format11-11-10-float-stores
Open

camezaro-intc wants to merge 2 commits into
boykopovar:mainfrom
camezaro-intc:format11-11-10-float-stores

Conversation

@camezaro-intc

@camezaro-intc camezaro-intc commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

What

Packs storage image stores into guest format 36 (Format11_11_10Float) in-shader via Format32UInt views rather than relying on Vulkan's VK_FORMAT_B10G11R11_UFLOAT_PACK32 write path. Real RDNA 2 hardware rounds toward zero and saturates finite values exceeding maximum representable range to 65024.0 (11-bit) and 64512.0 (10-bit), whereas host Vulkan drivers round to nearest-even and overflow to infinity.

Routes DCC fast clears for formats 36 and 43 through VK_FORMAT_B10G11R11_UFLOAT_PACK32 via DccClearTextureFormat so fast clears produce valid 3-channel packed float layouts rather than single-channel R32_UINT.

Tested

  • Windows 11, AMD Radeon RX 5700 XT (driver 32.0.21045.5002) with ANYPS5_REQUIRE_VULKAN=1, ANYPS5_NO_SHADER_CACHE=1, VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation:
    • ctest --test-dir build -R "agc_driver_image_converted_unorm|agc_driver_image_repacked_float|texture_format_lookup|agc_driver$" -V passed 100% with zero validation errors.

Checklist

@github-actions

github-actions Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

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 907 core/shader/recompiler/Optimization/src/ResourceMaterializer.cpp
PR 5371 core/shader/recompiler/Optimization/src/ResourceMaterializer.cpp
PR 6192 core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 6194 core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 6202 core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 6209 core/libs/prx/libSceAgcDriver/Graphics/src/DccMetadata.cpp
PR 6223 core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 6280 core/shader/recompiler/Optimization/src/ResourceMaterializer.cpp
PR 6412 core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
core/shader/recompiler/Optimization/src/ResourceMaterializer.cpp
PR 6481 core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 6488 core/shader/recompiler/Optimization/src/ResourceMaterializer.cpp
PR 6804 core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 7684 core/shader/recompiler/Optimization/src/ResourceMaterializer.cpp
PR 7689 core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
core/shader/recompiler/Optimization/src/ResourceMaterializer.cpp
PR 8077 core/shader/recompiler/Optimization/src/ResourceMaterializer.cpp
core/shader/recompiler/RdnaDecoder/src/RdnaDescriptorFormat.cpp
PR 8998 core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
core/shader/recompiler/Optimization/src/ResourceMaterializer.cpp
PR 9400 core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 9592 core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 9674 core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 9889 core/shader/recompiler/Optimization/src/ResourceMaterializer.cpp
PR 9897 core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 10049 core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 10159 core/libs/prx/libSceAgcDriver/Graphics/src/DccMetadata.cpp
PR 10193 core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
core/shader/recompiler/Optimization/src/ResourceMaterializer.cpp
PR 10233 core/shader/recompiler/Optimization/src/ResourceMaterializer.cpp
PR 10442 core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp

@thuanquang

Copy link
Copy Markdown
Contributor

Runs of this head (5236bb622) on AMD hardware and on lavapipe.

The edge rows on hardware. The seven Float36StoreEdges rows match an RX 6700 XT (gfx1031, AMD's Windows driver 32.0.21045.5002). Each row was stored with image_store through a format 36 T# and read back through a 32_UINT T#, as raw ISA through the HIP runtime. All seven dwords equal the test's expected values, with f32 denormals kept and with them flushed.

RX 6700 XT (Windows 11 26200, MinGW Release, ANYPS5_NO_SHADER_CACHE=1, ANYPS5_REQUIRE_VULKAN=1), the four tests from the body:

  • main a07e985c8 with only this PR's test changes: 3 of 4 pass. agc_driver_graphics fails with format 36 must be sampled as B10G11R11_UFLOAT and stored as R32_UINT. The new store case passes on main here, so AMD's own B10G11R11_UFLOAT_PACK32 storage write already converts as the hardware does.
  • main merged with this head: 4 of 4 pass, 3 rounds.
  • Khronos validation layer, -V: 4 of 4 pass, 0 VUID- lines. VK_LOADER_DEBUG=layer shows the layer inserted in agc_driver_image_converted_unorm and agc_driver_image_repacked_float.

lavapipe (WSL Ubuntu 24.04, Mesa 25.2.8 with LLVM 20.1.2 as in the Linux CI, GCC 13.3 Release with SPIRV-Tools on), agc_driver_image_converted_unorm. The tree is main d0852defa with #8055, #8884 and #8886 applied; none of them touches image stores.

  • With only this PR's test changes it fails: image_store of R11_G11_B10_FLOAT: texel 6 is 0xfc3f07e0, expected 0xfa3e0fc1. Texels 0 to 5 already match: lavapipe also rounds these fields toward zero, saturates and stores 0 for negatives. Only the NaN row differs. lavapipe writes the canonical quiet NaN in each field (0x7e0, 0x7e0, 0x3f0). The hardware keeps the top bits of the payload and sets the lowest mantissa bit when none of them is set (0x7c1, 0x7c1, 0x3e8).
  • With this PR: 3 of 3 pass.

Two notes:

@ryanc2112

Copy link
Copy Markdown

Tested on Linux / RADV (SteamOS 3.8.28, AMD Radeon RX 570 / Polaris10, Mesa 26.2.5, GCC 16.2.1, Release), this PR (5236bb6) merged onto main 3e91c8e vs main, with ANYPS5_REQUIRE_VULKAN=1 ANYPS5_NO_SHADER_CACHE=1 VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation (loader confirms the layer is inserted).

  • Focused set from the PR description plus agc_driver_image_store_*: 10/10 pass on both, zero VUID- on both.
  • Control: this PR's ImageConvertedUnorm.cpp on unpatched main fails with image_store of R11_G11_B10_FLOAT: texel 0 is 0xffc00000, expected 0xfc000000 (RADV writes the canonical all-ones NaN mantissa), and passes with the PR.
  • All agc_* + texture_format_lookup (855 tests): identical pass/fail set on both, identical validation output (6× VUID-VkWriteDescriptorSet-descriptorType-00337, 2× VUID-vkResetFences-pFences-01123 on both). No regressions observed.

One issue from reading the diff: remapGuestFormat now resolves format 36 to R32_UINT everywhere, and the DCC clear paths derive the clear layout from ResolveTextureFormat (DccMetadata.cpp:529,777,786, ShaderResources.cpp:740). On main format 36 uses the B10G11R11_UFLOAT_PACK32 layout (3 float channels, DccMetadata.cpp:409); with this PR it gets the R32_UINT layout (1 uint channel, :401), which FillDccClear treats as alpha. So Clear1111 fills 0x00000001 instead of 1.0 in each channel, and Clear1110 fills 0. No existing test covers a format-36 DCC clear, which is why the full run is unchanged. Could the DCC clear layout use the native format for 36 (and 43, which looks to have the same gap)?

AI-assisted: yes.

@camezaro-intc

Copy link
Copy Markdown
Contributor Author

Thanks @thuanquang and @ryanc2112 for the thorough review, measurements, and tests across real hardware and lavapipe!

  • PR Description: Corrected the 11-bit saturation limit note from 65504.0 to 65024.0 (0x7bf), and changed Fixes #8282 to Part of #8282 so the issue remains open for fix(agc): round 16-bit float image stores toward zero #8998.
  • DCC Fast Clear Layout: Added DccClearTextureFormat(guestFormat) returning VK_FORMAT_B10G11R11_UFLOAT_PACK32 for formats 36 and 43 (IsRepackedTextureFormat), and updated the clear-format resolution calls in DccMetadata.cpp and ShaderResources.cpp. FillDccClear now receives the native 3-channel layout (Clear1111 and Clear1110 produce 0x781e03c0u, Clear0000 produces 0u) instead of defaulting to single-channel R32_UINT. Added test coverage in packedFloatDccClearTests for both formats 36 and 43 under Clear1111, Clear1110, and Clear0000 with ReadTextureSurface.

All validation tests pass 100% with 0 VUID- validation errors on RX 5700 XT.

@MaxLikesCode

Copy link
Copy Markdown
Contributor

RTX 4090 (Ada) on Windows, head 9e8f18888 merged onto main cecb540a6 (clean). The four tests from the Tested section (agc_driver_image_converted_unorm, agc_driver_image_repacked_float, texture_format_lookup, agc_driver), plus the 8 tests matching dcc for the packed-float DCC clear change:

  • main: 12 of 12 in 3 runs without and 3 with the validation layer.
  • this PR: 12 of 12 in the same 6 runs, including the new R11_G11_B10_FLOAT store and sample checks in agc_driver_image_converted_unorm.
  • No run on either side logs a VUID-.

NVIDIA GeForce RTX 4090, driver 617.42, Windows 11 Pro 26200, WinLibs GCC 15.2.0 r7, Release, BUILD_TESTING=ON, ANYPS5_REQUIRE_VULKAN=1, ANYPS5_NO_SHADER_CACHE=1, ctest --test-dir build -R <tests> -V. Validation runs add VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation (Vulkan-ValidationLayers vulkan-sdk-1.4.363.0, implicit layers disabled); the loader log shows the layer inserted in every Vulkan test process, and no log has was not found but was requested by env var VK_INSTANCE_LAYERS.

AI-assisted: yes (Claude Code)

@oneandonlydean

Copy link
Copy Markdown
Collaborator

@camezaro-intc one integration issue is still there after the rebase: Format11_11_10Float is now classified as Uint for packing, but colorCompareReference accepts only Float and throws for format 36. Could you keep the format 36 emulated comparison path working when you compose the packing change, and run agc_driver_emulated_color_compare and agc_driver_emulated_color_compare_srgb_decode alongside agc_driver_image_repacked_float? This is from reading the source on the current head; we haven't done a new GPU run.

@camezaro-intc
camezaro-intc force-pushed the format11-11-10-float-stores branch from 8d5f750 to 68fc51f Compare October 25, 2026 03:32
@camezaro-intc

Copy link
Copy Markdown
Contributor Author

@oneandonlydean Thanks for catching that integration issue.

I've composed the fix into the packing change: colorCompareReference() in core/shader/recompiler/Optimization/src/ResourceMaterializer.cpp now explicitly includes IrBufferFormat::Format11_11_10Float (format 36) alongside IrTextureNumericClass::Float, preserving the emulated comparison path (EmulatedCompare::ReferenceZero) while maintaining the Uint repacking path for storage stores.

I ran the requested test suite with Vulkan validation layers enabled (ANYPS5_REQUIRE_VULKAN=1, ANYPS5_NO_SHADER_CACHE=1, VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation):

  • �gc_driver_emulated_color_compare: Passed (format 36 comparison now returns zero as expected)
  • �gc_driver_emulated_color_compare_srgb_decode: Passed
  • �gc_driver_image_repacked_float: Passed
  • �gc_driver_image_converted_unorm: Passed
  • 0 Vulkan validation errors (VUID-)

The branch has been updated and force-pushed. Could you please revalidate on your side whenever convenient?

This branch has not been deployed

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

Labels

agc libSceAgc* shader core/shader

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants