image_sample_d and image_sample_cd on a cube pass their gradients through the
same conversion as the face coordinates, which subtracts 1.0 to move AMD's
[1, 2] face range to [0, 1]. A gradient is a difference of coordinates, so the
bias turned a one-texel gradient into one of about -1 and the sample read the
smallest mip. Gradients now skip the bias.
agc_driver_image_sample_cube_derivatives samples every face of a 16x16 cube at
five levels through image_sample_d and checks the level and face it read.
TechnicalDebt records that the gradient handling follows Mesa and was not
measured on hardware.
DB_SHADER_CONTROL.DEPTH_BEFORE_SHADER (bit 12) is what a pixel shader compiled
for early depth/stencil sets: the depth and stencil tests and writes happen
before the shader runs, even when it kills pixels or writes memory. The bit
was accepted but never read, so such shaders got EarlyFragmentTests only when
Z_ORDER was EARLY_Z_THEN_LATE_Z and they had no kill or exports. Their killed
pixels then left depth unwritten, and occluded pixels still wrote memory.
EARLY_Z_THEN_RE_Z (Z_ORDER 3) was not treated as early either.
DecodePixelStageInfo now sets earlyZ for DEPTH_BEFORE_SHADER, and for Z_ORDER
1 or 3 under the existing kill and export conditions, including the stencil
reference export. The backend no longer repeats those conditions; it keeps
only the alpha-to-coverage one, so a shader with alpha-to-coverage still runs
its tests late. earlyZ keeps its place in the request, so the serialization
version does not change.
earlyFragmentTestsTests in agc_driver_graphics checks which DB_SHADER_CONTROL
values declare EarlyFragmentTests, and that alpha-to-coverage keeps Z_ORDER 1
and DEPTH_BEFORE_SHADER late, directly and after a serialization round trip.
stencilRefExportTests checks that DEPTH_BEFORE_SHADER with a stencil reference
export still decodes as early.
TechnicalDebt records that the bit follows Mesa and that its combination with
a Z export, a mask export, a stencil export or alpha-to-coverage was not
measured.
XPSemu PPSA97358 imports both from libkernel.prx; with the imports ahead
of them covered, its predicted next stops (relink registry order, not an
observed run) are:
FAIL: unresolved ELF import KaK52lYTBIs from libkernel.prx (execv, 7 call sites)
FAIL: unresolved ELF import kdguLiAheLI from libkernel.prx (execve, 4 call sites)
Today the title stops earlier at the observed
FAIL: unresolved ELF import aRo9AhFUXcM from libkernel.prx (sigsetjmp, merged in #3486)
As for execvp (#2827), the process image cannot be replaced here, so both
throw with the execvp message pattern once FreeBSD 11's execve would start
loading the image (freebsd-src 8c639945, sys/kern/kern_exec.c
exec_copyin_args, do_execve, exec_check_permissions; lib/libc/gen/exec.c
execv passes environ). Before that they fail as FreeBSD does: EFAULT for a
null argument vector or path, ENOENT and ENOTDIR from the lookup as stat
reports it, EACCES for a path that is not a regular file. Paths of
PATH_MAX bytes or more and strings over ARG_MAX throw instead of guessing
the console's limits. The execv calls in XPSemu's sources run in a fork
child (net/tap.c), and its fork fails with ENOSYS (ZiZc3/XPSemu 8eec07b4,
ps5/compat/libc_missing.c, ps5/build-title.sh --defsym).
NIDs computed with tools/nid_names.py and confirmed in aerolib.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
(cherry picked from commit 57f0fa37132bc6c78bc02282044a00e2db859484)
getsockopt and setsockopt on a libkernel socket knew four SOL_SOCKET options
(SO_REUSEADDR, SO_BROADCAST, SO_SNDBUF, SO_RCVBUF) and failed every other
one with ENOPROTOOPT. The Mound's EOS SDK reads SO_ERROR on two of its
sockets after a connect, which therefore always failed.
The SOL_SOCKET options now follow FreeBSD 11.4 sosetopt and sogetopt:
- SO_ERROR returns the pending error of the socket as a FreeBSD errno and
reports it once (Winsock does not clear it on read, so the library does).
- SO_TYPE, SO_ACCEPTCONN, SO_KEEPALIVE, SO_DONTROUTE, SO_OOBINLINE and
SO_LINGER are read from and set on the host socket; the boolean options
read back as their own bit, as FreeBSD returns so_options & option.
- SO_DEBUG, SO_USELOOPBACK, SO_REUSEPORT, SO_TIMESTAMP and SO_NOSIGPIPE stay
ENOPROTOOPT until a title needs one.
- A value is read from its first int and fails with EINVAL when shorter, a
getsockopt buffer is filled up to its length (sooptcopyin, sooptcopyout),
SO_SNDBUF and SO_RCVBUF below 1 fail with EINVAL, and SO_LINGER outside
0..65535 seconds fails with EDOM.
A connect on a non-blocking socket now fails with EINPROGRESS on Windows too
(it was EWOULDBLOCK, which a title waiting for the connection does not
expect).
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
With float16DenormPreserve, EmitF16BitsToF32 rebuilds the bits of a NaN
half after UnpackHalf2x16, because NVIDIA returns the default NaN and
Intel quiets it. When every use of the converted operand is an f32
comparison or a NaN test, directly or through abs and neg, only whether
it is NaN matters, so the conversion returns UnpackHalf2x16's result as
is. v_cmp_*_f16 goes from 11.5 to 4 SASS on an RTX 4060.
agc_driver_f16_to_f32_unpack adds v_cmp_u_f16 and v_cmp_lt_f16 over all
65,536 halves with each decode the device supports. Its SPIR-V check
requires the v_cvt_f32_f16 conversion to rebuild the NaN bits and the
compared conversions not to.
Palworld (PPSA23126, #2648) stops at start-up on the export, imported by
its bundled libdiscord_partner_sdk.prx:
FAIL: unresolved ELF import oiOi7vgPfAY from libSceAudioOut.prx
PPSA28416 imports it from its bundled party-ps5-shipping.prx as well. The
call itself has not been observed yet.
SharpProspero (5dfdb4b0, Interop/Audio/AudioOut2.cs:460-464) declares
`int sceAudioOut2EnableChat()`, "Allows chat audio alongside the
application's own", and the ps5-payload-dev SDK stub (f5d40f02,
sce_stubs/libSceAudioOut.c:62) exports it as well. There is no context or
handle to validate. The host mixes no chat audio and AudioOut2 has no chat
port, so the call records that chat audio is allowed (traced once with
APS5_TRACE_AUDIOOUT2) and returns 0. Whether the console fails it without
a chat session or when repeated is recorded in technical debt, and the
PPSA28416 "signature unknown" entry is dropped.
NID oiOi7vgPfAY matches tools/nid_names.py and the shadPS4 aerolib list.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
agc_shader_memory recompiles pixel and vertex programs in wave64 and
wave32 with ds_write_b8, ds_write_b16, ds_write_b8_d16_hi,
ds_write_b16_d16_hi, ds_add_u32, ds_inc_rtn_u32, ds_mskor_b32 and
ds_append, and requires that no atomic uses a Function pointer and that
no atomic or memory barrier uses Workgroup memory scope. With SPIR-V
tools enabled each of them failed validation with
VUID-StandaloneSpirv-None-04686 before the fix.
agc_driver_pixel_lds_read_modify_write draws a 64x8 target in wave64
and wave32. Each pixel uses its own 16-byte LDS slot: it writes bytes
and halves into initialised dwords, chains ds_add_rtn_u32,
ds_inc_rtn_u32 and ds_mskor_rtn_b32 on one dword and reads ds_append
from a counter every lane initialised, then stores the dwords and the
returned values to a buffer. It needs no subgroup wider than the host's,
so it runs on lavapipe.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Pixel, vertex-path and fetch programs keep LDS in a Function-storage
array private to each invocation. Sub-dword LDS writes (ds_write_b8,
ds_write_b16 and their _d16_hi forms), the 32-bit LDS atomics and
ds_append/ds_consume still emitted OpAtomicLoad, OpAtomicCompareExchange
or OpAtomicIAdd on that array, with Workgroup scope and a Workgroup
OpMemoryBarrier. Vulkan allows atomics only on Uniform, Workgroup,
Image, StorageBuffer, PhysicalStorageBuffer and TaskPayloadWorkgroupEXT
pointers (VUID-StandaloneSpirv-None-04686) and Workgroup memory scope
only in compute, mesh, task and tessellation control
(VUID-StandaloneSpirv-None-07321). With ANYPS5_ENABLE_SPIRV_TOOLS the
recompiler rejected such shaders; without it the invalid module went to
the driver.
InFunctionStorage now names the storage EmitMemoryElementPointer picks.
For Function storage, StoreSubwordInBounds, Atomic32, EmitAtomicUpdate,
SharedAtomicUpdate and AppendConsume load the dword, compute the new
value and store it, as scratch already did. The array belongs to one
invocation, so no other invocation can observe the dword in between.
Atomic32 takes the next value from AtomicNext32, which FlatAtomicNext32
now shares for its plain integer operations. The per-invocation LDS
model and what it means for ds_append are recorded as technical debt.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
sceAgcSetAmmSemaphoreMemory(memory, sizeInBytes) registers the AMM semaphore memory once and zeroes the first 8 bytes of each 32-byte label; sceAgcGetSemaphoreLabel(index, label) writes memory + 32 * index for an index inside the registered memory.
Unblocks New Joe & Mac Caveman Ninja (PPSA02801) which imports both symbols. Matches OpenAGC and sharpemu agreements on signatures, 16 KiB alignment, 32-byte stride, and zeroed label counters.
A failing _Pad primitive threw a host std::runtime_error, which no guest
catch can see. threadcall.cpp calls the checked wrappers of xthread
(_Mtx_lockX, _Cnd_waitX, _Thrd_startX), which pass a non-success code to
_Throw_C_error: _Thrd_nomem and _Thrd_timedout become
resource_unavailable_try_again, _Thrd_busy device_or_resource_busy and
_Thrd_error invalid_argument, raised through _Throw_Cpp_error, which main
now implements. A failing thread start is _Thrd_startX's
resource_unavailable_try_again.
_Release now wakes the launching thread with _Cnd_signal, as
threadcall.cpp does; libc has it since the pad was written.
guest_ampr_threads checks, in a forked child whose guest terminate
handler reports the thrown object, that _Release on the thread still
holding the pad's mutex throws std::system_error with EBUSY. It fails
with the previous host exception and with busy mapped to
invalid_argument.
Guest texture formats 51 (SNorm) and 55 (SInt) of the 10-bit packed group were missing from the texture lookup and the descriptor format table, so a descriptor using them threw 'unsupported guest texture format' while the UNorm (50) and UInt (54) siblings worked. Map them to A2B10G10R10_SNORM_PACK32 / A2B10G10R10_SINT_PACK32, classify them for sampling (float / signed integer), and list SINT among the integer formats.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Implement _ZNSt4_PadC2Ev, _ZNSt4_PadD2Ev, _ZNSt4_Pad7_LaunchEPP7pthread
and _ZNSt4_Pad8_ReleaseEv, which Deathloop (PPSA01670) and Minecraft
Legends (PPSA05510) import from libSceAmpr for the std::thread launch path.
The algorithm and object layout follow Dinkumware V6.00 thr/xthread and
thr/threadcall.cpp of Visual C++ 2013 (ganboing/crt.vc12 f1d47126): a
vtable pointer whose first slot is the pure virtual _Go(), then the
condition and mutex handles and bool _Started (0x8, 0x10, 0x18), with the
console's pointer-to-slot handles of libc Threads.cpp (#3079). The pad
uses libc's _Cnd_*/_Mtx_* exports, starts the guest thread with
pthread_create and an entry that calls _Go() and returns its result as
the exit code, as _Call_func does. The unverified layout, thread
attributes and error reporting are recorded in TechnicalDebt.md.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Track mutations against the current draw dependency mask and preserve device and shader registry identity in the draw key. Validate mutations, projected masks, PM4 packets and prepared graphics against full recomputation.
Written with AI assistance.
scan_library and collect_shaders read CMakeLists.txt, the ISA table and the opcode header with the locale codec. On Windows that is cp1252, so a UTF-8 file containing U+2010 or U+2192 raised UnicodeDecodeError. These reads now pass encoding="utf-8" and errors="ignore", and a subprocess test with an ASCII default codec covers it.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01V9UU71SP1UKGR51Sowbgmq
The repository check compared the file name to a lower-case set, so a
file added as CLAUDE.md, Agents.md or GEMINI.md passed the check while
claude.md was rejected. Compare the lower-cased name so every spelling
of an agent instruction file is reported.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01V9UU71SP1UKGR51Sowbgmq
The per-thread servent storage held std::string and std::vector
members, so getservbyname_nid_postfix registered a thread_local
destructor through __cxa_thread_atexit. On Windows that destructor runs
after emulated TLS freed the object, and prx_thread_local_destructors
(#4029) rejects libScePosixForWebKit.prx for it.
The result now lives in a thread_local struct of fixed-size char arrays
and an alias pointer array, sized for the longest name (submission),
alias (www-http), protocol (sctp) and alias count in the embedded table;
static_asserts check the sizes against the table and that the struct is
trivially destructible. The guest servent layout and the per-thread
result FreeBSD's getservent.c keeps in its NSS TLS state are unchanged.
Nothing is allocated, so the ENOMEM path is gone.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Implement getservbyname (H1bArJPagV0) in libScePosixForWebKit. Cloud
Play (PPSA99600) imports it from this library only (registry index 408,
call site 0x1042124); once fnmatch (#3545) is in, its predicted load
stop is:
FAIL: unresolved ELF import H1bArJPagV0 from libScePosixForWebKit.prx
The ps5-payload-dev SDK stubs (f5d40f02, sce_stubs/) declare
getservbyname in libScePosixForWebKit.c and not in libkernel.c or
libSceLibcInternal.c. The call site is the service-name branch of a
getaddrinfo inside the title: a non-numeric service is looked up with
protocol "tcp", "udp" or "sctp" and the port is read big-endian at
offset 16 of the result, which fixes the servent layout used here
(name, aliases, 32-bit port, protocol at 0, 8, 16, 24).
The guest has no /etc/services and the console's file is unknown, so the
function searches 37 lines of FreeBSD 11.4 etc/services (8c639945):
ftp-data, ftp, ssh, telnet, smtp, domain, tftp, http, pop3, ntp, imap,
https, rtsp, submission, imaps and pop3s with their aliases and
protocols, in file order. None of their names or aliases appears on an
earlier line of the full file, so these lookups answer as the full file
would. The search follows files_servent in lib/libc/net/getservent.c
(8c639945): exact, case-sensitive match on the name or an alias, a null
protocol takes the first match, the port in network byte order, the
result in per-thread storage like getserv's NSS TLS state. Any other
name returns null without touching errno, as for a name the file lacks.
The repository's getaddrinfo still resolves service names through the
host, so there was no table to share; this is recorded in
TechnicalDebt.md.
Co-Authored-By: Claude Fable 5.1 <[email protected]>