The blit that puts a generated frame on screen named VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL for an image that was never in that layout, and read it without ever taking ownership from the device that wrote it. framegen releases its outputs with newLayout = VK_IMAGE_LAYOUT_GENERAL and dstQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL, so this was a layout mismatch and a missing queue-family acquire at the same time. Undefined by the specification either way, and on a tiler the practical result is reading whatever survived in cache instead of what framegen wrote -- which is the corrupted rendering that appears whenever frame generation is switched on. The image is acquired from VK_QUEUE_FAMILY_EXTERNAL into the graphics family and transitioned GENERAL -> TRANSFER_SRC_OPTIMAL before the blit, then released back the same way afterwards, because framegen's own acquire barrier on the next generation assumes it finds the image exactly as it left it. This is about visibility and ownership, not timing: generate() already does not return until framegen's submission has completed.
ARMSX3
Uses the latest RPCS3 upstream code (the recent ARM64 improvements included).
Building
arm64-v8a and armv8.2 is supported. You need the Android SDK with NDK r27 or newer, CMake 3.30 or newer, and a JDK 17. Android Studio ships all of these.
Clone with submodules, then fetch the two third party checkouts that are not submodules:
git clone --recursive https://github.com/ARMSX2/ARMSX3.git
cd ARMSX3
git clone https://github.com/SnowflakePowered/librashader 3rdparty/librashader
git clone https://github.com/bylaws/libadrenotools android/armsx3-ui/app/src/main/cpp/libadrenotools
Build the core. This is the long part and produces an unstripped library of around 1.3 GB:
export ANDROID_HOME=$HOME/Library/Android/sdk
cmake -B build-android -G Ninja \
-DCMAKE_TOOLCHAIN_FILE=$ANDROID_HOME/ndk/<version>/build/cmake/android.toolchain.cmake \
-DANDROID_ABI=arm64-v8a -DANDROID_PLATFORM=android-31 \
-DCMAKE_BUILD_TYPE=RelWithDebInfo
cmake --build build-android --target rpcsx-android -j8
Strip it and put it where the app expects it:
llvm-strip --strip-unneeded build-android/android/libarmsx3-core.so
cp build-android/android/libarmsx3-core.so \
android/armsx3-ui/app/src/main/jniLibs/arm64-v8a/
Then build the app:
cd android/armsx3-ui
export JAVA_HOME="/Applications/Android Studio.app/Contents/jbr/Contents/Home"
./gradlew :app:assembleRelease
The apk lands in app/build/outputs/apk/release/.
Note that the core library has to be rebuilt and copied again whenever anything under rpcs3/ or android/src/ changes. Gradle does not build it for you.
The Discord Social SDK is proprietary and is not redistributed here. Get it from Discord's developer portal and drop it in app/libs/ and app/src/main/cpp/discord_sdk/ if you want that feature. The build skips it otherwise.
Running it needs PS3 firmware, which is not included. License
GPL-2.0-only, the same as RPCS3. See LICENSE. Some files may be licensed differently, check the file headers.
Based on RPCS3, https://github.com/RPCS3/rpcs3