android: run PS4 and PS5 titles on device - #14
Open
Force67 wants to merge 3 commits into
Open
Conversation
added 3 commits
July 27, 2026 22:01
The recompiler was compiled out of every Android build: delta/gpu gates it on pkg_check_modules finding SPIRV-Tools, which never resolves against the NDK sysroot, so DELTA_HAVE_SPIRV_BACKEND was undefined and every guest draw was dropped. Point PKG_CONFIG_LIBDIR at an NDK-built SPIRV-Tools to enable it; delta_gpu is a static library so only the library list propagates to the final link, and pkg-config hands back bare -l names when cross compiling, so resolve each entry to an absolute path. memfd_create is only declared by bionic at API 30 and we target 29, and the Android gfx backends were missing setTitle/overlaySetPerf.
The present blit stretched the framebuffer over the whole surface, so 16:9 content came out ~20% too wide on a 21:9 panel. The fit has to be solved in the landscape space the player sees and mapped back into image space for the blit: the swapchain image is portrait while the window is landscape, and the compositor scales each axis on its own rather than rotating. The controls were four hard-edged discs alpha-blended at a flat 0.40. They are now signed distance fields resolved with a pixel of coverage, and cover the pad the games actually need (twin sticks, d-pad, face buttons, shoulders, touchpad, options) instead of the four Isaac used. Layout is in height units so it keeps its proportions on any panel.
An adb-started Activity inherits no environment, so the DELTA_* knobs -- the emulator's whole debug interface -- were unreachable on Android, and with them DELTA_PS5_MODULES, without which no PS5 title can resolve a system module. android_main now reads <dataDir>/env.cfg and defaults DELTA_PS5_MODULES to the staged firmware. The launcher only browsed for .pkg, so PS5 titles could not be picked at all; it now takes .ffpkg and extracted game folders too. DELTA_ANDROID_LOGFILE tees the log pump to a file. logd drops bursts from a chatty uid and anything still in the pipe dies with the process, which is exactly when a crash dump is written. The activity was inset by the display cutout rather than using the whole panel.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
PS4 and PS5 titles now run on the phone through the NativeActivity app, at the
same point the host is at.
The load-bearing fix is that the Android build had no shader recompiler at all.
delta/gpuenables the direct SPIR-V backend only whenpkg_check_modulesfinds SPIRV-Tools and SPIRV-Headers, and neither resolves against the NDK
sysroot, so
DELTA_HAVE_SPIRV_BACKENDwas quietly undefined andRecompilewas compiled out. Every PS5 draw was dropped (
[agc] recompile FAILED ... draw dropped) and the frame was black. Building SPIRV-Tools with the NDK andpointing
PKG_CONFIG_LIBDIRat it turns the backend on; the CMake change hereis needed because
delta_gpuis a static library, so only the library listpropagates to the final link and pkg-config yields bare
-lnames when crosscompiling. Two smaller build breaks came with it:
memfd_createis onlydeclared by bionic at API 30 while we target 29, and both Android gfx backends
were missing
setTitle/overlaySetPerf.Presentation was a stretch to fill the surface, which made 16:9 content about
20% too wide on a 21:9 panel. Fitting it is not as simple as it looks: the
swapchain image is portrait while the window is landscape and the compositor
scales each axis independently instead of rotating, so the aspect fit is solved
in landscape screen space and the rect mapped back into image space for the
blit. Touch input and the overlay go through that same rect.
The touch controls were four hard-edged discs alpha-blended at a flat 0.40,
chosen around what Isaac needed. They are now signed distance fields resolved
with a pixel of coverage, laid out in height units so the pad keeps its
proportions on any panel, and cover twin sticks, a d-pad, the four face
buttons, shoulders, touchpad and options.
PS5 titles could not boot on Android at all: an adb-started Activity inherits
no environment, so
DELTA_PS5_MODULES(and every otherDELTA_*knob) wasunreachable.
android_mainreads<dataDir>/env.cfgbefore anything else anddefaults the PS5 module path to the staged firmware. The launcher only browsed
for
.pkg, so it now accepts.ffpkgand extracted game folders as well.DELTA_ANDROID_LOGFILEtees the log to a file, which is what made theremaining failures diagnosable: logd drops bursts from a chatty uid and
anything still in the pipe is lost when the process dies, which is exactly when
a crash dump is written.
Verified on a OnePlus 15 (SM8850, Android 16): PS4 Isaac in gameplay at ~265
fps, PS4 Undertale at 30 fps and interactive to the name-entry screen, PS5
Isaac Repentance in gameplay at 210-350 fps, all with zero unsupported opcodes
and driven entirely through the on-screen pad. Both Android configurations
(
DELTA_ANDROID_APPon and off) build, and each commit builds on its own. Thehost build is unaffected: it still resolves SPIRV-Tools to absolute paths and
keeps the backend enabled.
Dead Cells still does not get past
sceSysmoduleLoadModulefor libc, but itstops at the same place on the host, so it is not an Android regression. The
difference in symptom is that the SDK assert is stepped over by the
int 0x41/0x44/0x45handler in crash.cpp, which is#if defined(__x86_64__)and has no FEX equivalent, so the guest
ud2is fatal on ARM rather thanmerely hanging.