An invalid-descriptor fault check of a GPU-descriptor buffer access, and the
swizzle-selector check of a formatted load, is not emitted when an identical
check on the same descriptor under the same execution guard sits earlier in
the same IR block or in a dominating block. The fault record, the invocation
stop and the host error stay the same; only the pc stored for a fault that two
invocations race to record can differ. APS5_NO_FAULT_CHECK_DEDUP restores every
check.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Conflicts resolved:
- libSceAgcDriver CMakeLists.txt: main moved test registration into tests/cmake/<exe>.cmake (tools/agc_test_split.py resolve); this branch's nested image table tests now sit in agc_driver_image_table_tests.cmake, and its nested snapshot retry test sits next to main's descriptor phis test in agc_shader_memory_tests.cmake.
- ResourceMaterializer.cpp: table equality compares both this branch's nested/pointers and main's resourceViews; the footprint counts main's resource views and this branch's pointers.
- ShaderDiskCache.cpp: both sides grew the descriptor source record (this branch: TableColumn::buffer, 1 byte; main: requiredBlocks, an 8-byte count), so the decoder minimum is 72 + 1 + 8 = 81, and the field-count asserts are DescriptorSource 4 and TableColumn 19.
- ShaderDiskCache.hpp: FormatVersion 56, an unclaimed number (main has 52; 53, 54 and 55 are already set by other open PRs).
- ResourceMaterializer.cpp (semantic, no text conflict): main added the per-image resourceViews loop to Snapshot(source, table), and it uses the top-level table index; this branch moved that copying into CopyRecords(), which nested tables share and which has no table index. The loop now runs in Snapshot right after CopyRecords, as on main; nested tables carry no resource views, as before.
The descriptor web entry and APS5_STRICT_DESCRIPTOR_WEBS said "texels";
the fold takes image loads and samples only. A path through an image
gather or an image atomic's returned value still throws.
AI-assisted.
Allow byte and word SDWA destinations, with every source select, on
v_cvt_f32_i32 and v_cvt_f32_u32. The source is selected and extended,
converted once, and the low byte or word of the f32 bit pattern is placed
with DST_UNUSED pad, sign-extend or preserve (RDNA2 ISA 12.8 opcodes 5-6,
6.8 and 13.3.7 Table 88; LLVM 19.1.0 VOP1Instructions.td L288-L289 and
SIPeepholeSDWA.cpp destination folding).
On an NVIDIA RTX 3060 (driver 610.88), OpConvertUToF of an
OpBitFieldSExtract result converts the field as signed, so v_cvt_f32_u32
with a SEXT byte or word source whose top bit is set is wrong there for
any destination, already on main. Record it in shader debt, and test SEXT
on v_cvt_f32_u32 only with the top bit clear.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Allow byte and word destinations for v_ffbh_u32, v_ffbl_b32,
v_ffbh_i32 and v_bfrev_b32 through the existing SDWA translation path.
Check every source select, extension and partial destination mode against
a CPU model in wave32 and wave64 execution tests.
Sources: AMD RDNA2 ISA sections 6.8, 12.8 (opcode 59) and 13.3.7
Table 88; LLVM 19.1.0 VOP1Instructions.td lines 347-351 and 1194-1197,
and SIPeepholeSDWA.cpp destination folding. PS5 gfx1013 is unmeasured.
Lavapipe with validation: main rejects the new forms; both focused cases
and all ten SDWA tests pass with the change. Forcing source extraction
to zero-extend fails both new cases; restoring it passes. Conventions pass.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
In registration form a vertex module decodes the V# stride, swizzle,
bounds mode and format of every vertex buffer load at run time. Vertex
artifacts are now emitted specialized, as one above
registrationWordLimit already was; pixel artifacts keep registration
form. A vertex stage's pre-rasterization library is built at its first
draw instead of at registration.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_015W3M6NbYpmwWkzkL8YNLaF
Each invocation stores its host subgroup's native ballot word into a
separate wave_ballot array and one barrier replaces the previous three.
A private parity counter alternates two slot pairs so a ballot never
overwrites words a slower invocation is still reading. Offline NVIDIA
compiles of captured wall shaders were 15-24 % faster.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Without VK_EXT_image_view_min_lod, a T# clamp paired with an S# that
holds the LOD at 0 (no mip filter or MAX_LOD 0) threw, since the shader's
MinLod would sit above the sampler's maximum. The view clamp then reads
the clamp's level with the magnification filter, so such an S# is now
bound with MIN_LOD = MAX_LOD = the clamp, its mip filter kept (none
becomes point) and its magnification filter for both.
The builder still throws when that S# has different magnification and
minification filters (the view clamp leaves the LOD at 0 and the variant
raises it to the clamp, and AMD RDNA 4 and NVIDIA disagree on the view
clamp's choice), filters anisotropically in only one direction, or also
samples a table image or a mipmapped image with another clamp.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
MoltenVK has no VK_EXT_image_view_min_lod, so since #130 the first T#
with a MIN_LOD clamp above its base level threw. ASTRO BOT (PPSA21564
01.007.000) hits it on the title screen, about four minutes after boot.
MoltenVK does offer shaderResourceMinLod, which maps the SPIR-V MinLod
operand to Metal's min_lod_clamp.
On a device with shaderResourceMinLod, without the extension and
without graphics pipeline libraries, the new target flag
shaderImageMinLod moves the clamp into the shader:
- DescriptorBindingBuilder writes each direct image's clamp, relative
to the view's base level and bounded by its last level and MAX_MIP,
as a float specialization constant at MinLodBase + image.
- Samples of direct images take it as the MinLod operand, or as an FMax
on an explicit LOD when the clamp is above 0, combined with an
instruction's _cl clamp.
- The image view no longer chains the clamp there; image table entries
with a clamp are still rejected, and devices with the extension are
unaffected. APS5_NO_IMAGE_VIEW_MIN_LOD forces the shader lane.
- It throws when the clamp sits above a paired S#'s MAX_LOD or has no
mip filter, follows an explicit LOD or gradient with a nonzero S# LOD
bias, pairs with a run-time S# or different min and mag filters, or
meets image_get_lod, gathers at a clamp of a level or more, or the
emulated depth-compare or 11:11:10 sample.
- ValidateShaders accepts CapabilityMinLod when the device enables
shaderResourceMinLod.
- The flag is written after hostInterpolationFirst as request
serialization version 53; older versions read it as false.
The gaps, including llvmpipe applying the S# bias after the clamp, are
recorded in docs/dev/debt/shader.md.
Tested on an M-series Mac (MoltenVK 1.4.2, x86_64 under Rosetta):
image_sample_lod_clamp samples a T# with fractional and level clamps
over BASE_LEVEL 0 and 1 in both lanes, and fails without the shader
clamp or with an absolute one; graphics, shader disk cache, shader
memory and request serializer tests pass. PPSA21564 renders the title
and reaches the warp sequence after it.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
SpirvEmitter.cpp: main now calls Finalize() before filling info and checks
spanned-wave barriers on the words; keep that and run this branch's
VerifyScratchPoolReturns(state, words) on the same words before returning.