Cancelled runs show as failures on their commits, and PRs rarely get
pushed to often enough for it to pay off.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
FFmpeg has prebuilt libraries for every platform, 1.5 GB, and every job checked
all of it out, taking 2-3 minutes. checkout-submodules.sh fetches the other
submodules as before, and FFmpeg as a partial clone with a sparse checkout of
the given folders, plus the source headers since some builds have the ffmpeg
folder on the include path. A Linux x86-64 build gets 67 MB. Alpine, which
builds FFmpeg itself, gets the sources and none of the libraries.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Only five macOS jobs run at once, and with six, one waited about ten minutes
for a runner. The two builds take under five minutes each, a separate job
mostly added another checkout.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Keyed on the FFmpeg submodule, its build script and the Alpine release. Saves
the 3.3 minutes it took to compile it every run.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Actions cache was full (10 GB), mostly with caches saved by PR runs that only
that PR could restore, and the AppImage ccache had no size limit. Master's got
evicted, so even master builds found no cache and hit 0.3% of the time. PRs
still restore master's.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The test job needed the whole build matrix, so it only started once the slowest
build was done, though it only used three of its artifacts. Running the tests
right after those three builds also saves the artifact download and a second
round of package installs.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A zstd frame doesn't always declare its size, and a small one can expand to
gigabytes, so this is the limit that keeps a crafted dump from exhausting
memory. The largest section in the 1042-dump test set is 82 MB.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Follows up the command range validation:
- Don't require anything of the data commands' sizes or alignment. Version 2
dumps have empty VERTICES and CLUT commands, and old recorders didn't align
anything. Registers() drops a trailing partial word instead.
- Split register blocks bigger than the list buffer, which they overran.
- Clamp MEMCPYDATA and MEMSET to valid memory. Only their start was checked.
- Check the compressed sizes against the file, and the decompressed sizes
against what the frame declares, before allocating. Some version 5 dumps
leave the size out of the zstd frame; those are checked after decompressing.
- Don't let a large FRAMEBUF size wrap around in MarkNeededTargets.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
tvOS only does that with a Back press it gets to see, so the view controller
lets controller events through to UIKit while the top screen is top level
(the new TOP_LEVEL_CHANGED notification), and passes presses that aren't
keyboard keys on to super. Elsewhere Back stays ours.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Crafted ppdmp command ranges can extend past the decompressed push
buffer. Frame buffer playback can then copy adjacent host heap data
into emulated VRAM, exposing process memory through rendered output.
Validate each command's type, range, and minimum payload size before
constructing the replay executor.
ExtractZipContents checked each archive path for parent components
before removing stripChars. A name could become ../ only after
stripping and escape the install directory, allowing a crafted archive
to overwrite files in sibling PSP directories.
Validate both archive and output paths, and apply stripping consistently
when checking for overwrites.
Replaces the center-to-center scoring, which skipped a wide view between narrow
ones, since its center is far away even when its edge is right there. Now it
works like Android's FocusFinder: only views in the direction of the move are
candidates, ones in the origin's beam beat ones off to the side (going up or
down, unless those are in a nearer row), and otherwise the nearest wins, with
distance along the move weighted 13 times distance across it. Unlike Android,
the distance across is to the candidate's nearest edge rather than its center.
First/last and page moves keep their scoring.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Siri Remote setup builds on iOS too, the device type comes from the
interface idiom, and requests for things the platform says it lacks are
refused by checking the property. What's left ifdeffed is API tvOS doesn't
have at all. Reports say tvOS.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Generated from the iOS icon art by ios/generate_tvos_icons.py: the logo floats
over the background for the parallax effect.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The 2nd generation remote's ring has real direction buttons and a center
button, which take GCSupportsMultipleMicroGamepads. Its buttonA is pressed
along with all of them, which gave stray enters. Swiping is off for now, it
fought with the ring. The memory stick moves into a folder of its own, out
of the way of what the system keeps in Caches.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Tested on an Apple TV 4K. The micro gamepad's dpad buttons flicker with every
wobble on the touch surface, so read the finger position instead: swipes step
once per fixed distance, and clicks are arrows at the edges and enter in the
middle. The UI scale now matches a 1080p Android TV (320 dpi). b-tvos.sh
can sign, install and launch on a device.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Shares the iOS frontend, with camera, location, motion, photo/document
pickers, share sheet, clipboard, microphone, battery and rotation compiled
out. The view controller is a GCEventViewController, so controllers only
reach us through GCController, and the Siri Remote is read as a micro
gamepad and sent as arrow/enter/escape/back keys. tvOS has no persistent
storage besides NSUserDefaults, so the memory stick lives in Caches for now.
Configure with -DIOS_PLATFORM=TVOS. The MoltenVK submodule gets the tvOS
slice from the same stock v1.4.2 release.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
tvOS doesn't have sigaltstack, which broke the libretro tvOS build. The
exception handler now runs on the faulting thread's stack there.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
SDL3's Cocoa window already accepts file drags (as do the other SDL
video drivers), we just never handled SDL_EVENT_DROP_FILE.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
It's a submodule we don't patch, and at /W4 it produced a wall of
conversion warnings in every build.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
On iOS, the base search stepped up from 0x100000000 in 8MB increments,
right through the app's binary and early heap: about 100 failed
vm_remaps (each logged twice) every time a game started. On macOS,
Find4GBBase freed its probe allocation before the views were mapped.
Now the kernel picks a free range of exactly the span the views need,
which stays reserved and inaccessible, and the views are mapped over it
with VM_FLAGS_OVERWRITE. One try, no race, and the gaps between views
fault. Unmasked (macOS), ask for 4GB alignment first, which lets the
ARM64 JIT pointerify. The old search remains as a fallback.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
It checked views[i], the view that failed, instead of views[j], so after
a failed try it could release views it should skip, or skip ones it
should release.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Before Android 11, decorFitsSystemWindows(false) sets LAYOUT_STABLE, and
the system bar insets then keep the space of hidden bars. So in
landscape, where the status bar is always hidden, the UI had an empty
band at the top (seen on a Galaxy S8 and a Pocophone F1). Count only
the bars we show, and reapply the insets after changing that.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With 270 degree pre-rotation, the rotated y runs along the physical
height, but was clamped to the physical width, so scissors on the left
of the screen moved. This was #15773, which got that pre-rotation
disabled. The 90 degree case had the bounds swapped too, but only too
loose there.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The 270 degree pre-rotation was disabled in e6b7817cc6 for #15773 (UI
disappearing in reverse landscape on a Poco X3 Pro), which left reverse
landscape to the compositor, and every present returning SUBOPTIMAL. Try
it again: rotation is handled in place now, and the stale extent after a
rotation is fixed, so it needs retesting on Adreno.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Before Android 11, decorFitsSystemWindows(false) sets LAYOUT_STABLE, and
the system bar insets then keep the space of hidden bars. So in
landscape, where the status bar is always hidden, the UI had an empty
band at the top (seen on a Galaxy S8 and a Pocophone F1). Count only
the bars we show, and reapply the insets after changing that.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
On Android it's set on the Java UI thread right after writing g_display,
and read on the render thread, which then copies the dp size into the UI
bounds just once. With a plain bool the render thread could see the flag
before the new size.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Since rotation is handled in place, the swapchain is recreated right
after surfaceChanged, and the surface can still report the previous
orientation's extent. On a Galaxy S8+ this happened in about one in four
rotations, leaving a portrait swapchain on a landscape window or the
other way around, squashed into half the screen until the next rotation.
If the extent is exactly the window size transposed, use the window size.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>