Repository navigation
sync(upstream): integrate Batch 40 shader atomics, barycentric tessellation, and AGC resource fixes - #565
Conversation
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)
…for a null path (cherry picked from commit 274f092)
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
(cherry picked from commit 418d385)
(cherry picked from commit f07df07)
(cherry picked from commit 3f1dcad)
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)
(cherry picked from commit 432fe5c)
(cherry picked from commit 5070322)
(cherry picked from commit 256da96)
…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)
(cherry picked from commit a3ed32e)
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)
…iptors (cherry picked from commit c3c400a)
(cherry picked from commit 902b051)
(cherry picked from commit 27497f0)
(cherry picked from commit 5394684)
(cherry picked from commit fd87226)
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.
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configuration
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. Comment |
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_replayandanyps5_metal_guest_draw_replayfailed). To re-land boykopovar#6094 the bridge's BDA contract has to change first.Review fixes: the
"%p|%0"count incore/libs/tests/Formatting.cppis 5, not 4; the Metal driver now suppresses aflip'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.cppwere 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
tools/check_conventions.py --base origin/mainpass, 0 findings;git grep -nE '^(<<<<<<<|>>>>>>>)'empty.agc-mapbit-exact hash51a268f2e73efb9c(stable over the timed repeats);agc-live-map84 px against a main baseline dump (allowed 200, 0 timed repeats over);agc-menu67 px (allowed200, 0 timed repeats over). The unstable-hash warning on the two flickering frames is the known compute-shader race.
Findings
Formatting.cpp:204expected 5, not 4