A dump with sce_sys/playgo-scenario.json and no chunk table already answers
every chunk id as installed, but scePlayGoGetChunkId listed only chunk 0.
Ghost of Tsushima (PPSA02225) builds its set of installed chunks from that
list and never reads its English audio, two of its music archives or its
opening movie. scePlayGoGetChunkId now lists ids 0 to 999, the room that
title passes.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
#6106 made a Linux guest module with an initializer depend on
libkernel.prx, which exports the module-argument getter and setter that
its DT_INIT stub imports. That check still tested Init != 0, so a module
whose DT_INIT is 0 got the stub but not the dependency. With no other
libkernel.prx loaded, the executable then stopped with a symbol lookup
error, and a --module-dir module failed to load with "undefined symbol:
__aps5_get_pending_module_args_nid_no_patch". The check now uses HasInit,
like the writers.
guest_zero_initializer now checks that the Linux module lists
libkernel.prx, and its native load provides one.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Imports, type-3 mirrors and the buffers and textures placed in host memory share the driver's system memory heap. On Windows that heap is half the physical memory, so on a 16 GiB machine the old budget (the heap less 2 GiB) let imports hold about 6 of its 8 GiB, and host buffer allocations then overflowed into the 256 MiB device-local host-visible heap and failed. The budget now reserves the larger of 2 GiB and half the largest host heap.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Since #6470, a draw decode sets the pixel stage's iteratesSamples from the per-sample shading state and its sample locations from the draw's state, and a pixel shader that does not iterate runs once per pixel with sample 0. The sample-order test built its pixel stage from the registers alone, so its per-sample passes ran once per pixel and SampleID read 0. It now sets both fields as DrawDecode does.
#7147 added add_asan_test_options so the CPU-side tests pass in an
ANYPS5_ENABLE_ASAN build, and gave the relinker tests that load the
instrumented guest_module_args_host.prx into Python
verify_asan_link_order=0. guest_zero_initializer's Linux run loads the
same host library with ctypes.CDLL in a Python subprocess, so under ASan
it failed with "ASan runtime does not come first in initial library
list". It now runs with the same option.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
sceAudioInInput waits four block lengths (21 ms at 256 samples and
48 kHz) for the host device and returns silence when nothing arrived.
guest_audio_in_capture required the recording in the first four blocks
after sceAudioInOpen and in the first block after sceAudioInAsyncOpen.
On a loaded host the SDL disk driver's thread starts or runs late, a
block comes back silent, and the test aborted at captured == recorded.
Read until a block carries sound, at most 200 blocks, and check the
recording as before.
The test helper took the only entry of the shader cache root as the
version directory. It now opens the directory named after the current
shader cache source version, requires exactly one pipeline cache file
there, and only requires the root to hold no files, so other version
directories do not fail it.
AI-assisted: yes
The pipeline cache file lived in the shader cache root and every run
merged its pipelines into it, so pipelines built from SPIR-V of earlier
recompiler versions were never dropped. The file only grew (965 MB for
PPSA05684 after a few recompiler changes) and the driver loads all of
it into host memory at device creation.
The file now sits in the directory of the current shader cache source
version, next to the variants it was built from.
AI-assisted: yes
Each depth surface stores its plane through a storage image of its own,
kept for the surface's life. A title that switches output resolution
binds new depth targets over memory where the previous targets' planes
were, and the old images stayed live there. Storage images over the same
memory lend each other pending results, so a later store of the new
plane did not reach guest memory and buffer reads kept seeing the old
depth. A bind now drops the images and the pending store of older
surfaces whose planes overlap its plane over another range. A
same-range surface (another stencil or HTILE address) keeps its image.
The scan runs only when a surface or plane image was created since the
surface's last scan.
AI-assisted: yes
A depth surface lives in its Vulkan image, so a buffer read of its depth
plane saw guest memory the surface never wrote, and a buffer write into the
plane never reached the surface: binding the target again kept the old
depth.
- A single-sample 32-bit depth surface with the 64 KiB Z swizzle
(DB_Z_INFO SW_MODE 24) keeps a storage image in that swizzle over its
plane. A bind that writes or fast clears depth marks the plane stale;
FlushDepthPlanes copies the depth into the storage image and stores it
into guest memory. It runs from StorageTexture::FlushPending, when a
buffer upload finishes (over its regions and address space), and before
a dispatch for each GuestBuffers V# it binds (a cached dispatch reads
them without an upload). A reused build flushes its in-place buffer
regions, and an image lookup flushes the range it reads, as do the
write-stamp proofs that let a cached image or a reused build skip that
lookup: a stale plane's memory looks unchanged to them.
- Stale planes are kept as ranges under their own lock with an atomic
hull; a flush that overlaps none returns without the GPU and surface
locks.
- Every bind of such a surface, and every flush of its stale plane,
collects the plane's writes. Written by someone else since the surface's
previous bind, store or reload, the plane is reloaded from memory
instead of stored, so a guest write after a depth draw is not
overwritten by that draw's late store. A pending HTILE fast clear wins
over the reload.
- A color target flushes the stale planes under it before it retires their
surfaces, so a target that loads or blends reads the stored depth. A
retired surface's plane is no longer stale: a later flush never stores
its old depth over what the new owner of the memory wrote.
- The depth surfaces lock is recursive: a store reached from a flush under
DepthSurfaceTexture re-enters it.
- Draws pass whether they write depth, so read-only binds do not mark the
plane stale.
PPSA05684 copies its main depth plane into two ping-pong planes with a
buffer compute, draws the cage's depth into them and fogs its menu from the
result; without this the copy carried nothing and the fog covered the
cliff and the cage.
agc_driver_depth_plane_buffer_memory draws depth 0.5 into such a plane,
fetches vertices from it (the plane must hold 0.5), writes 0.75 into the
memory and draws at 0.5 under LESS (must pass), then checks the depth
written after the reload reaches memory again. On a new plane it writes
memory after a depth draw and before any store: a buffer read must keep
the guest bytes and the next bind must reload them; a guest write before a
depth draw must then lose to that draw. A linear texture at an offset into
a plane must read what memory holds after a flush, also when it is viewed
through its cached storage image after another depth draw. On a plane with
HTILE, an HTILE fast clear after a guest write must win. A color target
that blends ZERO/ONE over a plane just drawn at 0.5 must write back the 0.5
it loaded.
AI-assisted: yes
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.
guest_dynamic_loader and guest_dynamic_loader_fixed_base run the same
GuestDynamicLoader.cpp in the same working directory, and both copy the
module fixture to anyps5-relinked-module-for-test.prx.guest.prx and
anyps5-host-loaded-module-for-test.prx before loading it. Under ctest
--parallel one test rewrote or removed a file the other had mapped:
Bus error, or failed at GuestDynamicLoader.cpp:92. Give both one
RESOURCE_LOCK.
PPSA34015 (EA SPORTS FC 27) stopped with "Joining guest thread: Access is
denied": scePthreadJoin waited on a thread that another call released
under it, and then waited on its closed handle. As FreeBSD 11.4's
thr_join.c and thr_detach.c do with the joiner field, scePthreadDetach
now returns EINVAL while a thread waits to join the target, a second
concurrent scePthreadJoin returns EOPNOTSUPP, a cancelled join backs out,
and a completed join leaves the thread detached.
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.
Since #6196, a one-sample target under a multisampled rasterizer with
MSAA_ENABLE clear is drawn as one sample instead of refused, so the
overrasterized draw with MSAA_ENABLE clear now decodes as one sample without
merged coverage.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Pipeline creation and the pipeline store key read State::mergedCoverage,
but the journal's state codec and CanonicalPipelineState dropped it, so a
journalled merged-coverage pipeline replayed as a plain multisampled one
and the draw built its pipeline again. The codec and the canonical state
now carry it and the journal format becomes 4.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
A radeonsi-style GL driver smooths lines and polygons by rasterizing four
samples into a one-sample color target: PA_SC_AA_CONFIG has 4 samples,
DB_EQAA.OVERRASTERIZATION_AMOUNT is log2(4), and the pixel shader reads
SAMPLE_COVERAGE to scale alpha by the covered samples. The pixel is written when
any of the four samples is covered. DecodeState refused the one-sample target as
a sample-count mismatch.
Such a draw (MSAA_ENABLE set, no depth target, no per-sample shading, every
color target one-sample, OVERRASTERIZATION_AMOUNT matching the raster samples)
now decodes with mergedCoverage. Its pipeline keeps the raster sample count,
gives the color attachments one sample (VkAttachmentSampleCountInfoNV or the
render pass) and merges coverage (VK_COVERAGE_REDUCTION_MODE_MERGE_NV). The
device enables VK_NV_framebuffer_mixed_samples and VK_NV_coverage_reduction_mode
when it reports that combination; elsewhere the pipeline throws.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The custom MSAA sample-location debt entry keeps this branch's grid stand-in text and takes main's sentence on ANCILLARY and the position inputs of a once-per-pixel shader.
SPI_PS_INPUT_ENA/ADDR bit 14 (SAMPLE_COVERAGE_ENA) gives the pixel shader one
VGPR, after ANCILLARY, holding the samples the primitive covers. The decoder
refused it and the recompiler never loaded the VGPR. It is now loaded from
gl_SampleMaskIn[0] (sharing the input the partial quad sample mask already
declares). On a multisampled draw the hardware word is the whole pixel's
coverage while gl_SampleMaskIn holds only the invocation's samples when the
pixel shader runs per sample, so that case, and sample-rate or ancillary inputs
beside it, are refused.
Co-Authored-By: Claude Opus 5.5 <[email protected]>