Skip to content

fix(shader): index tessellation attributes at a constant address with constants - #8884

Merged
adriadam10 merged 2 commits into
boykopovar:mainfrom
thuanquang:fix/tess-constant-attribute-indices
Oct 22, 2026
Merged

adriadam10 merged 2 commits into
boykopovar:mainfrom
thuanquang:fix/tess-constant-attribute-indices

Conversation

@thuanquang

@thuanquang thuanquang commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

What

Fixes #8861.

TessellationPointer (SpirvModuleEmitter.cpp) computes the vertex, location and component indices of a tessellation attribute access from its address with OpUDiv, OpUMod, OpShiftRightLogical and OpBitwiseAnd. It does this even when the address is an immediate. In the default build nothing folds them, since SPIRV-Tools is off, so the driver gets access chains whose indices are arithmetic on constants.

AMD's Windows driver reads a per-vertex tessellation control output indexed that way wrongly. In agc_driver_tessellation's merged hull program, invocation 0 reads control point 2's level from the per-vertex record that stands in for LDS. That read came back wrong, so a patch was missing or drawn flat, and which one changed from run to run.

With an immediate address, the indices are now computed on the host and emitted as OpConstants, which is the shape glslang emits. Dynamic addresses are unchanged. The host clamps the control point as inPatch() does on the dynamic path: a hull input to inputControlPoints - 1 and, since e4de56f (from review), a domain input to outputControlPoints - 1.

How it was narrowed down on an RX 6700 XT, with local experiments that are not part of this PR:

Local change to main Merged hull case
none fails, a different check on each run
the program's one cross-record LDS read (ds_read_b32 at offset 72) replaced with a copy of its own register passes
that read pointed at the invocation's own record through a constant index (offset 8) fails like main, so it is not cross-invocation visibility
hull barrier with Workgroup memory scope and AcquireRelease | WorkgroupMemory | UniformMemory | ImageMemory instead of Invocation and None fails
the indices folded to constants (this PR) passes

The merged hull case also gets a new check: no access-chain index in its hull stage may be integer arithmetic on two constants. That catches this shape on every device, lavapipe included. On main the check fails.

Tested

Windows 11 26200, RX 6700 XT (gfx1031), AMD driver 32.0.21045.5002, MinGW GCC 15.2.0 Release, ANYPS5_REQUIRE_VULKAN=1. Unless a line says otherwise, the runs below are of 3f059e58c on main f47c85663; 054f8ff4d then added @MarcZX10's propagation to the new check, and e4de56f the domain-input clamp.

  • agc_driver_tessellation, 3 runs per side from renamed copies of the executable, so the driver's pipeline cache starts empty:
    • main fails 3 of 3: level-1 patch not drawn once, level-5 patch without interior points twice.
    • this PR passes 3 of 3.
  • --repeat until-fail:3: 10 of 10 pass with this PR. The 10 are agc_driver_tessellation, agc_driver_prepared_graphics, agc_driver_provoking_vertex, agc_driver_rect_list_corner, agc_driver_pixel_barycentric_emulation, agc_driver_graphics, agc_driver_bda_device, agc_shader_memory, agc_tessellation_lowering and agc_shader_disk_cache.
  • Khronos validation layer, ctest -V on the same 10, main d0852defa against the same change on d0852defa, then again on this head:
    • main passes 9 of 10 (agc_driver_tessellation fails); this PR passes 10 of 10.
    • 0 VUID- lines on either side.
    • VK_LOADER_DEBUG=layer shows the layer inserted in every GPU test process.
  • The new check alone, with the emitter change reverted, fails with the merged hull program indexes a tessellation attribute with arithmetic on constants instead of a constant.
  • The domain-input clamp (e4de56f), with this head merged into main 6ef5a1c4c9, on AMD driver 32.0.21045.16010 (this PC's driver since 2026-10-21; the runs above used 32.0.21045.5002): a new agc_tessellation_lowering case emits a domain read at the immediate address 3 * 16, with 3 output control points and a 16-byte stride, and checks that the access chain indexes control point 2.
    • With only the emitter line reverted, it fails: failed: a domain read at an immediate address past the last control point reads the last control point.
    • With the change, the 10 tests pass 3 of 3. Under the Khronos validation layer they pass 10 of 10 with 0 VUID- lines; VK_LOADER_DEBUG=layer shows the layer inserted.
    • The case builds the IR directly. I found no guest program that reaches it: the lowering refuses a domain read whose immediate offset ends past outputs * controlStride (TessellationLowering.cpp:744-746).

Other GPUs, from reviewers:

Not tested:

  • RADV. Lavapipe only in a later comment; NVIDIA only by @simnJS and @wachi35676 above.
  • The domain-input clamp on GPUs other than the RX 6700 XT, the RDNA 2 iGPU and the RTX 5070 Ti.
  • A title with registered type-3 programs.

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: Fixes AGC: agc_driver_tessellation's merged hull program draws a different wrong patch on each run on AMD's Windows driver #8861
  • Unblocks: none
  • GPUs tested: AMD Radeon RX 6700 XT (gfx1031), AMD Windows driver 32.0.21045.5002, Windows 11 26200; by reviewers: AMD Radeon 860M (gfx1152), AMD driver 32.0.13058.8001, Windows 11 26300 (@LeandroLP23); NVIDIA GeForce RTX 4080 SUPER, driver 616.92, Windows 11 Pro 26200 (@simnJS); AMD Radeon RX 6700 XT, AMD driver 26.10.1, Windows 11 22621 (@JJenkx); AMD Radeon RDNA 2 iGPU (gfx1036), AMD driver 32.0.21042.62, Windows 11, and NVIDIA GeForce RTX 5070 Ti, driver 617.42 (@wachi35676)
  • AI-assisted: yes (Claude Code)

🤖 Generated with Claude Code

@github-actions

github-actions Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

Other open pull requests touch the same code. Merging one will break the other, or both implement the same thing. If this one builds on them, list them in Depends on.

Pull request Conflicting files (lines on main) Same exports Same new files
PR 9743 core/libs/prx/libSceAgcDriver/tests/TessellationLowering.cpp L2-3, L7-8, L208
core/libs/prx/libSceAgcDriver/tests/execution/Tessellation.cpp L948
PR 9806 core/libs/prx/libSceAgcDriver/tests/TessellationLowering.cpp L137, L208

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 6235 core/shader/recompiler/SpirvBackend/src/SpirvModuleEmitter.cpp
PR 6657 core/libs/prx/libSceAgcDriver/tests/execution/Tessellation.cpp
PR 6959 core/shader/recompiler/SpirvBackend/src/SpirvModuleEmitter.cpp
PR 7201 core/shader/recompiler/SpirvBackend/src/SpirvModuleEmitter.cpp
PR 7642 core/libs/prx/libSceAgcDriver/tests/execution/Tessellation.cpp
core/shader/recompiler/SpirvBackend/src/SpirvModuleEmitter.cpp
PR 8563 core/shader/recompiler/SpirvBackend/src/SpirvModuleEmitter.cpp
PR 8564 core/shader/recompiler/SpirvBackend/src/SpirvModuleEmitter.cpp
PR 9020 core/shader/recompiler/SpirvBackend/src/SpirvModuleEmitter.cpp
PR 9335 core/shader/recompiler/SpirvBackend/src/SpirvModuleEmitter.cpp
PR 9356 core/shader/recompiler/SpirvBackend/src/SpirvModuleEmitter.cpp
PR 9387 core/shader/recompiler/SpirvBackend/src/SpirvModuleEmitter.cpp
PR 9508 core/libs/prx/libSceAgcDriver/tests/execution/Tessellation.cpp
core/shader/recompiler/SpirvBackend/src/SpirvModuleEmitter.cpp
PR 9748 core/shader/recompiler/SpirvBackend/src/SpirvModuleEmitter.cpp

@github-actions github-actions Bot added shader core/shader agc libSceAgc* labels Oct 21, 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.

The regression can miss the exact old index chain it is intended to reject. folded only records an integer op when both operand IDs are in constants. With the previous emitter, OpUMod(address, stride) can meet that condition, but the subsequent OpShiftRightLogical(UModResult, 4) and the component shift/and consume result IDs that are not added to constants or propagated through folded. The access-chain indices can therefore remain unmarked and the test may pass with the old emitter restored. Could the check evaluate/propagate constant-expression results (or inspect the expected access-chain index definitions recursively), and confirm that reverting only the emitter makes this assertion fail?

const auto opcode = words[at] & 0xffffu;
if (opcode == spv::OpConstant && count >= 3u) constants.insert(words[at + 2u]);
const bool integer = opcode == spv::OpIAdd || opcode == spv::OpIMul || opcode == spv::OpUDiv || opcode == spv::OpUMod || opcode == spv::OpShiftRightLogical || opcode == spv::OpBitwiseAnd;
if (integer && count == 5u && constants.contains(words[at + 3u]) && constants.contains(words[at + 4u])) folded.insert(words[at + 2u]);

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 small propagation change makes this catch chained expressions too:

Suggested change
if (integer && count == 5u && constants.contains(words[at + 3u]) && constants.contains(words[at + 4u])) folded.insert(words[at + 2u]);
if (integer && count == 5u &&
(constants.contains(words[at + 3u]) || folded.contains(words[at + 3u])) &&
(constants.contains(words[at + 4u]) || folded.contains(words[at + 4u]))) {
folded.insert(words[at + 2u]);
}

Then the OpShiftRightLogical and OpBitwiseAnd results derived from the folded OpUMod become marked before the access chain is checked.

@github-actions github-actions Bot added the fix error Closes an issue (Fixes #N) label Oct 21, 2026
… constants

TessellationPointer built the vertex, attribute and component indices of
an attribute access from its address with OpUDiv, OpUMod, OpShiftRightLogical
and OpBitwiseAnd even when the address was an immediate, and without
SPIRV-Tools nothing folded them. AMD's Windows driver (32.0.21045.5002 on an
RX 6700 XT, 32.0.21042.62 on an RDNA 2 iGPU) reads a per-vertex hull output
indexed that way wrongly: a merged hull program's level read came back
wrong, and agc_driver_tessellation drew a different wrong patch on each run.
A read of the program's own record through a constant index failed the same
way, and the test passes once the indices are OpConstants, as glslang emits
them.

The merged hull case now also checks that no access chain index of the hull
stage is arithmetic on constants, so the shape is caught on every device.

Fixes boykopovar#8861

Co-Authored-By: Claude <noreply@anthropic.com>
@thuanquang
thuanquang force-pushed the fix/tess-constant-attribute-indices branch from 3f059e5 to 054f8ff Compare October 21, 2026 05:31
@thuanquang

Copy link
Copy Markdown
Contributor Author

@MarcZX10 good catch, thank you. I applied your suggestion: an operand now counts if it is a constant or an already-folded result, so chained shifts and masks are marked too. The new head is 054f8ff4d.

On main's merged hull module (dumped from the same test):

  • The old check marked 5 index slots, all of them vertex indices (OpUDiv of two constants). It did fail on main, but only through those.
  • The propagating check marks 29: 5 vertex, 13 location and 11 component indices.

On the RX 6700 XT:

  • With only the emitter change reverted, the test fails at the new assertion (the merged hull program indexes a tessellation attribute with arithmetic on constants instead of a constant).
  • With the change, it passes 3 of 3.

@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 updated regression now propagates folded integer expressions through chained shifts/masks and checks the access-chain indices, addressing the false-negative risk I raised. The author reports the test fails with only the emitter change reverted and passes with the fix on the RX 6700 XT; the targeted AMD before/after runs and validation-layer results are recorded in the PR. I reviewed the updated diff and found no remaining blocker. I could not reproduce the GPU path in this Linux environment.

@thuanquang

Copy link
Copy Markdown
Contributor Author

A Linux run, since this PR's runtime CI jobs were skipped. It uses lavapipe from Mesa 25.2.8 with LLVM 20.1.2, the same driver as Linux CI, on Ubuntu 24.04 (WSL) with GCC 13.3, Release, -DANYPS5_ENABLE_SPIRV_TOOLS=ON as on CI, ANYPS5_REQUIRE_VULKAN=1 and ANYPS5_NO_SHADER_CACHE=1.

This PR's commit 054f8ff4d was applied onto a main d0852defa build. That tree also carries #8055's float-atomic files, which this test doesn't reach. agc_driver_tessellation passes 3 of 3, and the new SPIR-V check passes, so lavapipe's merged hull module has no constant-arithmetic indices either.

@DavidSamir

Copy link
Copy Markdown
Contributor

Independent test on a second AMD driver and an RDNA 2 iGPU, the setup the PR lists as not tested.

Setup: AMD Radeon 680M (RDNA 2 iGPU, Ryzen 7 6800H, deviceID 0x1681), AMD Windows driver 32.0.21030.2001 (Adrenalin 25.10.30.02, Vulkan 1.4.315), Windows 11 26200, WinLibs GCC 15.2.0 r7, Release. main is 1ff5c8ac5. The branch is this PR's head 054f8ff4d merged into that same main, built in a separate build directory. ANYPS5_REQUIRE_VULKAN=1 and ANYPS5_NO_SHADER_CACHE=1 on both sides.

agc_driver_tessellation, 3 runs per side from renamed copies of the executable (empty driver pipeline cache):

Run main this PR
1 fails: merged hull program, unculled: the level-1 patch was not drawn as one flat triangle, centre (16, 24, 40, 255) passes
2 fails: same check passes
3 fails: merged hull program, unculled: the patch with level 0 was not culled passes

Run 3 on main hits a third check that #8861 doesn't list, which fits the "different wrong patch on each run" reading.

ctest --repeat until-fail:10: main fails on the first iteration; this PR passes 10 of 10.

Khronos validation layer (SDK 1.4.363, VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation, ctest -V) on the PR's 10 tests (agc_driver_tessellation, agc_driver_prepared_graphics, agc_driver_provoking_vertex, agc_driver_rect_list_corner, agc_driver_pixel_barycentric_emulation, agc_driver_graphics, agc_driver_bda_device, agc_shader_memory, agc_tessellation_lowering, agc_shader_disk_cache):

  • main: 9 of 10 pass; agc_driver_tessellation fails.
  • this PR: 10 of 10 pass.
  • No was not found but was requested by env var VK_INSTANCE_LAYERS on either side.
  • The PR adds no VUID- lines. Both sides have the same single error, from agc_driver_rect_list_corner: VUID-VkShaderModuleCreateInfo-pCode-08737, Expected vector sizes of Result Type and the condition to be equal: Select (OpSelect %v4float with a scalar condition). It is on main already and unrelated to this change.

Result: the fix holds on a second AMD Windows driver version and on RDNA 2 integrated graphics.

AI-assisted: yes

@MarcZX10

Copy link
Copy Markdown
Contributor

Thanks for both follow-ups. The RX 6700 XT run with the emitter-only negative control confirms the new constant-index assertion catches the original path, and the Linux/lavapipe run extends coverage to the other CI driver. The independent Radeon 680M comparison is especially useful: three failures on the same main build versus 10/10 passes on this head, with the validation-layer suite also clean of new VUIDs.

@LeandroLP23

Copy link
Copy Markdown
Contributor

An RDNA 3.5 data point: Radeon 860M (gfx1152, Windows 11 26300), AMD driver 32.0.13058.8001, MinGW GCC 15.2 Release. ANYPS5_REQUIRE_VULKAN=1 ANYPS5_NO_SHADER_CACHE=1, and each run used a renamed copy of the exe, so the driver's pipeline cache started empty.

tree agc_driver_tessellation
main 2c4b116da9 5 of 5 pass
this PR 054f8ff4de 5 of 5 pass

So this driver and GPU don't show #8861: the merged hull check passes on main, and the 860M can't serve as a red control. The PR doesn't break it, and the new constant-index assertion passes here.

On the PR head, the 14 tests matching tess|hull|spirv|recompiler|geometry|^agc_driver_graphics$ pass. I built with -k 0; the only target that doesn't build is ImageArrayWindowPastLayerLimit.cpp, as on main.

@simnJS

simnJS commented Oct 21, 2026

Copy link
Copy Markdown

NVIDIA, Windows. GeForce RTX 4080 SUPER, driver 616.92 (32.0.16.1692), Windows 11 Pro 26200, Ryzen 9 7950X3D, WinLibs GCC 15.2.0 r7, Release.
Head 054f8ff4d merged into main cecb540a6 (clean merge).

ANYPS5_GPU=NVIDIA ANYPS5_REQUIRE_VULKAN=1 ANYPS5_NO_SHADER_CACHE=1, ctest --test-dir build -R "^(agc_driver_tessellation|agc_driver_prepared_graphics|agc_driver_provoking_vertex|agc_driver_rect_list_corner|agc_driver_pixel_barycentric_emulation|agc_driver_graphics|agc_driver_bda_device|agc_shader_memory|agc_tessellation_lowering|agc_shader_disk_cache)$" --output-on-failure --timeout 120 --repeat until-fail:3 -V.

Selected GPU name=NVIDIA GeForce RTX 4080 SUPER vendor=0x10de device=0x2702 subgroup=32 appears in agc_driver_tessellation, _pixel_barycentric_emulation, _prepared_graphics, _provoking_vertex and _rect_list_corner. agc_driver_graphics, agc_driver_bda_device and agc_shader_disk_cache print no device line. agc_shader_memory and agc_tessellation_lowering run on the CPU. No test skipped.

test with PR main SpirvModuleEmitter.cpp + PR tests
agc_driver_tessellation 3/3 (0.64, 0.63, 0.65 s) 0/3 (0.36, 0.38, 0.38 s): the merged hull program indexes a tessellation attribute with arithmetic on constants instead of a constant, which AMD's Windows driver reads wrongly
agc_driver_graphics 3/3 (6.48, 6.19, 6.32 s) 3/3 (6.15, 6.33, 6.28 s)
agc_driver_bda_device 3/3 (5.61, 1.30, 1.04 s) 3/3 (1.05, 1.09, 1.00 s)
agc_shader_disk_cache 3/3 (1.97, 1.79, 1.79 s) 3/3 (1.98, 1.83, 1.82 s)
agc_driver_pixel_barycentric_emulation 3/3 (0.51, 0.35, 0.35 s) 3/3 (0.39, 0.36, 0.37 s)
agc_driver_prepared_graphics 3/3 (0.39, 0.30, 0.33 s) 3/3 (0.31, 0.30, 0.30 s)
agc_driver_provoking_vertex 3/3 (0.43, 0.31, 0.32 s) 3/3 (0.32, 0.30, 0.30 s)
agc_driver_rect_list_corner 3/3 (0.39, 0.32, 0.31 s) 3/3 (0.33, 0.29, 0.29 s)
agc_shader_memory 3/3 (0.42, 0.29, 0.29 s) 3/3 (0.42, 0.29, 0.29 s)
agc_tessellation_lowering 3/3 (0.05, 0.02, 0.02 s) 3/3 (0.05, 0.02, 0.02 s)

With both files at main, the test file included, agc_driver_tessellation passes 3 of 3 (0.95, 0.64, 0.61 s). It passes 3 of 3 again with __GL_SHADER_DISK_CACHE=0 set; I did not check that the Windows driver honours that variable. All runs used the same executable name, not renamed copies. So this driver does not show #8861's wrong patches, and the PR's new SPIR-V check is the only red result on main here.

Khronos validation layer not run: the Vulkan SDK is not installed on this machine.

AI-assisted: yes

@adriadam10 adriadam10 self-assigned this Oct 21, 2026

@adriadam10 adriadam10 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the fix and the thorough multi-GPU data. One difference from the dynamic path remains:

  • SpirvModuleEmitter.cpp:850: the dynamic path passes the control point through inPatch(), which clamps with UMin for both ControlInput (to inputControlPoints - 1) and EvaluationInput (to outputControlPoints - 1). The immediate path clamps only ControlInput, so an immediate EvaluationInput address at or beyond stride * outputControlPoints gives an out-of-range access-chain index where main clamped. Please clamp EvaluationInput to outputControlPoints - 1 on the host as well, and add a case to the test with an immediate address past the last control point.

Everything else matches the dynamic path (LocalOutput/patch, own-lane kinds, % stride offsets).

@JJenkx

JJenkx commented Oct 21, 2026

Copy link
Copy Markdown
Contributor

Validated on AMD's Windows driver: Radeon RX 6700 XT, AMD proprietary driver 26.10.1, Windows 11 10.0.22621, WinLibs GCC 15.2 UCRT, Release.

agc_driver_tessellation, run 10 times one after another:

@wachi35676

Copy link
Copy Markdown
Contributor

The run on 32.0.21042.62 you asked for. AMD Radeon RDNA 2 iGPU (1002:13c0, gfx1036), AMD driver 32.0.21042.62, Windows 11, WinLibs GCC 15.2.0, Release, ANYPS5_GPU=AMD ANYPS5_REQUIRE_VULKAN=1 ANYPS5_NO_SHADER_CACHE=1. main is a6dcea927; the PR side is main with this head 054f8ff4d merged (clean), built in the same build directory. Each run used a renamed copy of the executable, so the driver's pipeline cache started empty.

main this PR
agc_driver_tessellation, AMD fails 3 of 3: merged hull program, unculled: the level-1 patch was not drawn as one flat triangle, centre (16, 24, 40, 255) passes 3 of 3
agc_driver_tessellation, RTX 5070 Ti (617.42) passes 3 of 3 passes 3 of 3

Your 10 tests plus agc_tessellation_factor_ring and the sample-order and multisample tests (23 in all, ctest -j1) on the PR side: the 5070 Ti passes them all; on the AMD iGPU only agc_driver_sample_order_grid_reference fails, which fails on main too (#9056's thread; not related to this change).

Not run: the Khronos validation layer (not installed on this machine).

AI-assisted: yes (Claude Code); results above were run on this machine.

…control point

The dynamic path of TessellationPointer passes the control point through
inPatch(), which clamps it with UMin to inputControlPoints - 1 for hull
inputs and to outputControlPoints - 1 for domain inputs. The immediate
path clamped only hull inputs, so a domain read at an immediate address
past the last control point indexed the input array past its end. It
now clamps domain inputs to outputControlPoints - 1 too.

Co-Authored-By: Claude <noreply@anthropic.com>
@thuanquang

thuanquang commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor Author

@adriadam10 done in e4de56f. The immediate path now clamps an EvaluationInput control point to outputControlPoints - 1, as inPatch() does on the dynamic path.

The new case is in agc_tessellation_lowering (CPU only). It emits a domain read at the immediate address 3 * 16, with 3 output control points and a 16-byte stride, and checks that the access chain indexes control point 2. It builds the IR directly because I found no guest program that reaches this: the lowering refuses a domain read whose immediate offset ends past outputs * controlStride (TessellationLowering.cpp:744-746).

RX 6700 XT, AMD driver 32.0.21045.16010, this head merged into main 6ef5a1c:

  • With only the emitter line reverted, the new case fails: failed: a domain read at an immediate address past the last control point reads the last control point.
  • With the change, the 10 tests from the description pass 3 of 3. Under the Khronos validation layer they pass 10 of 10 with 0 VUID- lines.

@wachi35676

Copy link
Copy Markdown
Contributor

Re-ran e4de56f3c on the same AMD driver as before: RDNA 2 iGPU 1002:13c0, 32.0.21042.62, Windows 11, WinLibs GCC 15.2.0, Release, ANYPS5_REQUIRE_VULKAN=1 ANYPS5_NO_SHADER_CACHE=1. The head is merged onto the earlier base, along with #9056, #9057 and #9503.

  • agc_driver_tessellation and agc_tessellation_lowering pass 3/3 on the iGPU (ANYPS5_GPU=AMD), so the EvaluationInput clamp keeps the fix there.
  • They also pass 3/3 on the RTX 5070 Ti (617.42).

AI-assisted: yes (Claude Code); results above were run on this machine.

@adriadam10
adriadam10 merged commit 3cd82ff into boykopovar:main Oct 22, 2026
16 checks passed
@adriadam10

Copy link
Copy Markdown
Collaborator

Checked the new commit against the dynamic path: an immediate EvaluationInput address is now clamped to outputControlPoints - 1 like inPatch() does, and the new agc_tessellation_lowering case (address 3 * 16 → control point 2) fails without the clamp. The multi-GPU runs from @JJenkx and @wachi35676 (RX 6700 XT, RDNA 2 iGPU, RTX 5070 Ti) cover the rest; merged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agc libSceAgc* fix error Closes an issue (Fixes #N) shader core/shader

Projects

None yet

Development

Successfully merging this pull request may close these issues.

AGC: agc_driver_tessellation's merged hull program draws a different wrong patch on each run on AMD's Windows driver

8 participants