ScrollView dropped every mouse event without the left button, so views inside
one never saw hovers or right clicks. This kept nested scroll views from
tracking hover for the mouse wheel, and GameButton's right-click info only
worked once a left click had set its hover flag.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
With touch or the mouse, the video started as soon as you pressed a game,
so watching it without launching the game took a careful drag-and-release.
Touch and mouse users can still see the video from the info button or a
long press.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The PSP's AVC decoder follows the H.264 output process (Annex C),
measured in the new pspautotests video/mp4/avchold on streams that
differ only in their headers, and video/mpeg/decodeend. With HRD
parameters and picture timing SEI, a picture comes out dpb_output_delay
after its access unit; Sony's movies have a one frame delay. Without, it
is bumped out of a buffer three frames deep, whatever the stream
declares. sceMpegAvcDecodeStop hands back what's left, and streams with
more than three reference frames are refused with 0x80628002.
We handed each picture back as soon as it was decoded. MGS Peace
Walker's movie player only checks for the end of a movie while its
clock is short of the movie's length, so its last picture landed right
on that limit and the game hung on a black screen after the cutscene.
ffmpeg still decodes the pixels, in display order; each access unit is
tagged with its index so frames can be matched back, and ffmpeg's H.264
parser supplies the picture timing. A call can now hand back several
pictures, as consecutive 0x2C byte descriptors the way mpeg.prx's
sceMpegAvcDecodeStop reads them, each in a frame buffer slot of its own
(reallocated when a savestate brings a block too small for that).
Not followed: with B-frames and no picture timing, the PSP can complete
several pictures in one call; here they come out one a call. All of
the game movies checked have picture timing.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Loading a savestate kept the current session's netAdhocInited,
netAdhocctlInited and matching-inited flags rather than the saved ones.
Loaded into a fresh boot, a state saved with adhocctl initialized (but not
connected) then failed every adhocctl call with NOT_INITIALIZED. MGS Peace
Walker shuts ad hoc down before a cutscene and retried
sceNetAdhocctlDisconnect forever, leaving the screen black.
Take the flags from the state, and bring the host side in line: start the
friendFinder and log in again when the state has adhocctl up and we don't,
stop it in the opposite case. Also save the product code, which that login
sends.
Also add a game.state.save debugger command, used to reproduce this.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The transposed extents f7ec86c5d5 worked around came from the size race
the previous commit fixed: with the size now applied between frames, the
workaround didn't fire once in 38 rotations on the Galaxy S8+ that hit it
in about one in four.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
backbufferResize comes from the UI thread, and changed g_display while the
render thread was drawing with it. Like iOS, it now leaves the new size for
the render thread to apply before its next frame, or applies it directly if
no render loop is running. A rotation in a resize that's superseded before
it's applied still forces the swapchain recreate.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
joystickAxis copies the axes in batches on the stack instead of allocating
per event, and bounds the count by the arrays it got. queryGameInfo's cache
is a local, in a helper so it's gone before the thread manager is torn down.
Removes Android_GetFreeSpaceByFilePath (never called) with its Java side, and
isLandscape, which only existed to call NativeGetAppInfo early.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- Scoped storage no longer flips on while no activity is registered: whether
legacy storage was preserved is fixed per install, so it's asked once.
- Free space reads as unknown (-1), not 0 bytes, without an activity.
- Strings from Java (file listings and info, crash history, the camera list,
the input debug string) go through GetJavaString, so names with characters
outside the BMP aren't mangled, and a null string can't crash the crash
history.
- Requests (inputbox, browse_*) whose command can't be delivered are failed
instead of left waiting forever.
- A font that fails to load uses the default typeface (-1) instead of font 0,
and is retried later if there was no activity yet. Missing exception checks
added in the text renderer.
- Method IDs and the storage callbacks are looked up once in JNI_OnLoad.
- Unknown permissions are logged correctly.
Also removes what was left of Moga support, the unused backbuffer format and
a stray MessageBox macro, and tidies System_GetCameraDeviceList.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The location permissions imply android.hardware.location as required,
on top of the .gps and .network subfeatures we already marked optional.
Also skip the permission prompt on devices without location hardware.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
RECORD_AUDIO implies android.hardware.microphone with required=true
unless declared otherwise, which hides the app from devices without one.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- Fixes#17608
Text fields took Ctrl or Cmd for copy/paste/undo; now it's Cmd on Apple
platforms and Ctrl elsewhere, as is Ctrl+F (Cmd+F) for game search. Word
delete in the search filter is Option+Backspace on Apple.
The ImGui debugger never got Super, so with ImGui's Mac Cmd/Ctrl swap,
its paste and other Ctrl shortcuts could not be reached at all on Mac.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The savedata tests printed the utility's results on every poll, so they
failed when PPSSPP's IO thread was caught partway through writing them.
They now print them once the utility reports FINISHED.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The hook on the decode function fixed hit-testing, but the solid color
picking frames could stay visible on screen, more so at high render
resolutions. Reading back at sceGeDrawSync(0), right after the game
waits for the pass, doesn't show them. Only the framebuffer the last
list drew to is read back. Rularia found and tested this at 10x on
ULJS00216.
The new ColorPickingDrawSyncReadback compat flag replaces the
ReplaceTables hook, and ULJS00247 (the third game's UMD) is added
alongside the others.
Co-Authored-By: Rularia <Rularia@outlook.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- Fixes#22514
The 3D investigation mode renders an ID picking pass into VRAM and reads
it back on the CPU to build the hit-test table. Hook the decode function
to flush the framebuffers to VRAM first, and force lower resolution for
effects to avoid stutter.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Big games fill 16 MB in normal play. It's now one constant shared by
every backend. ARM32's 32 MB branch range is the limit on going higher
there.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The native code space fills long before the arena did: Tekken 6 has it
30% full with the arena at 3%. The old limit was the 24 bits an emuhack
opcode had for the offset, which the block shadow no longer needs.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Shows the number of blocks, how full the native code space and the IR
arena are, and how many times each filling up cleared the cache.
The "Ran out of block numbers" message was logged for both of those, and
there is no block number limit. It now says which one filled up.
Also hide the GPU profile and allocator overlays by value on backends
that lack them. Cutting the last two off the list had been hiding the
framebuffer list since it was added after them.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
StopWebServer() only stopped a RUNNING server, while ShutdownWebServer()
joined in any state but STOPPED. Shutting down while the server was
still STARTING joined a thread nobody had told to stop, which then
entered its loop and never left. Stop it while STARTING too, and only
switch to RUNNING if no stop came in meanwhile.
Also make the report.ppsspp.org registration cancellable. It runs at
startup and every nine minutes, and couldn't be interrupted, so exiting
during a stalled one waited out its connect and 900s header timeouts.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
DualShock, DualSense and Switch Pro pads are read with a blocking
ReadFile on the input thread, and WM_DESTROY joins that thread. If the
pad stops sending reports the read never returns, so the window is gone
but the process stays. Cancel the thread's I/O until it stops, retrying
in case a cancel lands just before a read starts. This also covers the
synchronous writes the pads' shutdown does.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
MemoryMap_Shutdown deallocated each view, opening holes in the reserved
range, and then released the whole range. A mapping another thread got in
a hole meanwhile was unmapped along with it. On iOS that was Metal's
command buffer memory: headless crashed in vkQueueSubmit about a hundred
frame dumps into a launch. Map inaccessible pages over a released view
instead, so the range stays ours until ReleaseViewSpace.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Framebuffer ages are measured in flips, and the count carried over from
the previous game. Headless replaying several frame dumps in one process
(frametests.py --ios does, 100 per launch) then rendered a dump
differently from replaying it alone: Colin McRae Rally lost its car and
trees whenever any dump came before it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Fixes#22622
Escape is both the UI back key and the default pause key. The pause
screen listens to the control mapper, which UI screens pass keyboard
input to, so Escape in Settings closed Settings and the pause screen
under it at once, dropping straight back into the game. EmuScreen
already checks IsOnTop() for the same reason.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Recent gets the view mode and grid settings buttons. It has no path,
nothing to navigate, and its list comes from memory, so the path,
navigation and refresh stay out. Its old grid setting is no longer
migrated, like Games and Homebrew.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Tekken 6 draws its intro movie as one full-width sprite eight times, each
scissored to a 64-pixel strip. The fill cost model picked the thrashing
rate from the sprite's full 480-pixel width, charging ~51ms per frame, so
the game's sceGeDrawSync held it to 15fps. It plays at 30fps on a PSP.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
iOS only runs app bundles, so with HEADLESS=ON the iOS build makes
PPSSPPHeadless an app (org.ppsspp.headless) that starts UIKit and runs
the headless main on a thread with the arguments devicectl launched it
with. Vulkan only, and the IR interpreter since there's no JIT.
frametests.py --ios installs it, copies over the dumps the device lacks,
and compares each render with the host's Vulkan one like --adb does.
Each devicectl call costs a second or two, so the new --screenshot-dir
lets one launch render a batch of dumps.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
GetRootVolume() returns a relative path unchanged, so the path to create
came out empty: nothing was created, and it still returned true.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>