578 Commits
Author SHA1 Message Date
Dean 9bbb7f37c6 Merge pull request #8898 from camezaro-intc/format11-11-10-float-stores
fix(shader_recompiler): pack format 11_11_10 float image stores in shader
2026-10-27 01:03:40 +13:00
Dean d9f5bf4d91 Merge pull request #11120 from shahulmubeen-a/fix/shader-1d-store-through-2d-array
fix(shader): write 1D storage images through 2D-array stores at slice 0
2026-10-26 21:58:24 +13:00
Dean 943ea8acb2 Merge pull request #9957 from mrfelek/fix/shader-runtime-buffer-presence
fix(shader): read a buffer V#'s presence at run time instead of specializing it
2026-10-26 16:54:34 +13:00
Shahul Mubeen AandClaude Opus 5.5 b9d00c5d80 fix(shader): write 1D storage images through 2D-array stores at slice 0
An image_store with DIM 2D_ARRAY through a 1D T# had no runtime image
mode, so the dispatch stopped with "image descriptor is incompatible
with the static runtime image interface". #2348 added a 1D mode for
DIM 2D stores only.

Write-only 2D-array storage images now get the same 1D mode as the 2D
case. On RDNA2 (gfx1036, hardware oracle) such a store writes texel x
and ignores y when the slice is 0, and writes nothing for any other
slice, with DEPTH 0 or 3, so the store is skipped unless the slice is 0.

New execution test agc_driver_image_store_line_through_plane_array.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-26 00:10:03 +05:30
Adrià e317f41d59 Merge pull request #10440 from SuarezPM/ai/atomic64-keyed-tables
feat(shader): support 64-bit image atomics through keyed image tables
2026-10-25 11:58:35 +01:00
camezaro-intc e3f644040c fix(shader_recompiler): pack format 11_11_10 float image stores in shader 2026-10-24 21:32:14 -06:00
Adrià 66de8e7a12 Merge pull request #9177 from milescoviello/perf/draw-allocations
perf(agc): drop three per-draw allocations on the draw and materialize paths
2026-10-24 18:29:19 +02:00
Adrià c9b2660d56 Merge pull request #9567 from Izamaru/fix/rve-descriptor-references
fix(shader): refresh descriptor sources after redundant value elimination
2026-10-24 15:46:56 +02:00
Adrià 522e32e3b6 Merge pull request #7550 from gjonn/fix/shader-resinfo-any-descriptor-dimension
fix(shader): answer image_get_resinfo on any T# dimension
2026-10-24 15:30:15 +02:00
mrfelek 20311903c3 fix(shader): read a buffer V#'s presence at run time instead of specializing it
A buffer V#'s presence came from the dispatch's V# snapshot as the
specialization constant BufferBase + 2, which buildSpecializedModule
turns into a literal. One guest program then compiled to two SPIR-V
modules, one with the buffer bound and one with it still null, each a
separate pipeline. descriptor() now reads presence from the V# words at
run time, as registration modules already do, and the formatted-buffer
helper takes it from its valid parameter.

AI-assisted. Tested by me on my own machine.
2026-10-24 12:59:47 +00:00
Adrià 924b5628b3 Merge pull request #8632 from JJenkx/fix/srt-unsigned-bound-compare
fix(shader): decide an unsigned bound compare from its extreme operand
2026-10-24 11:56:35 +02:00
Adrià FranchandClaude Sonnet 5.5 424b8f90b1 fix(shader): a negated predicate excludes only conditions that imply its operand
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
2026-10-24 08:40:33 +02:00
xQuakes 418db9d2f8 fix(shader): accept a local tessellation index that nothing observes
A local program that keeps the relative patch index only on inactive
lanes, or in a vector-window slot nothing reloads, was refused as a
data use. Follow the index through the values that carry it, and
refuse only when a side effect still observes it.
2026-10-24 08:40:33 +02:00
Adrià a5a2c946a3 Merge pull request #10396 from CrimsonMac/fix/lds-misaligned-atomic64-fault
fix(shader): fault on misaligned 64-bit LDS atomics under the workgroup lock
2026-10-24 07:33:30 +02:00
JJenkxandClaude Opus 5.5 9ed24c8b41 fix(shader): decide an unsigned bound compare from its extreme operand
A resource block behind v_cmpx_gt_u32 exec, s, v0 and s_cbranch_execz keeps
its condition only if the compare can decide it, but UGreaterThan32 and
ULessThan32 needed both operands and v0 is a lane value. When the uniform
operand is 0 (or 0xffffffff on the other side) no lane can pass the compare,
so the walk can skip the block without the lane value.

UGreaterThan32 now yields false when its first operand is 0 or its second is
0xffffffff, and ULessThan32 when its first is 0xffffffff or its second is 0,
in the SRT interpreter and in the SRT tape alike; MayDecide keeps such a
condition when either operand is evaluable. Fully evaluable compares are
unchanged.

Destruction AllStars (PPSA02630) dispatches compute shader 0x200a220000 with
a thread count of 0 and leaves the V# in the skipped block stale (one
dispatch holds 00000000 00000000 00000000 ffffffff), which stopped it at
about 40 s with "buffer descriptor uses an unsupported type".

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-23 23:59:32 -04:00
Adrià FranchandClaude Opus 5.5 7b4b9d9814 fix(shader): zero the resinfo layer count for DIMs without layers
image_get_resinfo returns 0 in its third component when the instruction's
DIM has no layers (1D, 2D, 2D MSAA) and the T# is not 3D, as measured on
RDNA 2 in #7550. Keep 1D-array T#s on their first layer and MSAA T#s
refused, and record the unmeasured forms in the shader debt file.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-24 04:21:06 +02:00
Gjon Gojcevic 3ba1d39db6 fix(shader): answer image_get_resinfo on any T# dimension
image_get_resinfo with DIM 1D on a cube, 3D or 2D-array T# was refused
with "image address has too few coordinate components": the tracker made
a 1D image that only the query uses, and no 1D mode matches such a T#.
The returned size, layer count and levels come from the T#; DIM only sets
the number of address registers. A 1D image used only by dimension
queries now decodes the T#'s own dimension and accepts 2D, 1D array,
2D array, 3D and cube views.
The flag is stored in the shader disk cache, so FormatVersion moves to 38.

PPSA01317 queries a 64x64 cube with DIM 1D in a pixel shader.

AI-assisted: yes
2026-10-24 04:07:24 +02:00
Dean e2b9700a98 Merge pull request #7880 from klosixgaming-arch/fix/shader-indirect-column-phi-pointer
fix(shader): resolve table column pointers through Phi nodes
2026-10-24 13:22:58 +13:00
SuarezPM 9c3ffcf5b0 feat(shader): support 64-bit image atomics through keyed image tables
Table T#s keyed at runtime feeding image_atomic64_* now lower to
OpAtomic* on the table Atomic64View instead of faulting, mirroring
the 32-bit path: gate, dedup identity, binding flags and view
selection. Packed formats and BY element counts still fault; hosts
need VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT for the view format.
2026-10-23 21:14:39 -03:00
Adrià d48007d462 Merge pull request #8883 from EagleBearerYS/perf/shader-plan-retention
perf(shader): keep only what a resource plan's branch conditions can evaluate
2026-10-24 01:00:04 +02:00
Adrià 495b7c10ab Merge pull request #8792 from SuarezPM/ai/image-atomics-keyed-tables
feat(shader): support 32-bit image atomics through keyed image tables
2026-10-24 00:00:03 +02:00
Adrià dcd7e3a61e Merge pull request #8564 from JAB-dev/feat/agc-4-4-4-4-partial-writes
feat(agc): merge partial writes into 4_4_4_4 UNORM color targets
2026-10-23 23:23:11 +02:00
Adrià a0e858ff7b Merge pull request #8881 from thuanquang/fix/writelane-spill-window
fix(shader): keep a v_writelane lane known across computed-index window stores
2026-10-23 23:17:12 +02:00
Crimson cd329c060a fix(shader): fault on misaligned 64-bit LDS atomics under the workgroup lock 2026-10-23 23:59:53 +03:00
Adrià 11e8ad2934 Merge pull request #8713 from SeifKaroui/fix/shader-unused-phi-cycles
fix(shader): remove unused phi cycles before resource planning
2026-10-23 22:46:22 +02:00
Adrià 3c44638fc6 Merge pull request #8727 from hamb3r/perf/shader-cse-srt-readconst
perf(shader): eliminate redundant GetSrtResource and ReadConst in RVE
2026-10-23 21:54:52 +02:00
Yunus Shaikh 6f36f29ea3 fix(shader): answer phis and null bases in a trimmed plan as the program does
A plan copies a branch condition only as far as the evaluator reads it,
and an operation the evaluator does not read is kept without its
arguments. Two questions the walk asks still read below such a leaf.
ResolveInvariantPhi compares a phi's incoming values with
EquivalentValue, which follows their arguments, so two leaves with the
same operation looked equal in the copy where their arguments differ
in the program: a phi whose incoming values differ only below a vector
load resolved in the plan and not in the program, and the plan decided
a condition the program leaves open. LoadedFromMemory looks for a read
from memory anywhere below a raw read's handle, so a handle that
reaches memory only below a leaf lost it in the copy: a read from a
null base counted as a null root, and its condition stayed open where
the program decides it.

ownPlanValues now checks both after it copies. Each phi it copied in
part must resolve in the copy to the copy of what it resolves to in
the program, and each raw read's handle must be loaded from memory in
the copy when it is in the program. A phi that differs is copied whole;
a handle that differs keeps the arguments along its shortest path to a
read from memory (its whole closure if that path is already kept), and
the copy is made again. The checks only add values, so the loop ends,
at worst with the whole copy. IsMemoryRead names the operations that
LoadedFromMemory and the path both stop at.

Tested: agc_shader_memory's verifyPlanCopyAnswers walks a phi whose
incoming values differ only below a vector load, and a read from a null
base whose handle reaches memory only through a select arm the active
mask never takes, through the plan's tape, the plan's interpreter and
the program's own walk, and all three agree. Without the checks the
plan decides the first condition and leaves the second open.
2026-10-23 21:40:20 +02:00
fablevoid 402f891787 fix(shader): keep only what a resource plan's conditions can evaluate
A resource plan owns copies of the IR values its run-time evaluation
reads: the descriptor sources, the SRT reads, the uniform fills, and
the branch conditions that tell which images a dispatch can reach.
Below a scalar load from memory, the copy took every value the load
depends on, whether the evaluator can compute it or not. A condition
that reads memory after vector work (a load predicated by a vector
compare, an address computed from vector data) brought the program's
whole vector graph into the plan: in a title's programs 2.4 million of
2.6 million retained values, about 500 MiB, belonged to twelve or so
conditions per program.

Below a condition, the copy now follows only what the evaluator reads:
the arguments of values it can compute, and for a load from memory the
words of its descriptor and its offset; a value the evaluator cannot
compute is kept without its arguments, which is what evaluating it
needs (it does not evaluate). Descriptor sources keep their whole
closure, which the device image pre-pass walks.

Tested with a new test (agc_driver_resource_plan_retention): the plan
of a program whose branch condition reads a scalar load at an address
taken from vector data now keeps the same number of values for vector
chains of 1, 16 and 64 steps before the load (84, 114 and 210 before);
the device table, written image, buffer descriptor, memory and SRT
range and shader disk cache tests pass; in a title's corpus the plans
of 314 programs hold 40 thousand values instead of 837 thousand; the
corpus recompile with SPIR-V validation has no invalid module.

Resolved onto main: the retention test runs on DeviceTableFixture.hpp,
which main does not have, so the test and its CMake line are left out
here; the next commits test this on main.
2026-10-23 21:40:20 +02:00
fablevoid 9796a23046 fix(shader): copy only what the SRT evaluator reads of plan branch conditions
ExtractPlan copied the whole argument closure of every control-flow
condition into the plan. The draw-time walk (SrtDescriptorEvaluation)
uses a condition only when the evaluator computes it, and an operation
outside the evaluator's set ends the evaluation without reading its
arguments. For conditions on vector loads, image results or values
carried around loops the copy reached most of the program, and none of
it was ever read.

Detail::Evaluator::Reads names what the evaluator reads of a value:
nothing (an operation it does not evaluate, an immediate), its
arguments (the operations it evaluates, identities, phis, and the pairs
CompositeExtract reads through), or its whole closure (a raw read, whose
handle LoadedFromMemory walks). EvaluateInst returns early for a value
it reads nothing of, so the two cannot drift apart. ownPlanValues still
copies descriptor sources, SRT reads and fill values whole, and copies
a condition only as far as Reads goes: an operation it does not read is
copied without its arguments. The pure and guarded flat slots are
computed before the copy, from the same values as before.

Evidence: a title that registers about 5,700 shaders at load held
24.1 M copied IR values in its plans (about 5.4 GiB by value size), of
which 2.1 M were reachable from descriptor sources, SRT reads and fills
(counted by a local report over the recompiler's source map).

Tested: agc_shader_memory gains verifyPlanConditionPruning: a condition
on a load with a 64-addition address keeps the load as a leaf and none
of the additions, and conditions read through an extracted pair and
through a raw read still evaluate. It fails without the change. Full
ctest passes.

Resolved onto main: Reads is a static member of BasicEvaluator next to
MayEvaluate, and its operation list is main's evaluator's
(evaluatedArguments adds BitCount32, FindILsb32 and FindUMsb32; the
undefined values, which main never evaluates, read nothing). The
EvaluateInst guard reads the node's value, so it covers the compact
plans too. ownPlanValues now runs after the flat slots and before the
compact plan, and gives a value it keeps without arguments an empty
operand list, so the leaf drops the operand capacity main's IrValue
constructor reserves. Main's MayEvaluate already drops the condition on
the vector load, so the test checks that it is gone.
2026-10-23 21:40:20 +02:00
SuarezPM 548267bfa3 feat(shader): support 32-bit image atomics through keyed image tables
Table T#s keyed at runtime no longer fault on image_atomic_*32: the
table operation stays supported, elements carry the atomic flag through
dedup into the descriptor binding, and the table path binds AtomicView
like the direct path. 64-bit atomics stay unsupported, packed and BY
formats stay unsupported, and the debt entry records the relaxed
Device-scoped emission and the remaining gaps.
2026-10-23 21:22:29 +02:00
JAB-devandClaude Sonnet 5.5 8d54357e79 Merge branch 'main' of https://github.com/boykopovar/AnyPS5 into feat/agc-4-4-4-4-partial-writes
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
2026-10-23 21:18:00 +02:00
Adrià ad19afc31e Merge pull request #8518 from JJenkx/fix/srt-guard-condition
fix(shader): decide resource branch conditions from their uniform operand
2026-10-23 20:50:37 +02:00
milescovielloandClaude Opus 5.5 ad6a55121e fix(agc): read FMASK of up to 8 samples in every storage width
Since the synthetic FMASK mode was removed, a direct FMASK load reads
the stored word and only Fmask32_S8_F8 is accepted. A load from any
other FMASK format of up to 8 samples now reads the 8-, 16- or 32-bit
surface and expands it in the shader to 4 bits per sample, an index
past the fragment count reading 8 (unknown). One runtime image mode
handles every such format, reading the format from the descriptor at
run time or from a specialization constant.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-23 16:34:33 +00:00
Adrià 15e71dbe11 Merge pull request #7882 from klosixgaming-arch/fix/image-table-sampler-deduplication
fix(shader): deduplicate sampler table elements in ResolveImageTables
2026-10-23 17:47:25 +02:00
Adrià 83694b3db9 Merge pull request #7803 from thuanquang/fix/msaa-2d-sample-zero
fix(shader): read a 2D MSAA T# through DIM 2D as its sample 0
2026-10-23 17:24:59 +02:00
Izamaru 140cc40efe chore: merge current main into descriptor reference fix 2026-10-23 10:18:41 -03:00
Adrià 0cc23ad8ba Merge pull request #7811 from santhoshkumar-dev/codex/fix-pixel-wqm-interpolation
fix(shader): keep host interpolation across entry EXEC copies
2026-10-23 13:30:25 +02:00
JAB-devandClaude Sonnet 5.5 8415906b22 Merge branch 'feat/agc-4-4-4-4-color-target' into feat/agc-4-4-4-4-partial-writes
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
2026-10-23 12:09:28 +02:00
Dean 348157914f Merge pull request #6218 from harry-z-kang/codex/issue-6119-packed-storage
fix(agc): support packed 16-bit storage images
2026-10-23 22:44:30 +13:00
JAB-devandClaude Sonnet 5.5 870bacd092 Merge branch 'main' of https://github.com/boykopovar/AnyPS5 into feat/agc-4-4-4-4-partial-writes
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
2026-10-23 08:59:06 +02:00
milescovielloandClaude Opus 5.5 9e6966b121 perf(shader): cut small per-materialize allocations in binding population
Three allocations ran on every stage materialization:

- DescriptorBindingBuilder::Populate pushed one shaderDataUserWords
  entry per layout.userDataRegisters element without reserving, so the
  vector regrew through 1, 2, 4, ... Reserve the exact count first.
- GuestSamplersDescriptor appended each sampler's dwords without a
  reserve. Samplers are four dwords (the table path forces 4, and
  Populate indexes the result as element * 4), matching the
  resources.size() * 4 reserve GuestBuffersDescriptor already uses.
- ResolveImageTablesShared made a fresh shared ResolvedImageTables for
  every snapshot without image tables. With no tables,
  ResolveImageTables either throws (the shader expects tables) or
  returns a default-constructed result, so return one shared, immutable
  empty instance instead, still calling ResolveImageTables first so the
  mismatch keeps throwing. Its only caller reads the result through a
  const reference and never compares the pointer.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-23 05:44:03 +00:00
thuanquangandClaude 0a3ea213e1 fix(shader): read a 2D MSAA T# through DIM 2D as its sample 0
A DIM 2D image_load or image_sample of a 2D MSAA T# returns sample 0 on
RDNA2 (RX 6700 XT, measured through HIP; bilinear blends sample-0 texels).
The recompiler now reads such a direct sampled access as a 2D image, and
the driver binds a one-sample copy of the target's sample 0, refreshed by
a fragment pass before each binding. Peace Walker (PPSA18216) stops on
this read at the end of its opening movie.

Co-Authored-By: Claude <[email protected]>
2026-10-23 11:38:12 +07:00
MarcZX10 f6826208fb fix(shader): normalize offset perspective barycentrics 2026-10-23 06:32:27 +02:00
JAB-devandClaude Sonnet 5.5 d201de3f32 Merge branch 'main' of https://github.com/boykopovar/AnyPS5 into feat/agc-4-4-4-4-partial-writes
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
2026-10-23 04:09:40 +02:00
Dean a701f9f788 Merge pull request #6801 from JJenkx/feat/geometry-points-sized
feat(agc): rasterize geometry points with their point size
2026-10-23 14:38:10 +13:00
Dean Galvin 6990044dfb Merge main into feat/geometry-points-sized 2026-10-23 12:43:00 +13:00
JAB-devandClaude Opus 5.5 a44cdd7494 Merge branch 'main' of https://github.com/boykopovar/AnyPS5 into feat/agc-4-4-4-4-partial-writes
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-23 01:29:27 +02:00
Dean 944ff6c97e Merge pull request #9249 from Pacuka/fix/shader-3d-store-2d-array-tsharp
fix(shader): accept 3D image stores on 2D-array T#s
2026-10-23 11:06:04 +13:00
JAB-devandClaude Sonnet 5.5 4287ca1cf1 Merge branch 'main' of https://github.com/boykopovar/AnyPS5 into feat/agc-4-4-4-4-partial-writes
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
2026-10-22 23:09:07 +02:00
Dean a62feecd6c Merge pull request #7948 from Amoenus/codex/feat-native-owner-fmask
feat(agc): expose expanded FMASK for tracked native owners
2026-10-23 08:54:11 +13:00