Commit a95f91bceaa7dc47af8fed021699a95d4c94b380

Sylvain Becker 2019-01-02T18:06:33

Fixed bug 3250 - Wrong backbuffer pixel format on Android, keep getting RGB_565 Use the egl format to reconfigure java SurfaceView holder format. If there is a change, it triggers a surfaceDestroyed/Created/Change sequence.

diff --git a/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java b/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java
index a58ce34..b4d5c46 100644
--- a/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java
+++ b/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java
@@ -530,6 +530,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
     static final int COMMAND_CHANGE_TITLE = 1;
     static final int COMMAND_CHANGE_WINDOW_STYLE = 2;
     static final int COMMAND_TEXTEDIT_HIDE = 3;
+    static final int COMMAND_CHANGE_SURFACEVIEW_FORMAT = 4;
     static final int COMMAND_SET_KEEP_SCREEN_ON = 5;
 
     protected static final int COMMAND_USER = 0x8000;
@@ -627,6 +628,32 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
                 }
                 break;
             }
+            case COMMAND_CHANGE_SURFACEVIEW_FORMAT:
+            {
+                int format = ((int)msg.obj);
+                int pf;
+
+                if (SDLActivity.mSurface == null) {
+                    return;
+                }
+
+                SurfaceHolder holder = SDLActivity.mSurface.getHolder();
+                if (holder == null) {
+                    return;
+                }
+
+                if (format == 1) {
+                    pf = PixelFormat.RGBA_8888;
+                } else if (format == 2) {
+                    pf = PixelFormat.RGBX_8888;
+                } else {
+                    pf = PixelFormat.RGB_565;
+                }
+
+                holder.setFormat(pf);
+
+                break;
+            }
             default:
                 if ((context instanceof SDLActivity) && !((SDLActivity) context).onUnhandledMessage(msg.arg1, msg.obj)) {
                     Log.e(TAG, "error handling message, command is " + msg.arg1);
@@ -1032,6 +1059,14 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
         return SDLActivity.mSurface.getNativeSurface();
     }
 
+    /**
+     * This method is called by SDL using JNI.
+     */
+    public static void setSurfaceViewFormat(int format) {
+        mSingleton.sendCommand(COMMAND_CHANGE_SURFACEVIEW_FORMAT, format);
+        return;
+    }
+
     // Input
 
     /**
diff --git a/src/core/android/SDL_android.c b/src/core/android/SDL_android.c
index dd20a2b..9a3ba2b 100644
--- a/src/core/android/SDL_android.c
+++ b/src/core/android/SDL_android.c
@@ -222,6 +222,7 @@ static jclass mActivityClass;
 
 /* method signatures */
 static jmethodID midGetNativeSurface;
+static jmethodID midSetSurfaceViewFormat;
 static jmethodID midSetActivityTitle;
 static jmethodID midSetWindowStyle;
 static jmethodID midSetOrientation;
@@ -327,6 +328,8 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeSetupJNI)(JNIEnv* mEnv, jclass c
 
     midGetNativeSurface = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass,
                                 "getNativeSurface","()Landroid/view/Surface;");
+    midSetSurfaceViewFormat = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass,
+                                "setSurfaceViewFormat","(I)V");
     midSetActivityTitle = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass,
                                 "setActivityTitle","(Ljava/lang/String;)Z");
     midSetWindowStyle = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass,
@@ -374,7 +377,7 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeSetupJNI)(JNIEnv* mEnv, jclass c
     midSetRelativeMouseEnabled = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass, "setRelativeMouseEnabled", "(Z)Z");
 
 
-    if (!midGetNativeSurface ||
+    if (!midGetNativeSurface || !midSetSurfaceViewFormat ||
        !midSetActivityTitle || !midSetWindowStyle || !midSetOrientation || !midGetContext || !midIsTablet || !midIsAndroidTV || !midInputGetInputDeviceIds ||
        !midSendMessage || !midShowTextInput || !midIsScreenKeyboardShown ||
        !midClipboardSetText || !midClipboardGetText || !midClipboardHasText ||
@@ -964,6 +967,26 @@ ANativeWindow* Android_JNI_GetNativeWindow(void)
     return anw;
 }
 
+void Android_JNI_SetSurfaceViewFormat(int format)
+{
+    JNIEnv *mEnv = Android_JNI_GetEnv();
+    int new_format = 0;
+
+    /* Format from android/native_window.h,
+     * convert to temporary arbitrary values,
+     * then to java PixelFormat */
+    if (format == WINDOW_FORMAT_RGBA_8888) {
+        new_format = 1;
+    } else if (format == WINDOW_FORMAT_RGBX_8888) {
+        new_format = 2;
+    } else if (format == WINDOW_FORMAT_RGB_565) {
+        /* Default */
+        new_format = 0;
+    }
+
+    (*mEnv)->CallStaticVoidMethod(mEnv, mActivityClass, midSetSurfaceViewFormat, new_format);
+}
+
 void Android_JNI_SetActivityTitle(const char *title)
 {
     JNIEnv *mEnv = Android_JNI_GetEnv();
diff --git a/src/core/android/SDL_android.h b/src/core/android/SDL_android.h
index b2ff32e..1277a74 100644
--- a/src/core/android/SDL_android.h
+++ b/src/core/android/SDL_android.h
@@ -44,6 +44,7 @@ extern void Android_JNI_ShowTextInput(SDL_Rect *inputRect);
 extern void Android_JNI_HideTextInput(void);
 extern SDL_bool Android_JNI_IsScreenKeyboardShown(void);
 extern ANativeWindow* Android_JNI_GetNativeWindow(void);
+extern void Android_JNI_SetSurfaceViewFormat(int format);
 
 extern int Android_JNI_GetDisplayDPI(float *ddpi, float *xdpi, float *ydpi);
 
diff --git a/src/video/SDL_egl.c b/src/video/SDL_egl.c
index dfaf28e..685c65b 100644
--- a/src/video/SDL_egl.c
+++ b/src/video/SDL_egl.c
@@ -27,6 +27,7 @@
 #endif
 #if SDL_VIDEO_DRIVER_ANDROID
 #include <android/native_window.h>
+#include "../core/android/SDL_android.h"
 #endif
 
 #include "SDL_sysvideo.h"
@@ -885,6 +886,10 @@ SDL_EGL_CreateSurface(_THIS, NativeWindowType nw)
                                             EGL_NATIVE_VISUAL_ID, &format);
 
         ANativeWindow_setBuffersGeometry(nw, 0, 0, format);
+
+        /* Update SurfaceView holder format.
+         * May triggers a sequence surfaceDestroyed(), surfaceCreated(), surfaceChanged(). */
+        Android_JNI_SetSurfaceViewFormat(format);
     }
 #endif    
     if (_this->gl_config.framebuffer_srgb_capable) {