Since #8512 a raise redirects a target running host code once 50 ms have
passed since the raise began. A target inside a system call that is not a
wait, such as the NtWriteFile of an fwrite that holds its stream lock, can
stay there longer; the redirect then ran the handler with the lock held.
SONIC SUPERSTARS froze at frame 67 again on main this way, with its GC
raise delivered at ntdll!ZwWriteFile+20.
A target stopped right after a syscall instruction in ntdll now restarts
the 50 ms host-code window, so the raise keeps sampling until the call
returns and the target leaves host code, bounded by the 1 s retry limit.
guest_raise_in_system_call holds a writer in NtWriteFile on a slowly
drained pipe; it times out on main and passes with this change.
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Animal Well (PPSA22520) imports _Thrd_detach (L7f7zYwBvZA) from libc.prx and nothing exports it, so the Windows loader stops at startup. Register libkernel's pthread_detach with libc like pthread_create and pthread_join, and return _Thrd_error (4) when it fails.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01GtXavMkgCTCdmRpweviHcQ
A render recorded only the innermost system it was rendering, so a
destroy called from the callback of a system rendered inside another
system's callback was let through, and the outer render then used the
destroyed rack. Each system now counts the renders it is in. A destroy
first waits until no other thread holds the exclusive state, so a
non-zero count can only come from the calling thread's own stack.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
swscanf and swscanf_s threw "unsupported conversion" for %S and %C.
The console's Dinkumware wide scanner, read from the libc.prx that
PPSA21564 ships, treats them as invalid conversions: the scan stops
there and returns the fields assigned before them. A length modifier
or suppression does not change that.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The stem of a request and of a relinked module name was cut at the first dot,
so a request for Engine.Render.prx that missed could load Engine.Core.prx.guest.prx.
Only the last extension is removed now, as the review of the stem lookup asked,
and the variant-names test requests a dotted name that must not load the sibling
fixture module.
Co-Authored-By: lendinglibrary <[email protected]>
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
A title asks for a module by its console name and the relinker names the
converted module after the ELF it was built from: Unity IL2CPP titles load
Media/Modules/<name>.prx and Media/Plugins/<name>.prx while the dump holds
<name>.elf.guest.prx, so sceKernelLoadStartModule failed with 0x80020002
and the title stopped 3 s after start. After the exact and the
case-insensitive <name>.guest.prx lookups miss, take the sibling whose stem
matches the request and ends with .guest.prx, shortest name first.
Format tests/FlatScratch.cpp, drop the doubled blank line before its CMake
block and move the technical debt entry into the Functional list.
Co-authored-by: Prophet069 <[email protected]>
kevent threw NotImplemented for EVFILT_WRITE with NOTE_LOWAT above 1 on a socket, although the socket readiness check already reports free send-buffer space (SO_SNDBUF less SIOCOUTQ on Linux). The write event now fires once that space reaches the mark, as FreeBSD 11's filt_sowrite compares sbspace with kn_sdata, and stays silent while the space is below it. The debt entry no longer says a write mark is limited to 1. Reference: https://github.com/freebsd/freebsd-src/blob/release/11.0.0/sys/kern/uipc_socket.c
The multisampled merge accepts 2, 4 and 8 samples, but the execution
test drew only 2-sample targets. It now runs the same draws on 2, 4
and 8 samples, each count with its own target: a cutting merge under
a full write, then an X and a W merge drawn back to back. Every
sample is read back through a T# of the target's sample count and
checked against the standard sample locations. A partly merged pixel
is now any pixel with some, but not all, of its samples merged.
A count whose R16_UINT colour attachment with storage use the device
does not offer is skipped and printed. The test is skipped when the
device offers none of the three.
The debt entry on measured hardware now names the 4- and 8-sample
merges.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
The recompiler refused centre-located barycentrics in a multisampled
merge on a device without interpolation functions and fragment shader
barycentrics. It did so even when every sample sits at the pixel
centre, as in a draw raised from a one-sample rasterizer, where the
barycentrics are the centre's anyway. The refusal now applies only
when the merge's sample locations are off the centre. The pixel
request carries those locations for such a merge.
The recompile test runs on two states. On a 2-sample rasterizer, the
missing barycentrics throw, and the shader compiles once they are
present. On a raised draw, the shader compiles without them.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
A merge into a multisampled 4_4_4_4 target runs the pixel shader once
per sample. A shader that stores to guest memory, runs atomics or uses
GDS would then repeat those writes for every covered sample. An
8-sample pixel would add to a counter eight times. Such a merge now
throws.
The recompile request carries the merge's sample count, not whether
the guest asked for per-sample shading, so this also refuses shaders
the guest iterates itself, where the console repeats the writes too.
A recompile test checks that a 2-sample merging shader adding to a
buffer counter throws, and that the same shader without the merge
compiles.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
A partial write of a multisampled 4_4_4_4 target makes the draw shade
per sample. For a shader the guest runs per pixel, every invocation of
a pixel must then see the same inputs. Otherwise its colours and kill
decisions follow each sample, while the console runs one invocation.
The decode now throws in two cases when the guest did not ask for
per-sample shading. The first is a shader that reads the ancillary
word, whose sample number would become the invocation's. The second
is a shader that reads centroid, sample-located or pull-model
barycentrics, Z, 1/W, or a position at the centroid or a sample. That
case is allowed when every sample sits at the pixel centre, as in a
draw raised from a one-sample rasterizer. The recompiler throws for
centre-located barycentrics on a device without interpolation
functions and fragment shader barycentrics, where they would not be
rebuilt at the centre.
Decode tests run each moving input on a 2-sample rasterizer, where it
throws, and with PS_ITER_SAMPLE, where it decodes. The raised draw
keeps the located inputs and refuses the ancillary word. Centre and
upper-left positions, centre barycentrics, the front face and the
fixed-point position decode, and a recompile test covers the missing
barycentrics. The debt entry now lists what is kept and what throws.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Per-sample shading of a merging draw makes centroid and sample-located
inputs and the ancillary sample number follow the invocation's sample
(centre-located inputs too on devices without interpolation functions
and fragment shader barycentrics), and the 2-sample merge was measured
on one GPU only.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
The refusal of a merging shader that writes guest memory under late
tests fired in two cases where the early tests change nothing.
The first was a draw with no depth, stencil or depth-bounds test. Early
tests reject no pixel there, so every write the console makes still
happens. The target merge now carries whether the draw has such a
test, and the refusal applies only then. This adds one byte to the
version 40 merge fields of the recompile request.
The second was any GDS binding, including a shader that only reads GDS.
The refusal now looks for GDS writes, atomics, appends and consumes.
Tests: the depth and stencil decode checks the new flag, and the
static shader key depends on it. A counter-adding shader under late
tests compiles without a test and throws with one. A late-test merge
that reads GDS compiles, and one that adds to GDS throws.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
A merged 4_4_4_4 write runs its pixel shader after early depth and
stencil tests. Vulkan counts a sample for an occlusion query at those
tests, so pixels the guest shader kills under late tests would be
counted, and on the console they are not. Once the game has read an
occlusion counter the recorder counts samples for every later draw,
so from then on such a merge throws. The check runs where the recorded
and recipe draw paths prepare their inputs. The state records
DB_SHADER_CONTROL.KILL_ENABLE for it, which fits in the existing
padding.
The execution test starts sample counting and then checks two cases: a
merge that kills a checkerboard under late tests is refused, and a
merge that kills nothing still draws. A decode test reads KILL_ENABLE.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
A partial 4_4_4_4 write merges inside a pixel shader that declares
early fragment tests. When the guest runs the shader under late tests,
pixels that the depth or stencil test rejects still execute it on the
console, so their buffer and image stores, atomics and GDS operations
happen there. Under forced early tests they would be dropped. Such a
merge now throws, unless the guest asked for early tests itself. The
merged target's own image write does not count.
A recompile test checks two things for a merging shader that adds to a
buffer counter: under late tests it throws, and under the guest's early
tests it compiles with its one atomic add beside the merge. The same
shader without a merge still compiles under late tests.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
A one-sample target under a multisampled rasterizer whose
OVERRASTERIZATION_AMOUNT matches (radeonsi line and polygon smoothing)
decodes with mergedCoverage and is drawn through mixed-samples coverage
reduction onto its one-sample attachments. A merging draw leaves the
4_4_4_4 target out of the attachments, a combination that is not tested,
so a partial write of such a draw now throws; the limit is listed in the
technical debt file.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Occlusion counts are taken at the forced early tests, the refused merge
draws and why a late depth write was not used, and the one GPU the merge
was measured on.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
A CB resolve from a packed color target throws, so a 2-sample 4_4_4_4
target cannot be resolved by the color block.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
FreeBSD 11.4 kern_mprotect masks the argument with VM_PROT_ALL instead of
refusing it (sys/vm/vm_mmap.c:613). sceKernelMprotect already does this
since #5770; the POSIX mprotect export still failed with EINVAL.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
libusb's CMake generates version_describe.h by running gen-describe.ps1
with -ExecutionPolicy Bypass. An execution policy set by Group Policy
takes precedence over that switch, so with Restricted or AllSigned the
Windows build stops at version_describe.h. Describe the failure and a
.cmd stand-in, passed as LIBUSB_POWERSHELL_EXECUTABLE, that runs
gen-describe.sh with Git for Windows' bash as the PowerShell script does.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
On Windows the UCRT does not switch an r+, w+ or a+ stream from writing
to reading without fflush or fseek: fread after fwrite returned bytes of
the write buffer and the next flush wrote them over the file, and ungetc
failed on an update stream that was not already reading. On Linux glibc
does not switch either for ungetc, which pushes the byte back over the
pending write, drops the write and can corrupt the heap on the next read,
or for an fread of at least the buffer size, which drops the write and
reads from the old offset.
fread, fgetc, getc_unlocked, fgets, ungetc, ungetwc and fscanf now flush
pending output and mark the stream as reading first, as FreeBSD 11.4's
__srefill and __ungetc do, through _IO_switch_to_get_mode on glibc.
Writes directly after reads still go through the UCRT on Windows; the
gap is recorded in the libc technical debt.