Commit Graph
562 Commits
Author SHA1 Message Date
Romans Pokrovskis 7d0dd69f0a feat(agc): import completion-proven native HTILE clears 2026-10-15 14:00:57 +02:00
Adrià fdea36b836 Merge pull request #5524 from Amoenus/codex/native-depth-allocation-retirement
fix(agc): retire fully released native depth owners
2026-10-15 13:50:13 +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 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
Adrià e49ec591dc Merge pull request #1201 from MichonGoddijn231849/perf/pipelined-draws
perf(agc): pipeline queue-0 draw commits behind the packet worker
2026-10-15 12:11:00 +02:00
Romans Pokrovskis da9fe3c708 fix(agc): retire fully released native depth owners
Track successful releases cumulatively across the complete depth and HTILE ownership ranges. Preserve color retirement and share its single callback; keep retired image contents alive through sampled views and recorded work. Add registry, partial/failure/protection, remap and mixed teardown regressions. Depends on native depth sampling in PR5496 and its descriptor prerequisite PR4820.
2026-10-15 13:08:13 +03:00
Dean 2c4574adff Merge pull request #6247 from oneandonlydean/carry/register-clear-wait
perf(agc): clear a register fast clear without waiting for a known key store
2026-10-15 22:47:15 +13:00
3b34d1fdb6 perf(agc): pipeline queue-0 draw commits behind the packet worker (APS5_PIPELINED_DRAWS)
With APS5_PIPELINED_DRAWS=1, queue 0's worker decodes, captures and recompiles a draw and hands it to
a committer thread that records it (Graphics::Draw under the GPU lock), so the two run in parallel
instead of one after the other. Work the committer has not reached yet is tracked by the guest ranges
it will write; a later packet that reads or writes them, or one the pipeline cannot order, drains it.

Ordered as commit items instead of drains:
- labels (WRITE_DATA, RELEASE_MEM) and same-queue waits on them; APS5_PIPELINE_DRAIN_LABELS=1 drains;
- the end of a queue-0 submission and a released REWIND tail; APS5_PIPELINE_DRAIN_SUBMISSIONS=1 drains;
- the title's buffer fill kernels; APS5_PIPELINE_DRAIN_FILLS=1 drains;
- DMA_DATA immediates and copies (APS5_PIPELINE_DMA=1).
A draw's write ranges include the storage images it writes and its exact color and depth target
ranges (APS5_EXACT_DRAW_WRITES=1), not estimates.

Draw-path costs the pipeline exposed:
- ShaderMemory moves, so a commit owns its capture's pages;
- a submission made before the worker's current collect epoch began keeps the epoch, so a worker
  behind a queue of submissions walks a surface once per catch-up (APS5_SUBMISSION_EPOCH_EACH=1 bumps
  at every submission); a thread remembers the ranges it walked for the whole epoch;
- the pipeline signals only threads that wait; the pending-image and unit-shadow registries take a
  spinning slim lock instead of std::mutex (winpthreads contention was kernel events); ScanPending skips
  the registry walk when no pending image can overlap;
- fewer heap allocations per recorded draw (reused descriptor sets and scratch vectors, buffer pool
  size classes kept).

GTA V Performance mode, prologue bank interior, RTX 5080: 11.7 -> about 20 fps together with the cheaper
captures below it.
Off by default here; the follow-up turns it on.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Gjon Gojcevic <7807870+gjonn@users.noreply.github.com>
2026-10-15 11:34:28 +02:00
SP4C3B4R-8andClaude Opus 5.5 626cff7d26 fix(libSceAgcDriver): retire a depth surface once another writer covers its memory
A depth surface lives only in its Vulkan image, so a view of its memory
with another layout could only throw, and a matching view kept reading
the image after other writes over its memory. Retire the surface when a
color target or a written storage image it does not serve overlaps its
planes, or when a view it cannot serve finds guest memory over the planes
written since the surface was last bound; lookups then skip it and the
view reads the memory like any texture. Binding the target again brings
the surface back.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 11:00:36 +02:00
Adrià 0afa6a607e Merge pull request #6060 from parl0v/feat/watched-private-imports
perf(agc): keep Windows host imports of write-watched private memory watched
2026-10-15 10:54:43 +02:00
Adrià c4f03522a7 Merge pull request #5496 from Amoenus/codex/native-msaa-depth
feat(agc): sample native multisampled depth attachments
2026-10-15 10:54:18 +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
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
Josip Parlov ef5da022af fix(agc): settle watched imports on any copy queue and probe the settle itself
Review on #6060: the Windows probe now settles a 4,096-page import with the same 4-byte read
production uses and requires no marks after it. A failed settle destroys the import instead of
leaking it. The settle's destination, command buffer and fence are created once per device. Where
the graphics family has a single queue (AMD on Windows), the settle queue comes from another family
that copies, through a buffer aliasing the import's memory. The recorder tests' device gets the
settle queue too, and agc_driver_layered_volume_submit_other_family runs that path
(APS5_SETTLE_OTHER_FAMILY=1).
2026-10-15 09:46:48 +02:00
Josip Parlov 9ba58c2a60 perf(agc): keep Windows host imports of write-watched private memory watched
On Windows a host import without a section alias left guest write tracking, and its changes were
found by comparison. Since resident direct memory became private MEM_WRITE_WATCH memory, its
imports take that path, and every storage-texture refresh over it compares its whole snapshot.

ProbeImportWriteProtection gets a Windows body on MEM_WRITE_WATCH scratch memory, and
decideImportWatch keeps direct imports of private read-write memory watched when GetWriteWatch
stays honest after an import's first GPU use. The driver marks every imported page written until
that use completes, so each such import is settled inside ImportWatched's window by a 4-byte read on
a second queue of the graphics family (the imports lock comes after GpuMutex, so the main queue
cannot be used there). APS5_NO_WATCHED_PRIVATE_IMPORTS=1 keeps the comparisons.
2026-10-15 09:46:48 +02:00
DotDebian a61c70fc72 perf(agc): clear a register fast clear without waiting for a known key store
materializeRegisterClear clears the resident image to CB_COLOR_CLEAR_WORD
when the target's DCC keys read as the register clear code. Most of the
time those keys come from a key store the driver recorded itself
(NoteKeysFillOnGpu) and the GPU has not run it yet, so FillClear refused
with "keys pending" and the fallback waited for that store (SyncThrough).

The wait buys nothing when the newest recorded writer of the whole key
range is the noted store: ProvedCurrentDccKeys already answered from the
same memo (PendingStoreKeys), so the keys the GPU will hold are known and
are the code this clear stands for. The image clear and the
"uncompressed" key store after it are recorded into the same queue behind
that store and land after it, the order the wait gave.
KnownPendingDccKeys exposes that proof, and the register clear passes it
as FillClear's allowRegisterClear, which skips only the "keys pending"
refusal; the key scan still runs. Any other pending writer (a title
kernel, a later partial or wider write, a shadowed range) keeps the wait.

Tests: the proof answers only for a pending noted store covering the
range, and a clear recorded behind a pending register clear key store
leaves the clear word in memory and uncompressed keys.
2026-10-15 14:40:50 +13:00
Josip Parlov 8e56f56102 fix(agc): recycle detiler descriptor pools once their batches complete
TextureDetiler reset its descriptor pools only when the recorder was idle, so a recorder that keeps
work in flight grew a 64-set pool for every 64 detiles until vkAllocateDescriptorSets failed with
VK_ERROR_OUT_OF_DEVICE_MEMORY. PPSA25344 with its title near 9 FPS stopped on that after 12 and 22
minutes. Each pool now keeps the serial of the newest batch that used one of its sets, and a pool
whose batches completed (Recorder::CompletedThrough) is reset and reused before a new one is
created. The texture, image and CMASK pools share that ring.
2026-10-15 02:03:44 +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 90b20afac8 fix(agc): demote quad-mask pixels to helpers instead of killing them
With PA_SC_AA_MASK covering only some pixels of a quad, the uncovered pixels
run on the hardware as helper lanes, so derivatives of the covered pixels stay
defined. OpKill ends those invocations; OpDemoteToHelperInvocation keeps them
as helpers. The device enables VK_EXT_shader_demote_to_helper_invocation when
available and passes the DemoteToHelperInvocation capability and its SPIR-V
extension to the recompiler target and the graphics shader validation. A
demoted pixel also reads as a helper, so its initial EXEC bit is clear as on the
hardware. Without demote, OpKill stays for pixel programs that read no
neighbouring lanes; implicit-LOD sampling, LOD queries and cross-lane reads are
refused. The quad pixel mask execution test now also samples a mipmapped
texture with implicit LOD under the mask.
2026-10-15 12:59:39 +13:00
Romans Pokrovskis 7c510c6a4a fix(agc): retain ITERATE_256 for native depth descriptors 2026-10-15 02:15:38 +03:00
Romans Pokrovskis f56e3bc467 fix(agc): refuse native multisampled depth attachment feedback
Reject native sampled views of the depth image attached by the same draw before pipeline creation. Keep unrelated views, other devices and the single-sample path unaffected. Add unrun native-view refusal and scope controls; full dependency-stack build and runtime validation remain pending.
2026-10-15 02:15:38 +03:00
Romans Pokrovskis ee1ba73a2f feat(agc): sample native multisampled depth attachments
Adapt our preserved native-depth sampling work from c0d9edf and sample-aware footprint work from 6e35a877, retaining creation-time coherence and initial HTILE proof. The descriptor interface in upstream PR 4820 remains a separate prerequisite. This source draft has not been built or run.
2026-10-15 02:15:37 +03: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
Dean b9d9ec6051 Merge pull request #4915 from fdfawef324/fix/agc-pipeline-cache-one-writer
fix(agc): merge the pipeline cache file instead of overwriting it with one device's cache
2026-10-15 11:18:23 +13:00
Adrià 3f0936a4d3 Merge pull request #5522 from Nesyth/perf/agc-split-storage-write-back
perf(agc): write back a storage image spanning adjacent registered ranges on the GPU through each range's import
2026-10-14 23:35:13 +02:00
Adrià 4808d9c203 Merge pull request #5542 from winstrex/perf/bda-table-hits
perf(agc): share snapshot copies and the BDA table of repeated address-based builds
2026-10-14 23:17:47 +02:00
Adrià 0ae1deb850 Merge pull request #5906 from TheAggie/perf/agc-draw-snapshot-reuse
perf(agc): reuse draw snapshots across draws that nothing wrote between
2026-10-14 23:10:06 +02:00
Mehran ec615c145a perf(agc): skip the register read log while no log is open 2026-10-15 00:00:31 +03:00
Adrià FranchandClaude b0001cb676 fix(agc): bound unwritten draw snapshots to the current stamp and the snapshot budget
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-14 22:51:49 +02:00
Adrià 33001cebda Merge pull request #5466 from fdfawef324/codex/stencil-export-emulation
feat(agc): replay proven finite stencil reference exports
2026-10-14 22:49:30 +02:00
Scott SchusterandClaude Opus 5.5 98ce8af56d perf(agc): reuse draw snapshots and moved word buffers across draws that nothing wrote between
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 22:45:17 +02:00
fdfawef324andClaude Opus 5.5 8c8cd86cf8 fix(agc): merge the pipeline cache file instead of overwriting it with one device's cache
The driver keeps the replaced headless VulkanDevice alive next to the
windowed one, so a process holds two Graphics::PipelineCache objects for
the same vk-pipelines-*.bin. Each saved its own VkPipelineCache over the
whole file, periodically and at teardown, so the last writer dropped the
other object's pipelines and those of earlier runs.

A save now reads the file under a per-path mutex, validates it as the load
does, creates a temporary cache from it and merges this object's cache into
that temporary one, then writes the result atomically. Merging into the
temporary cache keeps the live cache free of the external synchronisation
vkMergePipelineCaches requires of its destination. A merge that adds
nothing leaves the file as it is, an unreadable file is not written over,
and a result smaller than the file on disk or the data loaded at start is
not written; an invalid file or one the driver refuses is replaced.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 16:45:14 -04:00
fdfawef324andCodex 77521f7ad2 feat(agc): replay proven finite stencil reference exports
Preserve instance and triangle order with one dynamic-reference shader pipeline. Require bounded references, complete export coverage, replay-safe mask control and resources; refuse unsupported side effects and feedback.

Co-Authored-By: Codex <noreply@openai.com>
2026-10-14 22:08:35 +02:00
XairRrR 8dbf06798c fix(shader): honour SPI_BARYC_CNTL.FRONT_FACE_ALL_BITS for the front-face input
The front-face VGPR was always +1.0 / -1.0, which is its form only while
FRONT_FACE_ALL_BITS is clear (current Mesa reads it with fgt 0 / fsign).
With the bit set, as Mesa 22.0 RADV programs it, a back face reads 0 and
a front face non-zero: ACO then tests it with v_cmp_lg_u32 0. Uncharted:
Legacy of Thieves Collection (PPSA05684) sets the bit and its two-sided
cloth shaders test v_cmp_lt_u32 0, so -1.0 (0xbf800000) made every back
face a front face: the insides of the menu skeleton's rags kept their
front normals and were lit white by the spot light behind them.

The pixel stage info now carries the bit (request version 26, cache and
draw keys), the decode reads SPI_BARYC_CNTL when FRONT_FACE is an active
input, and the translator turns the builtin into 0xffffffff / 0. The
exact front value is not measured (docs/dev/debt/shader.md).

AI-assisted: yes
2026-10-14 21:37:48 +02:00
Dean 5a605d6dc9 Merge pull request #5465 from winstrex/perf/space-pending-writes
perf(agc): find the address space regions under pending writes by search
2026-10-15 08:28:19 +13:00
Nesyth ea3a2152d7 perf(agc): write back a storage image spanning adjacent registered ranges on the GPU through each range's import 2026-10-14 21:23:36 +02:00
Dean 3bb8b6c198 Merge pull request #5760 from oneandonlydean/fix/storage-gpu-store-saved-bytes
fix(agc): save the bytes a GPU-side store writes outside the write watch
2026-10-15 07:58:34 +13:00
Adrià c5f6269796 Merge pull request #4767 from Swastik-51/fix/agc-fmask-decompress-msaa
fix(agc): handle FMASK decompress on MSAA targets
2026-10-14 20:31:07 +02:00
Adrià 0c9e980b72 Merge pull request #5111 from XairRrR/fix/agc-depth-array-slice-htile
fix(agc): give each slice of a depth array its own HTILE
2026-10-14 20:17:23 +02:00
Dean Galvin 69702ef105 fix(agc): save the bytes a GPU-side store writes outside the write watch
A write-back stored on the GPU over memory outside the write watch left its
units without saved guest bytes (only the CPU path saved them), so the next
store of results landing there threw (#5711), and every refresh re-uploaded
the image. The stored ranges are now copied from the retile scratch into a
host-visible buffer behind the store and become the saved bytes when the
batch completes; a store or refresh that needs them first syncs that batch.
Units without a write generation pending when their range leaves the watch
save their bytes there too.

The second-store fixture waits for the GPU before its surface is freed on
every return, as #5790 does for the other cases.
2026-10-15 07:03:17 +13:00
Swastik-51 02974ea767 fix(agc): reject DCC on multisampled targets outside FMASK decompress 2026-10-14 19:49:32 +02:00
Swastik-51 9394a6f51a fix(agc): handle FMASK decompress on MSAA targets 2026-10-14 19:49:32 +02:00
Adrià 26ce6e954a Merge pull request #4779 from MarcZX100/codex/null-tsharp-type-4139
fix(agc): treat type-0 texture descriptors as null
2026-10-14 19:47:43 +02:00
XairRrR 8fec47a4b2 fix(agc): give each slice of a depth array its own HTILE
A slice of a depth array target (DB_DEPTH_VIEW SLICE_START) offset its
depth and stencil addresses but kept the array's DB_HTILE_DATA_BASE as
its HTILE. Every slice then shared slice 0's metadata: a fast clear of
slice 0's HTILE cleared every slice, and a clear of any other slice's
HTILE matched none.

A slice's HTILE now starts at the base plus the slice times one slice's
pipe-aligned metadata, as addrlib addresses it (sliceSize * slice in
Gfx10Lib::HwlComputeHtileAddrFromCoord; HtileMetadataBytes is that slice
size). The recognized HTILE clear kernel now reports the bytes it
clears, 16 per thread (global_store_dwordx4 at the thread index << 4),
and a surface takes the clear when that range covers its HTILE, as a
DMA_DATA fill does; a clear over a whole array still clears every slice.

Uncharted: Legacy of Thieves Collection (PPSA05684) renders its sun
shadow cascades into the four slices of a 2048x2048 D16 array; each
slice's HTILE lies 256 KiB after the previous one.
2026-10-14 19:45:03 +02:00
Dean 8b8bfe0b6e Merge pull request #4820 from nicolasabosch/feat/agc-sample-msaa-color
feat(agc): sample a multisampled color target through its 2D MSAA texture
2026-10-15 06:42:29 +13:00
Adrià d9bfa0f3ad Merge pull request #4841 from gjonn/fix/agc-store-pending-at-flip
fix(agc): store small pending storage results at each flip
2026-10-14 19:34:50 +02:00
MarcZX100 c280018b0b fix(agc): treat type-0 texture descriptors as null 2026-10-14 19:17:15 +02:00
Dean 19e020a274 Merge pull request #1186 from MichonGoddijn231849/feat/depth-plane-array-base-slice
feat(agc): sample depth plane arrays from a later base slice
2026-10-15 06:04:53 +13:00
winstrexandClaude Opus 5.5 619be69796 perf(agc): share snapshot copies and the BDA table of repeated address-based builds
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 13:16:54 -03:00