Read-only addresses are not part of the dispatch key, so the fresh build after a refused
move replaced the template that serves the other address, and the two addresses
rebuilt each other. A refused dispatch now uses or builds an entry under the exact key
(read-only bases included) and leaves the movable template alone. The [dispmove] line
counts the rebuilds after a refusal, the builds inserted beside the template and the
dispatches served by an exact entry. Restores the MarkGpuWrites comment.
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).
Since #6003 a fiber with a context of 64 KiB or more runs on the
context itself, so the 64 KiB fiber of agc_driver_gpu_map_on_fiber
imports its mapping on a host thread on Windows too, and the test's
Windows-only expectation of no thread failed. The test now also maps
on a 16 KiB fiber, which keeps a host stack and imports on it on
Windows, and expects one import thread for the 64 KiB fiber on every
platform.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
agc_driver_rect_list_indirect compared the indirect draws' output with
the direct draws only, so it also passed when the records were read on
the CPU. Its records lived in a static array that is not guest memory,
so every indirect draw fell back to the CPU path as not imported.
The records now sit in a registered 64 KiB guest allocation, the test
turns on APS5_PROFILE_DRAW and reads the indirect-draw counters through
the new Graphics::IndirectDrawCounts, and it requires all four indirect
draws on the GPU path. It fails with APS5_NO_RECT_INDIRECT=1 and with
the IndirectDraw.cpp and Draw.cpp changes reverted (4 non-vertex path).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The test set neither mode, so ctest ran only the two-lane form. It now
recompiles each program two-lane and then spanned through
SpirvTarget::spannedWaves, checks that the spanned module asks for full
subgroups, and skips the spanned pass on a device without full 32-lane
compute subgroups.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A program that stores to a 2D multisampled texture writes the samples of
its host multisampled color target through a storage view. Targets are
created without storage usage; the first storage binding that resolves
to a target moves it to an image with storage usage, copying its samples
once, and keeps the previous image until the target is released. Storage
usage needs the device's shaderStorageImageMultisample feature and its
format at the target's sample count. A surface no draw rendered to is
created from its uniform color memory, as for sampling; other color
memory still throws.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The lock loop that emulates 64-bit LDS atomics runs only on the lanes
the guest's exec mask keeps, so a spanned wave's barrier-based ballot
there was not reached by both host subgroups. When one subgroup had no
active lane the other one paired its barriers with unrelated ones and
left the loop with lanes still pending, or the GPU hung (Ghost of
Yotei, program 0x80003af600). The elect and the lock are already per
host subgroup, so each subgroup now loops until its own lanes are done.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An import made at map time settles inside the guest's map call, so the mapping thread waits while the kernel maps the pages. A device that imports shared memory through host pointers settles nothing, so the test expects a settle only for a dma-buf import.
image_store with D16 data to a storage image of a SINT format threw
"stores 16-bit data to an image of a SINT format", both when the
descriptor is decoded and in the SPIR-V image emitter, and the runtime
image modes left out the SINT conversions for such images. God of War
Ragnarok (PPSA08330) stops on it in compute shader 0x1052a17900 right
after its MFSR setup.
Each 16-bit half is now converted like the D16 format buffer stores
(EmitD16StoreComponent): sign-extended, then saturated to the
component width as for 32-bit data. The buffer form was measured on
RDNA2 in #331; the image form is not measured (TechnicalDebt).
agc_driver_image_store_sint now stores D16 data with DMASK 0xf and 0x5
to all eight SINT formats and after an image_atomic_add on 32_SINT,
instead of expecting the refusal.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With pipelined draws, a DISPATCH_DIRECT on queue 0 whose dispatch-cache entry hits with a
recipe runs as an ordered commit item instead of draining the pipeline first. Misses, reads
that overlap writes still pending in the pipeline, verified data hits and writes that cannot
be ranged still drain. A dispatch that is resolved ahead (or adopted from a group resolved
ahead) and copy kernels keep the drained path; with the switch on, queue 0 does not resolve
dispatch groups ahead, since that drains the pipeline at every group. Off by default.
agc_driver_pipelined_dispatch counts drains per opcode (each dispatch drains with the switch
off); agc_driver_pipelined_dispatch_item checks that repeated dispatches do not drain, and that
a dispatch whose descriptor table a pending fill retargets drains and reads the new buffer.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Pipelines are now shared by every program that recompiles to the same
module, and a leading s_nop recompiles to the same one, so the second
dispatch reused the first pipeline. The new program also stores to the
second word.
Co-Authored-By: Claude <noreply@anthropic.com>
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
The NeighbourCopied wait accepted any pending result once the surface
image was live, so a pending result of the source surface could end it.
It now waits for a pending result overlapping the surface's range.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Reapplies #5791 (reverted by #6552). agc_driver_mesh_index_cache now skips
on llvmpipe like agc_driver_mesh does: llvmpipe aborts compiling these mesh
programs (LLVM ERROR: Cannot emit physreg copy), which is what turned main's
linux job red.
Co-Authored-By: Claude <noreply@anthropic.com>
agc_driver_mesh_index_cache aborts on the linux job (lavapipe, LLVM 20.1.2:
"LLVM ERROR: Cannot emit physreg copy instruction") on every main push build
since the merge (first red: 38777177302). The PR was merged on a
windows-only run after a linux-red batch was split.
Co-Authored-By: Claude <noreply@anthropic.com>
The lazy mode of agc_driver_prepared_shaders only checked dispatch output and failure reporting, which eager preparation also produces. Read the registered snapshot through Driver::RegisteredShaders: registration leaves it deferred with no prepared artifact, and the first dispatch prepares it.
APS5_LAZY_SHADER_PREPARE=1 keeps registration validation and decoding but skips queueing the preparation. Draws and dispatches prepare a deferred snapshot on first use and cache it; explicit ABI resolution still prepares its stages. Titles that register thousands of shaders at boot no longer hold every prepared shader in memory before the first frame.
Cover lazy dispatch, metadata and failure cases in both asynchronous and synchronous modes.
A depth surface is one level: the driver rejects draws that render a
depth mip. A sampled or storage view at the surface's address and extent
that starts at a later level, or a storage access to a later level, does
not touch that level, so it is not the depth plane. DepthSurfaceTexture
and DepthSurfaceStorage still sent such views to the surface, which
rejected the level. Forspoken (PPSA03984) builds a depth pyramid from its
1984x1116 D32 depth surface with a compute shader that samples one level
of a five-level R32F view and stores the next, and stopped there.
Both now leave such views to the texture and storage caches, as they
already do for a view of another extent or format.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>