Repository navigation
feat(shader): emulate barycentrics through tessellation on devices without geometry shaders - #7308
Merged
oneandonlydean merged 7 commits intoOct 17, 2026
Conversation
…stages Since boykopovar#3878 every vertex program that exports a position also writes gl_ClipDistance for the all-zero position distance. The tessellation stages generated for rect lists declared only gl_Position in gl_in, so their input interface no longer matched the vertex outputs; on MoltenVK the control stage then reads all-zero positions and every rect-list draw stops with "rect-list requires finite nondegenerate axis-aligned positions" (reported in boykopovar#1). The control and evaluation stages now declare the vertex program's gl_ClipDistance array in their per-vertex blocks and forward it. The generated fourth corner gets the clip distances interpolated with the same weights as its position, so the all-zero position clip keeps working for rect lists. Validation accepts gl_ClipDistance as a tessellation input and as a tessellation-control output. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QXdkh9PHBCPqGcGQPeikAe
On a device without geometry shaders, each triangle becomes a three-point patch at tessellation level 1. The evaluation stage takes the corner gl_TessCoord points at as its vertex and writes it as the weights, and passes every vertex's parameters for raw reads. The vertex clip distances are forwarded, so MoltenVK's stage interface matches the vertex output.
… shaders A triangle list without primitive restart whose pixel shader emulates barycentrics draws through the generated tessellation stages when the device has tessellation but no geometry shaders, as on MoltenVK. The pipeline uses a three-point patch list for it, keeps it out of pipeline libraries and validates the generated stages' modes and interface.
…ic-tessellation # Conflicts: # core/libs/prx/libSceAgcDriver/Graphics/src/Pipeline.cpp # docs/dev/debt/shader.md
This was referenced Oct 17, 2026
Open
|
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.
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.
|
11 tasks done
12 tasks done
11 tasks done
This was referenced Oct 18, 2026
Merged
12 tasks done
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
On a device without geometry shaders, a pixel shader that needs exact barycentrics or raw vertex values (and so uses the barycentric emulation) stops the draw with
Barycentric geometry SPIR-V: geometry shaders are unavailable. MoltenVK on Apple GPUs has no geometry shaders, so on macOS this ends many catalog titles, most of them a few seconds after start-up. MoltenVK does have tessellation, which can do the same job:BuildBarycentricTessellationShaders, next to the geometry stage inBarycentricGeometryShader.cpp). Each triangle of a triangle list becomes one three-point patch at tessellation level 1, so it comes out as the same single triangle. At each corner the evaluation stage readsgl_TessCoordto pick its vertex, then writes that corner as the weights and passes every vertex's parameters for raw reads. This is the same data the geometry stage provides. A flat parameter takes the first vertex's value, as the geometry stage's strip gives it.gl_ClipDistance, which every position export has written since fix(shader): clip primitives with an all-zero clip position #3878, goes through both stages. Without it, MoltenVK laid out the control stage's input differently from the vertex output: it read every position from the wrong offset, and nothing was drawn. fix(shader): forward gl_ClipDistance through the generated rect-list stages #7124 found the same for rect lists; this PR uses itsVertexClipDistanceCountand builds on it.geometryShader. The tessellation stages are used only when the device hastessellationShaderbut nogeometryShader, and only for a triangle list without primitive restart. Strips, fans and restart still throw, with a message saying so.ShaderValidationaccepts the generated stages and checks their execution modes and three-element interface arrays. A four-stage vertex pipeline whose pixel shader does not emulate barycentrics still fails with "incorrect graphics stage count".VertexOrderCw, which keeps the triangle's facing; the draw test checks this with face culling.shader.mddebt entries are updated.Commits: refactor, recompiler stages, driver wiring, tests, docs, then a merge of current
main. In the merge, #7251's new last-vertex rect-list control stage also gets #7124's clip-distance argument, without whichRectListShaders.cppdoesn't compile.Related: #7201 handles MoltenVK per-vertex inputs differently, by rebuilding them from barycentric coordinates and derivatives; #6941 covers the mesh path. Neither generates tessellation stages for the vertex path.
Tested
Apple M2, macOS 26.7.1, MoltenVK 1.4.2 (
geometryShaderfalse,tessellationShadertrue), x86-64 under Rosetta, on the community macOS stack (mugurc's port branches overmainfrom 15 Oct) with #7124 applied, Release build. The changed files of this branch, as merged with currentmain, also compile on this Mac with SPIR-V Tools on.main's own libc doesn't build on macOS, so the tests ran on the port stack.agc_driver_pixel_barycentric_emulation(extended). It now runs the geometry route where the device has geometry shaders and the tessellation route where it has tessellation; before, it skipped any device withoutgeometryShader.main's test reportsskipped, the device lacks geometryShader.v_interp_movP0/P10/P20) are exact, host interpolation is unchanged, and back- and front-face culling give the same result as the same draw without emulation.MVK_CONFIG_DEBUGshowed MoltenVK's control-stage input struct asuint4, uint, float4 gl_Positionagainst a vertex output ofout_param_0, gl_Position, gl_ClipDistance[1], i.e. a mismatched layout. Forwarding the clip distances fixed it.VertexOrderCcwthen failed the culling check andVertexOrderCwpassed.agc_driver_graphics_tests(new unit tests) passes. It covers:shaderClipDistance.agc_fragment_barycentric,agc_driver_interpolation_modes,agc_driver_draw_offset_indices,agc_rect_list_position_invariant,agc_driver_indirect_patched_stage;agc_driver_interpolation_f16(nofragmentShaderBarycentric).agc_driver_tessellation(hull relative patch index) andagc_driver_pixel_ancillary_word(its pixel shader needs the Geometry capability).Titles (homebrew catalog, checksum-checked, 60 s each, relinked for macOS):
All of these stopped with
Barycentric geometry SPIR-V: geometry shaders are unavailablebefore. For three of them I rebuilt the same tree without this change and re-ran them:From earlier runs of the same stack:
last provoking vertex requires VK_EXT_provoking_vertex with provokingVertexLast enabled, which the M2 also lacks; the generated stages could handle that too, as fix(agc): draw rect lists in last provoking vertex mode #7251 does for rect lists, so it's a follow-up.Device limits of the M2 that stop titles here, not tested past them: no
geometryShader,shaderFloat64,VK_EXT_provoking_vertexorVK_EXT_depth_range_unrestricted.Not tested yet: Windows and Linux. There the geometry route is unchanged and the tessellation route runs only from the extended test, which lavapipe and other drivers with tessellation will run in CI. vkQuake (PPSA99010) is not tested here; on this Mac it stops earlier, creating its Vulkan surface.
Checklist
main; no other open PR implements the same functionsNotImplemented_nid_no_patch); silent stubs are listed under Silent stubs in their library's technical debt file.mdfiles or images added to the repository (attach them to this PR)