With depth bias enabled, RADV sets POLY_OFFSET_PARA_ENABLE in
PA_SU_SC_MODE_CNTL next to the front and back enables, whatever the
topology; vkQuake's draws carry 0x3a46. The bit applies the offset to
points and lines, so it changes nothing for triangles, and Vulkan applies
depth bias only to polygons. It is now accepted with depth bias on
triangle topologies; point and line draws with it are still rejected.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With conservative rasterization disabled, RADV programs
PA_SC_CONSERVATIVE_RASTERIZATION_CNTL to NULL_SQUAD_AA_MASK_ENABLE alone,
where libSceAgc writes the two INNER_TO_NORMAL overrides (0x6000). A value
made of only those bits now decodes as disabled; overestimation (0x6001) keeps
its checks, and every other mode is still rejected.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
RADV sets OUT_OF_ORDER_WATER_MARK to 7 on every GFX10 draw, also when
OUT_OF_ORDER_PRIMITIVE_ENABLE is off. The watermark only tunes out-of-order
rasterization, which stays rejected, so the field is accepted alone.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The console's DCC of a single-level 4-byte SW_64KB_R_X surface is
ceil(W/512) * ceil(H/512) * 4096 bytes, 49152 for 1920x1080, but the
driver stored and read one key per 256 surface bytes (34560).
PPSA26344 retiles its render DCC into the displayable copy it
registers (cs_dcc_retile_32bpp); a retile of the stale tail gives the
mixed keys PPSA12544 stops on.
DccKeyCount gives that extent. Color target and storage image key
stores cover it when the DCC is pipe-aligned (CB_COLOR_ATTRIB3 bit 30,
T# word 6 bit 19), whose CB keys reach its last meta block, and throw
where it is not writable; unaligned DCC keeps one key per 256 bytes,
as do texture and color target key reads. DisplayBufferKeys reads the
display DCC over the extent, presents only when every key agrees,
names the first differing key's pixels and checks a pending image
against those keys.
Mode 0 of CB_COLOR_CONTROL turns color writes off, but a draw with a
written color target and this mode was skipped as unsupported. Count no
export as written when the mode is disable, so the draw renders without
a color attachment like the existing attachment-free path, and accept
the mode with any ROP3, which does not apply while writes are off.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A draw whose PA_SC_CONSERVATIVE_RASTERIZATION_CNTL (context 0x313) was
not the default 0x6000 threw in DecodeState and the draw precheck.
0x6001 sets OVER_RAST_ENABLE and now decodes to Vulkan's overestimation
mode, chained to the pipeline's rasterization state and its key.
The device enables VK_EXT_conservative_rasterization only when its
primitiveOverestimationSize is at most 1/256 pixel and it rasterizes
degenerate triangles; elsewhere the pipeline throws. Overestimation is
accepted only when triangles reach the rasterizer: VGT_GS_OUT_PRIM_TYPE
behind a geometry shader, VGT_TF_PARAM's output topology behind
tessellation, VGT_PRIMITIVE_TYPE otherwise. Other 0x313 values and
centroid interpolation still throw.
Adds the agc_driver_conservative_rasterization GPU test and extends
agc_driver_graphics.
The GFX10 lowering of a wave64 reduction scans rows with DPP row_shr
1/2/4/8 and v_permlanex16_b32 under EXEC -1, then joins lanes 31 and 63
with a scalar op. The console fills lanes outside the entry EXEC with
the identity, but on the host they can be helpers that sit out subgroup
operations or invocations that were never launched: on 64 lanes (RADV)
the emulated chain reads 0 or stale values from them, and on 32 lanes
lane 63 throws since #997.
EmitReadLane now recognises the sequence on any host for UMin, UMax,
SMin, SMax, IAdd, AND and OR when the keys are the identity outside the
entry EXEC. On 64 lanes, lanes 31 and 63 become subgroup reductions of
the keys of invocations 0-31 and 32-63; on 32 lanes or fewer, lane 31
reduces all keys and lane 63 is the identity. It throws without
subgroup arithmetic or on a subgroup wider than the wave. VulkanDevice
reports GroupNonUniformArithmetic and ShaderValidation checks it.
DecodeState and the draw precheck rejected DB_SHADER_CONTROL bit 16,
PRIMITIVE_ORDERED_PIXEL_SHADER (POPS), which runs the ordered section
of overlapping pixels' shaders in primitive order. The bit now reaches
the recompiler as a pixel stage field, and such a pixel shader declares
PixelInterlockOrderedEXT and runs its whole body between
OpBeginInvocationInterlockEXT and OpEndInvocationInterlockEXT; an
invocation that a BDA read fault kills ends the interlock first. The
POPS collision SGPRs read 0, so a title skips its POPS wait and runs
its per-collision loop once. An image_load still reads a sampled
binding, which misses an earlier overlapping primitive's image_store in
the same draw. The device enables VK_EXT_fragment_shader_interlock when
it has fragmentShaderPixelInterlock; without it the recompile throws,
as does a nonzero POPS_OVERLAP_NUM_SAMPLES. The field is part of the
recompile cache key, the draw key and the serialized request (version 10).
Use the synthetic shader input and export state when selecting the null pixel program. Keep ordinary shader validation unchanged. Written with AI assistance.
A compute program with COMPUTE_PGM_RSRC2.SCRATCH_EN takes its per-lane private size from the AGC
shader header (scratch_size_dw_per_thread) instead of being refused. The size travels in
ShaderComputeStageInfo (cache key, request serialization version 10) to the translator, whose
scratch accesses already lower to a per-invocation Function array of that many dwords.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Exclude COLOR_INVALID attachments from the effective write mask while preserving later MRT export indices and depth-only rendering. Validated with the graphics tests and Skyrim menu draws.
AI-assisted implementation and testing by OpenAI Codex.
A CMASK holds 4 KiB per 1024x512-pixel metablock, not one nibble per 8x8
tile of the target: 1920x1080 spans 0x6000 bytes, as titles clear it,
not 16200. The swizzled nibbles of the lower-right tiles lie past the
packed size, so the fast-clear check missed them and the expanded store
left them cleared.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A color target with both DCC and CB_COLOR_INFO.FAST_CLEAR keeps its fast
clear in the DCC keys and fills its CMASK with 0xF (expanded), as radv
does (radv_get_cmask_fast_clear_value) and as PPSA21567 does
(CB_COLOR_INFO 0x10042730, reported on #419). Such targets now decode;
their clear is materialized by the existing DCC path. A DCC target's
CMASK that is not all expanded throws.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Draws into a color target with CB_COLOR_INFO FAST_CLEAR (bit 13) were
rejected. The CMASK keeps one nibble per 8x8 tile: 0 means the tile is
fast-cleared and reads as CB_COLOR_CLEAR_WORD, 0xF means expanded (the
texels hold the color). The texture units and display scanout do not read
it, so a title runs a fast-clear eliminate pass before sampling or
flipping such a target.
DecodeColorBuffer now takes the CMASK address (CB_COLOR0_CMASK and
CB_COLOR0_CMASK_BASE_EXT) and the bytes one nibble per 8x8 tile spans.
Before a draw renders into the target, and in a fast-clear eliminate
pass, a CMASK whose nibbles are all 0 is materialized: the target is
filled with the clear texel (FillClear on its resident image, else
guest memory on the CPU) and the CMASK bytes are stored as expanded,
through the same GPU-ordered store as the DCC "uncompressed" keys
(0xFF either way). The result equals the draw followed by the eliminate
pass. An all-expanded CMASK changes nothing; a mixed one throws, as do
fast clears of DCC, mipmapped, 3D and array targets.
PPSA14632 (LEGO Horizon Adventures) fast-clears its two 3840x2160
display buffers through CMASK, so its final composite draw was dropped
on every frame and only black was presented.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Accept COMP_SWAP STD_REV and ALT_REV on 16_16_16_16 color targets and
map them onto RGBA16 with the same export component mappings used for
8_8_8_8. ALT on 16_16_16_16 is still refused.
COMP_SWAP 2 and 3 store a four-component export as ABGR and ARGB from the
lowest bits. Render such targets as RGBA8 and permute the pixel shader's
exports through the existing component mapping (0x1b and 0x93), as the
one-component swaps already do. Blending into them throws: the alpha
factors would read the wrong export component.
Accept PA_SC_MODE_CNTL_0.ALTERNATE_RBS_PER_TILE, CB_COLOR_CONTROL.DISABLE_DUAL_QUAD
and VGT_SHADER_STAGES_EN.MAX_PRIMGRP_IN_WAVE on the vertex path. They tune how the
hardware distributes work between render backends and waves and do not change the
rendered result. Mesa sets all three on GFX10.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Release the registry mutex while yielding for an outstanding lease even before a GPU pin waiter is registered. This lets the lease holder finish a nested allocation lookup and release its lease instead of deadlocking against an unmap.
Validation: the deterministic concurrent unmap/lookup regression fails at the lease deadline before the fix and passes after it. Graphics and guest-memory CTests pass. Live Skyrim stacks captured this cycle in a compute upload flushing a storage texture.
AI-assisted implementation.
DescriptorCache::Allocate returned no set when a set needed more
descriptors of one type than a chain pool holds (4,096 storage
buffers, 1,024 sampled or storage images, 512 samplers). A build's
own set then fell back to a pool of its own, but PrepareDrawBindings
has no fallback and threw "draw snapshot descriptor allocation
failed", so a recorded draw with such a set and a snapshotted input
was skipped.
Such a set now gets a pool sized to it (maxSets 1, no
FREE_DESCRIPTOR_SET_BIT), which Free destroys. Every set's count of
each type is first checked against the device's maxDescriptorSet*
limit; other descriptor types throw. The [descriptors] profile line
counts the dedicated pools.
Shader GDS accesses bind the same 64 KiB guest range that DMA_DATA packets
read and write, so both go through the existing CPU/GPU coherence tracking.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The validator takes the geometryShader and sampleRateShading enables from the
context (set where #295 enables them), so a device without them refuses the
draw instead of creating a module that needs features it never enabled.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Pixel shaders that export a coverage mask write gl_SampleMask, an
int[1] (or uint[1]) output. The validator rejected array interface
types; it now spells them elem[N] and accepts SampleMask as int[1] or
uint[1].
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The recompiler emits SampleId and Layer fragment inputs (pixel ancillary
data) and a FragDepth output with the DepthReplacing execution mode
(depth export), but the validator refused them, so those draws were
skipped. They are now accepted, as are the Geometry and SampleRateShading
capabilities those inputs need in fragment shaders. The device enables
both features when it has them.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A depth-only pass can leave a stale pixel program address in
SPI_SHADER_PGM_LO/HI_PS while never setting the pixel registers it does
not need. The draw then failed with "missing register at DWORD 0x1b3"
(SPI_PS_INPUT_ENA), although the hardware never launches that program:
with no color written (CB_TARGET_MASK & CB_SHADER_MASK == 0), no depth,
stencil or mask export (SPI_SHADER_Z_FORMAT 0 and those enables of
DB_SHADER_CONTROL clear), and neither KILL_ENABLE, EXEC_ON_HIER_FAIL,
EXEC_ON_NOOP nor EXEC_IF_OVERLAPPED set, the pixel shader has no effect
and is not executed.
PixelProgramUnset becomes PixelProgramSkipped: true for a zero program
address as before, and for such an inert pixel stage. Both use the
driver's null pixel program; the precheck and the decode agree.
PPSA14632 (LEGO Horizon Adventures) issues an HTILE expand this way
(DB_RENDER_CONTROL DEPTH/STENCIL_COMPRESS_DISABLE, CB disabled, depth
test and writes off) once per run.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A non-indexed mesh draw (DRAW_INDEX_AUTO, or a non-indexed indirect
record) gave the mesh program's hidden index buffer V# (user words 4..7)
a 4-byte range at the program's own code address, so the descriptor had
a guest address although the prologue never loads through it (the load
is predicated on the draw's index size). That range is bound from live
guest memory. When the program also reads guest memory by address, the
address build captures the program's code as an immutable snapshot, and
the two overlapped: the draw failed with "writable guest memory
overlaps an immutable snapshot", or, when the live bytes at the code
address had changed since the capture, "guest snapshot differs from the
writable memory it overlaps".
MeshIndexBufferDescriptor now returns a null V# (base and size 0, same
format word) for a non-indexed draw, which ShaderResources binds to its
empty placeholder buffer, and takes no unread address any more.
PPSA14632 (LEGO Horizon Adventures) hit this on its layered mesh-path
draws.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A draw with depth bias enabled read PA_SU_POLY_OFFSET_CLAMP (context
register 0x2df) with read(), but the context bank only held it once
the title wrote it. Titles that rely on the reset value had every such
draw skipped with "missing register in context bank at DWORD 0x2df".
The initial context state, which CLEAR_STATE also restores, now holds
the register as 0. That is the value in libSceAgc's own register
defaults (sceAgcGetRegisterDefaults2, every version) and in amdgpu's
GFX10 clear-state table. A clamp of 0 means no clamping, so it needs
no device feature.
A pixel or vertex shader with a 64-bit image atomic declares Int64Atomics,
Int64ImageEXT and SPV_EXT_shader_image_int64, which graphics shader
validation rejected ("SPIR-V requires unsupported device capability"),
so the draw was dropped. Compute dispatches are not validated this way.
The device records whether it enabled shaderImageInt64Atomics
(imageInt64Atomics in the device state and the graphics Context), and
ValidateShaders accepts the two capabilities and the extension when it
did.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
DrawRejection read 0x1c4 with read(), which throws when the register is
absent, against the function's rule that a missing register gives no
verdict there; it now reuses the value read with value() for the
DB_SHADER_CONTROL check. Tests pin the Z-export rules: formats 1, 2, 3
and 9 with Z_EXPORT_ENABLE accepted, format 0 rejected, the sample-mask
export accepted with 32_ABGR and rejected with 32_R, formats 4 to 8
rejected, and a missing 0x1c4 accepted.
The resource tracker refused a program's 33rd distinct V# with "buffer
resource limit exceeded". The 32 was a recompiler constant, not a
Vulkan limit: every buffer is one constant-indexed element of the guest
buffers binding, which ShaderResources checks against the device's
storage-buffer limits.
Drop ShaderInfo::MaxBuffers and the tracker's refusal, and size the
SPIR-V emitter's per-buffer offset list from the binding layout. When
the user data and offsets do not fit in the push constants, they all go
to the shader data buffer as before. ShaderResources counted only
storage buffers against maxPerStageResources (200 on Intel UHD) and now
adds the stage's sampled and storage images.
agc_driver_many_buffers reads and writes 52 and 124 buffers, and
agc_driver_graphics rejects buffers plus an image above the limit.