Skip to content

fix(agc): fix image table variant ties and the full walk over borrowers - #16263

Open
Capmare wants to merge 3 commits into
boykopovar:mainfrom
Capmare:fix/agc-variant-borrowers
Open

Capmare wants to merge 3 commits into
boykopovar:mainfrom
Capmare:fix/agc-variant-borrowers

Conversation

@Capmare

@Capmare Capmare commented Nov 6, 2026 •

Copy link
Copy Markdown
Contributor

What

Two bugs in the dynamic-resolution variant substitution from my #10256. A table entry can borrow the texture of another variant of its surface. Neither fix changes the rule that keeps such a table out of the reuse slots.

  1. Tie in the largest-accessible choice. The rule compared guest bytes only. Linear pitch aligns to 256 bytes, so a 32-wide and a 64-wide variant both take 1024 bytes, and the first one in the table won. The larger extent now wins a tie. RunLargest lists the wide variant first, so it never reached the tie.
  2. Full walk over a set with a borrower. A borrower took its own texture slot behind the other entries, and revalidateFull looked it up by its own extent. That walk could never pass. With the borrower ahead of another entry, the slot order failed it. With the borrower last, the lookup created the texture that substitution avoids and then failed it. A borrower now shares the slot of its representative. The walk repeats the choice, fails when it moved, and skips the borrowers. The own-image refresh (refreshOwnObjects) skips them too. Without that, a set with a borrower answered Uncached there at once, because two entries share one slot, and always took the full walk.

Left as it is:

  • The fast proof does not repeat the choice. main has the same gap, and the debt entry now states it.

This PR claims no change in speed. I found both bugs in the code and with tests, not from a wrong picture on a title. In 13 saved Wolverine runs, 130 surfaces are logged (122 largest accessible, 6 newest write, 2 active depth surface). The tie rule changes the chosen extent on none of them. The refreshOwnObjects skip has no test of its own: a scenario that reaches it needs a tiled surface with a pending alias, like OwnRefreshRepackAlias, and I could not build one cheaply. A hand-built table without a borrower also failed to reach it.

tools/pr_overlap.py reports #15563 (the walk loop and the representativeSources line) and #15710 (debt entry, line 341). It could not compare the other PRs it lists, so I searched the diffs of all 62 reported PRs for the variant code and the walk line. Only #15563 and #15710 touch the variant code. #10894, #11444 and #15563 also edit the walk's lookup line. None of them has the tie rule or skips borrowers in the walk. I will rebase on whichever lands first.

Tested

Rocky Linux 10.2 (kernel 6.12), i7-14700K, RTX 4070 SUPER, NVIDIA 615.71.10, Release. main c36ab99 and this branch (head c692bfd) on it, from the same machine and GPU. "Validation" means ctest -V with VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation, ANYPS5_NO_SHADER_CACHE=1 and ANYPS5_REQUIRE_VULKAN=1.

Tests main this branch
-R '^agc_driver_image_table', validation 7 of 8 pass 7 of 8 pass
-R '^agc_driver', validation 957 of 961 pass 957 of 961 pass
Full suite, ANYPS5_REQUIRE_VULKAN=1 only, run before the last commit (809d1f3) 4134 of 4140 pass 4134 of 4140 pass

Both sides fail the same tests:

  • Validation: agc_driver_division, agc_driver_f32_denormal_flush, agc_driver_image_table, agc_driver_mullit_f32_denormal_modes. agc_driver_image_table fails only because its regex catches VUID-VkDeviceCreateInfo-pNext-pNext, and the layer here is older than the driver.
  • Full suite: agc_driver_division, agc_driver_f32_denormal_flush, agc_driver_mullit_f32_denormal_modes, avplayer_http_patched_modules, ngs2_filter, vector_constant_factor_tininess.

The VUID- counts in the two ^agc_driver logs are identical:

2088 VUID-VkDeviceCreateInfo-pNext-pNext
  82 VUID-VkShaderModuleCreateInfo-pCode-08741
  82 VUID-VkShaderModuleCreateInfo-pCode-08739
  82 VUID-VkShaderModuleCreateInfo-pCode-08737
  18 VUID-VkPipelineColorBlendStateCreateInfo-pAttachments-00605
  14 VUID-VkPipelineShaderStageCreateInfo-pSpecializationInfo-06849
  14 VUID-VkPipelineShaderStageCreateInfo-module-parameter

Neither log reports was not found but was requested by env var VK_INSTANCE_LAYERS, apart from ctest printing its own regex.

agc_driver_image_table_variants also passes under the same validation settings on Intel RPL-S and on llvmpipe, both Mesa 25.2.7, selected with VK_DRIVER_FILES.

Negative controls of agc_driver_image_table_variants, run on the previous base 3a2cd3d with the final test:

Code The test stops with
main with the same guest bytes, the narrow variant ahead of the wide one did not borrow the wide one
Tie rule only a set over two surfaces and a borrowing entry holds 3 textures
Everything except the borrower skip in the walk the full walk looked up the own extent of a borrowing entry
Everything except the repeated choice in the walk a set whose borrowing entry moved to another representative proved current
Everything except the tie rule with the same guest bytes, the narrow variant ahead of the wide one did not borrow the wide one

The walk on main, with the tie rule added and the slot count check taken out of the test:

Table order The test stops with
Borrower first the full walk over a table with a borrowing entry failed
Borrower last the full walk looked up the own extent of a borrowing entry

This branch has not run on a title. A wider local branch with the same tie rule and slot sharing ran Marvel's Wolverine (PPSA03671) twice for about 125 presents on the RTX 4070 SUPER, with variant tables active, and logged no refusal or crash.

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: NVIDIA RTX 4070 SUPER, 615.71.10, Rocky Linux 10.2 (all tests above); Intel RPL-S, Mesa 25.2.7, and llvmpipe, Mesa 25.2.7, Rocky Linux 10.2 (agc_driver_image_table_variants only)
  • AI-assisted: yes

…uest bytes

The largest-accessible rule compared guest bytes only. Linear pitch aligns
to 256 bytes, so a 32-wide and a 64-wide variant both take 1024 bytes, and the
first one in the table won. The narrow variant then served both entries.
A borrowing entry took a texture slot of its own behind the other entries, and
the full walk of a cached set looked it up by its own extent. That walk could
never pass: the slot order failed it, or the lookup created the texture that
substitution avoids and then failed it.

A borrowing entry now shares the slot of its representative. The walk repeats
the choice, fails when it moved, and skips the borrowers.
@JJenkx

JJenkx commented Nov 6, 2026

Copy link
Copy Markdown
Contributor

Windows check of head 809d1f3f93, merged onto main 87448b3c91 (e03fe59dc2, clean merge).

Setup: Windows 11 Enterprise 22621, WinLibs GCC 15.2 UCRT, Release, Radeon RX 6700 XT, AMD driver 26.10.1. Run with ANYPS5_REQUIRE_VULKAN=1 and Vulkan validation layers 1.4.363, through the Windows test queue. The hosted Windows check does not run these tests on pull requests.

  • agc_driver_image_table_variants passes in 3 of 3 runs on the real device, none skipped.
  • The Vulkan device was created and the validation layer loaded in each run, with no VUID- errors.

AI-assisted: yes.

@github-actions github-actions Bot added docs agc libSceAgc* labels Nov 6, 2026
@oneandonlydean oneandonlydean self-assigned this Nov 6, 2026
@TechLevelZero

Copy link
Copy Markdown
Contributor

✅ NVIDIA GPU test: passed

PR head 809d1f3 merged onto main 82fcf46 · tested 2026-11-06 06:26 UTC · 20 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,918 passed · 4 failed (0 new, 3 also fail on main, 1 unstable on main) · 56 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,978 of 4,158 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 (986 tests run on the GPU)
Slow tests (>30 s, GPU tests timed with validation layers) ⚠️ agc_driver_pipeline_journal 120.1 s
Unstable on main (1, these also failed in recent main runs on this machine; not counted against this PR)
agc_driver_pipeline_journal: failed in 1 of the last 10 main runs
Failing on main too (3, not counted against this PR)
agc_driver_image_table
guest_mmap_executable
guest_socket_options_multicast
Validation IDs already present on main (9 IDs in 595 tests)
VUID-VkDeviceCreateInfo-pNext-pNext (595 tests): agc_driver, agc_driver_address_draw_space_reuse, agc_driver_address_passes, agc_driver_alias_copy_label, agc_driver_alpha_to_coverage, agc_driver_array_layer_target, agc_driver_bc_block_copy, agc_driver_bda_anchor_reads, and 587 more
VUID-VkShaderModuleCreateInfo-pCode-08737 (14 tests): agc_driver_dpp16_operands, agc_driver_dpp8_pk_fmac, agc_driver_dx10_clamp, agc_driver_f16_fma_denormal_modes, agc_driver_f16_fma_invalid_nan, agc_driver_float16_fma_rounding, agc_driver_float16_modifiers, agc_driver_float16_native, and 6 more
VUID-VkShaderModuleCreateInfo-pCode-08739 (14 tests): agc_driver_dpp16_operands, agc_driver_dpp8_pk_fmac, agc_driver_dx10_clamp, agc_driver_f16_fma_denormal_modes, agc_driver_f16_fma_invalid_nan, agc_driver_float16_fma_rounding, agc_driver_float16_modifiers, agc_driver_float16_native, and 6 more
VUID-VkShaderModuleCreateInfo-pCode-08741 (14 tests): agc_driver_dpp16_operands, agc_driver_dpp8_pk_fmac, agc_driver_dx10_clamp, agc_driver_f16_fma_denormal_modes, agc_driver_f16_fma_invalid_nan, agc_driver_float16_fma_rounding, agc_driver_float16_modifiers, agc_driver_float16_native, and 6 more
VUID-vkCmdCopyImage-srcImage-01548 (7 tests): agc_driver_depth_clear_hle, agc_driver_depth_plane_buffer_memory, agc_driver_depth_plane_partial_store, agc_driver_depth_plane_sampling, agc_driver_depth_storage_dispatch, agc_driver_depth_surface_from_storage, agc_driver_dispatch_move_depth
VUID-vkCmdCopyImage-srcImage-01551 (7 tests): agc_driver_depth_clear_hle, agc_driver_depth_plane_buffer_memory, agc_driver_depth_plane_partial_store, agc_driver_depth_plane_sampling, agc_driver_depth_storage_dispatch, agc_driver_depth_surface_from_storage, agc_driver_dispatch_move_depth
VUID-VkPipelineColorBlendStateCreateInfo-pAttachments-00605 (2 tests): agc_driver_prepared_exports, agc_driver_srgb8_color_target
VUID-VkPipelineShaderStageCreateInfo-module-parameter (1 test): agc_driver_float16_unused_nan_payloads
VUID-VkPipelineShaderStageCreateInfo-pSpecializationInfo-06849 (1 test): agc_driver_float16_unused_nan_payloads
Skipped (56)
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_gcn_display_present: skipped, no display: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
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_driver_vertex_elected_atomic_max: skipped, the device runs vertex programs in subgroups, so they keep their cross-lane reductions
agc_host_import_sparse: skipped, host imports are unavailable: /dev/udmabuf is not accessible
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_net_ctl_disconnected: 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_device_capability: 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_host_resolution_disabled: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
guest_video_out_host_resolution_four_k: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
guest_video_out_host_resolution_height_only: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
guest_video_out_host_resolution_limit: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
guest_video_out_host_resolution_malformed: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
guest_video_out_host_resolution_width_only: 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_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_backtoback: 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_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 de
Reproduce
git fetch origin 809d1f3f93906c727184201ceb13f2adff023958 82fcf46d250e0ec2f436ceffd607dd2ff04c62d7
git checkout 82fcf46d250e0ec2f436ceffd607dd2ff04c62d7 && git merge --no-ff 809d1f3f93906c727184201ceb13f2adff023958
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.

A borrowing entry shares the texture slot of its representative, so the slot check in refreshOwnObjects failed on the second entry of every such set and sent it to the full walk.

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* docs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants