From a2869a47cd7eeeac365ffd19cdf1df3d5029eada Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 8 Oct 2026 21:51:35 +0200 Subject: [PATCH] Android: Re-report the surface when the display density changes Now that density is in configChanges, a density change no longer recreates the activity - but it also doesn't resize the surface, so no surfaceChanged follows it. The DPI is only recalculated in backbufferResize, so the UI kept the old scale until the next real resize or a trip through the background. Re-report the surface we already have when the density has moved. The native side needs no change: Recalculate() already returns true when the dp size changes, which a density change does on its own. Also make the log line say which size changed, since the pixel size now stays put in this case. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01152igCdjTNhT29qvphPyPC --- android/jni/app-android.cpp | 6 +++- .../ppsspp/ppsspp/NativeSurfaceManager.java | 31 ++++++++++++++++++- .../src/org/ppsspp/ppsspp/PpssppActivity.java | 3 ++ 3 files changed, 38 insertions(+), 2 deletions(-) diff --git a/android/jni/app-android.cpp b/android/jni/app-android.cpp index 777b3a0ecc..5b6f4c50cd 100644 --- a/android/jni/app-android.cpp +++ b/android/jni/app-android.cpp @@ -951,6 +951,8 @@ extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeApp_backbufferResize(JNIEnv int old_w = g_display.pixel_xres; int old_h = g_display.pixel_yres; + int old_dp_w = g_display.dp_xres; + int old_dp_h = g_display.dp_yres; // pixel_*res is the backbuffer resolution. backbuffer_format = format; @@ -973,7 +975,9 @@ extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeApp_backbufferResize(JNIEnv 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 || rotated) { - INFO_LOG(Log::G3D, "%s detected (previously %d,%d) - calling NativeResized()", new_size ? "Size change" : "Rotation change", old_w, old_h); + // Note that a density change moves the dp size while the pixel size stays put. + INFO_LOG(Log::G3D, "%s detected (previously %dx%d px, %dx%d dp) - calling NativeResized()", + new_size ? "Size change" : "Rotation change", old_w, old_h, old_dp_w, old_dp_h); NativeResized(); } else { INFO_LOG(Log::G3D, "NativeApp::backbufferResize: Size didn't change."); diff --git a/android/src/org/ppsspp/ppsspp/NativeSurfaceManager.java b/android/src/org/ppsspp/ppsspp/NativeSurfaceManager.java index 1a48843a17..5227de6e7a 100644 --- a/android/src/org/ppsspp/ppsspp/NativeSurfaceManager.java +++ b/android/src/org/ppsspp/ppsspp/NativeSurfaceManager.java @@ -20,6 +20,13 @@ public class NativeSurfaceManager implements SurfaceHolder.Callback { // The fixed surface size we last asked for, or 0,0 for "size from layout". private final Point desiredSize = new Point(); + // What we last told the native side about the surface, and the density we told it with. + // A density change has to re-report it, see densityChanged(). + private int reportedWidth; + private int reportedHeight; + private int reportedFormat; + private float reportedDensityDpi; + public NativeSurfaceManager(final PpssppActivity a) { activity = a; } @@ -86,18 +93,40 @@ public class NativeSurfaceManager implements SurfaceHolder.Callback { } } - NativeApp.backbufferResize(width, height, format, activity.getWindowManager().getDefaultDisplay().getRotation()); + reportSurfaceSize(width, height, format); activity.notifySurface(holder.getSurface()); } @Override public void surfaceDestroyed(SurfaceHolder holder) { activity.notifySurface(null); + reportedWidth = 0; + reportedHeight = 0; // Autosize the next created surface. holder.setSizeFromLayout(); } + private void reportSurfaceSize(int width, int height, int format) { + reportedWidth = width; + reportedHeight = height; + reportedFormat = format; + reportedDensityDpi = densityDpi; + NativeApp.backbufferResize(width, height, format, activity.getWindowManager().getDefaultDisplay().getRotation()); + } + + // A density change rescales the UI but leaves the surface size alone, so no surfaceChanged + // follows it to carry the new density to the native side - the DPI is only recalculated in + // backbufferResize. Re-report the surface we already have, or the UI keeps the old scale + // until the next real resize. Call after updateDisplayMeasurements has picked up the change. + public void densityChanged() { + if (reportedWidth <= 0 || densityDpi == reportedDensityDpi) { + return; + } + Log.i(TAG, "Density is now " + densityDpi + ", re-reporting surface " + reportedWidth + "x" + reportedHeight); + reportSurfaceSize(reportedWidth, reportedHeight, reportedFormat); + } + public void updateDisplayMeasurements() { Display display = activity.getWindowManager().getDefaultDisplay(); DisplayMetrics metrics = new DisplayMetrics(); diff --git a/android/src/org/ppsspp/ppsspp/PpssppActivity.java b/android/src/org/ppsspp/ppsspp/PpssppActivity.java index d1c1ce07a0..a8b159faf3 100644 --- a/android/src/org/ppsspp/ppsspp/PpssppActivity.java +++ b/android/src/org/ppsspp/ppsspp/PpssppActivity.java @@ -1075,7 +1075,10 @@ public class PpssppActivity extends AppCompatActivity implements SensorEventList // The surface size change that comes with it is what actually updates the native side, except // for this, which the native side was told once at init. Changes on fold/unfold. NativeApp.sendMessageFromJava("smallestScreenWidthDp", String.valueOf(newConfig.smallestScreenWidthDp)); + // This re-measures the display, so the density check below sees the new value. updateSystemUiVisibility(); + // A density change doesn't resize the surface, so it needs separate handling. + surfaceManager.densityChanged(); } @Override