libSceVideodec's five exports were stubs that threw. Decoder creation,
decoding, flushing, resetting and deleting are implemented with the
structure layouts of shadPS4's PS4 library, and the decode runs through
libSceVideodec2, which decodes H.264 with FFmpeg. The picture is copied
into the caller's frame buffer with the pitch aligned to 64 and the coded
height, the chroma after the luma rows, and the picture information holds
the timestamps and the crop offsets.
A guest test decodes the H.264 fixture through the library and checks the
pictures against the reference hashes.
AnyPS5 resolves a title's imports by NID, so a title that imports a system
function no library provides fails to load with an unresolved import. The
PS5 3.20 export inventory lists 193 such exports across 37 PS5 system
libraries AnyPS5 implements but does not provide.
Declare them as throwing stubs so those titles load and reach their next
blocker. Each declaration calls NotImplemented_nid_no_patch and returns 0;
none of them implements the function. Declarations with a credible
prototype use it and cite the source with a pinned commit, and the rest
are declared without parameters, which resolves the import without making
an ABI claim. The technical-debt files record the limitation per library.
libSceMbus and libSceSystemService are left out because pull request #7821
declares them. libSceAgc is left out because its exports are versioned, so
the 3.20 NID names a different symbol from the one AnyPS5 ships.
libSceAvPlayer.native is left out because it compiles libSceAvPlayer's
Export.cpp.
Names and NIDs come from the PS5 3.20 export inventory at
https://github.com/DNNDHH/PS5-3.20_Libs/tree/b2a77c09cd71c01f34c790cfbe98c751a13262ad
The guest socket layer relies on a few Linux calls:
- The equeue wait uses poll with the timeout rounded up to a millisecond;
macOS has no ppoll.
- A readable stream socket whose peer closed is reported with POLLHUP by
peeking one byte; macOS has no POLLRDHUP.
- FIONREAD on a datagram socket, and the byte count that fstat and kevent
report for it, is SO_NREAD, the size of the next datagram; macOS adds the
source address to FIONREAD.
- socketpair throws for SOCK_SEQPACKET, which has no AF_UNIX pair on macOS.
- gethostbyname replaces gethostbyname_r, which macOS lacks.
The UDP test sends on its connected socket without an address, as #7475
does, because macOS, like FreeBSD, fails sendto with an address on a
connected socket with EISCONN. The log test uses a datagram pair with
enlarged buffers instead of SOCK_SEQPACKET.
sscanf, vsscanf, sscanf_s and vsscanf_s threw on Linux for %ls, %lc, %l[, %S and %C, because glibc stores a 32-bit wchar_t per character into the guest's 16-bit buffer. ScanGuest, the per-directive scanner the _s forms already use, now scans those fields itself: the input is decoded as UTF-8, mirroring the narrow printf family's UTF-8 output, and each character is stored as one 16-bit unit, the width and the _s size counting characters; %ls skips leading white space and stops at the next, %l[ matches an ASCII scanset with ranges and negation, and a %lc field that meets the end of the input early keeps what it read, as FreeBSD's convert_wchar does. sscanf and vsscanf route a format with a wide conversion through ScanGuest and keep the host path otherwise. The UTF-8 decoding and scanset matching live in ScanWideField.cpp, which throws for input that is not UTF-8, a character outside the BMP, a scanset member outside ASCII and positional arguments next to a wide conversion; wide conversions in fscanf still throw.
A path of a descriptor web whose dwords depend on the program counter, EXEC
or a lane mask selected the first descriptor, and an image arm whose words
are not a T# was bound as a null image. Both are assumed never to be taken,
but nothing reported it if a lane took one, so a wrong image or zeros went
unnoticed.
The folded path now gets its own selector value, which still selects the
first descriptor and records an InvalidDescriptor BDA fault (new IR
DescriptorFault) when a lane reaches the read with it. An image arm is
checked in the shader with the words the selected arm read: not a null
descriptor, and a TYPE from 2 to 7 or a FORMAT outside the GFX10 image
format table records the same fault with the arm's first two words. Both
faults are recorded only for lanes the image instruction's EXEC enables. The
materializer binds a null image only for exactly those words; any other
invalid arm is refused as before. The GFX10 format ranges are shared
between both checks. A web whose every path is folded no longer leaves its
selector Phis in the program.
Only reads split through a descriptor web bind the fault buffer, which
keeps their dispatches out of pipelined dispatch and stencil replay; splits
along incoming edges keep requiring a valid T# and bind none. The debt entry and
the APS5_STRICT_DESCRIPTOR_WEBS row say so, and note that a shader that
also uses an image table reads its fault buffer back only when a table
record is poisoned.
The descriptor Phi and undefined format tests expect the fault buffer only
for descriptor webs, and a T# shared by every arm of a split S# must stay
mandatory. agc_driver_descriptor_web_faults dispatches a web with two SRT
arms, each over its own texture, and a program-counter path: a lane on
either valid arm reads that arm's texture without a fault, a lane on the
folded path or on an undefined arm faults at the read, and nothing faults
or is written with EXEC empty.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
validImageDescriptor accepted any nonzero FORMAT, so words that are no T#
passed whenever their TYPE nibble was 8 or more. An optional descriptor web
arm holding such words was then not bound as a null image, and the dispatch
failed on a sampled image of an unsupported format instead. PPSA23566
(UFC 6) has such an arm (formats 402-463): a compute shader picks one of 32
SRT T#s through an s_setpc_b64 jump table indexed by min(i, 32), and the
default entry reaches the image_sample_lz with the loop-entry value of the
T# registers, which a constant-buffer load filled with floats. The console
never samples that arm: the default entry is taken only from iteration 32
on, when the registers hold iteration 31's T#.
A FORMAT outside the GFX10 image format table (Mesa gfx10-rsrc.json
GFX10_FORMAT: 1-77, 128-154, 156-182, 265-292) now makes the descriptor
invalid. An optional descriptor web arm is bound as a null image, as other
invalid arms are; a direct image is refused as invalid unless it is a null
descriptor, and an image table entry faults when selected with the
InvalidFormat reason.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The descriptor web fold covered only program-counter values. PPSA23566
(UFC 6) compute shader 0x1163c84000 also has a path whose T# registers hold a
lane mask accumulated in a loop ("a Phi that does not resolve to one value:
Phi(CompositeExtractU32x4(Ballot(FPUnordGreaterThanEqual32), ...), BitwiseAnd32(...))"),
and throws on it while a career fight loads.
Treat EXEC and Ballot results like the program counter, also through loop
Phis: such a path selects the first descriptor, as before f5ba4e9c6.
Unwritten registers keep their own image. APS5_STRICT_DESCRIPTOR_WEBS=1
throws as before. The descriptor Phi test expects the program-counter, EXEC
and compare-mask entries to plan the loop's two SRT T#s.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
f5ba4e9c6 made a T# split across SRT descriptors throw when one path's
descriptor dwords depend on the program counter. Such a path appears when a
loop's entry edge reaches the read with registers left from s_getpc_b64; a
descriptor built from the program counter is garbage on hardware too, so the
path does not reach the read in a working title. PPSA23566 (UFC 6) throws on
this for compute shader 0x1163c84000 while loading a career fight ("descriptor
web: a descriptor dword depends on the program counter").
Select the first descriptor on such a path again, as before f5ba4e9c6, for
program-counter values only; EXEC and compare-mask values still throw.
APS5_STRICT_DESCRIPTOR_WEBS=1 throws as before. The descriptor Phi test now
expects the program-counter entry to plan the loop's two SRT T#s.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Queue 0's draw committer records the draws the packet worker hands
over. When the worker's APS5_SAMPLE_WORKER stacks wait in
DrawPipeline::Enqueue, the committer is the thread that bounds the
frame, and only APS5_SAMPLE_THREADS sees it: 40 addresses, 12 frames
deep, without whole stacks.
APS5_SAMPLE_COMMITTER=<file> attaches the worker's sampler to the
committer when its thread starts and writes the same two files. Both
use one start function, and StopWorkerSampler stops both.
The sampled lookup kept the whole array's layer count: a texture over an
array of more than maxImageArrayLayers layers read and snapshotted the
whole surface and then threw in the Texture constructor, on every lookup,
even when the descriptor viewed a few slices. A menu that samples a
16x16 array of up to 8065 layers through its image tables spent
~55 ms per frame reading those surfaces only to reject them.
cachedTexture now applies the window the storage path uses
(StorageArrayWindow, renamed ArrayLayerWindow since both paths use it):
a view whose slices fit the limit is served as an array of its own
starting at its first slice, and a view whose slices alone exceed the
limit throws before anything is read. A 2D image is one layer whatever
its last array field holds and is no longer refused by the storage path.
agc_driver_image_array_window_past_layer_limit samples and loads three
slices at 8100-8102 of an 8103-layer 1D array (before: "a texture array
with more layers than maxImageArrayLayers is not implemented") and checks
that a view of all its layers is refused with the window's error on a
device whose limit is lower.
AI-assisted: yes
A volume's depthOrLastArray is its depth, bounded by maxImageDimension3D,
not by maxImageArrayLayers: a 2049 to 4096 deep volume is a valid image
and threw since the window was introduced. Reported by Dextroid17.
AI-assisted: yes
A PS5 array may hold up to 8192 layers; Vulkan devices allow fewer (2048 on
NVIDIA). A storage view of such an array created its whole image, with more
layers than the device allows: vkCreateImage is then invalid
(VUID-VkImageCreateInfo-arrayLayers-02256) and a store into a layer the device
did not back faults the GPU. Uncharted: Legacy of Thieves Collection (PPSA05684) views a 16x16 RGBA8
array of up to 7809 layers in slices of a few hundred to 2048 in its
orphanage chapter, which lost the device (Xid 109, write invalid) a few minutes in.
StorageArrayWindow describes the viewed slices as an array of their own
starting at the first viewed slice when the whole array is past the limit;
a non-XOR swizzle does not depend on the slice index, so the slices detile
alike. Views whose slices alone exceed the limit, XOR swizzles that mix in
the slice, and any other image past the limit now throw instead of creating
an invalid image.
AI-assisted: yes
On PS4 firmware 10.71 sceNetInetPtonEx reads IPv4 text the way
inet_aton does, not the way sceNetInetPton does: "1.2.3" is 1.2.0.3,
"127.1" is 127.0.0.1, hex and octal parts are accepted, a part value
wraps at 32 bits ("1.4294967296" is 1.0.0.0) and the text ends at the
first whitespace. Two differences from BSD inet_aton were measured: a
part starting with "09" is decimal ("0989" is 989), and an octal part
containing 8 or 9 fails.
The flags argument changed nothing for 0, every single bit up to
0x100, 0x10000, 0x80000000 and -1, so it is ignored instead of
throwing. IPv6 still converts as sceNetInetPton does, which matches
the console.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Without VK_EXT_shader_stencil_export (NVIDIA), stencil reference exports
are emulated by replaying the draw once per value. An export the prover
could not bound to at most 16 values was refused. The replay shader
compares the export's low eight bits, so an unbounded export now
replays all 256 values, and proven values are reduced to their low
eight bits as the comparison sees them.
Refs #4276
Co-Authored-By: Claude Opus 5.5 <[email protected]>
DecodeState and DrawRejection rejected PA_CL_CLIP_CNTL bit 16
(CLIP_DISABLE), skipping draws that set it. Vulkan handles viewport
guard-band clipping automatically without requiring explicit clip
toggles. Accept bit 16 in ClipControlMask without altering depthClamp,
and record the unmodelled console clipping behavior in technical debt.
Tested with agc_driver_graphics_tests.