Commit Graph
440 Commits
Author SHA1 Message Date
AlxcBTW a58a709116 fix(agc): compare moved dispatch buffers at their build-time clamped size
A read-only V# the build clamps (size above the descriptor range limit cut to the
mapped end, stride overhang cut to the allocation end) was compared with the template
by its raw size, so an unchanged buffer counted as moved, was refused over the limit
and the dispatch rebuilt every time; a moved one with an overhang was snapshotted past
the allocation end. The build and the move proof now take the range from one function
(ShaderResources::guestBufferBytes), compare clamped with clamped and snapshot the
clamped range.

An overlay without a descriptor set is refused like one that could not be made, and
recording one throws instead of binding the template's set.
2026-10-17 11:23:47 +02:00
AlxcBTW 89d255c5f3 perf(agc): serve compute dispatches whose read-only buffers moved from the cached template
The content key of a compute stage leaves the base address and size of its
read-only guest buffers out, as a draw's key does. A template hit whose such
buffers moved is proved the way a draw's is (ShaderResources::MovedDispatchBuffers:
read-only, read in place when built, in reach, nothing pending over the new range)
and binds snapshots of the new ranges in a descriptor set of its own, kept with the
batch that records the dispatch. A refused proof builds the dispatch fresh, as
before. APS5_NO_DISPATCH_MOVE=1 turns the path off, APS5_DISPMOVE_MAX_KIB caps the
bytes snapshotted per dispatch.

A template whose storage image lies over memory that a depth surface covers is no
longer proved from stamps (fastRevalidate): cachedStorageTexture answers such a
binding with the plane's colour mirror, copied in from the depth image for every use,
and nothing stamps the appearance of a depth surface after the build. The full walk
decides, and a stale image can no longer be copied over the depth image.

Tests: Graphics.cpp (verdicts of the proof), execution DispatchMove (real device:
moved, exact, shortened, stored-over, own-output and written-range refusals) and
DispatchMoveDepth (a depth surface appearing over a template's plain storage image,
planes inside and outside the write watch, imports watched and unwatched).
2026-10-17 09:08:47 +02:00
Romans Pokrovskis a0c51d5778 feat(agc): import uniform multisampled DCC fast clears 2026-10-16 21:13:39 +02:00
Adrià 24528f4e5a Merge pull request #5907 from simonbronk/feat/mixed-sample-truncate
feat(agc): rasterize a multisampled draw into one-sample targets at sample 0's locations
2026-10-16 21:05:45 +02:00
Adrià 6fd4de2666 Merge pull request #5937 from milescoviello/fix/db-render-control-copy-sample
fix(agc): accept a copy's sample selection on a draw that copies nothing
2026-10-16 21:05:36 +02:00
Adrià FranchandClaude 11f83f2d47 test(agc): keep the vertex BDA shader code static
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-16 18:33:34 +02:00
Adrià FranchandClaude a65d42755b test(agc): bound the cancelled journal replay from its own start
The cancelled replay's bound was taken from the totals before the torn-tail replay, which already
adds one present pipeline; when a worker reached the graphics recipe before the cancel, the test
failed (13 of 600 runs with 24 in parallel).

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-16 18:13:46 +02:00
milescovielloandClaude Opus 5.5 2d5f761cb5 fix(agc): discard pipeline journals written before the mesh field
The layout guards only build on Linux with libstdc++, so a Windows or
macOS build of main after #5884 wrote journals whose mesh records lack
outputPrimitiveSize under the new shader-cache source version. The
journal format is now 3, so such a file is discarded instead of being
read with the new codec. MarcZX100 pointed this out.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 11:45:11 +00:00
milescovielloandClaude Opus 5.5 b1e88d5995 fix(agc): journal the mesh output primitive size
#5884 added MeshConfiguration::outputPrimitiveSize, and #5875's pipeline
journal guards the layouts it encodes. The two merged separately, so on
Linux with libstdc++ PipelineJournal.cpp no longer compiles:
MeshConfiguration is 40 bytes, ShaderStages (which holds an optional
one) 112. The guards now name those sizes, and the recipe codec writes
and reads the new field, so a replayed line-strip geometry pipeline
keeps its two-vertex primitives.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 11:36:25 +00:00
Adrià 65d56a297c Merge pull request #5804 from MarcZX100/codex/pixel-interlock-terminate-2009
fix(agc): stop pixel invocations on BDA faults when supported
2026-10-16 13:35:18 +02:00
Adrià 645644c488 Merge pull request #5884 from AnthonyClemens/fix/agc-geometry-line-strip-output
feat(agc): draw line-strip output of NGG geometry programs as mesh lines
2026-10-16 13:25:36 +02:00
Adrià Franch b85146dbf5 test(agc): keep the recompiled words alive in the terminate tests 2026-10-16 13:10:31 +02:00
Adrià Franch 00fdf5b4c4 test(agc): give the vertex terminate test the ClipDistance capability 2026-10-16 13:10:31 +02:00
MarcZX100 8a82811d9b fix(agc): preserve draw parameter profile validation
Restore the shaderDrawParameters feature guard while adding shaderTerminateInvocation support. Cover enabled and disabled DrawParameters profiles, and pass the termination feature to the correct shader validation argument.
2026-10-16 13:10:28 +02:00
MarcZX100 502a972f2d test(agc): update terminate checks for current APIs 2026-10-16 13:10:28 +02:00
abnergtz 0fe8527a0a test(agc): cover terminate invocation specialization, stage boundaries and disabled feature 2026-10-16 13:10:28 +02:00
abnergtz 0e8ce286e1 fix(agc): validate OpTerminateInvocation itself, not only its extension
The validator only checked SPV_KHR_terminate_invocation when it saw the
OpExtension, so a module using OpTerminateInvocation without declaring
the extension, or in a non-fragment stage, was accepted. Require the
fragment stage, the enabled shaderTerminateInvocation feature and the
declared extension at the instruction itself.

Refs #2009
2026-10-16 13:10:28 +02:00
abnergtz 42cd3f2ec4 feat(agc): gate SPV_KHR_terminate_invocation on shaderTerminateInvocation
Shader validation accepts the extension only in fragment shaders and only when the device enabled shaderTerminateInvocation. The flag is part of the validation memo key.

Refs #2009
2026-10-16 13:10:28 +02:00
abnergtz 7041ba8d9a fix(recompiler): terminate pixel invocation on BDA fault when supported
Pixel invocations stopped by a BDA fault now end with OpTerminateInvocation when the target offers SPV_KHR_terminate_invocation, and keep OpKill otherwise. OpKill is not enough on AMD driver branch 21045, where a guest atomic after the kill still lands once per faulting pixel.

Based on the approach in poonasor/AnyPS5@73969879.

Refs #2009
2026-10-16 13:10:28 +02:00
Adrià FranchandClaude 52d8d6ce28 fix(agc): journal the pipeline state fields main added
The replayed stencil reference, the reversed blend, the quad sample masks
and the tessellation instance patches and draw parameters change the
pipeline a draw creates, so the recipe carries them; the file format is
bumped and the layout guards follow the new sizes.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-16 12:52:28 +02:00
Adrià FranchandClaude addcdc7c41 fix(agc): journal the sample location grid and per-sample shading of a pipeline
#5861 added both to the pipeline state and its store key; the recipe dropped them, so a
replayed pipeline keyed another configuration.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-16 12:52:28 +02:00
Adrià FranchandClaude Fable 5.1 4aafda8e3b perf(agc): journal the pipelines of a run and build them ahead on the next one
A graphics pipeline the store builds or a compute pipeline a dispatch builds is
appended to pipelines.journal next to the shader cache entries, as the
materialized result of each stage (the specialized SPIR-V, bindings and push
constants) plus the recipe the pipeline was built from: the stages'
identities, vertex input layout, descriptor set layout keys and the state
fields the Pipeline constructor reads. When a VulkanDevice is created with a
window (a headless device waits for its first draw or dispatch, since the
window's device usually replaces it first) the journal is loaded and its
pipelines are built on a pool of threads while the title loads, so the first
draw or dispatch of a configuration seen on an earlier run finds its pipeline
resident instead of compiling it on the queue worker.

The pipeline stores key on RecompileResult::Identity, a hash of the module
words, specialization constants, subgroup width and bindings that is the same
on every run (SharedSpirv::ContentHash, computed once per shared module),
rather than on the process-lifetime variant ids; a generated stage is keyed
like any other. CachedPipeline builds outside the store's mutex and the
library parts and link are built outside the library store's mutex, so replay
threads and queue workers build in parallel; a concurrent build of the same
key keeps the first inserted. A replayed pipeline enters the store at its
least recently used end and a full store takes none, and its optimized relink
waits for the first draw that binds it, so the title's own pipelines come
first in both. The compute pipeline creation moves into
VulkanDevice::createComputePipeline, shared by dispatches and the replay. The
store key also covers the color component mapping, the depth target's sample
count and a depth bias clamp, which the constructor reads.

The file names the device it was written for (the properties the driver's
pipeline cache file is named by) and starts over for another; a torn tail is
cut at a record boundary; two runs sharing the directory take turns on a lock
file and keep each other's records; a read failure never starts the file
over. A device cancels its replay before it is replaced or destroyed, and a
replaced device destroys its pipelines then rather than at the driver's stop.

APS5_NO_PIPELINE_JOURNAL=1 disables it; APS5_PIPELINE_JOURNAL_THREADS,
APS5_PIPELINE_JOURNAL_ENTRIES (the first recorded), APS5_PIPELINE_STORE_ENTRIES
and APS5_PIPELINE_JOURNAL_MAX_MIB bound it; APS5_PROFILE_DRAW prints a
[pipeline-journal] summary. APS5_VERIFY_SET_LAYOUTS=1 now also checks a
dispatch's set layout against the one described from its shader. The lavapipe
test suite, which shares one cache directory, runs with the journal off except
for the journal's own tests.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P6hw3kRAuQdfcU9YCZgaoK
2026-10-16 12:52:28 +02:00
simonbronkandClaude Opus 5.5 2c1b825ae5 test(agc): expect the color sample-count refusal for a one-sample target under a 2x scan without MSAA_ENABLE
#5882 lets a multisampled scan without MSAA_ENABLE through the earlier
check, so the draw is now refused where its one-sample color target meets
the rasterizer's sample count.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 09:00:29 +02:00
simonbronkandClaude Opus 5.5 b766ce4fb5 feat(agc): keep sample, sample-index and per-sample shading on the sample-zero path
A multisampled rasterizer drawing into one-sample targets keeps
PERSP_SAMPLE, LINEAR_SAMPLE and ANCILLARY inputs, and with PS_ITER_SAMPLE
also centroid inputs, since only sample 0's coverage reaches the targets.
Coverage inputs, and the sample index with POS_X_FLOAT or POS_Y_FLOAT,
still throw. The input rule for the non-iterated case follows
fdfawef324's proposal on #5907 (PPSA07411).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 08:58:33 +02:00
simonbronkandClaude Opus 5.5 9bf98992ff feat(agc): rasterize a multisampled draw into one-sample targets at sample 0's locations
A draw whose rasterizer has more samples than its color or depth targets
threw "a color target's sample count differs from the rasterizer's" or
"the depth target's sample count differs from the rasterizer's". When
every target has one sample, MSAA_ENABLE is set, and there is no
alpha-to-coverage, no PS_ITER_SAMPLE and no sample-dependent pixel input,
only sample 0's coverage reaches the targets, so draw it with one sample
at sample 0's location in each pixel of the grid. One-sample depth images
are created sample-location compatible when the device allows it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 08:58:33 +02:00
Adrià 7b20318e89 Merge pull request #5882 from billythemenace2/fix/agc-msaa-target-without-msaa-enable
fix(agc): rasterize a multisampled target without MSAA_ENABLE at the pixel center
2026-10-15 23:58:24 +02:00
Adrià 82c0ab9aae Merge pull request #5855 from tototomate123/fix/hfw-depth-clear-current-main
fix(agc): ignore stale depth clear flags when no planes are bound
2026-10-15 23:01:15 +02:00
billybobpicklioandClaude Opus 5.5 a0347cfed5 feat(agc): draw line-strip output of NGG geometry programs as mesh lines
A geometry program with VGT_GS_OUT_PRIM_TYPE 1 was refused as an
unsupported output assembly. Each primitive export of an NGG line-strip
program is one line whose indices are packed like a triangle's, so the
mesh module now declares OutputLinesEXT with PrimitiveLineIndicesEXT for
it. A subgroup gets VGT_GS_MAX_VERT_OUT - 1 lines per input primitive and
at least GE_MAX_OUTPUT_PER_SUBGROUP line slots; fast launch keeps using
PRIM_AMP_FACTOR. The output size is part of the cache, draw, validation
and pipeline keys, and the request serialization version becomes 31.
Triangle-strip geometry is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 15:39:35 -04:00
milescovielloandClaude Opus 5.5 4cdd2f4834 fix(agc): accept a copy's sample selection on a draw that copies nothing
DB_RENDER_CONTROL.COPY_CENTROID and COPY_SAMPLE select the sample that
DEPTH_COPY or STENCIL_COPY copies. Forspoken (PPSA03984) draws with
DB_RENDER_CONTROL 0xc0, DEPTH_COMPRESS_DISABLE and COPY_CENTROID with
neither copy bit set, and stopped at 43 s because both
DepthMaintenanceRejection and decodeDepth took the selection for a copy.

Accept the selection fields when no copy is enabled; draws that copy are
still rejected.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 16:54:42 +00:00
Adrià 2cefed5499 Merge pull request #5778 from meh7an/fix/agc-buffer-range-limit-by-mapped-memory
fix(agc): bind a V# past the range limit by the memory behind it
2026-10-15 18:50:36 +02:00
Adrià 489466d3f9 Merge pull request #5734 from YossiYad/fix/strip-last-provoking
fix(agc): refuse last-vertex strips only for reads of a vertex slot
2026-10-15 15:03:44 +02:00
Adrià 3ee5371915 Merge pull request #5627 from AlxcBTW/fix/agc-htile-written-by-any-kernel
fix(agc): take depth fast clears from HTILE written by any kernel
2026-10-15 14:52:34 +02:00
Adrià b3f9f89e62 Merge pull request #5604 from babyhuey/fix/agc-geometry-vgpr-count
fix(agc): accept geometry programs with fewer GS and ES input VGPRs
2026-10-15 13:59:30 +02:00
AlxcBTW cc022df348 fix(agc): take a slice of a depth array from its own HTILE only when its words are uniform
A fill or clear the driver recognizes over an HTILE drops the range's last-read generation, so the
next bind reads the words and stores them back even when the write tracker did not see the fill's
stores. A depth view of slice 1 or later reads the HTILE at its own address
(DB_HTILE_DATA_BASE + slice * HtileMetadataBytes); the HTILE word layout is only modelled for slice 0,
so such a slice takes the clear and the store-back only when all its words are equal and keeps its
fill-time fast clears otherwise. DepthTarget::slice carries DB_DEPTH_VIEW SLICE_START.

agc_driver_depth_fast_clear_submit: an unrecognized kernel clears the HTILE on two frames in a row and
both clears are taken; slice 1 with words that are not all equal is refused and stored back untouched;
slice 1 with equal words takes the clear. agc_driver_graphics checks the decoded slice.
2026-10-15 13:53:50 +02:00
Adrià 39d3ae13eb Merge pull request #5304 from tv7/fix/stencil-ref-export-unused
fix(agc): drop an unused stencil test value export from draws without a stencil test
2026-10-15 13:24:56 +02:00
NikoandClaude Opus 5.5 c434467f6c fix(agc): form reversed-order blend factors from copies of the export
The reversed-order blend computed the factors Vulkan cannot apply per
channel in the pixel shader (1 - x in fp32, a clamp for UNORM targets
and, when both positions needed it, a premultiplied export) and passed
them to the blend as a dual-source second color. A plain blend converts
the export once and forms 1 - x and the products from that converted
value, so the two paths can round differently. On UNORM8 the difference
reaches one step per substituted factor: an Intel iGPU stored 161 where
the exact blend is 159.75 for SRC_COLOR + ONE_MINUS_SRC_COLOR with an
export of 0.5 over 192 (160 through SWAP_STD), and on an RTX 5080 and
lavapipe the split path differed from the same draw into a SWAP_STD
target by up to 2 steps on other inputs.

The pixel shader now only copies values. Each channel of the second
color is the exported alpha, the channel's own export or the constant 0
or 1, and a channel of the first color whose source factor is ONE may
become 1 with its export moved into the factor. Every factor, 1 - x and
product comes from the blend through SRC1_COLOR, SRC1_ALPHA and their
ONE_MINUS forms, applied to copies of the same export values that the
first color carries. TranslateReversedBlend searches for Vulkan factors
and copy routes that reproduce each channel's guest factors and throws
for combinations no routing reproduces, such as ONE_MINUS_SRC_ALPHA in
the alpha equation next to SRC_COLOR in the color equation: of the 1995
factor combinations the shader used to compute, 932 are routed and the
others throw again, as on main. GT7's 0x65010504 is among the routed
ones. The code is now four 2-bit routes for each color, the same for
every format, and the post-pass emits no arithmetic.

agc_driver_reversed_order_blend also draws each case into a SWAP_STD
target, which Vulkan blends alone, and requires identical stored bits;
the comparison with the exact blend keeps its 1-step tolerance.
agc_driver_graphics checks every factor combination TranslateReversedBlend
accepts against the guest equations and that the post-pass adds no
arithmetic instructions.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 12:51:27 +02:00
NikoandClaude Opus 5.5 16ea32c97d feat(agc): blend into color targets with a reversed component order
8_8_8_8 and 16_16_16_16 targets with COMP_SWAP 2 or 3 keep the exported
alpha in their first channel and red or blue in their fourth, so a plain
Vulkan blend would run the alpha equation on a color channel. Such draws
threw "blending into a color target with a reversed component order is
not implemented" (Gran Turismo 7, #4782).

The AMD SI and CIK register references describe CB_TARGET_MASK in the
order of components after blending and before COMP_SWAP is applied, and
RADV programs CB_BLENDn_CONTROL without regard to the swap while it
renders R4G4B4A4, B4G4R4A4, R5G5B5A1 and B5G5R5A1 through SWAP_STD_REV
and SWAP_ALT_REV and passes the CTS blend tests on Navi10. The color
block is therefore taken to blend in export order: the alpha equation
and source-alpha factors use the exported alpha and the destination
alpha is the first channel.

TranslateReversedBlend keeps the factor pairs Vulkan applies per channel
in the pipeline. Other source factors are computed by the pixel shader
from its MRT0 export (clamped for UNORM targets, as BLEND_CLAMP says)
and handed to the blend as a dual-source second color, which the
fragment output post-pass adds at location 0 index 1; when both
positions need it, the export is premultiplied by its source factor.
The code is a pipeline specialization, serialized in request version
26, and stays out of the prepared shader key.

sRGB, SNORM and integer targets, constant and second-source factors,
destination alpha in the color equation, destination factors the two
equations do not share, different color and alpha operations, MIN or
MAX with factors other than ONE, other color exports when the shader
computes factors, and devices without dualSrcBlend still throw, now
with the blend control, mapping and format in the message.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 12:51:27 +02:00
fdfawef324andCodex 3490838653 fix(agc): omit reference-independent stencil exports
Co-Authored-By: Codex <noreply@openai.com>
2026-10-15 12:51:24 +02:00
Dean 721db55dcd Merge pull request #6066 from meh7an/perf/agc-register-read-log-when-open
perf(agc): skip the register read log while no log is open
2026-10-15 21:45:35 +13:00
Dean db4e4b071f Merge pull request #5893 from ThatsLeo/perf/agc-unified-memory-budgets
perf(agc): keep a smaller staging pool on system-memory heaps
2026-10-15 21:44:40 +13:00
Adrià 2baae7aa30 Merge pull request #6168 from parl0v/fix/detiler-pool-recycle
fix(agc): recycle detiler descriptor pools once their batches complete
2026-10-15 10:43:52 +02:00
Adrià FranchandClaude 15734fb3fa fix(agc): keep detiler descriptor pools unrecycled without a recorder
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-15 10:14:29 +02:00
Dean d92a8dad39 Merge pull request #1189 from MichonGoddijn231849/fix/cb-resolve-tiled-targets
fix(agc): CB resolve into any tiled color target
2026-10-15 17:15:57 +13:00
Josip Parlov 0e15b9be97 fix(agc): reuse the current detiler descriptor pool once its batches complete
When the current pool filled, the search for a completed pool started after it and skipped it, so a
title whose batches had all completed got a new pool instead of resetting the full one. The search
now ends at the current pool. A detiler test fills three pools' worth of sets with no batch in
flight and requires the pool count to stay the same.
2026-10-15 02:17:14 +02:00
fdfawef324 1ffc5f672b feat(agc): emulate per-pixel multisample coverage masks
Decode the four PA_SC_AA_MASK fields at the rasterized sample count. Use the native Vulkan mask when all four pixels agree and apply varying masks in the fragment shader, preserving helpers and combining coverage with alpha-to-coverage and shader mask exports. Add the normalized masks to pipeline, draw and shader keys and the versioned replay request.

Refuse unsupported conservative-raster, centroid and early depth/stencil memory-write cases. Synthetic readbacks cover driver submission, depth/stencil suppression, fragment stores and one-sample and four-sample coverage.
2026-10-15 13:00:34 +13:00
Michon 72518f64fb feat(agc): single-sample sample masks as a per-quad-pixel discard
With one sample, PA_SC_AA_MASK leaves one coverage bit per pixel of the 2x2 quad,
so a draw can cover only some pixels of every quad (GTA V renders a target one
quarter of the pixels at a time this way). The pixel stage info carries that 4-bit
mask; a fragment shader whose mask is not full starts by killing the invocation
unless its gl_FragCoord quad position is covered, and runs without early fragment
tests. The mask is part of the recompile cache key and the serialized request
(version 24). Sample masks of multisampled draws stay refused.
2026-10-15 12:59:39 +13:00
Dean 4bdfc9c801 Merge pull request #5631 from moong15/codex/skip-unused-pixel-stage
fix(agc): skip unused pixel stages with retained export formats
2026-10-15 12:33:48 +13:00
Dean 28fb252c62 Merge pull request #4341 from MarcZX100/codex/accept-vertex-stage-2002008-4329
fix(agc): accept reported vertex stage state
2026-10-15 12:14:32 +13:00
umang 843f7e963e fix(agc): skip unused pixel stages with retained export formats 2026-10-15 11:35:54 +13:00
Dean 80ccb9fb1e Merge pull request #5483 from ee6aba54/fix/agc-storage-cache-budget
fix(agc-driver): size the storage image cache from the device's reported memory budget
2026-10-15 11:26:11 +13:00