Repository navigation
feat(shader): read hull inputs at a control-point index computed from data - #4727
Conversation
… data A hull program may read its input control points from LDS at an index it computes from data, such as an index loaded from memory or min(invocation, n). The tessellation lowering refused such a read because its address is not affine in the invocation and relative patch. The address evaluator now carries a dynamic term for a hull LDS read: a value that is not affine but does not depend on the relative patch index, with the multiple it is scaled by. Terms of the same value add up ((t << 1) + t of t = index << 3 is 24 * index); terms of different values keep the greatest common divisor of their multiples. The read is lowered from the program's own address arithmetic, and the relative index may reach it only with the stride of a patch's inputs. A computed offset that is not a whole number of control points is refused. The SPIR-V emitter clamps a hull input control-point index to the patch's last input, recorded as technical debt: on the console an index past the patch reads LDS of a neighbouring patch.
|
A second-vendor run, to go with the RTX 5090 one. Setup: Windows 11 (26200), WinLibs GCC 15.2.0 r7, Release, CI configure flags, an RTX 4070 Laptop GPU and an Intel Raptor Lake-S iGPU (
Written with AI assistance. |
|
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.
|
|
Main regression found:
Reproduce: The failure is inside the driver, which usually means the emitted SPIR-V is malformed in a way lavapipe and the Windows drivers tolerate but RADV does not — the hull input indexing this PR adds is the prime suspect. Happy to provide the full backtrace, the generated SPIR-V dump, or bisect further within the commit if useful. |
|
Additional data point on the regression: I checked whether the open #4723 (the hull input component-offset fix, rebased on top of current main including this PR) resolves the segfault — it does not; |
|
Thanks for the bisect. I think this is a Mesa 26.2 bug, not something wrong in the SPIR-V this PR emits:
So it is best reported to Mesa; the four |
What
Tessellation lowering refuses a hull LDS read whose input control-point index is computed from data. Its address is not affine in the invocation and relative patch, so the read fails with "the tessellation ring or LDS address is not affine". PPSA01317's hull programs loop over a per-patch mask and read input control points at an index loaded from memory, so main refuses these draws. Stop line: the lowering accepts such a read when the computed part of the address is a whole number of control points and does not depend on the relative patch index.
AddressEvaluatorgives a hull LDS read (only that access kind) a dynamic term: a value that is not affine but is computed without the relative patch index, and the multiple it is scaled by. Terms of the same value add up, so(t << 1) + toft = index << 3is24 * index. Terms of different values keep the gcd of their multiples. The dynamic term never passes through masks, shifts right, disjoint ORs, selects or phis whose arms differ.inputs * localStridein the relative index. When the read has no invocation term, that also sets the local stride.requireRelativeIndependenceaccepts the relative index reaching such a read only with that stride, which the existing replacement of the index by 0 removes.TessellationPointerclamps a hull input control-point index toinputControlPoints - 1(UMin), on both the fast path and the general path. This differs from the console, where an index past the patch reads LDS of a neighbouring patch. The host has no such memory, and Vulkan leaves an out-of-rangegl_inindex undefined. The index is only known when the program runs, so only the offset can be refused at compile time. The clamp is recorded indocs/dev/debt/shader.md. For reads with a static index, the lowering already proves the index is in range, so the clamp has no effect on them.HullSquaredAddress(addressinv * inv) is now refused as "not a whole number of control points" instead of "not affine". It is still refused, and its expected reason is updated.This overlaps the open tessellation stack #4082 → #4114 → #4163 → #4172 → #4201 → #4222 → #4450. In particular, #4201 edits
requireRelativeIndependence. None of those PRs accepts a data-computed control-point index. This PR is based onmainand will rebase on whichever merges first.Tested
Windows 11, MinGW-w64 GCC, NVIDIA RTX 5090 Laptop (Vulkan), Release,
ANYPS5_NO_SHADER_CACHE=1.agc_driver_tessellationgains two triangle-patch hulls derived from itsHullCode:HullDynamicIndexreads its input control point atmin(inv, 2) << 5(v_min_u32thenv_lshlrev_b32). It must draw likeHullCode(levels 1/0/5, culling, winding).HullHalfSlotIndexscales the same index by 16, half the 32-byte slot. It must be refused as not a whole number of control points.Before (main, with the new tests):
With the refusal check removed, the
HullDynamicIndexdraw fails on main with the same error:After:
Before this change, all four tessellation and control-flow tests passed on main (without the new fixtures).
agc_structurizer,agc_shader_memoryandagc_validate_programalso pass with the change.Not tested: console behaviour, or the full ctest suite.
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)