Commit Graph
175 Commits
Author SHA1 Message Date
Adrià 98145b48d8 Merge pull request #7426 from DavidSamir/feat/shader-barycentric-tessellation-last-vertex
feat(agc): draw the last provoking vertex through the barycentric tessellation stages
2026-10-21 13:08:47 +02:00
Yunus Shaikh 8c9c8eb5b5 Merge main into fix/agc-sample-location-grid-exact
main 7ce3b1df3e took disk-cache format 43 (#8295) for its own layout, so this
branch's format moves to 44. The request serializer stays at 42: main
still writes 41.
2026-10-20 23:48:14 -07:00
Yunus Shaikh 6d09797d6b Merge main into fix/agc-sample-location-grid-exact 2026-10-21 05:39:42 +00:00
Dean GalvinandMuhammad Wasif Ali Wasif 490adefc09 Merge origin/main into PR 8134
Co-authored-by: Muhammad Wasif Ali Wasif <[email protected]>
2026-10-21 14:56:22 +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
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 <[email protected]>
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 <[email protected]>
2026-10-20 15:55:50 +02: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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
2026-10-19 17:26:37 +02:00
David 63e763f443 Merge remote-tracking branch 'origin/main' into feat/shader-barycentric-tessellation-last-vertex
# Conflicts:
#	docs/dev/debt/shader.md
2026-10-19 18:27:34 +04: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 <[email protected]>
2026-10-19 12:53:13 +02:00
Yunus Shaikh 53cc193a3c Merge main into fix/agc-sample-location-grid-exact
#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.
2026-10-18 22:52:06 -07: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
Yunus Shaikh 18463ff5c2 Merge main into fix/agc-sample-location-grid-exact
#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.
2026-10-18 20:56:57 -07:00
Dean Galvin 41764f27ac Merge main into pr-4650
# Conflicts:
#	core/shader/recompiler/ShaderDiskCache.cpp
2026-10-19 15:36:07 +13:00
Karan Vora 6d92220829 perf(agc): stage raw buffer elements a dispatch sweeps
Since 2688b7646 a read and written V# element is staged in device memory
up to 16 MiB when the direct dispatch's threads times the V# stride cover
at least half of it. A raw buffer has stride 0, so it never passed and
kept the 2 MiB written window: GL storage buffers compiled by Mesa stay
bound in place in the host import however hard a dispatch sweeps them.

The PS5 OpenGL Showcase's particle update (262,144 threads, each loading
and storing its own 32-byte record of an 8 MiB SSBO) took about 53 ms of
GPU per frame on an RTX 4060 bound in place; staged it takes about 0.1 ms
plus 2.2 ms of bulk copies.

The recompiler already records the furthest byte each buffer resource's
accesses reach past their base (maxByteExtent). The binding plan now
carries it per guest buffer element (DescriptorBinding::bufferExtent,
shader disk cache format 37), and a raw element uses it as its record
size in the sweep test. Strided elements are unchanged.
2026-10-19 03:43:19 +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
Yunus Shaikh 745f199d5a Merge main into fix/agc-sample-location-grid-exact
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.
2026-10-18 18:30:37 -07: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 866ad41ea1 Merge main into fix/agc-sample-location-grid-exact
Keeps MultisampleTargetOrderTarget next to #6175's MultisampleTargetView, which now also returns the target's image.
2026-10-18 15:50:54 -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
Yunus Shaikh 340f3aa13a Merge main into fix/agc-sample-location-grid-exact
Resolves MultisampleTarget against #6635: the sampled view takes the requested view type and keeps the sampled-only usage when the target has a storage view for the guest's sample order.
2026-10-18 13:37:01 -07:00
Dean ca1c4c89cd Merge pull request #6635 from hamb3r/fix/shader-msaa-array-descriptor-shape
fix(shader,agc): support multisampled 2D array descriptor image shape and runtime views
2026-10-19 09:32:18 +13:00
David 8f4a50d727 Merge remote-tracking branch 'origin/main' into feat/shader-barycentric-tessellation-last-vertex
# Conflicts:
#	core/libs/prx/libSceAgcDriver/Graphics/src/Pipeline.cpp
#	core/shader/recompiler/SpirvBackend/src/BarycentricGeometryShader.cpp
#	docs/dev/debt/libSceAgcDriver.md
#	docs/dev/debt/shader.md
2026-10-19 00:15:47 +04:00
Yunus Shaikh a74f343e58 Merge main into fix/agc-sample-location-grid-exact 2026-10-18 11:30:40 -07:00
Yunus Shaikh dc47a81b02 Merge main into fix/recompiler-once-per-pixel-sample-inputs 2026-10-18 11:30:31 -07: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 <[email protected]>
2026-10-18 17:43:35 +02:00
Gjon Gojcevic a2e79fb3fd fix(shader): bind an unnormalized S# normalized when it samples only null images
An S# that forces unnormalized coordinates was refused when it samples a
T# the shader declares 3D, 2D-array, cube or multisampled, since Vulkan
allows unnormalized coordinates only with a single-level 1D or 2D view.
A null T# reads zeros at any coordinate, and a T# whose channels all
select constants is emitted as those constants without a sample, so when
the S# samples no other T# its coordinates cannot change a result. Such
an S# is now marked in its binding (samplerCoordinatesIgnored) and the
driver creates its sampler without FORCE_UNNORMALIZED. The flag is part
of the binding content key and of the shader disk cache, whose format
version is raised to 38. An S# that also samples a real T# while a null
T# of such a shape shares it is still refused. PPSA01317 pairs an
unnormalized clamped bilinear S# with a null 3D T# and a 3D T# whose
channels all select 0 for image_sample_lz in a compute shader during
boot.

AI-assisted: yes
2026-10-18 09:02:31 -04: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
David 814f17982b Merge remote-tracking branch 'origin/main' into feat/shader-barycentric-tessellation-last-vertex
# Conflicts:
#	docs/dev/debt/libSceAgcDriver.md
2026-10-18 09:40:45 +04:00
Yunus Shaikh 8f6f7d7500 Merge main into fix/agc-sample-location-grid-exact 2026-10-17 19:10:21 -07:00
Yunus Shaikh 2848253fe4 Merge main into fix/recompiler-once-per-pixel-sample-inputs 2026-10-17 19:06:51 -07:00
hamb3r ed85bd05ce Merge remote-tracking branch 'origin/main' into fix/shader-msaa-array-descriptor-shape
# Conflicts:
#	core/libs/prx/libSceAgcDriver/Graphics/src/MultisampleTarget.cpp
#	core/libs/prx/libSceAgcDriver/tests/execution/SampleMultisampleTarget.cpp
2026-10-18 04:53:06 +03: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 <[email protected]>
2026-10-18 14:27:48 +13:00
Dean 63da333b7a Merge pull request #4048 from Mouad-Scriptz-0/perf/recompiler-select-load-guards
perf(recompiler): select guest memory loads instead of branching around them
2026-10-18 13:56:36 +13:00
Yunus Shaikh ddf072e6f3 Merge main into fix/recompiler-once-per-pixel-sample-inputs
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.
2026-10-17 17:03:27 -07:00
Dean 54c5eff8ac Merge pull request #7308 from DavidSamir/feat/shader-barycentric-tessellation
feat(shader): emulate barycentrics through tessellation on devices without geometry shaders
2026-10-18 12:57:13 +13:00
David ac8e3c1ecc feat(shader): take flat values from the provoking vertex in the barycentric tessellation stages 2026-10-18 02:46:53 +04:00
David a968198710 Merge remote-tracking branch 'origin/main' into feat/shader-barycentric-tessellation
# Conflicts:
#	core/libs/prx/libSceAgcDriver/Graphics/src/Pipeline.cpp
#	docs/dev/debt/shader.md
2026-10-18 02:30:39 +04:00
David 02a4bdf08a feat(shader): build the barycentric emulation stages from tessellation
On a device without geometry shaders, each triangle becomes a three-point
patch at tessellation level 1. The evaluation stage takes the corner
gl_TessCoord points at as its vertex and writes it as the weights, and
passes every vertex's parameters for raw reads. The vertex clip distances
are forwarded, so MoltenVK's stage interface matches the vertex output.
2026-10-18 02:16:51 +04:00
Gjon Gojcevic 49b0e805f0 feat(agc): implement 11_11_10 float color targets through 32-bit uint attachments
Color format 7 (COLOR_11_11_10, float) keeps its 10-bit component in the
low bits; with the reversed component order (COMP_SWAP 2) that is blue,
with red in the high 11 bits. Vulkan has no such layout, so the target was
refused at decode.

Render it the way 10_11_11 unorm targets are rendered: an R32_UINT
attachment, the reversed export mapping 0xc6, and a new
ColorExportPacking::Float11_11_10 that makes the pixel shader pack each
export with the format-43 image store conversion (toward zero, overflow to
the largest finite value, negatives to zero, NaN kept). Blending, partial
writes, 16-bit integer exports, DCC and the other component orders throw.

AI-assisted: yes
2026-10-17 17:29:21 -04:00
Dean e815fb4170 Merge pull request #7251 from thuanquang/fix/rect-list-last-provoking-vertex
fix(agc): draw rect lists in last provoking vertex mode
2026-10-18 10:28:06 +13:00
thuanquangandClaude Opus 5.5 f2a4236ab6 fix(agc): draw rect lists in last provoking vertex mode
The generated rect-list control stage gave every corner of a rectangle the
flat inputs of its first vertex, so last mode was refused for rect lists.
BuildRectListShaders now also builds a control stage that takes them from
the rectangle's third vertex when the pixel shader has a flat input, and a
draw in last mode uses it.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-18 02:38:26 +07:00
Alex ColliniandClaude Opus 5.5 603dc01dbf feat(agc): store to images selected through image tables
An IMAGE_STORE whose T# comes from a runtime-indexed image table used to
poison the whole table as an unsupported operation. Written, non-atomic
table images now get storage modes, a STORAGE_IMAGE table binding (260,
the sampled image table moves to 261 and keeps the variable count), and
storage views of tracked storage textures at the same element indices.
Every bound entry is marked written, so each dispatch writes back all of
the table's storage images. Atomic, packed, BY2/BY4 and dynamic-mip table
stores still fault. Tables with written entries are not reused.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-17 08:45:46 +02: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 <[email protected]>
2026-10-17 12:18:50 +13:00