Skip to content

feat(agc): sample non-sRGB textures through FORCE_DEGAMMA samplers as sRGB views - #4487

Merged
oneandonlydean merged 3 commits into
boykopovar:mainfrom
Pipodi:feat/agc-forced-srgb-views
Oct 14, 2026
Merged

oneandonlydean merged 3 commits into
boykopovar:mainfrom
Pipodi:feat/agc-forced-srgb-views

Conversation

@Pipodi

@Pipodi Pipodi commented Oct 12, 2026

Copy link
Copy Markdown
Contributor

What

A guest sampler with FORCE_DEGAMMA makes the hardware decode the texels of a non-sRGB 8-bit texture as sRGB. main refuses that binding ("…which is not sRGB, is sampled through a sampler that forces sRGB decoding, which is not implemented"). With this change the binding samples an sRGB view of the same image:

  • Views. Texture::SrgbView creates the view on first use, for the range the binding needs (full, first layer or base level). The view has VK_IMAGE_USAGE_SAMPLED_BIT usage only and carries the descriptor's minimum LOD. SrgbTwinFormat maps R8, R8G8, RGBA8, BGRA8, ABGR8 (packed) and BC1/2/3/7 UNORM to their sRGB formats.
  • Images. Snapshot images whose format has an sRGB twin are created with VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT, so the view is valid. Textures viewed from storage images are already mutable.
  • Binding. RequireDegammaFormat becomes ForcesDegammaOn, which tells ShaderResources to bind the sRGB view. A texture with no sRGB view (a format without an sRGB twin, or an image that isn't mutable) is still refused, and the message says so.

Tested

Windows 11, RTX 4090.

  • agc_driver_image_sample_force_degamma. The case that expected a rejection for 8_8_8_8_UNORM now checks:

    • through a FORCE_DEGAMMA sampler with point filtering, the texels decode as sRGB and match the same bytes sampled as 8_8_8_8_SRGB;
    • with bilinear filtering they also match 8_8_8_8_SRGB;
    • without FORCE_DEGAMMA, the same texture still samples the raw UNORM values;
    • 32_FLOAT, which has no sRGB twin, is still refused with the new message.

    On main the new test fails with the old refusal.

  • Validation layer (VK_LAYER_KHRONOS_validation, SDK 1.4.363.0): the test passes with no errors or warnings. To check that the layer covers the change, I built it once without VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT on the image. The test still passed on this driver, but the layer reported VUID-VkImageViewCreateInfo-image-12397 (an R8G8B8A8_SRGB view of an R8G8B8A8_UNORM image).

  • Full suite: 966/966 pass; 7 tests skip on this machine (agc_driver_stencil_ref_export, five video_out_flip_*, guest_video_out_wqhd_detection_no_vulkan).

  • Ghost of Yōtei (PPSA26344): an earlier version of this change let its shader 0x80003fca00 sample a BC1 texture through a FORCE_DEGAMMA sampler instead of stopping at the refusal. That version didn't create the image as mutable, which this one fixes.

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 (NotImplemented_nid_no_patch); silent stubs are listed in TechnicalDebt (the remaining case is a refusal)
  • No notes, investigation .md files or images added to the repository
  • New third-party code is a submodule built from source (none)
  • Generic behaviour, not specific to one title
  • Depends on: none
  • AI-assisted: yes

🤖 Generated with Claude Code

… sRGB views

A sampler with FORCE_DEGAMMA decodes the texels of a non-sRGB 8-bit texture
as sRGB. Such a binding was refused; it now samples an sRGB view of the same
image. Snapshot images whose format has an sRGB twin (R8, R8G8, RGBA8, BGRA8,
ABGR8 packed, BC1/2/3/7 UNORM) are created with MUTABLE_FORMAT, and storage
images are already mutable. The view is made on first use for the full,
first-layer or base-level range, with sampled usage only and the descriptor's
minimum LOD. A format without an sRGB twin is still refused.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions github-actions Bot added the agc libSceAgc* label Oct 12, 2026
@oneandonlydean oneandonlydean self-assigned this Oct 12, 2026
@oneandonlydean

Copy link
Copy Markdown
Collaborator

SrgbTwinFormat maps VK_FORMAT_R8_UNORM and VK_FORMAT_R8G8_UNORM to their sRGB formats without checking that the device can sample them (the new switch in Texture.cpp). Main already has devices that can't: srgbDecodeFormats in TextureFormat.cpp samples the UNORM format and decodes in the shader there, so on those the forced view would be created with an unsupported format. Please keep the refusal for these two where the device lacks the format, or leave them out until a title needs them.

Has this version been run on PPSA26344? The description says only an earlier one was.

@Tamalero

Copy link
Copy Markdown
Contributor

Another data point: High on Life (PPSA15388) stops on this error in its home base (a later save):

AGC graphics: a texture of guest format 1, which is not sRGB, is sampled through a sampler that forces sRGB decoding, which is not implemented

With this PR cherry-picked onto my stack (main 3377986a plus #1077, #425, #3202 and #1418), it gets past that stop and stays in gameplay. The agc_ suite has no new failures (Linux, RTX 4090). Details on #4736.

Tested and written by Claude (AI assistant) on a contributor's machine.

@xXPBSXx

xXPBSXx commented Oct 13, 2026

Copy link
Copy Markdown
Contributor

Windows test (MinGW GCC 15.2, Release, Windows 10, RTX 4080 SUPER). Built on main 88107b7de together with thirteen other open GPU PRs (their own commits cherry-picked, no merge commits), so only the tests that belong to this PR say something about it:

  • tests/execution/ImageSampleForceDegamma.cpp (agc_driver_image_sample_force_degamma): 3 of 3 runs passed.

Not tested: no game run. The batch was built once, not per PR; nothing failed, so no bisect was needed.

AI-assisted (Claude Code).

… in the shader

SrgbTwinFormat mapped R8_UNORM and R8G8_UNORM to R8_SRGB and R8G8_SRGB
without asking the device. Where 8_SRGB or 8_8_SRGB is decoded in the
shader (context.srgbDecodeFormats: the device cannot sample the sRGB
format, or APS5_SRGB_SHADER_DECODE=1), the forced view would have been
created with a format the device cannot sample. Those two formats now
get no twin there, so a FORCE_DEGAMMA sampler on them keeps the refusal.
The image is no longer created MUTABLE_FORMAT either.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Pipodi

Pipodi commented Oct 13, 2026

Copy link
Copy Markdown
Contributor Author

@oneandonlydean thanks, you're right. SrgbTwinFormat now takes the context and returns no twin for R8_UNORM / R8G8_UNORM when the matching bit is set in srgbDecodeFormats. That covers both a device that can't sample R8_SRGB / R8G8_SRGB and APS5_SRGB_SHADER_DECODE=1. On those devices the image isn't created MUTABLE_FORMAT any more, and a FORCE_DEGAMMA sampler on such a texture keeps the existing refusal. The other formats are unchanged. agc_driver_graphics checks the twin with no bits, with 8_8 only, and with both.

On PPSA26344: no, this exact head hasn't run there. Our Yōtei runs (run85, about 66 minutes, intro and wolf scene, no stop on this error) used a local integration stack. It has the same forced-sRGB change plus the MUTABLE_FORMAT fix that's now in the PR, but on an older base with other unmerged work. So it's evidence for the change, not a run of this head. Tamalero's High on Life result above is on their own stack too.

Tests
  • Windows NVIDIA, Release, BUILD_TESTING=ON: 966/966 pass, 7 skipped (stencil ref export, video-out flip tests)
  • agc_driver_graphics (new twin checks) and agc_driver_image_sample_force_degamma pass.
  • tools/check_conventions.py --base origin/main passes.

Tested and written by Claude (AI assistant) on a contributor's machine.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@oneandonlydean
oneandonlydean merged commit afc8541 into boykopovar:main Oct 14, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agc libSceAgc*

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants