Skip to content

fix(shader): emulate sRGB sampling when unsupported - #5371

Open
likecrank-dotcom wants to merge 1 commit into
boykopovar:mainfrom
likecrank-dotcom:fix/agc-srgb-sampling-fallback
Open

likecrank-dotcom wants to merge 1 commit into
boykopovar:mainfrom
likecrank-dotcom:fix/agc-srgb-sampling-fallback

Conversation

@likecrank-dotcom

Copy link
Copy Markdown

What

Issue #3751 reports sampled R8_SRGB/R8G8_SRGB images failing on devices that cannot sample those Vulkan formats. This adds a shader fallback for direct, single-mip 2D images: fetch texels through the UNORM view, decode each texel from sRGB, then apply point or bilinear filtering. The shader receives the sampler state through runtime metadata in registration modules or specialization constants in specialized modules.

Unsupported shapes and sampler modes still fail with explicit diagnostics; gathers and bindless image tables remain unsupported. Updated the old sRGB load test so it no longer expects ordinary sampling to fail when the fallback is enabled. The separate fallback test checks R8 and RG8 point and bilinear results against a per-texel decode-and-filter oracle.

Tested

Windows 11 Pro, WinLibs MinGW GCC 15.2.0, CMake 4.4.4, NVIDIA GeForce RTX 5060 Ti (driver 617.14).

  • Built the shader and AGC test targets.
  • Focused CTest group: agc_shader_memory, agc_driver_image_sample_force_degamma, agc_driver_image_srgb_load, agc_driver_image_sample_srgb_fallback, and agc_driver_emulated_color_compare_srgb_decode: 5/5 passed, repeated three times (15 successful executions).
  • tools/check_conventions.py --base origin/main --head HEAD and git diff --check origin/main...HEAD passed.
  • No Ghost of Yōtei package was available; title runtime and PS5 gfx1013 equivalence were not tested. The decode-before-filter order follows the measurements cited in issue #3751.

Checklist

  • Based on current main; no other open PR implements the same functions
  • One topic per PR; follow-ups go in a new PR
  • No comments in code except technical debt
  • Unimplemented paths throw; gathers and unsupported fallback cases retain explicit diagnostics
  • No investigation notes or screenshots added to the repository
  • New third-party code is a submodule built from source: n/a
  • Generic behavior, not specific to one title
  • Depends on: none
  • Unblocks: none claimed; title runtime was not available
  • GPUs tested: NVIDIA GeForce RTX 5060 Ti, driver 617.14, Windows 11 Pro
  • AI-assisted: yes (OpenAI Codex); the human author remains responsible for review and submission

AI assistance: OpenAI Codex (AI) implemented and validated this change. The human author remains responsible for review and submission.
@coltken95

Copy link
Copy Markdown

Tested on Linux x86-64 (Release build, lavapipe / llvmpipe LLVM 20.1.2), with 273e269 merged into main 18c438b:

  • With the PR: all eight tests in the PR's targets pass, including the new agc_driver_image_sample_srgb_fallback, plus agc_driver_image_srgb_load and agc_driver_image_sample_force_degamma.
  • The other seven also pass on main; the new fallback test only exists with the PR, so there is no failing-on-main comparison.

AI-assisted: yes (Claude Code)

@adriadam10 adriadam10 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Measured on RDNA2 (gfx1035) with tools/hw-oracle: image_sample_lz of 8_SRGB and 8_8_SRGB with point filtering returns the bf16 SrgbToLinear table value bit for bit. That holds under wrap, clamp-to-edge and all three clamp-to-border colours, out-of-range coordinates included. Bilinear decodes before filtering and stays within 1.1e-3 of a decode-then-filter model (8-bit HW weights). So the fallback's semantics match the hardware. Build and the AgcDriver/Agc tests pass on the PR head. The PR needs to be reworked on current main before it can go in:

  • Conflicts with main that aren't mechanical. #4475 replaced ImageResource::indirectRoot/NoIndirectImage with image tables (NoTable), and the runtime image metadata block this PR extends in DescriptorBindingBuilder.cpp:448-450 no longer exists. The new table path has to decide what happens to an sRGB table entry (still zero-read, or refused).
  • main now turns unsupported images into rejectImage(PoisonReason::SrgbUnsupported, ...) in decodeImageDescriptor instead of throwing. The throws in emulatedSrgbSampleState (ResourceMaterializer.cpp:587-627) should follow that model, so an unsupported shape behaves the same way as on main.
  • The execution test only exercises clamp-to-edge without offsets (SamplerDescriptor word0 0x92). EmitEmulatedSrgbSample also implements wrap, clamp-to-border (transparent black, opaque black, white) and texel offsets, and none of these run. Please add rows with coordinates outside [0, 1] for each address mode and one with an offset. The point rows can also compare against SrgbToLinear bit for bit instead of within 0.005, because the hardware does.

This was referenced Oct 15, 2026

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* build docs needs rebase Conflicts with main, rebase needed shader core/shader

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants