DecodeShaderStages accepts LS, HS and an NGG passthrough ES, reads the
3-bit VGT_TF_PARAM fields, refuses its other bits but DISTRIBUTION_MODE,
and needs HOS levels that keep [1, 63]; 0x286-0x287 join the draw key.
Local and domain programs are prepared with their stage group: its
headers are merged over one set of defaults, and a local program left
unbound by the hull header is prepared at its first draw.
The local program ends at its jump into the hull half.
TessellationLowering lowers LDS and ring addresses that are affine in
the control point and relative index to tessellation interfaces with
strides from the code, and refuses accesses outside the patch, per-patch
writes from other control points and a modified primitive export. Hull
lanes read their own saved exec bit, also of host-subgroup-masked
copies; other masks are refused, gl_InvocationID loads as a scalar and
factors clamp to 63.
Map red and blue exports, write masks and constant-color blend factors together. Reject conflicting simultaneous target constants.
Semantics: Mesa 26.2.2 src/amd/common/ac_formats.c ac_translate_colorswap; console equivalence remains unverified. Graphics tests passed. Written with AI assistance.
Allocate cached sets without individual-free pools. Reset a pool after its
last owner releases it. Keep stable pool indices, skip full pools, and
terminate if reset fails. No GPU wait is added.
This avoids RADV 26.2.2's affected individual-free allocation path.
Validation: Fedora 44 Release graphics tests pass. The reset-failure
regression fails on the previous behavior and passes on this change.
llvmpipe and RX 6600 pass the 3,301-set lifecycle test with core and
synchronization validation. Windows was not tested.
AI-assisted: yes.
A fill was taken to cover the surface when it spanned ceil(w/8)*ceil(h/8)*4 bytes, a linear HTILE layout. In
the pipe-aligned SW_64KB_Z_X layout a surface's HTILE words lie across a 32 KiB metadata block per 1024x512
pixels (AMD PAL gfx10 addrlib: a 16x16 surface has a valid word at offset 260), so a fill of the linear size
cleared tiles it never wrote. HtileMetadataBytes gives that extent; the fast clear tests fill it (the compute
fixture now dispatches one group per KiB with TGID_X).
Reported with a PAL reproducer by @Amoenus.
Co-Authored-By: Amoenus <5391396+Amoenus@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Rebased onto main as one commit (the six commits of #374). A uniform fill over a depth surface's whole
HTILE (DMA_DATA, the fill kernels or a CPU store) clears the depth and stencil aspects its ZMask and
SMem fields say, to DB_DEPTH_CLEAR / DB_STENCIL_CLEAR, when the surface is next bound or sampled.
Main's RADV clear_htile_mask recognition (#2229) now goes through the same pending clear: an HTILE clear
marks the matching surfaces' depth aspect, and one for a surface not created yet is applied when it is
first bound. Main's HTILE address decode and this one are merged into one (TILE_SURFACE_ENABLE, a
nonzero DB_HTILE_DATA_BASE and a depth format).
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
vkQuake's NGG culling vertex shaders load only the vertex ID
(SPI_SHADER_PGM_RSRC2_GS ES_VGPR_COMP_CNT 0), and DecodeShaderStages still
required 3 for a program routed to the mesh path. The merged ES inputs keep
their positions whatever the count, and the mesh entry loads all of them,
so the count is now checked only for real geometry programs, as the GS
VGPR count already was.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
RADV sets PARTIAL_TG_EN in the dispatch initiator for an unaligned direct
dispatch, with each axis's last-group size in the upper half of
COMPUTE_NUM_THREAD_X/Y/Z, and TUNNEL_ENABLE on every GFX10 dispatch. The
validator rejected PARTIAL_TG_EN, and DecodeComputeStageInfo read the
whole register, so a partial size would have widened the workgroup.
A direct dispatch with PARTIAL_TG_EN now runs (groups - 1) * full + last
threads on each axis through the dispatch-size limit USE_THREAD_DIMENSIONS
already uses, or plain groups when every last group is complete; a zero
or oversized last group throws. The workgroup size is NUM_THREAD_FULL.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An 8_8 target with SWAP_ALT keeps the x export in its first channel and
the alpha export in its second, and the color block blends that second
channel with the alpha equation. Blending into such a target threw.
With one equation for color and alpha the draw blends as before. With a
separate alpha equation the pipeline draws twice: the first pass writes
the first channel with the color equation, the second writes the second
channel with the alpha factors and operation moved into its color
equation. The split is refused, by throwing, for draws that write depth
or stencil, use per-face depth bias, or whose pixel shader writes memory,
since those would repeat; factors of the destination alpha throw since
the target keeps it in its second channel. Pipeline libraries are not
used for split pipelines.
DB_ALPHA_TO_MASK 0xaa01, the enable bit with the four offsets at 2 and no OFFSET_ROUND, reaches the pixel stage, which keeps a pixel when its MRT0 alpha is at least one half. Dithered or rounded settings, and an MRT0 that is missing, swizzled, packed or exported without a floating-point alpha, still throw. God of War Sons of Sparta (PPSA28997) stopped on it a few minutes into play.
Key 0x10 (GFX9_DCC_CLEAR_SINGLE in Mesa) marks a 256-byte block whose texels all equal its first texel. A CB DCC decompress pass over uniform comp-to-single keys now writes that texel over its block and stores uncompressed keys; a fast-clear eliminate over them throws.
The window offset register is already required to be zero, so the enable bit has no effect on a draw that gets this far.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
CB_COLOR_INFO COMP_SWAP 1 (SWAP_ALT) on a two-channel format stores the
x and w exports in its two channels (Mesa si_translate_colorswap,
"X__Y"). COLOR_8_8 UNORM and SNORM targets with it bind as R8G8 with
export mapping 0xec; blending into them still throws, since Vulkan
would apply alpha factors to the wrong channel.
Uncharted: Legacy of Thieves Collection (PPSA05684) stopped in its
first level with "unsupported color format 3 number type 0 component
swap 1".
A stale storage snapshot is revalidated by comparing every tracker block
stamped since it was taken. A title that binds buffers a dispatch writes
in place every frame (the whole declared range stamped, few pages really
changed) makes the graphics worker compare gigabytes per second.
Compares of 1 MiB or more are now split by block across a small pool of
helper threads (hardware threads / 8, from 1 to 4). The compare is memory
bound, so the worker's share roughly halves rather than dividing by the
thread count. A caller that finds the pool busy compares on its own
thread. Results and the patch-in-place rules are unchanged.
agc_driver_graphics_tests parallelCompareTests: per-span results on the
pool and serial paths, and two threads comparing at once.
Every small host buffer (size classes below 1 MiB: draw and dispatch data,
copied regions, snapshots) had a VkDeviceMemory of its own. When the pool
missed, the worker paid a vkAllocateMemory and vkMapMemory, and the release
thread a vkUnmapMemory and vkFreeMemory, for each one. The frees also stall
the worker's vkQueueSubmit in the driver.
A host-visible buffer of a size class now gets its own VkBuffer bound into a
slot of a shared block (2 MiB, or 8 slots for the large classes) per memory
type, size class and device-address use, mapped once. Releasing it destroys
only the VkBuffer and returns the slot; a block is freed when it empties and
its slab already keeps an empty one. A slot is used only when the buffer's
alignment and the non-coherent atom divide its size class, so the slot
offset is valid for the bind and Invalidate covers exactly the slot. The
pool still retains released buffers by class as before; only what backs
them changed.
CB_BLENDn_CONTROL factors 15-18 (BLEND_SRC1_COLOR, BLEND_INV_SRC1_COLOR,
BLEND_SRC1_ALPHA, BLEND_INV_SRC1_ALPHA) threw "unsupported blend
factor". They blend MRT0 with the pixel shader's MRT1 export as the
second source, as RADV and radeonsi program it.
DecodeState maps them to the VK_BLEND_FACTOR_SRC1_* factors and accepts
them only with pixel exports to slots 0 and 1, color writes to slot 0
alone, an MRT1 export with MRT0's export format and shader mask, an
ADD, SUBTRACT or REVERSE_SUBTRACT operation and an identity component
order. The blend is draw state, so the specialized module of the
registered pixel shader moves its MRT1 output to location 0 index 1,
which ValidateShaders requires; pipelines need dualSrcBlend, now enabled
when present. The request field dualSourceBlend is in the module key,
the result memo, the draw key and the serialized request (version 15).
DecodeColorTileMode rejected 2D color targets with a nonzero MIP0_DEPTH, so
an array target could only be rendered into through a view of a surface that
declares one slice. radeonsi sets CB_COLOR_ATTRIB3.MIP0_DEPTH to the last layer
of an array target (si_state.c, ac_descriptors.c), and Mesa-built homebrew
emits such targets. The view's slice already moves the target by one slice
size; it is now also checked against MIP0_DEPTH.
The buffer pool's device tier (detiler scratch buffers and the staging
shadows of written guest buffers) retained at most 512 MiB by default.
A title whose working set of these buffers is larger allocates and
frees device memory continually: PPSA14632 (LEGO Horizon Adventures)
had 70761 misses and 69828 evictions per 10 s with 485 of 512 MiB
retained, each a vkAllocateMemory or vkFreeMemory.
The default budget is now an eighth of the largest device-local heap,
and at least the old 512 MiB, so a 16 GiB card retains up to 2 GiB and
an 8 GiB card 1 GiB. APS5_STAGING_POOL_MIB still sets it.
Only the constructor knows the device, so only the budget comes from the
heap. Whether the tier is in use at all (APS5_STAGING_POOL_MIB unset or
not 0) stays a static check, DeviceTierEnabled, which Capacity, Usage and
tierFor share, so the size classes and the tier stay consistent.
On PPSA14632 with 2 GiB the device tier has 1312 misses and 99
evictions per 10 s (1628 MiB retained), and presents rise from about 34
to about 39 per 10 s.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A strided vertex fetch whose index is at or past the descriptor's num_records threw and aborted the title. PPSA01325 draws its fullscreen composite as a 4-vertex strip over a 3-record buffer, so the fourth vertex past the records stopped presentation.
Hardware returns (0, 0, 0, 0) for such a fetch with OOB_SELECT 0 and 1, measured on RDNA2 gfx1036 with tools/hw-oracle in #2241. VertexBufferReadSize now spans the whole fetch, and the staging copy reads the record bytes then zero-fills from num_records * stride onward. Each such fetch gets its own copy, outside the shared copies of its sibling attributes, the host-import in-place path and the draw-snapshot cache. OOB_SELECT 2 and 3 keep throwing past num_records, since each needs its own rule. Recorded in docs/dev/TechnicalDebt.md.
A draw that rasterizes both faces with different front and back depth
bias was rejected, since Vulkan has one depth bias per draw and the
cull mode is pipeline state. Such a draw is now recorded twice in the
same pass: front faces with the back faces culled and the front bias,
then back faces with the front faces culled and the back bias. A face
whose offset is disabled gets no bias.
Vulkan counts the framebuffer colour attachments against maxPerStageResources
for the fragment stage. The draw's attachment count now seeds the fragment
stage's resource total in ShaderResources, so a pixel shader whose buffers and
images fit the limit but whose pipeline exceeds it throws instead of creating
an invalid pipeline. The draw resource cache key carries the attachment count,
so a cached build is never reused by a draw with more attachments.
RADV clears depth by rewriting HTILE with its clear_htile_mask kernel
(ZMASK to 0) instead of writing depth memory. Recognize that kernel and
clear the matching host depth surface to DB_DEPTH_CLEAR when it is next
bound; the depth target now records its HTILE address.
AI-assisted (Claude Code).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>