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.
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.
A Vulkan hull invocation runs one output control point of one patch, so a
lane mask that mixes lanes of other patches cannot be read. Ghost of Yotei
has eight merged hull programs that apply s_wqm_b64 to a ballot; with 3
output control points a console lane quad spans two patches.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
image_sample_lz with a bilinear S# returned the same nearest texel as a
point S# for 8-, 16- and 32-bit UINT and SINT formats on RDNA2 (gfx1036)
through the hardware oracle, which the point-filtered S# copy for integer
image table entries matches. The debt entry said this was assumed.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
R, G and B are 10-bit unsigned floats with a 4-bit exponent (bias 7) and
a 6-bit mantissa, A is a 2-bit UNORM, as image_load returns them on
RDNA2 (gfx1036) through the hardware oracle. The format stays refused.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
A workgroup looking for a scratch pool slot now loads the lock and tries the compare-exchange only when it reads free, so waiting workgroups stop issuing atomics on locks their holders use. In the scratch dispatch bench on an RTX 4090 with about 9 slots for 32768 workgroups (APS5_SCRATCH_POOL_MIB=1) the dispatch goes from 1377 ms to 1308 ms; with the default 64 MiB pool it is unchanged (389 to 395 ms). The debt notes the measured runtime cost of the pool against Function arrays.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
NVIDIA's front end spends tens of seconds per large compute program on the
dynamically indexed Function arrays that held the per-lane scratch. A compute
program that uses scratch (scratch_* or a FLAT access that the aperture split
routes to the private aperture) now keeps it in a storage buffer instead, so
no Function array is declared or indexed. FLAT routing is unchanged.
The driver allocates one buffer per compute pipeline on its first dispatch,
capped by APS5_SCRATCH_POOL_MIB (default 64), holding a lock word and an
invocation counter per slot followed by the slots, and binds it in descriptor
set 2 (the layout of the device-memory LDS buffer). The shader takes the slot
count from the array length. Invocation 0 of each workgroup claims a slot with
a compare-exchange scan that starts at its linear workgroup id and spins until
it wins one; a barrier publishes the slot. Every invocation decrements the
slot's counter on every compute exit and the last one frees the lock, so
divergent exits and concurrent dispatches of one pipeline share the buffer
safely. The emitter fails the compile if a compute return lacks the release.
Programs without scratch keep their SPIR-V and pipeline layout.
The buffer is decorated Coherent: without it NVIDIA lost earlier byte stores
of a sequence of byte read-modify-writes to one dword. Lane-private
read-modify-writes no longer use atomics.
Tests: a new execution test covers the private aperture reached through a
table load, a literal and a computed address (store, atomic, and both ways
through scratch_*), a callee reached through s_swappc_b64, isolation of 64
workgroups over one or two slots, divergent wave exits with a second dispatch
reusing the slots, and the module shape (no Function array, no binding in a
program without scratch). The guarded memory load fixture skips the slot
acquisition.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
With alpha-to-coverage and DB_SHADER_CONTROL.MASK_EXPORT_ENABLE the pixel shader now writes SampleMask as the AND of its MRT0 alpha coverage and its MRTZ mask export instead of throwing, as Vulkan multisample coverage ANDs the shader sample mask with the alpha-to-coverage mask. Adds eight- and two-sample GPU tests and a shader debt entry for the rule, which is not measured on hardware.
LLVM has explicit int_amdgcn_sdot8 and int_amdgcn_sudot8 patterns with a clamp operand, so the integer dot clamp entry now says only that there is no generic saturating-add dot8 pattern like the dot2 and dot4 ones.
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
The device-dependent skip accepted any wrong result on a device without
f64 DenormPreserve, and a run that excused rows still reported a pass.
Require the result to match a flushed mode's row, pin that with a negative
control and return the skip code. Record what the saved gfx1035 rows show
about the rule in the debt entry.
Co-Authored-By: Claude Opus 5.5 <[email protected]>