Skip to content

fix(agc): name the V# fields when a vertex fetch exceeds its descriptor record count - #9604

Open
ebarr24 wants to merge 1 commit into
boykopovar:mainfrom
ebarr24:ws/ppsa01746-vertex-fetch-exceeds-descripto
Open

ebarr24 wants to merge 1 commit into
boykopovar:mainfrom
ebarr24:ws/ppsa01746-vertex-fetch-exceeds-descripto

Conversation

@ebarr24

@ebarr24 ebarr24 commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

What

A vertex fetch past NUM_RECORDS threw only 'vertex fetch exceeds descriptor record count', which does not say which V# fields decided the RDNA 2 range check. The message now appends OOB_SELECT, stride, NUM_RECORDS and whether the index is the vertex or the instance index, with the index. The behaviour is unchanged; it is still a throw. Kena PPSA01746 stops on this in the bring-up of #4073, and the values show what the next step must implement.

Tested

Windows 11, MinGW-w64 GCC 15.2, Release build with tests. agc_driver_graphics passes with this change; the new test fails on main.

Validation layer (vulkan-sdk-1.4.363.0), on main 11f976b and on this change, with VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation, VK_ADD_LAYER_PATH set to the layer, ANYPS5_NO_SHADER_CACHE=1 and ANYPS5_REQUIRE_VULKAN=1: ctest -V -R "agc_driver_graphics". Neither log contains was not found but was requested by env var VK_INSTANCE_LAYERS; the change adds no VUID- errors (0 with the change, 0 on main).

ctest -V log, main
--timeout 120
UpdateCTestConfiguration  from :C:/Users/ebarr/ps5-emulation/work/s1/.wsbuild/DartConfiguration.tcl
Test project C:/Users/ebarr/ps5-emulation/work/s1/.wsbuild
Constructing a list of tests
Done constructing a list of tests
Updating test list for fixtures
Added 0 tests to meet fixture requirements
Checking test dependency graph...
Checking test dependency graph end
test 495
    Start 495: agc_driver_graphics

495: Test command: C:\Users\ebarr\ps5-emulation\work\s1\.wsbuild\tests\agc_driver_graphics_tests.exe
495: Working Directory: C:/Users/ebarr/ps5-emulation/work/s1
495: Environment variables: 
495:  ANYPS5_NO_SHADER_CACHE=1
495:  APS5_NO_PIPELINE_JOURNAL=1
495: Environment variable modifications: 
495:  PATH=path_list_prepend:C:/Users/ebarr/ps5-emulation/work/s1/.wsbuild/core/libs/libs/unpatched
495: Test timeout computed to be: 120
495: [time] scheduler tick raised to 0.5 ms (was 0.50 ms, now 0.50 ms, timed waits fine)
495: [src\HostCpu.cpp:193 operator()] host CPU AMD Ryzen 7 3700X 8-Core Processor: has SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, LZCNT, BMI1, BMI2, MOVBE, CMPXCHG16B, LAHF/SAHF, AVX, AVX2, FMA, F16C, AES, PCLMULQDQ, RDRAND, RDSEED, ADX, SHA, CLFLUSHOPT, CLWB, RDPID, XSAVEOPT, XSAVEC, SSE4A, PREFETCHW, CLZERO, OS AVX state (XCR0); lacks none
495: [gpu] always-pass depth/stencil state is rendered without a depth target (DB_DEPTH_CONTROL=0x007007b3)
495: [gpu] viewport depth clamp bounds [-1, 2] on a float depth target are clipped to [0, 1]: the device has no VK_EXT_depth_range_unrestricted
495: [gpu] layer/viewport index vertex exports are ignored (PA_CL_VS_OUT_CNTL=0x01240000)
495: [gpu] DCC keys of mipmapped color targets are ignored
495: [gpu] no 2x2 sample location grid at sample count 2 on this device: sample locations varying between pixels take pixel (0,0)'s in every pixel (the device lacks sampleRateShading)
495: [gpu] no 2x2 sample location grid at sample count 1 on this device: sample locations varying between pixels take pixel (0,0)'s in every pixel (its pixels hold different locations)
495: [gpu] no 2x2 sample location grid at sample count 2 on this device: pixel (0,0)'s sample locations stand in for every pixel, and each pixel's samples are put in the guest's order at the bounds of its render passes
495: content-key count=0 data=0 movable=0 words=70 capacity=70 hash=12276112778106431680
495: content-key count=0 data=0 movable=1 words=70 capacity=70 hash=16547703523611771548
495: content-key count=0 data=1 movable=0 words=327 capacity=327 hash=18195637788575597601
495: content-key count=0 data=1 movable=1 words=70 capacity=70 hash=6884676608767608045
495: content-key count=1 data=0 movable=0 words=89 capacity=89 hash=3582826753038562111
495: content-key count=1 data=0 movable=1 words=89 capacity=89 hash=9518511843953525419
495: content-key count=1 data=1 movable=0 words=346 capacity=346 hash=3684355951081846730
495: content-key count=1 data=1 movable=1 words=89 capacity=89 hash=8486460719680651956
495: content-key count=31 data=0 movable=0 words=389 capacity=389 hash=2872353339945041207
495: content-key count=31 data=0 movable=1 words=389 capacity=389 hash=11292844791518677155
495: content-key count=31 data=1 movable=0 words=646 capacity=646 hash=16275665856175105250
495: content-key count=31 data=1 movable=1 words=389 capacity=389 hash=4084850990441387724
495: content-key count=32 data=0 movable=0 words=399 capacity=399 hash=9001008430028590267
495: content-key count=32 data=0 movable=1 words=399 capacity=399 hash=5471292191449946447
495: content-key count=32 data=1 movable=0 words=656 capacity=656 hash=9565516749443825062
495: content-key count=32 data=1 movable=1 words=399 capacity=399 hash=15118118974702537264
495: content-key count=33 data=0 movable=0 words=418 capacity=418 hash=10382587997612106155
495: content-key count=33 data=0 movable=1 words=418 capacity=418 hash=11706275810969384511
495: content-key count=33 data=1 movable=0 words=675 capacity=675 hash=1776364597915029880
495: content-key count=33 data=1 movable=1 words=418 capacity=418 hash=13690582611633829486
495: content-key count=16384 data=0 movable=0 words=168518 capacity=168518 hash=15297671208421994211
495: content-key count=16384 data=0 movable=1 words=168518 capacity=168518 hash=8322610684387165047
495: content-key count=16384 data=1 movable=0 words=168775 capacity=168775 hash=13444188082477402620
495: content-key count=16384 data=1 movable=1 words=168518 capacity=168518 hash=6566449801145079954
495: Unused stencil reference sample equivalence passed: 22 accepted states, 12 dependent countermodels
495: All 256 MSAA CMASK byte classifications passed
495: AGC graphics: unexpected failure: AGC graphics: vertex fetch exceeds descriptor record count
1/1 Test #495: agc_driver_graphics ..............***Failed    2.20 sec

0% tests passed, 1 tests failed out of 1

Total Test time (real) =   2.34 sec

The following tests FAILED:
	495 - agc_driver_graphics (Failed)
Errors while running CTest
Output from these tests are in: C:/Users/ebarr/ps5-emulation/work/s1/.wsbuild/Testing/Temporary/LastTest.log
Use "--rerun-failed --output-on-failure" to re-run the failed cases verbosely.
ctest -V log, this change
--test-dir C:\Users\ebarr\ps5-emulation\work\s1\.wsbuild -R agc_driver_graphics -V --timeout 120
UpdateCTestConfiguration  from :C:/Users/ebarr/ps5-emulation/work/s1/.wsbuild/DartConfiguration.tcl
Test project C:/Users/ebarr/ps5-emulation/work/s1/.wsbuild
Constructing a list of tests
Done constructing a list of tests
Updating test list for fixtures
Added 0 tests to meet fixture requirements
Checking test dependency graph...
Checking test dependency graph end
test 495
    Start 495: agc_driver_graphics

495: Test command: C:\Users\ebarr\ps5-emulation\work\s1\.wsbuild\tests\agc_driver_graphics_tests.exe
495: Working Directory: C:/Users/ebarr/ps5-emulation/work/s1
495: Environment variables: 
495:  ANYPS5_NO_SHADER_CACHE=1
495:  APS5_NO_PIPELINE_JOURNAL=1
495: Environment variable modifications: 
495:  PATH=path_list_prepend:C:/Users/ebarr/ps5-emulation/work/s1/.wsbuild/core/libs/libs/unpatched
495: Test timeout computed to be: 120
495: [time] scheduler tick raised to 0.5 ms (was 0.50 ms, now 0.50 ms, timed waits fine)
495: [src\HostCpu.cpp:193 operator()] host CPU AMD Ryzen 7 3700X 8-Core Processor: has SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, LZCNT, BMI1, BMI2, MOVBE, CMPXCHG16B, LAHF/SAHF, AVX, AVX2, FMA, F16C, AES, PCLMULQDQ, RDRAND, RDSEED, ADX, SHA, CLFLUSHOPT, CLWB, RDPID, XSAVEOPT, XSAVEC, SSE4A, PREFETCHW, CLZERO, OS AVX state (XCR0); lacks none
495: [gpu] always-pass depth/stencil state is rendered without a depth target (DB_DEPTH_CONTROL=0x007007b3)
495: [gpu] viewport depth clamp bounds [-1, 2] on a float depth target are clipped to [0, 1]: the device has no VK_EXT_depth_range_unrestricted
495: [gpu] layer/viewport index vertex exports are ignored (PA_CL_VS_OUT_CNTL=0x01240000)
495: [gpu] DCC keys of mipmapped color targets are ignored
495: [gpu] no 2x2 sample location grid at sample count 2 on this device: sample locations varying between pixels take pixel (0,0)'s in every pixel (the device lacks sampleRateShading)
495: [gpu] no 2x2 sample location grid at sample count 1 on this device: sample locations varying between pixels take pixel (0,0)'s in every pixel (its pixels hold different locations)
495: [gpu] no 2x2 sample location grid at sample count 2 on this device: pixel (0,0)'s sample locations stand in for every pixel, and each pixel's samples are put in the guest's order at the bounds of its render passes
495: [gpu] host import of 0x1dece4e0000+0x20000 failed at vkAllocateMemory (-2); falling back to copies, requested by access
495: [gpu] host import of 0x1dece4e0000+0x20000 failed at vkAllocateMemory (-2); falling back to copies, requested by access
495: [gpu] host import of 0x1dece4e0000+0x20000 failed at vkAllocateMemory (-2); falling back to copies, requested by access
495: [gpu] host import budget: 0 MiB live of 0 MiB (APS5_HOST_IMPORT_MIB); 1 imports (0 MiB) refused so far, 0 of them remembered, last 0x1ded0270000+0x30000 by build
495: [gpu] host import of 0x1decfaa0000+0x10000 failed at vkAllocateMemory (-1000072003); falling back to copies, requested by map
495: [gpu] host import of 0x1decfaa0000+0x10000 failed at vkAllocateMemory (-1000072003); falling back to copies, requested by map
495: [gpu] host import of 0x1decf200000+0x10000 failed at vkAllocateMemory (-2); falling back to copies, requested by access
495: [gpu] host import of 0x1dedf800000+0x800000 failed at vkAllocateMemory (-2); falling back to copies, requested by build
495: [gpu] host import of 0x1dedf410000+0x10000 failed at vkAllocateMemory (-2); falling back to copies, requested by access
495: [gpu] host import of 0x1dedf450000+0x10000 failed at vkAllocateMemory (-2); falling back to copies, requested by access
495: [gpu] host import of 0x1dedf470000+0x10000 failed at vkAllocateMemory (-2); falling back to copies, requested by access
495: [gpu] host import of 0x1dedf490000+0x10000 failed at vkAllocateMemory (-2); falling back to copies, requested by access
495: [gpu] host import budget lowered to the 0.1 MiB live after vkAllocateMemory failed 3 times in a row
495: [gpu] host import of 0x1dedf410000+0x10000 failed at vkAllocateMemory (-2); falling back to copies, requested by access
495: [gpu] host import budget lowered to the 0.1 MiB live after vkAllocateMemory failed within an eighth of the budget
495: [gpu] host import budget: host heap 1 reports a VK_EXT_memory_budget budget of 8 MiB and a usage of 8 MiB with 0 MiB of imports live, which leaves imports 0 MiB of the 4 MiB APS5_HOST_IMPORT_MIB sets; the setting stays, as the report never lowers it
495: [gpu] host import of 0x1dedf450000+0x10000 failed at vkAllocateMemory (-2); falling back to copies, requested by access
495: [gpu] host import budget: host heap 1 reports a VK_EXT_memory_budget budget of 8 MiB and a usage of 8 MiB with 0 MiB of imports live, which leaves imports 0 MiB of the 8192 MiB of the default; the default stays until an import's vkAllocateMemory fails
495: [gpu] host import of 0x1dedf450000+0x10000 failed at vkAllocateMemory (-2); falling back to copies, requested by access
495: [gpu] host import budget: host heap 1 reports a VK_EXT_memory_budget budget of 8 MiB and a usage of 8 MiB with 0 MiB of imports live, which leaves imports 0 MiB of the 8192 MiB of the default; imports are held to it since an import's vkAllocateMemory failed
495: [gpu] host import budget: host heap 1 reports a VK_EXT_memory_budget budget of 8 MiB and a usage of 8 MiB with 0 MiB of imports live, which leaves imports 0 MiB of the 8192 MiB of the default; the default stays until an import's vkAllocateMemory fails
495: [gpu] host import of 0x1dedf3f0000+0x10000 failed at vkAllocateMemory (-2); falling back to copies, requested by access
495: [gpu] host import budget: host heap 1 reports a VK_EXT_memory_budget budget of 8 MiB and a usage of 8 MiB with 0 MiB of imports live, which leaves imports 0 MiB of the 8192 MiB of the default; imports are held to it since an import's vkAllocateMemory failed
495: [gpu] texture 0x700f7fcb00 (format 74) has single DCC keys at 0x700f7fc940; its texels are read as stored
495: [gpu] texture 0x700f7fcb00 (format 56) has mixed DCC keys at 0x700f7fc940; its texels are read as stored
495: [gpu] texture streaming feedback (LOD warning / mip statistics) is not reported
495: [gpu] texture DCC color transform is ignored (word6=0x01980000 word7=0x00000000)
495: content-key count=0 data=0 movable=0 words=70 capacity=70 hash=12276112778106431680
495: content-key count=0 data=0 movable=1 words=70 capacity=70 hash=16547703523611771548
495: content-key count=0 data=1 movable=0 words=327 capacity=327 hash=18195637788575597601
495: content-key count=0 data=1 movable=1 words=70 capacity=70 hash=6884676608767608045
495: content-key count=1 data=0 movable=0 words=89 capacity=89 hash=3582826753038562111
495: content-key count=1 data=0 movable=1 words=89 capacity=89 hash=9518511843953525419
495: content-key count=1 data=1 movable=0 words=346 capacity=346 hash=3684355951081846730
495: content-key count=1 data=1 movable=1 words=89 capacity=89 hash=8486460719680651956
495: content-key count=31 data=0 movable=0 words=389 capacity=389 hash=2872353339945041207
495: content-key count=31 data=0 movable=1 words=389 capacity=389 hash=11292844791518677155
495: content-key count=31 data=1 movable=0 words=646 capacity=646 hash=16275665856175105250
495: content-key count=31 data=1 movable=1 words=389 capacity=389 hash=4084850990441387724
495: content-key count=32 data=0 movable=0 words=399 capacity=399 hash=9001008430028590267
495: content-key count=32 data=0 movable=1 words=399 capacity=399 hash=5471292191449946447
495: content-key count=32 data=1 movable=0 words=656 capacity=656 hash=9565516749443825062
495: content-key count=32 data=1 movable=1 words=399 capacity=399 hash=15118118974702537264
495: content-key count=33 data=0 movable=0 words=418 capacity=418 hash=10382587997612106155
495: content-key count=33 data=0 movable=1 words=418 capacity=418 hash=11706275810969384511
495: content-key count=33 data=1 movable=0 words=675 capacity=675 hash=1776364597915029880
495: content-key count=33 data=1 movable=1 words=418 capacity=418 hash=13690582611633829486
495: content-key count=16384 data=0 movable=0 words=168518 capacity=168518 hash=15297671208421994211
495: content-key count=16384 data=0 movable=1 words=168518 capacity=168518 hash=8322610684387165047
495: content-key count=16384 data=1 movable=0 words=168775 capacity=168775 hash=13444188082477402620
495: content-key count=16384 data=1 movable=1 words=168518 capacity=168518 hash=6566449801145079954
495: Unused stencil reference sample equivalence passed: 22 accepted states, 12 dependent countermodels
495: All 256 MSAA CMASK byte classifications passed
495: Graphics validation tests passed
1/1 Test #495: agc_driver_graphics ..............   Passed   12.88 sec

The following tests passed:
	agc_driver_graphics

100% tests passed out of 1

Total Test time (real) =  13.03 sec

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: PPSA01746 Kena (PPSA01746) on Windows: null global slot written by a title setter at app.exe+0x1c7a46b #4073
  • GPUs tested: NVIDIA GeForce RTX 3080, driver 32.0.16.1692; Microsoft Windows 11 Pro; Khronos validation layer on main and this change, no new VUIDs
  • AI-assisted: yes

🤖 Generated with Claude Code

@github-actions github-actions Bot added the unblocks title Names a title ID on the Unblocks line label Oct 22, 2026
@github-actions

github-actions Bot commented Oct 22, 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 1395 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 4040 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 5441 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 5925 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 6194 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 6235 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 6280 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 6481 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 6548 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 6808 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 7256 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 7642 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 8246 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 9356 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 9387 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 9489 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 9508 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 9675 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 9748 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 10435 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 10886 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp

@fogydes

fogydes commented Oct 22, 2026

Copy link
Copy Markdown
Contributor

Reviewed; verified this is behavior-preserving and the message is honest. The throw condition is exactly the old one (Require(recordsUnchecked || index < records, ...) ⇔ if (!recordsUnchecked && index >= records) Require(false, ...)), the string is only built on the failure path so the per-fetch hot path pays nothing extra, and the interleaved Require(stride != 0 || required <= ZeroStride_AVAILABLEBytes ...) chain below is untouched so the next rejection keeps its own message.

I checked the exact-string assertions against the test fixtures rather than trusting them: fields = {0x1000, 32u << 16u, 3, ...} decodes to stride 32 / NUM_RECORDS 3, 0x2004dfacu >> 28 & 3 = OOB_SELECT 2, and the effective fetch index (maxIndex + instances - 1 + firstInstance = 3 + 1 - 1 = 3) gives "vertex index 3" — matches. The zero-stride case's {0x1000, 0, 8, ...} + instance bit gives stride 0 / records 8 / select 1 / index 8 with fetchIndex 1 → "instance index 8" — matches. Since expectFailure matches by substring (.find(reason) != npos), the pre-existing "record count" assertions stay valid even though the message got longer, so the layered old/new pattern is a compatible way to tighten the assertion.

One note: the run legs (windows, linux, register-context) had not executed at review time, so the new exact literals only get their first real exercise when they run — they should, given the decode above, but that's the check to watch on the next green run.

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

The change is behavior-preserving: the record-count throw condition is unchanged, the diagnostic is constructed only on the failure path, and subsequent zero-stride/address-range checks remain in their prior order. The exact expected strings match the fixture field decoding. Exact-head conventions and git diff --check pass; hosted conventions, eligibility, intake, labels, and progress report pass. Product Linux/Windows jobs are skipped, so those checks did not independently run the test here.

Before approval, please attach or link the paired ctest -V validation-layer logs required for AGC changes and state explicitly that neither run contains was not found but was requested by env var VK_INSTANCE_LAYERS and that the PR introduces no new VUID- errors versus main. The checklist currently asserts this, but the test section only says the focused test passes and does not provide the required validation-layer/no-cache invocation or the log evidence.

The reported Kena rate changes from 14.0 fps on main to 13.6 fps on this change. Since this is a performance comparison, please add the two valid same-machine/scene summary lines and attach the traces using the repository Performance report format, or remove the unsupported fps comparison if it is incidental and not a claimed performance result. Include the exact title bring-up discussion link (currently #4073) and keep its PR list current as required by the contribution rules.

@github-actions github-actions Bot added the agc libSceAgc* label Oct 22, 2026

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

I refreshed exact head ecc035657c814259a1d47dd7f500ebb410094b34 against current main 3ca07d086d5f44fbe3c00370e7f03953ab46ca1b: git diff --check and conventions pass, and the current-main merge tree is clean. The diagnostic is still failure-path-only and preserves the existing throw condition; the exact-string test expectations were independently checked against the fixture fields. Hosted conventions/eligibility/labels/report pass, but Linux/Windows product jobs are skipped. I did not run the GPU test locally.

The existing review evidence requests remain unresolved: please attach the paired ctest -V validation-layer logs for main and this head, including the exact invocation and confirmation that neither run has the VK_INSTANCE_LAYERS warning or new VUIDs. The Tested section also compares Kena at 14.0 and 13.6 fps. Since the change is diagnostic-only, remove that incidental performance comparison unless you intend to report a performance result; if retained as a result, include same-scene summary lines and traces using the repository performance-report format.

The PR base is dce41a89478876a8e3ea9c346b1dac00bb31c8cd, behind current main. Please update to current main and refresh the convention/test evidence on the resulting head. This is a request for the current-main and review-evidence requirements only; it is unrelated to the obsolete intake hold.

…or record count

A vertex fetch past NUM_RECORDS threw only 'vertex fetch exceeds descriptor record count', which does not say which V# fields decided the RDNA 2 range check. The message now appends OOB_SELECT, stride, NUM_RECORDS and whether the index is the vertex or the instance index, with the index. The behaviour is unchanged; it is still a throw. Kena PPSA01746 stops on this in the bring-up of boykopovar#4073, and the values show what the next step must implement.
@ebarr24
ebarr24 force-pushed the ws/ppsa01746-vertex-fetch-exceeds-descripto branch from ecc0356 to 56ea15a Compare October 22, 2026 17:26
@JJenkx

JJenkx commented Oct 22, 2026

Copy link
Copy Markdown
Contributor

Additional title hitting this diagnostic path: The Eternal Cylinder (PPSA06369) aborted after 90.4 seconds on clean main 6a6a35fdf5c2612821345be89309180622782d89. The 60-second capture was black; gameplay was not verified. The final log says:

[videoout] presentation failed: AGC graphics: vertex fetch exceeds descriptor record count
terminate called after throwing an instance of 'std::runtime_error'
  what():  AGC graphics: vertex fetch exceeds descriptor record count

Reviewed this PR at 56ea15a2382a5a765fbae268b22ad252c19e1305: its diagnostic would provide the missing OOB_SELECT/stride/NUM_RECORDS/index values while retaining the throw. This run did not include this PR, so it is evidence of another affected title, not validation of the change or a claim that it fixes the title. The existing zero-fill handling from merged #2573 does not establish which remaining rule this title needs.

Independent run review, report/log/image SHA-256s and limitations. Full local logs were retained.

@JJenkx

JJenkx commented Oct 22, 2026

Copy link
Copy Markdown
Contributor

A second title with this PR's message: The Eternal Cylinder (PPSA06369) 01.003.000, on main 6a6a35fdf5 with only libSceAgcDriver.prx rebuilt with this PR merged. Radeon RX 6650 XT, RADV Mesa 26.2.4. It stops 88.5 s in with:

vertex fetch exceeds descriptor record count: OOB_SELECT 2, stride 12, NUM_RECORDS 303, vertex index 319706

Without this PR, the same run stops at 90.4 s with the plain message.

That's OOB_SELECT 2 with a nonzero stride. Mesa's RDNA 2 descriptor code says what the range check is for each mode (ac_descriptors.c L824–L841 at mesa-26.2.4):

GFX10:
 - 0: (index >= NUM_RECORDS) || (offset >= STRIDE)
 - 1: index >= NUM_RECORDS
 - 2: NUM_RECORDS == 0
 - 3: if SWIZZLE_ENABLE: swizzle_address >= NUM_RECORDS
      else: offset >= NUM_RECORDS

So with OOB_SELECT 2 and NUM_RECORDS 303, the fetch at index 319706 is not out of bounds on the hardware. It reads at base + 319706 × 12 with no clamp. VertexBufferReadSize treats only OOB_SELECT 0 and 1 as record-checked for a nonzero stride (recordsUnchecked = stride == 0 ? select != 1 : select <= 1), so OOB_SELECT 2 lands in this throw. Handling it would mean sizing the read from the index (stride × index + format bytes) whenever NUM_RECORDS is nonzero, with no zero-fill, and the same in VertexBufferExtent, which sizes from NUM_RECORDS today.

@ebarr24 if you're already implementing this next step, I'll leave it to you. Otherwise I can open a PR for OOB_SELECT 2 with a strided buffer and test it on this title. Kena's values from #4073 would show whether it covers that case too.

AI-assisted: yes (Claude Code).

ebarr24 added a commit to ebarr24/AnyPS5 that referenced this pull request Oct 22, 2026
…h OOB_SELECT 2 and 3

A strided vertex fetch with OOB_SELECT 2 or 3 threw whenever its index was at or past NUM_RECORDS, which stopped Kena PPSA01746 (its own descriptor values are not captured yet) with the same message that The Eternal Cylinder PPSA06369 printed for stride 12, NUM_RECORDS 303 and vertex index 319706 (reported by JJenkx on boykopovar#9604). RDNA 2 checks only NUM_RECORDS == 0 for OOB_SELECT 2, and for OOB_SELECT 3 compares NUM_RECORDS with the fetch's byte range without using the index (Mesa ac_descriptors.c at mesa-26.2.4, measured on gfx1036 in boykopovar#2241). The fetch is now sized from its index in those cases, and the cases the hardware reads as zeros (NUM_RECORDS 0 for select 2, NUM_RECORDS below the fetch's bytes for select 3) still throw, as does the extent of an indirect draw's fetch, which NUM_RECORDS no longer bounds.
ebarr24 added a commit to ebarr24/AnyPS5 that referenced this pull request Oct 23, 2026
…h OOB_SELECT 2 and 3

A strided vertex fetch with OOB_SELECT 2 or 3 threw whenever its index was at or past NUM_RECORDS, which stopped Kena PPSA01746 (its own descriptor values are not captured yet) with the same message that The Eternal Cylinder PPSA06369 printed for stride 12, NUM_RECORDS 303 and vertex index 319706 (reported by JJenkx on boykopovar#9604). RDNA 2 checks only NUM_RECORDS == 0 for OOB_SELECT 2, and for OOB_SELECT 3 compares NUM_RECORDS with the fetch's byte range without using the index (Mesa ac_descriptors.c at mesa-26.2.4, measured on gfx1036 in boykopovar#2241). The fetch is now sized from its index in those cases, and the cases the hardware reads as zeros (NUM_RECORDS 0 for select 2, NUM_RECORDS below the fetch's bytes for select 3) still throw, while an indirect draw, whose counts are unknown when its vertex ranges are copied, still copies the descriptor's NUM_RECORDS range.
@adriadam10 adriadam10 self-assigned this Oct 23, 2026
@adriadam10
adriadam10 dismissed MarcZX10’s stale review October 24, 2026 10:20

Dismissing a stale review: the requested changes were addressed after it (new head and/or updated description with the asked-for runs) and the merge queue blocks on it. Please request changes again if anything is still open.

@ycbuzi

ycbuzi commented Oct 25, 2026

Copy link
Copy Markdown
Contributor

A Windows run of this head: Windows 11 Home 10.0.26200, WinLibs GCC 15.2.0 r7 (MinGW-w64 UCRT), Release. 56ea15a238 merged onto main 2e773bff38 with no conflicts.

  • The build has no errors. Its two __builtin_memcmp bound warnings (stl_algobase.h:1889) also appear in the negative-control build below, which uses main's VertexInput.hpp, so they don't come from this change.
  • agc_driver_graphics passes both runs of ctest --repeat until-fail:2, three times over.
  • Negative control: Graphics/include/VertexInput.hpp taken from main, with the test unchanged. It then fails with AGC graphics: unexpected failure: AGC graphics: vertex fetch exceeds descriptor record count, which is main's message without the V# fields.

agc_driver_graphics opens no Vulkan device: none of the three runs logs a Selected GPU line, and none of its sources creates a device. So this is a Windows run of the CPU-side state checks, not a GPU result, even though I ran it with ANYPS5_GPU set to an RTX 4070 SUPER, a GTX 1650 SUPER and a Radeon iGPU in turn.

This PR and #9694 both change tests/Graphics.cpp; they merge with each other without conflicts.

AI-assisted: yes (Claude Code)

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* unblocks title Names a title ID on the Unblocks line

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants