A color view of several depth slices of a 3D target (CB_COLOR_VIEW
SLICE_START < SLICE_MAX) was rejected as "color views of several array
slices are unsupported". Titles render such volumes with one draw: an
instanced draw whose vertex stage picks each primitive's slice through
the misc position export (PA_CL_VS_OUT_CNTL USE_VTX_RENDER_TARGET_INDX
with VS_OUT_MISC_VEC_ENA).
Depends on #423, which carries PA_CL_VS_OUT_CNTL to the recompiler.
- DecodeColorBuffer takes the slice range of a 3D target
(ColorTarget::layers, clamped to the surface's last slice), allows DCC
on 3D targets, and sizes a tiled 3D target by its whole surface
(SurfaceForTarget moves to State.cpp for that). DecodeState sets
State::renderLayers and, for a layered draw, USE_VTX_RENDER_TARGET_INDX
(State::layerExports); color targets of different slice counts and
layered draws with a depth target throw.
- The driver adds State::layerExports to the PA_CL_VS_OUT_CNTL bits #423
passes (it already passes VS_OUT_MISC_VEC_ENA), so the render target
index reaches gl_Layer only for layered draws and stays ignored
elsewhere as before.
- A vertex stage writing gl_Layer declares ShaderViewportIndexLayerEXT
and SPV_EXT_shader_viewport_index_layer when the device offers them
(the device enables VK_EXT_shader_viewport_index_layer when present),
instead of SPIR-V 1.5 ShaderLayer, which a Vulkan 1.1 device cannot
take. Graphics validation accepts the capability, the extension and a
vertex Layer output when it is enabled, and a per-primitive Layer
output of a mesh stage.
- The resident target's attachment view is a 2D array view of the
slices, and the framebuffer has that many layers (Framebuffer and
AcquireFramebuffer take the layer count).
The execution test agc_driver_layered_volume_draw draws three bands,
one per layer, into slices 1..3 of a 4-slice 64 KiB-tiled volume and
reads every slice back: slice 0 stays untouched and slice 1 + L holds
only band L. It also recompiles a mesh program with the layer export and
validates it against the layered state. The mesh case does not draw:
lavapipe's LLVM backend aborts compiling that mesh pipeline ("Cannot
emit physreg copy instruction"), which a test cannot catch. On RADV the
same mesh draw renders the bands into the right slices.
PPSA14632 (LEGO Horizon Adventures) renders its 64x64x64 RGBA16F
translucency lighting volumes (two DCC targets, 64 instances) this way.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
DecodeShaderStages accepted only clockwise triangle patches and no HOS
level clamp narrower than [1, 63], so terrain drawn as TRI_CCW quad
patches with VGT_HOS_MAX_TESS_LEVEL 9 aborted. Quad domains and TRI_CCW
now decode and emit Quads and VertexOrderCcw; isolines, other
partitionings and point or line output still throw.
VGT_HOS_MIN/MAX_TESS_LEVEL are read per draw and pushed in the last 8
bytes of the pre-rasterization push constant slot, where the hull reads
them to clamp its factors; they stay out of every key and the recompile
request, so one hull serves every level. Zero, negative and NaN outer
factors still cull; clamps outside 0 <= min <= 63, max >= 1,
min <= max throw. Quad hulls write four outer and two inner factors at
a 24-byte stride, the layout Mesa's TF ring store uses.
DecodeState mapped points, lists, strips, fans, rect lists and patches
but threw "unsupported primitive type 3" for VGT_PRIMITIVE_TYPE 3, the
line strip (DI_PT_LINESTRIP in Mesa's r600d.h). Record of Lodoss War
(PPSA05347) stops on it after a few minutes.
Vulkan allows primitive restart for line strips without the list
restart extension, and the precheck, the pipeline and the provoking
vertex check already treat the strip class that way; only the decode
lacked the case. The point and line depth bias enable stays rejected on
line strips like on line lists, and a line strip gets the line primitive
class for a pixel shader that reads the ancillary word.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
ApplyFastClear took the color fill before the CMASK clear, so a partial
fill of a multisampled target's color memory threw at the next use even
when a CMASK fast clear was pending over the whole target. The CB reads
a cleared tile's color from the clear registers whatever the memory
holds, so the CMASK clear is applied and the recorded fill dropped.
DecodeColorMetadataPass treated a CB_COLOR_CONTROL resolve as one only
when PA_SC_AA_CONFIG has a sample count, and checked the source against
it. A title that resolves with the rasterizer single-sample fell through
to the draw path and threw "only normal color rendering with copy ROP is
supported (... mode resolve)".
A color target's sample count is CB_COLOR_ATTRIB.NUM_SAMPLES, separate
from the rasterizer's; radeonsi itself writes PA_SC_AA_CONFIG 0 for a
multisampled framebuffer when rasterizer multisampling and line
smoothing are off. So a resolve is decoded when either the rasterizer or
CB0 is multisampled, and its sample count is CB0's. When the rasterizer
is multisampled, the source still has to match it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A multisampled target's samples live only in its host image, so a fill
of its color memory never reached them: a title that clears its MSAA
targets that way (with no CMASK) kept drawing over the previous frame.
A uniform fill over the whole color memory now clears the host image to
that value at the target's next use, the same way a CMASK fast clear
does, and a pending CMASK clear still takes precedence. The color memory
is sized with addrlib's block dimensions for the sample count
(ComputeThinBlockDimension): a 64 KiB block holds width x height x
samples elements, laid out width first for 1x and 4x. A fill over part
of it, over a target whose footprint is not computed, or with a value
that has no exact clear value in the format throws at the next use.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A fast-clear materialization threw when a CMASK nibble held a code other
than 0 (cleared) or 15 (expanded). PPSA18391 (engine: Clickteam Fusion) fast
clears a target whose CMASK it never initialized, so some nibbles hold
leftover values such as 1 and 10, and presentation failed on the first
frame.
Such a tile now keeps its texels like an expanded tile, on the CPU path
and in the compute pass. A cleared tile of a DCC target still throws.
The graphics and CMASK fast-clear tests now check that an unknown code
leaves the tile unchanged instead of expecting the throw.
The SPIR-V emitter declares extra views of the guest buffers binding:
buffers_coherent for GLC or DLC accesses (#2369) and buffers_u64 for
64-bit atomics. Each is another StorageBuffer variable on the same set
and binding, decorated Aliased, which Vulkan allows.
ShaderValidation, which checks the stages of every draw, accepted one
StorageBuffer variable per binding with u32 elements only, so such a
graphics shader was refused with "duplicate SPIR-V resource binding".
A second variable is now accepted when the binding is the guest buffers
array and every variable on it is Aliased; an aliased view may hold u64
elements. Other duplicates are still refused. agc_driver_graphics
validates pixel shaders with a GLC store and a 64-bit atomic, and checks
that the same modules without Aliased are refused.
The kernel reads its value with s_buffer_load_dword through the V# in
user[4..7] and stores it with buffer_store_format_x through the V# in
user[0..3]. When the value V# covers less than a dword (NUM_RECORDS
times its stride, or NUM_RECORDS bytes for stride 0) the load returns 0,
and a store format other than 32_UINT, 32_SINT or 32_FLOAT converts the
value, so in both cases the HTILE does not receive the dword read from
memory. The match now requires both. Kena's own dispatch (format
32_UINT, a value V# of one 16-byte record) still matches.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PPSA01802 (Kena: Bridge of Spirits) clears its depth HTILE every frame
with its own compute kernel: a 9-word dword fill that stores, through
the stride-4 V# in user[0..3], a value loaded from the pointer in
user[4..5]. Neither the DMA_DATA hook nor the fill kernels the driver
recognizes saw it, so the depth kept the first frames' contents and the
base pass and sky failed their depth test almost everywhere.
The kernel is matched exactly when the dispatch is decoded, the value is
read from guest memory, and the range is passed to NoteDepthMetadataFill
like a fill, so the whole-HTILE and ZMask rules apply unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Pipeline libraries take ownership of shader modules during prebuild. Treat null handles as a no-op so moved-from modules do not decrement the live-object count twice.
Marvel's Wolverine draws into a 256x256 mipmapped 2D target
(CB_COLOR_ATTRIB3 0x4dc6c000, no array slices) through CB_COLOR_VIEW
0x4046000: slices 0 to 35 at mip 1. The view's last slice is not bounded
by the surface on that path, so the draw renders into slice 0.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A CB_COLOR_VIEW whose SLICE_MAX is past SLICE_START was rejected. Without
a render target index export every primitive goes to SLICE_START, so the
target is that slice, as for a one-slice view. Layered draws into such a
view, and views of several 3D slices, still throw.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Apply the source-configured D_X XOR refusal during color decoding as well as direct layout construction. Regression tests reject each raw column-bit combination before storage or rendering is selected. Existing resident-array and packed-mip refusal paths remain in force.
AI-assisted implementation and validation: Codex.
Map SW_64KB_D_X color surfaces through the existing source-backed texture equations and mip geometry. Keep display and render-target equation caches separate. Reject unresolved raw column bits for the new mode instead of accepting them.
Cover the captured PPSA99902 descriptor, independent source offsets, pipe/bank tags, transfers, array/mip placement and resident/non-resident GPU draws. Record unmeasured console behavior in TechnicalDebt.
CPU validation on main e013f8c9: captured-descriptor failure 5/5; changed passes 5/5; pinned AMD addrlib reference 536940 addresses per run, five runs. Full build and GPU validation are tracked externally. AI-assisted implementation and validation: Codex.
With PA_SC_AA_CONFIG at one sample and MSAA_ENABLE off, the hardware scans
each pixel once and gives every sample of a multisampled color target its
result: radeonsi programs exactly this when GL multisampling is disabled on
a multisampled framebuffer (si_emit_msaa_config leaves sc_aa_config 0), and
GL defines it as single-sample rasterization with full coverage. Such a draw
without depth or alpha-to-coverage now rasterizes the target's sample count
with every sample location at the pixel center, which covers all samples
exactly when the center is covered.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Goat Simulator 3 draws a triangle list whose indices are all 0xffffffff
with primitive restart off. Each fetch past a descriptor's records reads
zeros (out-of-bounds select 0 or 1), but the zero-padded vertex copies
were sized to the highest index: 160 GiB, which vkAllocateMemory refused.
When the highest index is at least 64Ki vertices past the largest
per-vertex record count, the draw now uses a copy of its indices with
every index past that count moved to it. Each attribute reads zeros
there as at the original index; only the vertex index the shader sees
changes, so indices closer to the records are left as they are.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Vulkan's standard 8x sample 7 is (0.9375, 0.0625), (7, -7) in signed sixteenths; the table had (7, -8), so the
standard pattern (PPSA99902's PA_SC_AA_SAMPLE_LOCS words 0xbd153fd1 / 0x9773f95b) was refused as nonstandard.
Regression row with those words.
Reported by @Amoenus.
Co-Authored-By: Amoenus <5391396+Amoenus@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 9a1a0672cac0f8e3dcaa6e28cbe6b7b684a40a1f)