Each GCN instruction is re-encoded to its RDNA form and decoded by the
existing RDNA decoder, so the PS4 path shares the recompiler. Covers the
legacy VS stage (program at the VS slot, user SGPRs from s0, vertex and
instance index in v0-v3), fetch shaders linked as user-data calls, MIMG
(image_sample and friends), PS4 buffer descriptors (GCN DATA_FORMAT /
NUM_FORMAT, 44-bit base) and T# image descriptors (GCN tiling in word 7).
The GCN switch is keyed into the shader disk cache. PS5 behaviour is
unchanged: every PS4-only rule is gated on GcnGuestShaders().
A geometry program with VGT_GS_OUT_PRIM_TYPE 0 (point list) was refused
as an unsupported output assembly, halting Cocoon (PPSA08766) on boot
with "VGT_GS_OUT_PRIM_TYPE other than a triangle strip, or a line strip
from a geometry program, is unsupported".
Each primitive export of an NGG point-list geometry program outputs one
point whose vertex index is stored directly in PrimitivePointIndicesEXT,
so the mesh module now declares OutputPoints with PrimitivePointIndicesEXT
for it when outputPrimitiveSize is 1. The point primitive export extracts
the 9-bit vertex index from the packed primitive export word and stores
it to the output array. A subgroup gets up to maxVertices points, with
provoking vertex 0 and point raster primitive topology.
Tested with Cocoon (PPSA08766) which now progresses past pipeline
creation and initial frame draws into gameplay.
AI-assisted: yes. Written with AI assistance and reviewed by me.
When the graph is built without the wave size and the return address
escapes under only one of wave32 and wave64, the graph records that size
and its error instead of throwing, and translation throws it only at
that size. A wave64 program that reads a compare mask written over a
call's link pair from a scalar instruction is now recompiled, while the
same program at wave32, where the high dword still holds the return
address, is refused.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
A registered type-3 hull program holds the local and the hull part of a
tessellation draw in one binary, addressed through SPI_SHADER_PGM_LO_LS
(SH 0x148) with no SPI_SHADER_PGM_LO_HS: the local part runs on the lanes
below s3[7:0] and writes LDS, an s_barrier follows, and the hull part runs
on the lanes below s3[15:8] and may store the registers the local part
filled. The draw decode asked 0x148 for a type-5 local half, and
PPSA11386 (007 First Light) stopped in its level load with "registered
program refers to an incompatible shader binary type".
The draw decode now gives a registered type-3 program both the local and
the hull role and marks the tessellation configuration mergedHull. The
local stage only passes gl_VertexIndex and gl_InstanceIndex in a 16-byte
record. The hull stage runs the whole program, one invocation per output
control point: v2 and v5 come from the record of control point
min(gl_InvocationID, inputs - 1), v3 is the relative vertex id, and the
LDS becomes a per-control-point output array that a control point writes
in its own record and reads in any record of its patch after the barrier.
Registers live across the barrier stay in the invocation.
The hull stage of a merged program runs at one lane per invocation on
every device (HostSubgroupSize 1). Its lanes are gl_InvocationID, not host
subgroup invocations, so the s_cbranch_execz around the local part tests
the invocation's own lane. With the device's subgroup it took a subgroup
ballot, and lavapipe, whose subgroup stages lack the tessellation control
stage, rejected the draw ("subgroup capability 61 is unsupported for
shader stage 2").
The lowering refuses more input than output control points, LDS writes
outside the own record, reads outside the patch's records, barriers that
some invocations do not reach or that sit in a loop, reads or writes of
another lane's register, outputs beyond the device limits, and fetch
subroutines. Type 3 is prepared with its stage group like type 5 and
takes its float mode from RSRC1_HS. The hull user-data address (SH
0x102/0x103) is optional for a merged program: s[0:1] take it, unchecked,
when the draw sets it and are zero otherwise.
Both stages refer to one binary, so a draw lists each code and header
region once (AppendProgramMemory); a request's memory regions must not
overlap. An indirect draw's record words go into every program whose user
data holds the register, so the hull stage of a merged program reads
them too.
mergedHull is part of the recompile cache key, the draw decode comparison
and the request serialization (version 39).
Co-Authored-By: Claude Opus 5.5 <[email protected]>
A ds_ordered_count with offset1 bit 4 set swaps the first active lane's value into the GDS counter instead of adding it. Emit it as one device-scope atomic exchange through the same path as the ordered add, and return the counter's previous value to every active lane.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
v_fma_f16, v_fmac_f16, v_fmamk_f16, v_fmaak_f16 and v_fma_mix_f32 with
f16 sources left the NaN of an invalid operation to the driver, so
inf * 0 gave 0x7fff and 0x7fffffff on NVIDIA where the hardware gives
the default NaN 0xfe00 and 0xffc00000. An inf * 0 product, or a NaN
from sources that are not NaN, now gives the default NaN; NaN sources
are still left to the driver.
v_add_f64 and v_mul_f64 ignored the FLOAT_MODE f16/f64 denormal field.
On RDNA2 (gfx1031) bit 6 clear flushes both inputs to a zero of their
sign, and bit 7 clear flushes a sum below 2^-1022 and a product whose
exact value rounded to 53 significant bits with an unbounded exponent
is below 2^-1022. The product test scales one source by 2^64 and
compares the host product with 2^-958.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
v_floor_f64, v_ceil_f64, v_fract_f64, v_frexp_mant_f64 and
v_frexp_exp_i32_f64 ignored the FLOAT_MODE f16/f64 denormal field. On
RDNA2 (gfx1031) bit 6 clear flushes a denormal input to a zero of its
sign, so v_ceil_f64 of 2^-1074 is 0 instead of 1, and bit 7 clear
flushes the denormal result v_fract_f64 gives for a positive denormal.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
With DB_SHADER_CONTROL.STENCIL_OP_VAL_EXPORT_ENABLE the pixel shader
supplies the value that REPLACE_OP and the add and subtract operations
use in place of DB_STENCILREFMASK.STENCILOPVAL. The bit was refused as a
whole, which stopped Onimusha: Way of the Sword (PPSA27836) at a
DB_SHADER_CONTROL 0x45 draw with DB_STENCIL_CONTROL 0x40040 (REPLACE_OP
on depth pass, both faces), write mask 0xff and compare ALWAYS.
The export is accepted with the 32_GR and 32_ABGR Z formats. When no
reachable operation through a non-zero write mask reads the value, it
cannot change the result and is ignored. Without a test value export, a
reachable REPLACE_OP becomes REPLACE with the exported value as
FragStencilRefEXT (or the bounded replay on devices without the
extension), provided both faces compare without the test value and use
no ONES or REPLACE_TEST; early tests throw. The add and subtract
operations, and REPLACE_OP with a test value export, still throw.
The value is read from bits 8-15 of the second MRTZ channel: the
title's pixel shader shifts it left by 8 right before exp mrtz
(v_lshlrev_b32 v0, 8, v0). That is the only evidence for the layout and
it is listed as technical debt. The pixel stage info carries the new
flag into the cache key, the draw keys and request serialization
version 31.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
#6503 took request serialization 36 for its float32 flush flag, so this branch's sample order moves to 37. The version relabels in ShaderMemory.cpp and RequestSerializerTests.cpp drop both trailing flags and the sample order.
Devices with DenormFlushToZero for f32 run the mixed denormal-flush programs with and
without the hardware mode at startup; when every result matches, add, sub, mul, fma,
floor and ceil in the default rounding mode drop their software flush.
#4650 took request serialization version 35 for its depth remap flag, so this branch's sample order moves to 36. The serialization tests drop #4650's trailing byte from every older version they build, as main's do, along with the iteration fields and the sample order.
Combines this branch's sample order with #6470's once-per-pixel and once-per-sample inputs. The pixel request keeps both sides' fields: #6470's iteration, position location and sample locations are serialized at version 34, and the sample order after them at version 35. The serialization tests move the sample-order bytes after the iteration fields and drop both from older versions. The pixel info collector adds sample order to the SampleLocationsVary inputs, and the draw keys compare and hash both. EmitSampleOffset's iterated index already goes through GuestSampleIndex, since the SampleId builtin does. The shader cache stays at FormatVersion 40, and the sample-location debt entry takes #6470's sentence on the position inputs.
SPI_PS_INPUT_ENA/ADDR bit 14 (SAMPLE_COVERAGE_ENA) gives the pixel shader one
VGPR, after ANCILLARY, holding the samples the primitive covers. The decoder
refused it and the recompiler never loaded the VGPR. It is now loaded from
gl_SampleMaskIn[0] (sharing the input the partial quad sample mask already
declares). On a multisampled draw the hardware word is the whole pixel's
coverage while gl_SampleMaskIn holds only the invocation's samples when the
pixel shader runs per sample, so that case, and sample-rate or ancillary inputs
beside it, are refused.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
ConvertF16F32 built an (x, 0.0) f32 pair and packed it, and unary f16 results
(v_rcp_f16, v_sqrt_f16, ...) were packed with a 0.0 high half: the constant half
went through the whole f32-to-f16 conversion each time, which without native
f16 is a bit-level rounding sequence. Both now convert the one value; the high
half of the bits is zero as before, so the results are the same.
Test: agc_f16_single_convert recompiles four v_rcp_f16 with and without native
f16 and requires no (x, 0.0) f32 pair; on main each case emits four.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01XBXM4pgkMHYEtqN1EQni2P
minMaxF16Bits compares the halves as ordered integers (the low 16 bits
sign-extended, with the magnitude bits of a negative half inverted),
then replaced the result when both halves were zero: max took a & b and
min took a | b. The ordered integers already put -0 (-1) below +0 (0),
so the compare picks +0 for max and -0 for min, which is what the
both-zero select produced. Every caller passes halves with their upper
16 bits clear (readF16Bits masks them, the packed path extracts them),
and for those all 2^32 pairs of each give the same bits with and
without the select. Each f16 min, max, min3, max3 and med3 now emits
five instructions fewer per pair.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The remap mode stays a specialization constant and cache key input. Scale and
offset are two push words at byte 104, patched per draw, so draws that differ
only in depth range share one pipeline. The recipe, journal and serializer
carry the mode only.
Without VK_EXT_depth_range_unrestricted a viewport depth range outside
[0, 1] threw. Minecraft (PPSA17221) draws its world with scale 1 and
offset 0 in negative-one-to-one clip space, so its depth is the raw z/w
clamped by PA_SC_VPORT_ZMIN/ZMAX. On such a device the vertex shader now
scales clip z so z/w is the console's depth, the pipeline clamps depth at
the console's bounds, and two clip distances restore the near and far
planes that depth clamping removes. Mode, scale and offset travel as
pipeline specialization constants from the draw's vertex stage info, in
both the per-draw and the registration-module path; mesh and tessellation
draws with such a range still throw.
The console's depth clamp bounds are clipped to [0, 1]: exact for a
normalized depth target or none, and reported once for a tested or
written float depth target, where a depth below 0 is stored as 0
(Minecraft clamps its float depth target to [-1, 1]). The shader
validator accepts the remap's two extra clip distances next to the one
a program may already export.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Main's EmitSetAttribute debt entry now says the generated rect-list and
barycentric tessellation stages forward the vertex shader's clip array.
It sits next to this branch's PERSP_SAMPLE and pixel position entries,
which main left as they were; keep main's entry and this branch's two.
v_floor_f64, v_ceil_f64, v_fract_f64, v_frexp_mant_f64 and
v_frexp_exp_i32_f64 ignored the FLOAT_MODE f16/f64 denormal field. On
RDNA2 (gfx1031) bit 6 clear flushes a denormal input to a zero of its
sign, so v_ceil_f64 of 2^-1074 is 0 instead of 1, and bit 7 clear
flushes the denormal result v_fract_f64 gives for a positive denormal.
Co-Authored-By: Claude Opus 5.5 <[email protected]>