Commit Graph
177 Commits
Author SHA1 Message Date
Dean GalvinandMuhammad Wasif Ali Wasif 490adefc09 Merge origin/main into PR 8134
Co-authored-by: Muhammad Wasif Ali Wasif <76695420+wachi35676@users.noreply.github.com>
2026-10-21 14:56:22 +13:00
Dean 57fdffd915 Merge pull request #8697 from oneandonlydean/feat/f32-denorm-preserve
feat(shader): request DenormPreserve 32 where the device preserves f32 denormals
2026-10-21 13:29:41 +13:00
Dean bcdb033754 Merge pull request #7560 from parl0v/perf/window-store-liveness
perf(shader): drop window stores no relative read can see
2026-10-21 10:48:39 +13:00
Dean Galvin a07ad30578 feat(shader): request DenormPreserve 32 where the device preserves f32 denormals
The recompiler asked for DenormPreserve only for 16-bit and 64-bit floats,
so a device that flushes 32-bit denormals by default (RADV, MoltenVK) flushed
them whatever the guest's float mode said. target.float32DenormPreserve is set
from shaderDenormPreserveFloat32 when denormBehaviorIndependence allows a 32-bit
mode, is part of the cache key and of the request serialization (version 41),
and makes the module declare DenormPreserve 32 unless the 32-bit flush is
already taken in hardware. APS5_NO_HW_F32_PRESERVE=1 turns it off.
2026-10-21 10:45:24 +13:00
Adrià 0c54584946 Merge pull request #6611 from meh7an/perf/shader-validate-vertex-inputs
perf(shader): validate vertex stage inputs without building them
2026-10-20 22:28:45 +02:00
Dean 2185dbf92e Merge pull request #5656 from Raghav314/perf/agc-data-hit-user-word-mask
perf(agc): data-only draw hits compare only the user words a stage reads
2026-10-21 08:32:28 +13:00
Muhammad Wasif Ali WasifandClaude Opus 5.5 243925113f fix(shader): order wave LDS accesses with a memory barrier on AMD's proprietary driver
A guest wave's lanes see each other's LDS writes without a barrier, so
the recompiler adds a subgroup-scope OpControlBarrier between an LDS
write and the next LDS access when the guest wave is one host subgroup
(WaveLdsScope). AMD's proprietary Windows driver 32.0.21042.62 (Vulkan
driver 2.0.353, "AMD proprietary shader compiler", Radeon 0x13c0)
compiles that barrier to s_barrier, as the pipeline's internal ISA
shows (26 s_barrier for the guest's 9 in a small LDS reduction). In a
workgroup of several waves, the waves that enter a branch holding LDS
accesses then execute extra s_barriers, which pair with the other
waves' barriers, and those waves read LDS before it is written. LLPC
compiles a subgroup-scope control barrier to a wave barrier instead.

PS5LM Plus (PPSA99581) answered with garbage on that driver: the first
compute dispatch of its first graph, an RMS norm with a 512-thread
wave32 LDS tree reduction, scaled every row except its first 32
elements by a partial sum, while NVIDIA matched a NumPy reference and
the inputs were identical.

On that driver the barrier is now a subgroup-scope OpMemoryBarrier,
which it compiles to no instruction. A 32-lane subgroup is one hardware
wave there, which runs its lanes in lockstep and issues its LDS
instructions in order; Vulkan does not guarantee that, so it is
recorded as debt. Other drivers keep the control barrier. The flag is
part of the shader cache key, and agc_shader_replay takes
--wave-lds-memory-barriers to replay a request the way that driver
compiles it.

agc_driver_lds_tree_reduction sums over eight wave32 waves the way the
guest does, with its last four steps inside one wave and no s_barrier
between them: before, thread 32 read 1936 instead of 32896 on the AMD
driver; it passes on AMD and NVIDIA now. agc_subgroup_barrier checks
the driver quirk and the emitted barriers on every runner. PS5LM Plus
now answers " Paris. It is the largest city in Europe ..." on the AMD
iGPU without flash attention, as on NVIDIA and the CPU.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 20:24:01 +05:00
Jan ŠléglandClaude Opus 5.5 8b8219dcef feat(agc): run registered merged hull programs (binary type 3)
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 <noreply@anthropic.com>
2026-10-20 15:55:50 +02:00
Mehran 5bb72c6b12 perf(shader): validate vertex stage inputs without building them 2026-10-20 15:18:49 +03:00
raghav314andClaude Opus 5.5 6bfb4c5a63 perf(agc): data-only draw hits compare only the user words a stage reads
A data-only hit (#494) reused a cached stage only when every user data word
of the stage was unchanged. A stage records the user words it depends on when
it is captured: the words its SRT walk reads as values or bases
(SrtUserDataUse), the words its binding layout forwards into shader data
(userDataRegisterReads), and the vertex fetch table words of its vertex stage
info. A cached stage is now a candidate when only words outside that set
changed; its captured memory is validated as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 03:57:03 +05:30
sussyandClaude Sonnet 5.5 4d60321f1f feat(shader): emulate per-vertex parameters on the mesh path
A pixel shader that reads per-vertex parameters (v_interp_mov of P10 and
P20) on a device without VK_KHR_fragment_shader_barycentric now works on
the mesh path too. The mesh program stages each such parameter in
workgroup memory and writes the values of the three vertices of every
primitive as a per-primitive output, in the order of the triangle
indices; the pixel shader reads them from there.

The emulation throws when the staging, the output components or the
output memory exceed the device's mesh limits, or when the mesh
configuration uses a provoking vertex other than the first.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-19 17:26:37 +02:00
sussyandClaude Sonnet 5.5 dd41527ce2 feat(shader): emulate smooth barycentrics on the mesh path
A pixel shader that reads barycentrics on a device without
VK_KHR_fragment_shader_barycentric used to need a vertex shader so a
generated geometry stage could follow it, which a mesh pipeline cannot
have. The mesh program is now compiled a second time with the layout
its pixel shader needs: it writes its clip position as a varying and the
three corner positions of each primitive as per-primitive outputs, and
the pixel shader solves for the weights, for both smooth and linear
interpolation.

The layout is part of the mesh cache key, the stored artifact and the
captured request. Without VK_EXT_mesh_shader the draw still throws, now
saying so. Per-vertex parameters on the mesh path still throw.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-19 17:26:37 +02:00
simonbronkandClaude Opus 5.5 7563b4a480 fix(agc): replace with a stencil operation value the pixel shader exports
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 <noreply@anthropic.com>
2026-10-19 12:53:13 +02:00
Adrià aaaff21edf Merge pull request #6733 from meh7an/perf/shader-result-memo-sets
perf(shader): keep memoized results in a set-associative table
2026-10-19 12:20:45 +02:00
Dean 323ece2445 Merge pull request #7445 from elliot1377/fix/agc-dispatch-split-base
fix(agc): split oversized dispatches with workgroup offset specialization
2026-10-19 18:51:58 +13:00
ThatsLeo ac14d6317d perf(shader): flush f32 denormals in hardware when a startup probe matches the emulation
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.
2026-10-19 07:00:13 +02:00
elliot 11a7b61d72 fix(agc): split oversized dispatches with workgroup offset specialization
A dispatch over maxComputeWorkGroupCount was split into vkCmdDispatchBase
chunks whose base reached the limit, which VUID-vkCmdDispatchBase-baseGroupX-00421
forbids, and NVIDIA refused the split outright.

Compute modules now declare WorkgroupOffset specialization constants (default 0)
that the recompiler adds to WorkgroupId and GlobalInvocationId and keeps
unmaterialized. Each chunk is recorded with vkCmdDispatch from group 0, bound to
a pipeline variant specialized with the chunk's base. The NVIDIA throw is gone;
device-memory LDS splits still throw.

Fixes #7375
2026-10-18 22:54:33 -05:00
Dean Galvin 41764f27ac Merge main into pr-4650
# Conflicts:
#	core/shader/recompiler/ShaderDiskCache.cpp
2026-10-19 15:36:07 +13:00
Adrià 23629c2847 Merge pull request #6454 from EagleBearerYS/perf/shader-image-table-reuse-v3-pr
perf(agc): share one image table per heap and write epoch through capture, compare, resolution and descriptors
2026-10-19 03:39:03 +02:00
Dean Galvin 4d4ae6e5eb Merge main into pr-4650
# Conflicts:
#	core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
#	core/shader/recompiler/ControlFlow/src/RequestSerializer.cpp
#	core/shader/recompiler/tests/RequestSerializerTests.cpp
2026-10-19 14:32:36 +13:00
Adrià 00666eeb36 Merge pull request #6470 from EagleBearerYS/fix/recompiler-once-per-pixel-sample-inputs
fix(recompiler): run a pixel shader the guest does not iterate once per pixel
2026-10-19 03:21:34 +02:00
Yunus Shaikh 106b79e007 Merge main into perf/shader-image-table-reuse-v3-pr
The data-hit verification keeps this branch's pending-span query on its ShaderMemory and takes #5958's CaptureInvocation, which retries a capture with converted samples.
2026-10-18 17:04:23 -07:00
Yunus Shaikh 10b798fb99 Merge main into perf/shader-image-table-reuse-v3-pr
Keeps this branch's tagVariantRuns declaration next to main's dumpRequest suffix parameter in Driver.hpp, and reads #6232's pointer-chain test words from its table's snapshot, where this branch keeps them.
2026-10-18 17:03:39 -07:00
Adrià 0fd3555ad6 Merge pull request #5958 from ps54all/feat/shader-converted-image-sample
feat(shader): sample converted unorm images in the shader
2026-10-19 00:24:10 +02:00
Dean Galvin cf4d1f4a97 Merge main into pr-4650
# Conflicts:
#	core/shader/recompiler/ShaderDiskCache.cpp
2026-10-19 11:15:57 +13:00
Yunus Shaikh d13a90d015 Merge main into fix/recompiler-once-per-pixel-sample-inputs
Resolves the shader debt file bullet by bullet: main's EmitSetAttribute entry, and this branch's PERSP_SAMPLE/LINEAR_SAMPLE and pixel-position entries.
2026-10-18 15:14:25 -07:00
Adrià fb9a1eb8f3 Merge pull request #6178 from MarcZX10/codex/release-undrawn-resource-plans-6139
perf(agc): release unused registered shader resource plans
2026-10-18 22:20:27 +02:00
Josip Parlov d1596f2723 perf(shader): drop window stores no relative read can see 2026-10-18 21:55:41 +02:00
ps54allandClaude Opus 5.5 8545c23013 feat(shader): sample converted unorm images in the shader
10_11_11_UNORM (format 30) images are read and written through an
R32_UINT view, so the hardware sampler cannot filter them. image_sample
of a 2D or 2D array view now fetches the one or four texels at LOD 0,
decodes them and blends them in the shader, with bilinear weights on
the 8-bit grid, for point or bilinear filtering with wrap or
clamp-to-edge addressing.

A shader gets the converted sample mode only after a converted
descriptor reaches one of its sampled images: that capture throws
ConvertedSampleRequired and the driver prepares the program again
with GuestContext::convertedSamples.

The R10_G11_B11 float format is sampled natively since #7271 and keeps
its refusal on the converted path.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 17:43:35 +02:00
Dean Galvin 441ff87188 fix(agc): give a depth-remapped vertex shader its push constant stage
A remapped vertex shader reads the scale and offset from the push block, but
the pipeline's push constant stages only counted programs with push data of
their own, so a shader with none got no stage in a non-GPL layout and its
scale and offset never arrived. The result now says it reads them, and the
push stages include the vertex stage for it. The draw test gains a fetchless
remapped vertex shader with no push data.
2026-10-18 22:51:26 +13:00
Dean Galvin 5db206aba0 fix(agc): read the depth remap scale and offset from push constants at run time
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.
2026-10-18 19:01:14 +13:00
Yunus Shaikh 6720211da1 Merge main into perf/shader-image-table-reuse-v3-pr 2026-10-17 19:24:20 -07:00
Yunus Shaikh 2848253fe4 Merge main into fix/recompiler-once-per-pixel-sample-inputs 2026-10-17 19:06:51 -07:00
NikoandClaude Opus 5.5 b28e6c83de fix(agc): keep viewport depth scale and offset out of the shader cache key
Only the remap mode changes what the vertex shader compiles to. Scale and
offset are specialization constants that each materialization takes from
its own request, so they no longer split the compiled variant per depth
transform. The result memo hashes them with the snapshot instead, so one
prepared vertex shader does not hand the module specialized for one
transform to a draw with another. sameVertexInfo repeated its first
comparison without paClVsOutCntl; the repeat is dropped.

A test pins the version 27 layout (the remap fields are the last bytes
of a vertex request), a version 25 replay, truncation and trailing-data
refusal, and that scale and offset leave the cache key alone while the
mode does not. agc_depth_range_remap materializes one prepared vertex
shader with two transforms and checks that each gets its own module.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 14:27:48 +13:00
Mouad-Scriptz-0andClaude Fable 5.1 53212b18ac feat(agc): remap a viewport depth range the device cannot express into the vertex shader
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 <noreply@anthropic.com>
2026-10-18 14:27:48 +13:00
Yunus Shaikh a53d23f810 Merge main into perf/shader-image-table-reuse-v3-pr
Main's #6402 stores to image tables: a table with a written entry takes
the fresh path, as it does on main, and so does one without a sampled
table binding, whose entries the fresh path rejects. The shared place
step uses the binding as a pointer. Main's #6614 frees descriptor sets
from shared pools one by one, while this branch keeps only dedicated
pools, so both stay. #7101's bulk key read counts its unmapped-page
skips as unmapped, and its key words sit next to this branch's write
stamp and compared runs.
2026-10-17 16:05:44 -07:00
Mouad-Scriptz-0andClaude Fable 5.1 0a9ee3698a perf(recompiler): keep LDS loads branched and drop the LDS sentinel
NVIDIA's compiler predicates a branched LDS load at no cost, while the
selected form costs about 2.5 instructions per dword and splits a
ds_read_b128 into four loads (RTX 4060 measurements by @karanvora2599 in
loads therefore keep the branch of main, in workgroup, function and device
memory alike, and the sentinel dword that only they read goes away: the LDS
array is the program's dwords plus the lock again, and the device-memory
decision reserves the lock alone. The sentinel budget tests become lock
budget tests at that boundary, and the guarded-load test pins the branch.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-17 12:19:09 +13:00
jweidenh 21a3bd5606 fix(recompiler): reserve LDS sentinel and lock headroom 2026-10-17 12:18:50 +13:00
Mouad-Scriptz-0andClaude Fable 5.1 ccaeeed416 fix(recompiler): point selected guest loads at locations nothing writes
A load selected instead of branched still accesses memory, so its fallback
element must be one no write can race with: scratch keeps element 0, LDS in
workgroup or function memory reads a sentinel dword appended after the
program's LDS and lock, and storage buffers read element 0xfffffffe, which
robustBufferAccess2 turns into a zero load without a memory access. The
device enables robustBufferAccess2 when it has it and the target carries the
flag; without it, and for LDS in device memory, buffer loads keep their
selections. The aligned high word of a buffer read re-reads the low word's
element instead of word 0. agc_guarded_memory_loads traces the emitted loads
in both device modes.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-17 12:18:50 +13:00
Yunus Shaikh bd09c49374 Merge main into fix/recompiler-once-per-pixel-sample-inputs
Main took request serialization versions 31 (output primitive size) and
32 (spanned waves), and #6683 uses 33, so the pixel iteration fields move
to version 34. A version 32 request keeps its spanned-waves flag and reads
no pixel iteration.
2026-10-16 12:41:06 -07:00
Adrià db7d9de5e4 Merge pull request #5405 from Pipodi/feat/spanned-wave64-compute
feat(recompiler): run single-wave wave64 compute programs at one lane per invocation on 32-lane hosts
2026-10-16 21:05:55 +02:00
fdfawef324andClaude Opus 5.5 b9a3296138 fix(shader): drop rebuilt IR when a prepared artifact serves the reload
Prepared captures pass their source handle to the plan reload. When the handle
matches the request, its artifact serves the draw, so the rebuilt resource
program is not kept even if the push layout differs from the artifact's.
A handle that does not match the source is rejected before the entry changes.
Same change as f1b42dae4 on top of c00b0dfb9.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 15:24:12 +00:00
Alex ColliniandClaude Opus 5.5 7a6cc71786 feat(agc): carry spanned waves in the target and require full subgroups
APS5_SPANNED_WAVE is now read once by the driver, which sets
SpirvTarget::spannedWaves only on a device with 32-lane compute subgroup
control and computeFullSubgroups. The recompiler no longer reads the
environment. The field is part of the cache key and of the request
serialization (version 32), so a cached or replayed module keeps the mode
it was built in.

A spanned module numbers its lanes SubgroupId * 32 +
SubgroupLocalInvocationId, which needs two full 32-lane subgroups. The
artifact records this as fullSubgroups (disk cache and pipeline identity
included), and the driver creates those pipelines with
REQUIRE_FULL_SUBGROUPS. Compute pipeline captures accept the flag with a
required subgroup size.

The two-lane fallback now catches only SpannedWaveUnsupported, thrown for
a shuffle wider than 32 bits; other emit errors surface as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 14:12:58 +02:00
Yunus Shaikh 51d4babc64 Merge main into perf/shader-image-table-reuse-v3-pr 2026-10-16 05:09:29 -07:00
Adrià c8044c3a7a Merge pull request #5914 from fdfawef324/codex/vertex-lane-bounds
fix(shader): fold fixed 32-lane vertex bounds
2026-10-16 13:47:56 +02:00
Alex ColliniandClaude Opus 5.5 80e3d90ed6 feat(recompiler): run single-wave wave64 compute programs at one lane per invocation on 32-lane hosts
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 13:43:36 +02:00
Yunus Shaikh 19907d6ed4 Merge main into perf/shader-image-table-reuse-v3-pr
Resolves #4943's draw relocation against this branch: tagVariantRuns, which now builds a draw variant's runs and words, also records the captured words it shares with a table's supplied blocks, per region as before. A variant whose runs relocation splits keeps sharing for the draw cache's word compare, and skips the vouched validation, which already requires one run per region.
2026-10-16 03:25:29 -07:00
Mehran 92e5b971c6 perf(shader): keep memoized results in a set-associative table 2026-10-16 10:55:47 +03:00
Yunus Shaikh 2cd0c9107a fix(recompiler): run a pixel shader the guest does not iterate once per pixel
The ancillary input's sample number (bits 11:8) was the SampleId
builtin in every pixel shader. Vulkan enables sample shading for a
shader that uses SampleId, so a shader that reads the sample field or
the whole ancillary word ran once per sample on a multisampled draw
even when the guest runs it once per pixel (PS_ITER_SAMPLE clear), and
FragCoord, and with it POS_X_FLOAT and POS_Y_FLOAT, moved to the
sample. The sample number is now SampleId only when the request says
the guest iterates the shader, and otherwise 0, the iterated sample
number of a pixel the hardware does not iterate.

The other inputs that depend on the sample follow where the console
evaluates them:
- PERSP_SAMPLE and LINEAR_SAMPLE are interpolated with
  InterpolateAtOffset at sample 0's offset in a shader the guest does
  not iterate, and in an iterated one at the offset of the host's
  SampleId, read from a table of the guest's locations, because Vulkan
  leaves plain barycentrics under sample shading at an
  implementation-defined position (lavapipe uses the pixel centre).
- PERSP_CENTER and LINEAR_CENTER are interpolated at offset 0 in an
  iterated shader.
- POS_X_FLOAT and POS_Y_FLOAT follow SPI_BARYC_CNTL: the centre is
  floor(FragCoord) + 0.5 under sample shading, a sample position in a
  shader the guest does not iterate is the centre plus sample 0's
  offset, and POS_FLOAT_ULC gives the upper-left corner.

The offsets need InterpolationFunction (sampleRateShading) and the
fragment-shader barycentric path; devices without them keep the host's
default positions. The shader disk cache format goes to 39.
2026-10-15 16:06:38 +00:00
Yunus Shaikh d21b0801a4 Merge upstream main into perf/shader-image-table-reuse-v3
Brings the series onto main 4e9a2a871 (#1193, #1201, #1202, #6060,
#6333 and the descriptor word tracking of 682b07eb0).

Resolutions:
- ShaderMemory: the column memo's supplied and spilled blocks now sit
  on #1193's page vector, page pool and word masks. Pages are found by
  binary search, since a spilled block can add many pages, and a block
  placed into a lazily read page fills the rest of the 16-word blocks it
  touches, so a later lazy read never overwrites placed words.
- ResourceMaterializer and SharedValues: the selected-record path and
  the words index carry availableDwordMask, as the snapshot hash does.
  A selected record's dwords past the end of its buffer count as read
  zeros, which is what a scalar buffer load returns there, so a key past
  the heap still selects a null image without reading the heap.
- DescriptorCache: kept table sets live beside #1201's recycled sets.
- Tests and CMake: both sides' tests are kept.
2026-10-15 08:54:44 -07:00