mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-14 15:00:30 +02:00
Android: Handle rotation and window resizing without recreating the activity
Every rotation, fold or window resize destroyed the activity and with it all of graphics, then built it all up again. Declare those config changes handled, so they arrive as a surfaceChanged and go through the same resize path as a desktop window resize. That path needed three things it didn't have on Android: - The GPU_DISPLAY_RESIZED message, left out for Android since 2020 when DeviceRestore covered every size change. - A fixed (hardware scaled) surface size is now recomputed on each in-place surface change, since surfaceCreated no longer runs on a rotation. - A 180 degree flip keeps the size but changes the surface transform, so the display rotation is passed along and a change in it is a resize too. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
1 parent
c7a2cb6f63
commit
d0e45b94d9
6 files changed
+52
-10
No files matched your search
+3
-1
@@ -1345,7 +1345,9 @@ void NativeFrame(GraphicsContext *graphicsContext) {
|
||||
g_screenManager->resized();
|
||||
|
||||
// TODO: Move this to the GraphicsContext objects for each backend.
|
||||
#if !PPSSPP_PLATFORM(WINDOWS) && !defined(ANDROID)
|
||||
// (Android used to be left out here, since every size change there was a full graphics restart,
|
||||
// and DeviceRestore covers it. Rotation and window resizing are in-place now.)
|
||||
#if !PPSSPP_PLATFORM(WINDOWS)
|
||||
PSP_CoreParameter().pixelWidth = g_display.pixel_xres;
|
||||
PSP_CoreParameter().pixelHeight = g_display.pixel_yres;
|
||||
System_PostUIMessage(UIMessage::GPU_DISPLAY_RESIZED);
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
<meta-data android:name="android.max_aspect" android:value="2.4" />
|
||||
<activity
|
||||
android:name=".PpssppActivity"
|
||||
android:configChanges="locale|keyboard|keyboardHidden|navigation|uiMode"
|
||||
android:configChanges="locale|keyboard|keyboardHidden|navigation|uiMode|orientation|screenSize|screenLayout|smallestScreenSize|density"
|
||||
android:theme="@style/ppsspp_style"
|
||||
android:launchMode="singleInstance"
|
||||
android:resizeableActivity="true"
|
||||
|
||||
@@ -940,8 +940,14 @@ extern "C" void Java_org_ppsspp_ppsspp_NativeApp_shutdown(JNIEnv *, jclass) {
|
||||
INFO_LOG(Log::System, "NativeApp.shutdown() -- end");
|
||||
}
|
||||
|
||||
extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeApp_backbufferResize(JNIEnv *, jclass, jint pixel_xres, jint pixel_yres, jint format) {
|
||||
INFO_LOG(Log::System, "NativeApp.backbufferResize(%d x %d)", pixel_xres, pixel_yres);
|
||||
extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeApp_backbufferResize(JNIEnv *, jclass, jint pixel_xres, jint pixel_yres, jint format, jint rotation) {
|
||||
INFO_LOG(Log::System, "NativeApp.backbufferResize(%d x %d, rotation %d)", pixel_xres, pixel_yres, rotation);
|
||||
|
||||
// The display's Surface.ROTATION_*. A 180 degree flip changes this but not the size, and the swapchain
|
||||
// still needs recreating, for the pre-rotation.
|
||||
static int lastRotation = -1;
|
||||
const bool rotated = lastRotation != -1 && rotation != lastRotation;
|
||||
lastRotation = rotation;
|
||||
|
||||
int old_w = g_display.pixel_xres;
|
||||
int old_h = g_display.pixel_yres;
|
||||
@@ -966,8 +972,8 @@ extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeApp_backbufferResize(JNIEnv
|
||||
INFO_LOG(Log::G3D, "RecalcDPI: g_dpi=%d scaled_dpi_x=%f scaled_dpi_y=%f display_scale_x=%f display_scale_y=%f g_dpi_scale_x=%f g_dpi_scale_y=%f dp_xres=%d dp_yres=%d",
|
||||
display_dpi, dpi_x, dpi_y, display_scale_x, display_scale_y, g_display.dpi_scale_x, g_display.dpi_scale_y, g_display.dp_xres, g_display.dp_yres);
|
||||
|
||||
if (new_size) {
|
||||
INFO_LOG(Log::G3D, "Size change detected (previously %d,%d) - calling NativeResized()", old_w, old_h);
|
||||
if (new_size || rotated) {
|
||||
INFO_LOG(Log::G3D, "%s detected (previously %d,%d) - calling NativeResized()", new_size ? "Size change" : "Rotation change", old_w, old_h);
|
||||
NativeResized();
|
||||
} else {
|
||||
INFO_LOG(Log::G3D, "NativeApp::backbufferResize: Size didn't change.");
|
||||
|
||||
@@ -41,7 +41,9 @@ public class NativeApp {
|
||||
public static native int getDesiredBackbufferHeight();
|
||||
|
||||
public static native void setDisplayParameters(int display_xres, int display_yres, int dpi, float refreshRate);
|
||||
public static native void backbufferResize(int bufferWidth, int bufferHeight, int format);
|
||||
// rotation is the Surface.ROTATION_* of the display. A change in it alone (a 180 degree flip) keeps the size
|
||||
// but the swapchain still has to be recreated, for the pre-rotation.
|
||||
public static native void backbufferResize(int bufferWidth, int bufferHeight, int format, int rotation);
|
||||
|
||||
public static native boolean isLandscape();
|
||||
public static native boolean isAtTopLevel();
|
||||
|
||||
@@ -111,6 +111,9 @@ public class PpssppActivity extends AppCompatActivity implements SensorEventList
|
||||
// switched-away from or rotated etc.
|
||||
private boolean shuttingDown;
|
||||
|
||||
// surfaceChanged now also fires for rotations and resizes, where the thread just keeps going.
|
||||
private boolean renderLoopRunning = false;
|
||||
|
||||
// Allow for multiple connected gamepads but just consider them the same for now.
|
||||
// Actually this is not entirely true, see the code.
|
||||
private final ArrayList<InputDeviceState> inputPlayers = new ArrayList<>();
|
||||
@@ -898,10 +901,15 @@ public class PpssppActivity extends AppCompatActivity implements SensorEventList
|
||||
return;
|
||||
}
|
||||
|
||||
if (renderLoopRunning) {
|
||||
Log.i(TAG, "startRenderLoopThread: already running, surface changed in place");
|
||||
return;
|
||||
}
|
||||
|
||||
Log.w(TAG, "startRenderLoopThread: Starting thread");
|
||||
|
||||
applyFrameRate(mSurface, 60.0f);
|
||||
runRenderLoop(mSurface);
|
||||
renderLoopRunning = runRenderLoop(mSurface);
|
||||
}
|
||||
|
||||
private synchronized void joinRenderLoopThread() {
|
||||
@@ -915,6 +923,7 @@ public class PpssppActivity extends AppCompatActivity implements SensorEventList
|
||||
// This will wait until the thread has exited.
|
||||
Log.i(TAG, "requestExitRenderLoop");
|
||||
requestExitRenderLoop();
|
||||
renderLoopRunning = false;
|
||||
}
|
||||
|
||||
void setupSystemUiCallback() {
|
||||
@@ -1085,7 +1094,8 @@ public class PpssppActivity extends AppCompatActivity implements SensorEventList
|
||||
@Override
|
||||
public void onConfigurationChanged(@NonNull Configuration newConfig) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
Log.i(TAG, "onConfigurationChanged");
|
||||
Log.i(TAG, "onConfigurationChanged: orientation=" + newConfig.orientation + " density=" + newConfig.densityDpi
|
||||
+ " screen=" + newConfig.screenWidthDp + "x" + newConfig.screenHeightDp + "dp");
|
||||
if (m_hasNoNativeBinary) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -110,9 +110,31 @@ public class SizeManager implements SurfaceHolder.Callback {
|
||||
|
||||
Log.i(TAG, "Surface changed. Resolution: " + width + "x" + height + " Format: " + format);
|
||||
// The window size might have changed (immersive mode, native fullscreen on some devices)
|
||||
NativeApp.backbufferResize(width, height, format);
|
||||
updateDisplayMeasurements();
|
||||
|
||||
// A rotation or a window resize no longer recreates the activity, so a fixed-size (hardware scaled)
|
||||
// surface has to be re-fixed here for the new display size and aspect. The fixed size is what the
|
||||
// surface will report, so only do it when it doesn't already match, or this would loop.
|
||||
if (!holder.isCreating()) {
|
||||
Point newDesired = new Point();
|
||||
getDesiredBackbufferSize(newDesired);
|
||||
boolean fixed = desiredSize.x > 0 && desiredSize.y > 0;
|
||||
boolean wantFixed = newDesired.x > 0 && newDesired.y > 0;
|
||||
if (wantFixed && (newDesired.x != width || newDesired.y != height)) {
|
||||
Log.i(TAG, "Display changed, re-fixing surface size to " + newDesired.x + " x " + newDesired.y);
|
||||
desiredSize.set(newDesired.x, newDesired.y);
|
||||
holder.setFixedSize(newDesired.x, newDesired.y);
|
||||
return; // Another surfaceChanged is coming, with the new size.
|
||||
} else if (!wantFixed && fixed) {
|
||||
Log.i(TAG, "Display changed, surface no longer needs a fixed size");
|
||||
desiredSize.set(0, 0);
|
||||
holder.setSizeFromLayout();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
NativeApp.backbufferResize(width, height, format, activity.getWindowManager().getDefaultDisplay().getRotation());
|
||||
|
||||
if (!paused) {
|
||||
activity.notifySurface(holder.getSurface());
|
||||
} else {
|
||||
|
||||
Reference in new issue
Block a user