Skip to content

fix(shader): hand a geometry program strip and fan triangles in the order of its provoking vertex mode - #7893

Open
thuanquang wants to merge 3 commits into
boykopovar:mainfrom
thuanquang:fix/strip-first-provoking-order
Open

thuanquang wants to merge 3 commits into
boykopovar:mainfrom
thuanquang:fix/strip-first-provoking-order

Conversation

@thuanquang

@thuanquang thuanquang commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

What

Follow-up to #7883, built on it. #7883 measured on an RX 6700 XT (probe source and output) the order in which AMD's geometry engine hands a geometry program its input triangles:

Input First provoking vertex Last provoking vertex
strip, odd triangle i (i, i+2, i+1) (i+1, i, i+2)
fan, triangle i (i+1, i+2, 0) (0, i+1, i+2)

The translator's mesh entry gives odd strip triangles as (i+1, i, i+2) in both modes, so in first mode a geometry program's flat values for odd strip triangles come from v[i+1] instead of v[i]. It also gives fans as (i+1, i+2, 0) in both modes, which is why #7883 kept refusing last-mode fans.

This change makes the order follow the mode (mesh.provokingVertex, which is 0 in first mode and the output's last slot in last mode):

  • first-mode strips get odd triangles as (i, i+2, i+1);
  • last-mode fans get (0, i+1, i+2);
  • last-mode strips and first-mode fans are unchanged.

The refusal of last-mode fans assembled for a geometry program goes away. For strips and for fans, the two orders are rotations of each other, so each triangle keeps its winding and culling does not change. Restart handling and the parity reset are untouched.

mesh.provokingVertex is already part of every key that holds a translated module (pipeline, draw and register keys, pipeline journal and request serializer), and translated modules are keyed by the recompiler's source hash. So no key or format version changes.

The console's order is not measured, and the debt entry says so. The entry is also cut to 999 characters, since this change closes the strip and fan part of the gap.

Tested

Windows 11 26200, AMD Radeon RX 6700 XT (gfx1031), driver 32.0.21045.5002, WinLibs GCC 15.2.0 r7, Release, BUILD_TESTING=ON, ANYPS5_NO_SHADER_CACHE=1.

This head (d054ce3afb) is one commit on #7883's new head 0bd8f6188a, which is rebased over #7426 onto main 2c4b116da9. #7883 has since been merged (merge commit d27d05ec14, whose second parent is 0bd8f6188a), so this PR's diff against main is now this one commit. In ValidateProvokingVertex this change still removes the fan refusal and keeps main's generated-primitive Require. The PROVOKING_VTX_LAST debt entry keeps this PR's version plus #7426's statement that the generated barycentric tessellation stages give each corner the last vertex's flat values (972 characters; the opengnm link is now named rather than linked, to stay under 1000). On this head:

  • agc_driver_graphics, agc_driver_mesh, agc_driver_mesh_provoking_vertex, agc_driver_mesh_provoking_layer, agc_driver_provoking_vertex and feat(agc): draw the last provoking vertex through the barycentric tessellation stages #7426's agc_driver_pixel_barycentric_emulation pass 3 of 3.
  • Khronos validation layer A (main 2c4b116da9) and B (this head), the same six tests: six of six pass on both, with no VUID- line and no was not found but was requested; the only layer output on both is WARNING-VkImageSubresourceRange-layerCount-compatibility.

The results below were measured on the previous head 40bd67bef.

  • agc_driver_mesh_provoking_vertex:
    • The strip case now also checks that in first mode, triangle 1 takes vertex 1's colour.
    • A new fan case (indices {1, 0, 2, 3}) checks that in last mode, triangle 0 takes vertex 2's colour and triangle 1 vertex 3's, and in first mode, vertex 0's and vertex 2's.
  • agc_driver_graphics: last-mode fans through a geometry program now validate.
  • Red, with the translator as on fix(agc): draw triangle strips through a geometry program with the last provoking vertex #7883: triangle strip, first provoking vertex, triangle 1 (the color of vertex 1): pixel (26, 48) channel 1 is 0, expected 255.
  • With the strip fixed but the fan order unchanged: triangle fan, last provoking vertex, triangle 0 (the color of vertex 2): pixel (12, 32) channel 1 is 255, expected 0.
  • With the fan refusal put back, both tests fail with last provoking vertex is unsupported for triangle fans assembled for a geometry program.
  • Green: agc_driver_graphics, agc_driver_mesh, agc_driver_mesh_provoking_layer, agc_driver_mesh_provoking_vertex and agc_driver_provoking_vertex pass 3 of 3.
  • Khronos validation layer (vulkan-sdk-1.4.363.0), VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation, ANYPS5_NO_SHADER_CACHE=1, ANYPS5_REQUIRE_VULKAN=1, ctest -V, same RX 6700 XT, on main 38de0a470 (other test files modified locally; none of these tests' sources), on fix(agc): draw triangle strips through a geometry program with the last provoking vertex #7883 59cabc57b and on fix(shader): hand a geometry program strip and fan triangles in the order of its provoking vertex mode #7893 606321886: agc_driver_graphics, agc_driver_mesh, agc_driver_mesh_provoking_vertex, agc_driver_mesh_provoking_layer and agc_driver_provoking_vertex pass on all three. No log reports was not found but was requested or any VUID- error. The layer's only output is the same WARNING-VkImageSubresourceRange-layerCount-compatibility warning in agc_driver_mesh_provoking_layer on all three trees.
  • python tools/check_conventions.py --base origin/main passes.
  • Other GPUs, from reviewers:
    • AMD RX 9070 XT and Intel UHD 770 on Windows (@savvaniss): with this branch's tests on main as the red side, the last-provoking-vertex geometry draws fail on main and pass here. The UHD 770 has no mesh shaders, so the mesh test skips there.
    • AMD RX 7900 XT on Linux, RADV (@DavidAmsellem): full suite 1636 of 1638, the same two failures as on main.
  • Not tested: titles, and the console.

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: fix(agc): draw triangle strips through a geometry program with the last provoking vertex #7883 (merged)
  • Fixes: none
  • Unblocks: none
  • GPUs tested: AMD Radeon RX 6700 XT (gfx1031), driver 32.0.21045.5002, Windows 11 26200
  • AI-assisted: yes (Claude Code)

🤖 Generated with Claude Code

@github-actions

github-actions Bot commented Oct 19, 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 2434 docs/dev/debt/libSceAgcDriver.md
PR 4040 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 4072 core/shader/recompiler/Translation/src/InstructionTranslator.cpp
PR 4448 docs/dev/debt/libSceAgcDriver.md
PR 4449 docs/dev/debt/libSceAgcDriver.md
PR 5058 docs/dev/debt/libSceAgcDriver.md
PR 5441 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 5609 core/libs/prx/libSceAgcDriver/Graphics/src/Pipeline.cpp
PR 5925 core/libs/prx/libSceAgcDriver/Graphics/src/Pipeline.cpp
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6186 docs/dev/debt/libSceAgcDriver.md
PR 6194 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6223 docs/dev/debt/libSceAgcDriver.md
PR 6235 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 6273 docs/dev/debt/libSceAgcDriver.md
PR 6280 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6292 core/libs/prx/libSceAgcDriver/Graphics/src/Pipeline.cpp
PR 6300 docs/dev/debt/libSceAgcDriver.md
PR 6412 docs/dev/debt/libSceAgcDriver.md
PR 6481 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6539 core/libs/prx/libSceAgcDriver/Graphics/src/Pipeline.cpp
PR 6548 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6549 docs/dev/debt/libSceAgcDriver.md
PR 6612 core/libs/prx/libSceAgcDriver/Graphics/src/Pipeline.cpp
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
core/shader/recompiler/Translation/src/InstructionTranslator.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6615 core/libs/prx/libSceAgcDriver/Graphics/src/Pipeline.cpp
PR 6639 core/libs/prx/libSceAgcDriver/Graphics/src/Pipeline.cpp
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6741 core/libs/prx/libSceAgcDriver/Graphics/src/Pipeline.cpp
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6801 core/libs/prx/libSceAgcDriver/Graphics/src/Pipeline.cpp
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6804 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6808 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6867 docs/dev/debt/libSceAgcDriver.md
PR 6868 docs/dev/debt/libSceAgcDriver.md
PR 6959 core/libs/prx/libSceAgcDriver/Graphics/src/Pipeline.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6977 docs/dev/debt/libSceAgcDriver.md
PR 7201 core/libs/prx/libSceAgcDriver/Graphics/src/Pipeline.cpp
PR 7256 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 7275 core/libs/prx/libSceAgcDriver/Graphics/src/Pipeline.cpp
PR 7604 docs/dev/debt/libSceAgcDriver.md
PR 7642 core/libs/prx/libSceAgcDriver/Graphics/src/Pipeline.cpp
docs/dev/debt/libSceAgcDriver.md
PR 8105 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 8246 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 8365 docs/dev/debt/libSceAgcDriver.md
PR 8395 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 8527 docs/dev/debt/libSceAgcDriver.md
PR 8542 docs/dev/debt/libSceAgcDriver.md
PR 8592 docs/dev/debt/libSceAgcDriver.md
PR 8672 docs/dev/debt/libSceAgcDriver.md
PR 8999 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 9020 core/libs/prx/libSceAgcDriver/Graphics/src/Pipeline.cpp
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
core/shader/recompiler/Translation/src/InstructionTranslator.cpp
docs/dev/debt/libSceAgcDriver.md
PR 9186 docs/dev/debt/libSceAgcDriver.md
PR 9335 core/libs/prx/libSceAgcDriver/Graphics/src/Pipeline.cpp
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
core/shader/recompiler/Translation/src/InstructionTranslator.cpp
docs/dev/debt/libSceAgcDriver.md
PR 9356 core/libs/prx/libSceAgcDriver/Graphics/src/Pipeline.cpp
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 9387 core/libs/prx/libSceAgcDriver/Graphics/src/Pipeline.cpp
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 9431 docs/dev/debt/libSceAgcDriver.md
PR 9432 docs/dev/debt/libSceAgcDriver.md
PR 9450 core/libs/prx/libSceAgcDriver/Graphics/src/Pipeline.cpp
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 9489 core/libs/prx/libSceAgcDriver/Graphics/src/Pipeline.cpp
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 9592 docs/dev/debt/libSceAgcDriver.md
PR 9672 docs/dev/debt/libSceAgcDriver.md
PR 9673 docs/dev/debt/libSceAgcDriver.md
PR 9674 docs/dev/debt/libSceAgcDriver.md
PR 9675 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 9676 docs/dev/debt/libSceAgcDriver.md
PR 9700 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 9721 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 9748 core/libs/prx/libSceAgcDriver/Graphics/src/Pipeline.cpp
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
core/shader/recompiler/Translation/src/InstructionTranslator.cpp
docs/dev/debt/libSceAgcDriver.md
PR 9891 docs/dev/debt/libSceAgcDriver.md
PR 9892 docs/dev/debt/libSceAgcDriver.md
PR 9893 docs/dev/debt/libSceAgcDriver.md
PR 9895 docs/dev/debt/libSceAgcDriver.md

@github-actions github-actions Bot added shader core/shader docs agc libSceAgc* labels Oct 19, 2026
@savvaniss

Copy link
Copy Markdown
Contributor

Intel and AMD Windows data: with this PR's test changes, the last-provoking-vertex geometry draws fail on main and pass with the PR, on an AMD RX 9070 XT and an Intel UHD 770.

Windows 11 Pro 26300, WinLibs GCC 15.2.0 r7, Release, every execution test built, ANYPS5_NO_SHADER_CACHE=1, serial CTest. Intel UHD Graphics 770 (8086:a780), driver 32.0.101.7088. AMD Radeon RX 9070 XT (1002:7550), driver 32.0.31041.1004, with VkCache emptied first. This head 606321886 (which carries #7883) merged into main 85029a00f. "Without" means only this branch's diff to tests/Graphics.cpp and tests/execution/MeshProvokingVertex.cpp, applied to main 85029a00f.

Tests, ×3 UHD 770 RX 9070 XT
This head: the 30 tests built from those files 29 pass; agc_driver_mesh_provoking_vertex skips (no mesh shaders on this GPU) 30 of 30 pass
Without agc_driver_graphics fails: last provoking vertex is unsupported for triangle strips or fans assembled for a geometry program; the mesh test skips agc_driver_graphics fails the same way, and agc_driver_mesh_provoking_vertex aborts with that error

AI-assisted: yes (Claude Code)

@DavidAmsellem

Copy link
Copy Markdown
Contributor

First AMD-on-Linux (RADV) run of this PR. Merged onto main 43a2abaf7 (clean merge), built in full and compared with the same main, on the same machine.

AMD Radeon RX 7900 XT (RADV NAVI31, gfx1100), Mesa 25.2.8, Linux Mint 22.3 (Ubuntu 24.04 base), kernel 7.0.0-38, GCC 13.3, Release.

Full suite (ANYPS5_REQUIRE_VULKAN=1 ctest -j8): 1636/1638 with this PR, against 1636/1638 on main. The failures are the same two on both, so this PR adds none: agc_driver_image_table_vouched_lookups (#7766, fixed by #7916) and agc_driver_guest_memory_lifetime (#7784). The PR adds no new ctest entry; every existing test it touches passed.

GPUs tested: AMD Radeon RX 7900 XT (RADV NAVI31, gfx1100), Mesa 25.2.8, Linux Mint 22.3 / kernel 7.0.0-38

AI-assisted: yes

@oneandonlydean

Copy link
Copy Markdown
Collaborator

@thuanquang a heads-up for the rebase: main has since taken the last provoking vertex through the barycentric tessellation path (#7426), and that change touched the same checks this PR relies on, so the conflict needs a decision rather than keep-both.

  • In ValidateProvokingVertex (Pipeline.cpp), main dropped !BarycentricPatches(...) from the generated-primitive Require and added a new one: Require(!meshPrimitives || (topology != TRIANGLE_STRIP && topology != TRIANGLE_FAN), "last provoking vertex is unsupported for triangle strips or fans assembled for a geometry program"). That guard refuses exactly the case this PR implements, so after a plain merge your strip/fan ordering is unreachable in last mode. Please remove or narrow it as part of the rebase and check how it combines with your own triangle-strip Require on the line after it.
  • The PA_SU_SC_MODE_CNTL.PROVOKING_VTX_LAST entry in docs/dev/debt/libSceAgcDriver.md was rewritten on both sides (yours from the first sentence, main in a later part), so it needs one combined entry rather than both versions.

A last-mode strip case through a geometry program that would have hit main's new refusal would pin the result.

…rder of its provoking vertex mode

The translator handed a geometry program odd strip triangle i as
(i+1, i, i+2) and fan triangle i as (i+1, i+2, 0) in both provoking
vertex modes. An RX 6700 XT hands a geometry shader odd strip triangles
as (i, i+2, i+1) in first mode and fan triangles as (0, i+1, i+2) in
last mode, so with the first provoking vertex the flat inputs of odd
strip triangles came from vertex i+1 instead of i. Take the mode from
the mesh configuration's provoking vertex, which is already part of
every pipeline and shader cache key, and drop the last-mode refusal of
fans assembled for a geometry program.

Co-Authored-By: Claude <noreply@anthropic.com>
@thuanquang
thuanquang force-pushed the fix/strip-first-provoking-order branch from 40bd67b to d054ce3 Compare October 21, 2026 15:03
@github-actions github-actions Bot removed the needs rebase Conflicts with main, rebase needed label Oct 21, 2026
@thuanquang

Copy link
Copy Markdown
Contributor Author

@oneandonlydean thanks for the heads-up. The rebase to d054ce3 handles it, and since #7883 has merged, this PR's diff against main is its one commit:

  • ValidateProvokingVertex: feat(agc): draw the last provoking vertex through the barycentric tessellation stages #7426's refusal of last-mode triangle strips and fans assembled for a geometry program is removed. main's generated-primitive Require stays as it is.
  • This PR's own triangle-strip Require still refuses last mode with explicit per-vertex interpolation (the expectFailure in ProvokingVertexTests). Flat and smooth inputs validate for strips and fans.
  • MeshProvokingVertex now draws a triangle strip and a triangle fan in last mode through a geometry program, the case main's refusal threw on, and the fan in first mode.
  • The PROVOKING_VTX_LAST debt entry is one combined entry.

The test runs are in the description.

@github-actions github-actions Bot added the needs rebase Conflicts with main, rebase needed label Oct 22, 2026
@github-actions github-actions Bot removed the needs rebase Conflicts with main, rebase needed label Oct 22, 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* docs shader core/shader

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants