Skip to content

sync(upstream): integrate Batch 40 shader atomics, barycentric tessellation, and AGC resource fixes - #565

Merged
RINNECODER merged 111 commits into
mainfrom
team/upstream40
Oct 18, 2026
Merged

RINNECODER merged 111 commits into
mainfrom
team/upstream40

Conversation

@RINNECODER

Copy link
Copy Markdown
Owner

Summary

Upstream sync batch 40: 111 commits / 67 upstream PRs on top of main, plus 2 fork slice fixes, 5 integration commits,
the rebase reconciliation and the review fixes. Slices: libkernel/relinker (27 picks), libc/SystemService/JobManager/
AGC execution (22 picks, 1 reverted), shader recompiler (15 picks, 2 reverted), AGC graphics (22 picks), AGC
resources (16 picks).

Highlights: boykopovar#7024 boykopovar#7108 boykopovar#7114 (EFAULT for null buffers), boykopovar#7092 boykopovar#7140 boykopovar#7151 (sockets), boykopovar#7095 (sysarch and GS base),
boykopovar#7123 (thread frame chains), boykopovar#3186 (JobManager compute), boykopovar#7184 (BDA-table store scan), boykopovar#7207 (11_11_10 float
targets), boykopovar#7330 boykopovar#7487 and the barycentric-emulation tessellation route, boykopovar#7374 (last provoking vertex for geometry
programs), boykopovar#7016, boykopovar#7312, boykopovar#7337, boykopovar#7189, boykopovar#7573, and the FreeBSD poll/select behaviour for files, the random device,
descriptors 0-2 and kqueues.

Reverted at integration: boykopovar#7356 (the fork already defines those math exports) and boykopovar#6094 with its test (the direct
32-bit atomic path no longer references the BDA fault buffer, so the Metal bridge refuses the module with "BDA ABI
requires page-table or fault-buffer descriptor metadata"; anyps5_metal_rect_replay and
anyps5_metal_guest_draw_replay failed). To re-land boykopovar#6094 the bridge's BDA contract has to change first.

Review fixes: the "%p|%0" count in core/libs/tests/Formatting.cpp is 5, not 4; the Metal driver now suppresses a
flip's end-of-pipe event on a queue that raises its own RELEASE_MEM interrupts, as the Vulkan driver does since
2aa6bfc (the interrupt callback reports whether it reached the title, and every Metal replay call site returns
true as the game's callback does); the unused includes in PreparedPublication.cpp were dropped.

Rebase reconciliation: the rebase kept the pre-rebase side of four conflicting files and re-added one test block
main already had. The main-side content the picks had replaced is restored (the ADX lowering include and matcher,
the shader cache format version 40, the Metal driver's pending-write APIs) and only one copy of the pthread
frame-chain test target remains. The branch's DepthSurface marker fix came back redundant and was dropped.

Validation

  • Conventions: tools/check_conventions.py --base origin/main pass, 0 findings; git grep -nE '^(<<<<<<<|>>>>>>>)' empty.
  • Rosetta CTest (x86_64): 25/25 passed.
  • Native Metal CTest (arm64, guest-replay): 63/63 passed.
  • Replay gate under the AGC lock: agc-map bit-exact hash 51a268f2e73efb9c (stable over the timed repeats);
    agc-live-map 84 px against a main baseline dump (allowed 200, 0 timed repeats over); agc-menu 67 px (allowed
    200, 0 timed repeats over). The unstable-hash warning on the two flickering frames is the known compute-shader race.

Findings

Finding Severity Resolution
Formatting.cpp:204 expected 5, not 4 P2 fixed
Metal path missing the flip end-of-pipe suppression P2 fixed
unused includes and declaration nit fixed

milescoviello and others added 30 commits October 18, 2026 18:06
kevent threw for NOTE_LOWAT. On a socket's EVFILT_READ it now sets the
low-water mark as FreeBSD 11's filt_soread does: the event fires once the
buffered bytes reach it, or at end of file or on a listening socket, and
a later change of the knote replaces it. EVFILT_WRITE takes a mark of 1,
where the host's writability stands in for a free byte; other write marks
and marks below 1 still throw. A pipe ignores the mark, as filt_piperead
does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit e1d4ccb)
…titimer

setitimer refuses to arm the CPU interval timers and already reads and
disarms them as zero, so they are never armed. getitimer threw for them
instead of reporting that state, as FreeBSD's kern_getitimer does for a
timer that is not set.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 9f704dc)
FreeBSD's fstat looks the descriptor up before it copies the result
out, so a bad descriptor still fails with EBADF and an open one fails
with EFAULT when sb is null. fstat and sceKernelFstat threw
std::invalid_argument instead.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit be17961)
…troy for a null attribute

Both threw std::invalid_argument for a null or uninitialized attribute.
FreeBSD's libthr returns EINVAL for one, as the other scePthread
attribute calls here already do. The clock id is still stored as
given.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 62ac8d6)
…ream sockets

On Linux, FIONREAD on a datagram socket reports the next datagram only,
where FreeBSD's sbavail counts every queued byte, so a read mark above 1
there could never fire. kevent now throws for it as before; stream
sockets and marks of 1 are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 91fbafd)
… zero record

Unreal Engine walks the frame-pointer chain until it reads a return
address of 0 and never checks the frame pointer itself. Guest threads
started with whatever rbp the host code held, so the walk ran into host
start-up frames (glibc's saved rbp 0x21 in a LEGO Batman core dump,
address 8 in Returnal on Windows) and faulted. Fibers ended their chain
with a null frame, and makecontext started its function with rbp 0, so
the same walker read address 8 there too.

Guest threads now start through a thunk that points rbp at a
{saved rbp 0, return address 0} record, as the relinker's entry stub
does for the main thread; the fiber trampolines push the same record,
and the makecontext start function is built with frame pointers so its
frame, over the zero return address makecontext stores, ends the chain.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit ff9bf22)
sceKernelGetdirentries on a descriptor that is not a directory returned
ENOTDIR from the host getdents64 on Linux, and ENOTDIR for every descriptor
missing from the directory table on Windows, including invalid ones.
FreeBSD 11.4's kern_getdirentries returns EINVAL when the vnode is not a
directory.

Return EINVAL for a regular file on both hosts and EBADF for an invalid
descriptor on Windows. Test getdents and getdirentries on a regular file and
list the pipe case, which still fails with ESPIPE on Linux, in the library's
technical debt file.

Written with AI assistance (Claude).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
(cherry picked from commit 9dc6542)
socket() returned EPROTONOSUPPORT for every socket type it does not create.
FreeBSD 11.4's socreate returns EPROTOTYPE when no protocol is found, the
protocol is 0 and the type is not 0, and EPROTONOSUPPORT when a protocol was
given. Its inet domain (in_proto.c) has SOCK_RAW entries in every kernel and
a SOCK_SEQPACKET entry only with SCTP, and no SOCK_RDM or other type.

Return EPROTOTYPE for a type the inet domain never has, such as SOCK_RDM,
with protocol 0. SOCK_RAW and SOCK_SEQPACKET keep EPROTONOSUPPORT, since
whether the console creates them is not known. Test the unknown types and
mismatched protocols for AF_INET and AF_INET6, and list the socket types and
families that are not created in the library's technical debt file.

Written with AI assistance (Claude).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit a6c123c)
…d rename for a null path

(cherry picked from commit 7bb7608)
PSFlyCast (PPSA99247) imports pthread_condattr_setpshared (3BpP850hBT4)
from libkernel and fails to load without it:
"./app.elf: symbol lookup error: ./app.elf: undefined symbol: 3BpP850hBT4".

The attribute stores PTHREAD_PROCESS_PRIVATE (0) or
PTHREAD_PROCESS_SHARED (1); a null or uninitialized attribute and any
other value return EINVAL without changing it, following FreeBSD 11
libthr thr_condattr.c and pthread_mutexattr_setpshared here. Sharing
across processes is not modeled, as for mutexes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Sovthwyu4H63RMbRVha2Sy
(cherry picked from commit 05b457d)
The Wine port (PPSA99995) ships an ntdll module that imports sysarch
(b7uXQmnfB2s). libkernel did not export it, so loading stopped with
"undefined symbol: b7uXQmnfB2s" before the title ran.

Export sysarch as a stub that reports that it is not implemented: the
title loads and runs its launcher without calling it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 162f4af)
sysarch's AMD64_GET_FSBASE, AMD64_GET_GSBASE and AMD64_SET_GSBASE now
follow FreeBSD 11's amd64 sysarch on Linux x86-64 through arch_prctl: the
GS base is the calling thread's, a base at or above VM_MAXUSER_ADDRESS
returns EINVAL and a null argument EFAULT. AMD64_SET_FSBASE, whose base
guest and host code share for their TLS, other operations and other hosts
still throw. Wine sets its TEB this way.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit d7c83db)
…dule

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 70ff799)
…attr_setpshared

Measured on a PS5 (firmware 12.70): the getter reports 0, and of the
values 0, 1, 2 and -1 the setter accepts only 0 and checks the value
before the attribute. A null or uninitialized attribute, or a null
output, crashes the console; here it throws.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit bdf3adb)
…pshared and add pthread_condattr_getpshared

On a PS5 (firmware 12.70), of the values 0, 1, 2 and -1,
pthread_condattr_setpshared accepts only 0 and leaves the attribute
unchanged otherwise. pthread_condattr_getpshared reports 0 and returns
EINVAL for a null, uninitialized or destroyed attribute, also with a
null output. With an initialized attribute a null output crashes the
console; here it throws.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit c00c58a)
poll threw for any descriptor that is neither a socket nor a pipe, so a title polling a file it also reads stopped there. FreeBSD 11.4 hands a vnode to VOP_POLL, and both vop_stdpoll and vop_nopoll return POLLIN, POLLRDNORM and POLLOUT of the requested events for every event poll accepts and never POLLPRI, POLLRDBAND or POLLWRBAND. A file, a directory or a file read from app0.zar now answers that without a host call. File::IsVnode tells such a descriptor apart from the host file type without throwing, so a host socket lent by libSceNet still reaches its own path.

(cherry picked from commit 7e26c1a)
poll threw for /dev/random and /dev/urandom, which select already treats as ready. FreeBSD 11.4's randomdev_poll, once the device is seeded, narrows a request that has POLLIN or POLLRDNORM to those bits and returns any other request whole, POLLOUT and the band bits included. poll now answers that, and the test that relied on the random device throwing uses a kqueue descriptor, which poll still does not support.

(cherry picked from commit d0c3385)
…SD's poll routines do

selscan asks a descriptor once, with the flags of every set it is in (POLLRDNORM for the read set, POLLWRNORM for the write set, POLLRDBAND for the exception set, plus POLLHUP and POLLERR), and marks each set whose flags the answer shares. A seeded random device's randomdev_poll narrows a request with POLLRDNORM to that bit and returns any other request whole, so in the read set it is readable and in no other set, and otherwise it is in each write and exception set it was asked in; select reported it readable and writable together and never exceptional. A regular file or directory went to the host poll, which on Windows threw; vop_stdpoll makes it readable and writable and never exceptional, which select now answers in process on every host, as poll does.

(cherry picked from commit aabd0e7)
…t uses

select takes descriptors 0 to 2 as a console title's terminal with no input: 0 is never readable and 1 and 2 are always writable. poll threw for them unless the host happened to attach a pipe, so the same title could select on its standard streams but not poll them. poll now gives the same answer, with POLLOUT, the one bit ttydev_poll reports for a writable terminal, for 1 and 2 and nothing for 0.

(cherry picked from commit 7462945)
A kqueue descriptor is readable while one of its events is triggered and
is never writable or exceptional, as FreeBSD's kqueue_poll answers, on
both hosts. On Windows select threw for it, and on Linux its /dev/null
placeholder was reported readable and writable.

A descriptor that stops being a socket, a kqueue or a pipe during the
wait now fails the call with EBADF when it was closed and is selected
again with the rest of the timeout when its number was reused, as
FreeBSD's kern_select looks every descriptor up again in each pass,
instead of throwing. On Windows a host descriptor that is not a pipe
throws when select starts, before waiting.

Depends on boykopovar#7139.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 6d4c7c3)
The tests build their working directories with tempfile.TemporaryDirectory()
and std::filesystem::temp_directory_path(), so every executable they generate
lands in the user's system temp directory. On Windows, Microsoft Defender
quarantines those generated binaries as Trojan:Win32/Wacatac.H!ml, and the
nine tests that run one fail with WinError 5 (access denied) on a clean
checkout: autorun_exit_status, optional_plt, empty_tls, tls_function_coverage,
executable_segments, windows_icon, guest_needed_modules,
guest_module_directories and windows_import_modules.

Point TMPDIR, TEMP and TMP at a build-local directory for every test
registered here, so generated executables stay inside the build tree. Test
artifacts are then removed with the build directory, and a contributor who
needs an antivirus exclusion can scope it to the build tree instead of the
system temp directory.

(cherry picked from commit 39dd854)
…e environment

set_tests_properties replaced the ASAN_OPTIONS that add_asan_test_options appends to
guest_module_args, guest_deferred_dependencies and guest_module_fini in ASan builds.
Append the TMPDIR, TEMP and TMP settings instead.

(cherry picked from commit 5e340fa)
…'s read event

A read event on a listening socket took its data from FIONREAD, which a listening socket refuses on Linux, so kevent and sceKernelAddReadEvent reported 0 connections while saying one was ready. FreeBSD 11.4 gives a listening socket filt_solisten, which reports so_qlen, the completed connections waiting for accept. Ready now checks SO_ACCEPTCONN and on Linux reads a TCP listener's accept backlog from TCP_INFO, where tcp_get_info puts it in tcpi_unacked; with no host call for the count (Windows, macOS, a listener that is not TCP) it reports 1, the lower bound the readiness already implies.

(cherry picked from commit b40e0bf)
Rosetta sets RDTSCP's ECX to its constant TSC_AUX, 0xAAAAAAAB, which is
not a processor index. --to-rosetta already makes RDPID return processor
0 for the same reason, so code reading the processor through RDTSCP saw
a different value from code reading it through RDPID.

--to-rosetta now moves RDTSCP into an optional stub that runs the
instruction unchanged and then loads 0 into ECX with a MOV, which
leaves the counter in EDX:EAX and the flags as they were. A site with no
movable instruction after it for the jump is kept, as for RDPID. The
Intel target and a plain relink are unchanged.

(cherry picked from commit 57e52c1)
Converted guest modules never ran their DT_PREINIT_ARRAY entries: the
reader validated the array and the unused-NID filter kept its targets,
but no writer emitted or ran it. ld.so runs a shared object's preinit
array only for the main executable, so the Linux output runs the
entries from the DT_INIT stub before the module initializer; the macOS
and Windows outputs run them before the initializer in their startup
stubs, and the deferred Windows output exports a thunk that runs them
before the initializer for runtime-loaded modules. A module with a
preinit array and no initializer is still rejected, since the Linux
stub exists only with one.

(cherry picked from commit 9c43211)
The Windows deferred preinit thunk pushed r12, r13 and r14 and then
popped r12, r13 and r14, so the caller got r12 and r14 back swapped.
InitializeDeferredModule keeps the module base, table and count live
across the call to the thunk, so a compiler that keeps any of them in
r12 or r14 sees corrupted loader state after opening a deferred module
that has a preinit array. Pop in reverse push order instead and pin the
new bytes in test_guest_preinit.

(cherry picked from commit 6574ade)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
(cherry picked from commit e751268)
…ockets::Stat

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DgW4n3qYgi5jAAohEmXRQj
pushkarreddyy and others added 25 commits October 18, 2026 18:06
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 724b166)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 86b05a0)
…by a depth clear

A compute kernel that stores one colour to every texel of a storage image over a depth plane (a shadow atlas clear) copied
the whole plane depth image -> staging buffer -> mirror before the dispatch and mirror -> staging buffer -> depth image
after it, although the kernel reads nothing and writes every texel.

A dispatch of the 15-word 8x8x1 image clear kernel (direct, no partial last group) whose T# lies on a depth surface now
reads its colour from guest memory under the GPU mutex, the place the kernel reads it. When the dispatch covers the whole
plane, the plane is one layer of level 0, the colour is a value the plane's format holds exactly (0 or 1 for a 16-bit
unorm view, 0 or 0xffff for a 16-bit uint view, 0 or a normal float in (0, 1] for a 32-bit view) and nothing is waiting to
write the colour, the dispatch still writes the mirror but the copy-in is left out, and the copy-out becomes a clear of the
depth image to that value. The colour is read again when the copy-out is replaced; a changed value keeps the copy-out.
Every other dispatch, stencil planes and declined values keep both copies.

agc_driver_depth_clear_hle_tests runs the clear sequences with the clear taken and with the copies, and compares the depth
image texel by texel through the mirror, the guest memory and the depth tests.

(cherry picked from commit c05b256)
Halve the grown bound (not below 1024 entries) once a window of the
bound's uses times a shrink window was served by at most a quarter of
it, and reset the bound on Clear(). The shrink window starts at 8 and
doubles (up to 1024) each time growth undoes the last shrink, so a set
of keys that comes back over a longer span stops the bound from
oscillating. The entries over the bound leave at the next insert, with
the other evictions.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XBXM4pgkMHYEtqN1EQni2P
(cherry picked from commit bea4be8)
The test now sets a base bound of 32 entries and a first shrink window
of 2 (ResourceCache::SetBase, applied at the next Clear()) and turns
dispatch recipes off, so every dispatch goes through the cache: grow,
shrink, regrow, backoff and the Clear() reset take about 1.2k
dispatches instead of about 100k.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XBXM4pgkMHYEtqN1EQni2P
(cherry picked from commit f27ad68)
Guard incomplete imports and preserve mutation waiter errors and progress.

Follow-up to boykopovar#2575; refs boykopovar#2352.

(cherry picked from commit 3047980)
f68ab45 duplicates definitions the fork already has (redefinition errors).

This reverts commit 17ab20050c90dc27998251019972ea3df1de2dac.
…ycentric stages include

Brings only SpirvClipDistances.hpp from upstream 2b9c131 (its rect-list
stage changes stay skipped), and adds samplerCoordinatesIgnored to the Metal
ConversionKey now that DescriptorBinding carries it (size assert 448 -> 472).
…ch 40 picks

- Split the chunked ShaderRegistry container members into ShaderRegistryChunks.cpp
  so the Metal replay build (which does not compile ShaderRegistry.cpp) links them.
- MetalDriver rebuilds the filtered registry instead of erasing through the const
  entries the chunked registry hands out.
- Socket.cpp: declare GuestEbadf, used by the Unknown-revents select path.
boykopovar#6094)

cde860417 stops the direct 32-bit buffer atomic path from referencing the
BDA fault buffer, so modules keep a BDA ABI version without page-table or
fault-buffer metadata and the Metal shader bridge refuses them
(anyps5_metal_rect_replay and anyps5_metal_guest_draw_replay fail). Reverted
with its test d35a29a92 until the bridge's BDA contract accounts for it.

This reverts commits d35a29a92 and cde860417.
- tests: the "%p|%0" count is 5 characters, not 4.
- Metal: suppress the flip end-of-pipe event on a queue that raises its own
  RELEASE_MEM interrupts, as the Vulkan driver does since 2aa6bfc; the
  interrupt callback now reports whether it reached the title.
- tests: drop the includes and the declaration the review found unused.
The rebase kept the pre-rebase side of four conflicting files and re-added
one test block main already had. Restore the main-side content the picks
had replaced (the ADX lowering include and matcher, the shader cache
format version, the Metal driver's pending-write APIs) and keep one copy
of the pthread frame-chain test target.
…callbacks

The Metal driver's interrupt callback now answers whether the event
reached the title, so every Configure call site in the Metal replays
returns true as the game's callback does.
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ⚠️ Failed 2026-10-18T23:30:10.258193Z db16c7a PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

@coderabbitai

coderabbitai Bot commented Oct 18, 2026

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 1c9db37a-a6f6-4ade-94e4-f5be683372fc
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@RINNECODER
RINNECODER merged commit 2ac97dd into main Oct 18, 2026
1 check passed
@RINNECODER
RINNECODER deleted the team/upstream40 branch October 18, 2026 23:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.