Skip to content

fix(agc): keep sRGB storage images in their UNORM twin on every driver - #10859

Merged
oneandonlydean merged 1 commit into
boykopovar:mainfrom
maximilianfv:fix/agc-srgb-storage-unorm-twin
Nov 2, 2026
Merged

oneandonlydean merged 1 commit into
boykopovar:mainfrom
maximilianfv:fix/agc-srgb-storage-unorm-twin

Conversation

@maximilianfv

Copy link
Copy Markdown
Contributor

What

StorageFormatOrUndefined (libSceAgcDriver/Graphics/src/Texture.cpp) kept an 8-bit sRGB texture in its sRGB format for storage whenever the driver reported VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT for it, and used the UNORM twin only as a fallback. The Vulkan spec applies a linear-to-sRGB encode when a shader stores to an sRGB storage image (Texel Encode), so a guest store of raw code 8 lands as 49: agc_driver_image_srgb_sample_copy and its forced variant sample the decode of 49. agc_driver_recover_srgb_allocation fails differently: CanSrgbExpandFrom requires the storage format to equal the sampled UNORM format, so it refuses the sRGB storage surface as the source of an expansion copy.

Drivers that report no storage support for these formats took the UNORM fallback and never hit this. MoltenVK 1.4.2 reports it for R8_SRGB, R8G8_SRGB, R8G8B8A8_SRGB, B8G8R8A8_SRGB and A8B8G8R8_SRGB_PACK32, and is conformant in doing so; the bug is that the code relied on the driver lacking sRGB storage.

The five 8-bit sRGB formats now always use their UNORM twin for storage, before the sRGB format itself is checked. Packed formats keep their branch first. With no platform guard, drivers without sRGB storage take the same path as before. A driver that supports sRGB storage but not storage for the UNORM twin now gets VK_FORMAT_UNDEFINED instead of the sRGB format.

Prior art, credited with Co-authored-by trailers:

Tested

main does not build on macOS by itself. I tested on mugurc's macOS series (ci/macos-series-2, 27e9689) merged with main at 522e32e, plus the other open macOS fixes (#10419 build parts, #10540, #10562, #10641) and some unopened test fixes. Only this change differed between the two sets of runs.

Setup: Apple M1 Pro, macOS 27.0.1, x86_64 build under Rosetta 2, Vulkan through MoltenVK from the LunarG Vulkan SDK 1.4.363. Every run used ANYPS5_REQUIRE_VULKAN=1 ANYPS5_NO_SHADER_CACHE=1 VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation with ctest -R '^(agc_driver_.*srgb.*|agc_driver_image_.*)$' -E 'audio_in|voice' -V (68 tests), three runs with and three without this change.

  • Without: 64/68 in every run. agc_driver_image_srgb_sample_copy, agc_driver_image_srgb_sample_copy_forced and agc_driver_recover_srgb_allocation fail. agc_driver_image_plane_bias_on_single_level_volume also fails, which is unrelated and covered by test(agc): skip plane-bias reduction cases without min/max sampler reduction #9125.
  • With: 67/68 in every run. Only agc_driver_image_plane_bias_on_single_level_volume fails.
  • Validation: 123 Validation Error lines without and 123 with, with the same VUID set (VUID-VkDeviceCreateInfo-pProperties-04451 and others, already there before this change). Neither log contains was not found but was requested by env var VK_INSTANCE_LAYERS.
  • On MoltenVK the change also reaches the multisample paths (MultisampleTarget.cpp storage format and sameStorageForm, and StorageSrgbTwin in MultisampleRetirement.cpp no longer skips). Same setup, ctest -R '^(agc_.*multisample.*|agc_driver_.*msaa.*|image_msaa_load|agc_driver_srgb8_color_target|agc_driver_emulated_color_compare_srgb_decode|agc_driver_.*srgb.*)$' (36 tests), three runs each way: 30/36 without, 33/36 with. The three sRGB tests above are the only difference. agc_driver_multisample_retirement, agc_driver_native_multisample_depth and agc_driver_sample_mask_multisample fail both ways with the same message. agc_driver_multisample_retirement stops before StorageSrgbTwin ("the device cannot write the multisampled color target's format as a storage image at its sample count", covered by test(agc): skip the MSAA retirement storage promotion without shaderStorageImageMultisample #8604), so that check is still not exercised on this host. 63 Validation Error lines both ways, same VUID set.
  • Not run on Linux or Windows.

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 under Silent stubs in their library's technical debt file
  • No notes, investigation .md files or images added to the repository (attach them to this PR)
  • New third-party code is a submodule built from source
  • Generic behaviour, not specific to one title
  • Depends on: none
  • Fixes: none
  • Unblocks: none
  • GPUs tested: Apple M1 Pro, MoltenVK (Vulkan SDK 1.4.363), macOS 27.0.1
  • AI-assisted: yes

🤖 Generated with Claude Code

StorageFormatOrUndefined kept an 8-bit sRGB storage texture in its sRGB
format whenever the driver reported storage support for it, and fell
back to the UNORM twin only otherwise. Shader stores to an sRGB storage
image are sRGB-encoded, so a guest store of a raw code landed encoded.
MoltenVK 1.4.2 reports storage support for these formats:
agc_driver_image_srgb_sample_copy and its forced variant sampled the
encoded value, and agc_driver_recover_srgb_allocation failed because
CanSrgbExpandFrom refused a storage format that differs from the
sampled UNORM format. The five 8-bit sRGB formats now always use their
UNORM twin for storage.

Co-authored-by: Ycaro Gabriel <280482597+ycarogabriel-lgtm@users.noreply.github.com>
Co-authored-by: Himansh Raj <67262056+iamthehimansh@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

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

Reviewed exact head 290f9eed01224dd071752c4ad0cd0657d772602b against current main.

The five 8-bit sRGB formats now select their UNORM twin before querying the sRGB format's storage support, while the existing packed-format branch remains first. This matches Vulkan's image-write rule: stores to sRGB formats apply linear-to-sRGB encoding, whereas the guest storage path needs the raw encoded byte values. Using the UNORM twin avoids the extra encode and also lets the sRGB expansion path recognize the source format. If the twin itself lacks storage support, returning VK_FORMAT_UNDEFINED is preferable to using an sRGB view with different write semantics. The Vulkan spec documents this in Texel Encode.

The PR reports same-composition MoltenVK controls with three runs per side: the three targeted regressions fail without the change and pass with it; the unrelated #9125 failure and the same validation VUID set remain on both sides. I did not independently run the GPU tests. Hosted eligibility, conventions, intake, labels and report checks pass; product jobs are skipped by repository policy. Linux and Windows are not reported as tested. I found no blocking issue in the format-selection change.

AI-assisted review: yes.

@github-actions

github-actions Bot commented Oct 25, 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 1368 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 1395 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 5609 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 6187 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 6188 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 6192 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 6197 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 6209 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 6280 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 6481 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 6987 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 6989 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 6995 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 7002 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 7085 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 7256 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 7514 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 7604 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 7642 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 8246 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 8484 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 8707 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 9508 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 9884 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 10064 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 10193 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 10249 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 10256 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 10743 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 11485 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 12746 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 12921 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 13251 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 13796 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 13863 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 13920 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 13928 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 13929 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 14261 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 14262 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 14302 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 14311 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 14943 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp

@ycbuzi

ycbuzi commented Oct 25, 2026

Copy link
Copy Markdown
Contributor

Windows check on three non-Apple drivers. 290f9eed01 merged onto main 63a863d3b0 (8512095280, clean), Windows 11 Home 10.0.26200, WinLibs MinGW-w64 GCC 15.2.0 (ucrt-posix-seh r7), Release, ANYPS5_REQUIRE_VULKAN=1 ANYPS5_NO_SHADER_CACHE=1, one device at a time with ANYPS5_GPU:

GPU this PR main
NVIDIA GeForce RTX 4070 SUPER (616.92) 3/3 pass 3/3 pass
NVIDIA GeForce GTX 1650 SUPER (616.92) 3/3 pass 3/3 pass
AMD Radeon(TM) Graphics, RDNA2 iGPU (32.0.21030.2001) 3/3 pass 3/3 pass

The three are agc_driver_image_srgb_sample_copy, agc_driver_image_srgb_sample_copy_forced and agc_driver_recover_srgb_allocation. So dropping the platform guard changes nothing on these drivers. Not run: the validation layer, MoltenVK. AI-assisted: yes (Claude Code)

@oneandonlydean oneandonlydean self-assigned this Oct 26, 2026
iamthehimansh added a commit to iamthehimansh/AnyPS5 that referenced this pull request Oct 26, 2026
…0859

imellag's earlier boykopovar#10676 already makes PendingList::published build with
Apple's libc++, and maximilianfv's earlier boykopovar#10859 keeps sRGB storage images
in their UNORM twin on every driver, which covers MoltenVK. Drop both hunks
here and depend on those PRs.

@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 second Apple GPU, on a main-based tree, with both MoltenVK builds.

Machine: Apple M2 Max, macOS 27.2, x86_64 Release build under Rosetta 2.
Tree: main b986c11a34 + the open macOS PRs needed to build and open a device (#10366, #7631, #10659, #10660, #11249, #11358, #10669, #10552, #7804, #10676, #11447, #11437, #11554, #11705) + this PR at 290f9eed01 (clean merge). Control: the same tree without this PR. ANYPS5_NO_SHADER_CACHE=1, -j1 --timeout 30.
Drivers: MoltenVK 1.4.2 (LunarG SDK 1.4.363.0) and MoltenVK main + SPIRV-Cross #2704.

ctest -R srgb (7 tests) Without With (3 runs)
MoltenVK 1.4.2 image_srgb_sample_copy and _forced fail 7/7 pass (1 skip, see below), 3/3
MoltenVK main + #2704 same 2 fail same, 3/3
  • Full ^agc suite, 1037 tests, MoltenVK 1.4.2: 41 failures without, 39 with. The two sRGB tests are the only difference, so nothing new fails.
  • Validation layer (VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation, SDK 1.4.363.0, loader output shows it inserted) on the same 7 tests: the same single VUID on both sides, VUID-VkPipelineColorBlendStateCreateInfo-pAttachments-00605 ×2 from agc_driver_srgb8_color_target, which this PR does not touch. No new VUID-.
  • agc_driver_recover_srgb_allocation cannot be checked on a main-based macOS tree yet: it runs from agc_driver_sampled_cache_budget_tests, which loads libvulkan.so.1, so it reports "skipped, no usable Vulkan device: AGC graphics: cannot load Vulkan" (and fails with that message under ANYPS5_REQUIRE_VULKAN=1) with and without this PR. Your 64→67 result for it came from the series tree with your extra test fixes; that file is one of the ones #10920 touches.

GPUs tested: Apple M2 Max (MoltenVK 1.4.2 and MoltenVK main + #2704)

Written with AI assistance (Claude Code). I ran the builds and tests above on my machine.

@TechLevelZero

Copy link
Copy Markdown
Contributor

✅ NVIDIA GPU test: passed

PR head 290f9ee merged onto main bb04a4f · tested 2026-10-30 01:17 UTC · 24 min

GPU NVIDIA RTX 2000 Ada Generation, driver 595.99.02, Vulkan 1.4.329
Host Ubuntu 26.04.1 LTS, kernel 7.0.0-38-generic, container ubuntu:24.04
Logs build and test logs for this run
Build ✅ passed (Release, -DANYPS5_ENABLE_SPIRV_TOOLS=ON)
Tests ✅ 2,235 passed · 3 failed (0 new, 3 also fail on main) · 40 skipped (ANYPS5_REQUIRE_VULKAN=1)
Test setup CPU-only tests without a GPU; GPU tests (and any CPU-only test that failed or skipped without one) once on the GPU with VK_LAYER_KHRONOS_validation and ANYPS5_NO_SHADER_CACHE=1; main ran the same way
Test selection 2,278 of 2,918 tests run: the ones this change can reach, chosen by tools/select_tests.py from main's build graph
Vulkan validation ✅ no new validation IDs vs main (856 tests run on the GPU)
Slow tests (>30 s, GPU tests timed with validation layers) ⚠️ agc_driver_bda_device 60.5 s
Failing on main too (3, not counted against this PR)
agc_compute_pipeline_inspection
guest_mmap_executable
guest_socket_options_multicast
Passed on retry (1, failed in the parallel run, passed when re-run with a 360 s timeout; not counted against this PR)
agc_driver_job_manager_compute_capacity: Failed in the parallel run; also passed only on retry in 64 other runs in the last 7 days
Validation IDs already present on main (4 IDs in 397 tests)
VUID-VkDeviceCreateInfo-pNext-pNext (397 tests): agc_compute_pipeline_replay, agc_driver, agc_driver_address_passes_draw_transitions, agc_driver_address_passes_targets_split, agc_driver_alias_copy_label, agc_driver_array_layer_target, agc_driver_array_layer_target_cpu, agc_driver_bda_anchor_reads, and 389 more
VUID-vkCmdCopyImage-srcImage-01548 (11 tests): agc_driver_depth_clear_hle, agc_driver_depth_plane_buffer_memory, agc_driver_depth_plane_cpu_write_after_memo, agc_driver_depth_plane_cpu_write_after_page_unwatch, agc_driver_depth_plane_cpu_write_after_partial_unwatch, agc_driver_depth_plane_partial_store, agc_driver_depth_plane_partial_store_unimported, agc_driver_depth_storage_dispatch, and 3 more
VUID-vkCmdCopyImage-srcImage-01551 (11 tests): agc_driver_depth_clear_hle, agc_driver_depth_plane_buffer_memory, agc_driver_depth_plane_cpu_write_after_memo, agc_driver_depth_plane_cpu_write_after_page_unwatch, agc_driver_depth_plane_cpu_write_after_partial_unwatch, agc_driver_depth_plane_partial_store, agc_driver_depth_plane_partial_store_unimported, agc_driver_depth_storage_dispatch, and 3 more
VUID-VkPipelineColorBlendStateCreateInfo-pAttachments-00605 (2 tests): agc_driver_prepared_exports, agc_driver_srgb8_color_target
Skipped (40)
agc_driver_bda_reads_shadowed_results: skipped, the device reports watched host memory written when it imports or reads it
agc_driver_bda_reads_shadowed_results_per_build: skipped, the device reports watched host memory written when it imports or reads it
agc_driver_msaa_dcc_compared_import_2: skipped, the device reports host imports that keep write protection, so the write-watch probe compares none of them
agc_driver_msaa_dcc_compared_import_4: skipped, the device reports host imports that keep write protection, so the write-watch probe compares none of them
agc_driver_msaa_dcc_compared_import_8: skipped, the device reports host imports that keep write protection, so the write-watch probe compares none of them
agc_driver_sample_order_grid_reference: skipped, the device does not keep depth drawn at custom sample locations at those locations, even after a transition that names them: the composite of uniform renders holds the guest's depth in 0 of 3005 sloped samples, so no path can be compared with it bit for bit
agc_driver_sparse_dma_buf_import: skipped, host imports are unavailable: /dev/udmabuf is not accessible
agc_driver_stencil_ref_export: skipped, the device lacks VK_EXT_shader_stencil_export
agc_host_import_sparse: skipped, host imports are unavailable: /dev/udmabuf is not accessible
agc_import_settle_initial_dcc: skipped, the device has no deferred settle of host imports: imports under 1 MiB wait for one only on Windows
agc_unit_shadow_completion_store: skipped, the device reports watched host memory written when it imports or reads it
guest_http_uri_locale: 
guest_net_ctl: skipped, the host has no IPv4 address
guest_video_out_color_space: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
guest_video_out_hdr: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
guest_video_out_high_frame_rate: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
guest_video_out_output_mode: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
guest_video_out_resolution_status: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
guest_video_out_wqhd_detection: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
video_out_flip_controls: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_out_flip_cpuflip: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_out_flip_cpuflip_in_order: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_out_flip_eop: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_out_flip_eop_aftergpu: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_out_flip_eop_main: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_out_flip_fresh: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_out_flip_labels: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not
Reproduce
git fetch origin 290f9eed01224dd071752c4ad0cd0657d772602b bb04a4f1ea0175e9e4f149f0359a764d62ff3296
git checkout bb04a4f1ea0175e9e4f149f0359a764d62ff3296 && git merge --no-ff 290f9eed01224dd071752c4ad0cd0657d772602b
git submodule update --init --recursive
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=ON -DANYPS5_ENABLE_SPIRV_TOOLS=ON
cmake --build build && cmake --build build --target libs
VK_DRIVER_FILES=/nonexistent/icd.json ctest --test-dir build -E '^(agc|shader|recompiler|videoout|video_out|guest_video_out|vulkan)|gpu' --timeout 120 --parallel 32 --output-on-failure
ANYPS5_REQUIRE_VULKAN=1 ANYPS5_NO_SHADER_CACHE=1 VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation \
  ctest --test-dir build -R '^(agc|shader|recompiler|videoout|video_out|guest_video_out|vulkan)|gpu' --timeout 120 --parallel 4 --output-on-failure
# failures are then re-run alone: --timeout 360 --parallel 2; new validation IDs: the test alone, twice, --parallel 1

Automated build and test on a contributor's NVIDIA machine; it does not replace upstream CI. A new comment is posted for each new push. Full logs.

@oneandonlydean
oneandonlydean merged commit adfee10 into boykopovar:main Nov 2, 2026
11 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.

6 participants