Skip to content

fix(agc): accept fractional-even tessellation partitioning - #5402

Merged
adriadam10 merged 1 commit into
boykopovar:mainfrom
codingreapermaps:feat/agc-fractional-even-partitioning
Oct 14, 2026
Merged

adriadam10 merged 1 commit into
boykopovar:mainfrom
codingreapermaps:feat/agc-fractional-even-partitioning

Conversation

@codingreapermaps

@codingreapermaps codingreapermaps commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

What

Tessellation with VGT_TF_PARAM.PARTITIONING 3 (fractional-even) threw only triangle and quad domains with integer or fractional-odd partitioning and triangle output are supported by the reference path. #5234 left this mode for its own PR; this is that PR.

  • Partitioning 3 compiles to Vulkan's SpacingFractionalEven, which radeonsi programs as PART_FRAC_EVEN. The draw state, the shader input info, the SPIR-V emitter and the pipeline's module check all accept it.
  • Its factors are bounded at 64, as for integer partitioning; only fractional-odd keeps 63.
  • The lower end of the range is not clamped in the hull program: Vulkan raises every factor of a fractional-even patch that is not culled to at least 2, which is also the D3D11 range for this mode ([2, 64]). A VGT_HOS_MAX_TESS_LEVEL below 2 therefore still tessellates at 2; the console's order of that clamp and the minimum is not measured and is recorded in docs/dev/debt/shader.md.
  • Power-of-two partitioning (1) still throws.

Tested

Windows 11, MinGW-w64 GCC 15.2.0, NVIDIA GeForce MX450 (driver 581.83) and lavapipe (Mesa 26.2.4, mesa-dist-win).

  • agc_driver_graphics_tests: VGT_TF_PARAM 0x4004d decodes as partitioning 3 and is no longer refused; 0x40045 (power of two) still is.
  • agc_driver_tessellation_tests: new RequireFractionalEvenPartitioning checks that the domain module has fractional-even spacing and that the hull bounds factors at 64. Its domain program lowers each domain point by 3·min(u, v, w), so edge points stay in place and only an interior point reaches below the patch. With integer spacing the level-1 patch covers nothing below its base and the level-5 patch does. With fractional-even spacing the level-1 patch does too (raised to level 2), the level-0 patch is culled and the level-5 patch has interior points. All tessellation tests pass on NVIDIA and lavapipe.
  • PPSA12361 (Transport Fever 2: Console Edition): without the change it stops with the error above while loading a map; with it the map loads (its ambient audio plays) and the title reaches its first frame of the map, where it stops on an unrelated multisampled storage image write.
  • The tests ran on this branch, on main at 43349d433. The title ran on a local branch with this change and unrelated local changes (feat(agc): sample a multisampled color target through its 2D MSAA texture #4820 among them).

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
  • Unblocks: PPSA12361 (no Game bring-up discussion yet)
  • GPUs tested: NVIDIA GeForce MX450, driver 581.83, Windows 11; lavapipe (Mesa 26.2.4), Windows 11
  • AI-assisted: yes

@coltken95

Copy link
Copy Markdown

Tested on Linux x86-64 (Release build, lavapipe / llvmpipe LLVM 20.1.2), with 6e52733 merged into main 18c438b:

  • With the PR: agc_driver_graphics passes (it fails on main), but agc_driver_tessellation fails at the new fractional-even case:
    AGC graphics: fractional-even partitioning: the level-1 patch was not raised to level 2 with a domain point at its centre, (255, 0, 0, 255)
  • On main the same test stops earlier, as expected, with only triangle and quad domains with fractional-odd partitioning and triangle output are supported by the reference path.

I can't tell from here whether this is specific to lavapipe's tessellator; the PR was tested on an NVIDIA MX450 under Windows.

AI-assisted: yes (Claude Code)

@oneandonlydean

Copy link
Copy Markdown
Collaborator

coltken95's lavapipe run fails the new case: the level-1 patch was not raised to level 2 with a domain point at its centre. CI runs these tests on lavapipe, so please find out whether the test or the clamp is wrong there.

The branch also carries a copy of #5234's commit; once #5234 is in, please rebase so only yours is left.

RINNECODER added a commit to RINNECODER/AnyPS5 that referenced this pull request Oct 14, 2026
* fix(agc): accept integer tessellation partitioning

Ported from upstream PR boykopovar#5234, adapted to our triangle/fractional-odd
only tessellation path: VGT_TF_PARAM.PARTITIONING 0 decodes, emits equal
spacing and bounds factors at 64. Metal still refuses guest tessellation
draws in MetalRenderState.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DgW4n3qYgi5jAAohEmXRQj

* fix(agc): accept fractional-even tessellation partitioning

Ported from upstream PR boykopovar#5402 (its integer-partitioning base commit is
the previous commit), adapted to our triangle-only tessellation path:
VGT_TF_PARAM.PARTITIONING 3 decodes, emits fractional-even spacing and
bounds factors at 64. Metal still refuses guest tessellation draws.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DgW4n3qYgi5jAAohEmXRQj

* fix(shader): place hull input components by their offset in the control-point slot

Ported from upstream PR boykopovar#4723 (shader hunk; its Vulkan execution test is
not ported).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DgW4n3qYgi5jAAohEmXRQj

* fix(shader): lower hulls with one input or one output control point (partial)

Ported from upstream PR boykopovar#5457, commits 1, 4 and 5 of 5 (hull exec masks
restored through phis, input stride from the patch term, one output
control point per patch). Vulkan execution-test hunks are not ported.

Skipped from boykopovar#5457, with reasons:
- relative patch index rebuilt as data: needs GE_CNTL.PRIM_GRP_SIZE and
  BREAK_WAVE_AT_EOI in TessellationConfiguration, VGT_LS_HS_CONFIG
  patchesPerGroup and the request key/serializer additions. None of
  these exist on main, which only lowers triangle fractional-odd hulls.
- recording BDA faults in hull programs: drops a refusal whose safety
  rests on upstream hull work we lack; the refusal stays.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DgW4n3qYgi5jAAohEmXRQj

* fix(shader): honour SPI_BARYC_CNTL.FRONT_FACE_ALL_BITS for the front-face input

Ported from upstream PR boykopovar#5314. Tracks SPI_BARYC_CNTL in the draw key and
shader request key, and bumps the request serialization to version 24
(shared with the following slice-offset port, which adds no second bump).

Not ported: the ShaderMemory serializer-version assertions of the PR,
which build on upstream test scaffolding absent from main.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DgW4n3qYgi5jAAohEmXRQj

* fix(shader): propagate color view slice to pixel ancillary input

Ported from upstream PR boykopovar#5500, adapted to main: the draw decode sets the
color view slice as layerBase (the layer-export decode this PR also
touches does not exist on main, so its diagnostic and layers hunks are
skipped). layerBase is added to the pixel info, request key, shader info,
disk cache and pipeline specialization constants. The request
serialization stays at version 24, bumped once by the front-face commit.
The shader disk cache format is bumped to 36.

Not ported: unrelated hunks the upstream commit carried in Recompiler.cpp
(dot-product capability option) and its ShaderMemory serializer tests.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DgW4n3qYgi5jAAohEmXRQj

* test(shader): cover tessellation partitioning, hull slot placement, layerBase and serializer v24

Fix the stale serialization version expectation in the shader memory test,
add pixel ancillary rows with a non-zero layerBase, extract PixelLayerBase
for a derivation test, and point the FrontFace note at TechnicalDebt.md.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DgW4n3qYgi5jAAohEmXRQj

---------

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-authored-by: XairRrR <dev910382@gmail.com>
@codingreapermaps
codingreapermaps force-pushed the feat/agc-fractional-even-partitioning branch from 6e52733 to c3de6c7 Compare October 14, 2026 09:53
@codingreapermaps

Copy link
Copy Markdown
Contributor Author

The test was wrong, not the clamp. The test pixel shader reads the colour with v_interp_mov_f32 from P0, so every tessellated triangle is flat-shaded with its provoking vertex. The check at the centre therefore depended on which vertex the tessellator emits first, and that order is implementation-dependent. NVIDIA puts the centre point first in each of the six triangles around it, so the centre read 255. lavapipe puts an edge point first, so it read 0. Integer spacing with every factor at 2, which this PR does not touch, gives the same split: 255 on NVIDIA, 0 on lavapipe.

The new test does not depend on the vertex order. Its domain program lowers each point by 3·min(u, v, w), so edge points stay in place and only an interior point reaches below the patch's base. With integer spacing, the level-1 patch covers nothing below its base. With fractional-even spacing, it does (raised to level 2). The level-5 patch covers that area in both modes. It passes on NVIDIA and on lavapipe (Mesa 26.2.4), which raises the level-1 factors to 2 like the D3D11 tessellator it is built on (TriProcessTessFactors).

Rebased on main now that #5234 is in; only this PR's commit is left.

@github-actions github-actions Bot removed the needs rebase Conflicts with main, rebase needed label Oct 14, 2026
@codingreapermaps
codingreapermaps force-pushed the feat/agc-fractional-even-partitioning branch from c3de6c7 to ba4201d Compare October 14, 2026 14:26
@github-actions github-actions Bot added the needs rebase Conflicts with main, rebase needed label Oct 14, 2026
@adriadam10 adriadam10 self-assigned this Oct 14, 2026
VGT_TF_PARAM.PARTITIONING 3 now compiles to Vulkan's fractional-even
spacing, which radeonsi programs as PART_FRAC_EVEN. Its factors are
bounded at 64 like integer partitioning; Vulkan raises the remaining
ones to at least 2, the D3D11 range for this mode.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@adriadam10
adriadam10 force-pushed the feat/agc-fractional-even-partitioning branch from ba4201d to f8e8aca Compare October 14, 2026 19:27
@adriadam10

Copy link
Copy Markdown
Collaborator

Checked on a rebase onto current main (only docs/dev/debt/shader.md conflicted; I kept main's relative patch index line and this PR's lines): scoped build + ctest green; agc_driver_graphics and agc_driver_tessellation also pass on CI's lavapipe (Mesa 25.2.8). With the code changes reverted both tests fail, so they pin the change. The fractional-even test no longer depends on the tessellator's vertex order. Pushing the rebase; merging once CI is green.

@github-actions github-actions Bot removed the needs rebase Conflicts with main, rebase needed label Oct 14, 2026
@adriadam10
adriadam10 merged commit f2aa48a into boykopovar:main Oct 14, 2026
8 checks passed
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