Bug 1232456 - Create EGL surface through widget; r=snorp
authorJim Chen <nchen@mozilla.com>
Wed, 23 Dec 2015 22:03:34 -0500
changeset 277596 4b23cb28ee3d5b19f6e67ea65a21967d87de3b1e
parent 277595 425588347628fcab6e66284bcbbfdc2a8931464f
child 277597 fa4764e92630be77049acaed6aed57015a324dbd
push id16783
push userryanvm@gmail.com
push dateSat, 26 Dec 2015 01:50:11 +0000
treeherderfx-team@4a559a618d67 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssnorp
bugs1232456
milestone46.0a1
Bug 1232456 - Create EGL surface through widget; r=snorp This patch makes GLContextProviderEGL create EGL surfaces through nsWindow/nsIWidget on Android. nsWindow then calls GLController in Java to actually create the surface.
gfx/gl/GLContextProviderEGL.cpp
mobile/android/base/java/org/mozilla/gecko/gfx/GLController.java
mobile/android/base/java/org/mozilla/gecko/gfx/LayerView.java
widget/android/AndroidBridge.cpp
widget/android/AndroidBridge.h
widget/android/GeneratedJNIWrappers.cpp
widget/android/GeneratedJNIWrappers.h
widget/android/nsWindow.cpp
widget/nsIWidget.h
--- a/gfx/gl/GLContextProviderEGL.cpp
+++ b/gfx/gl/GLContextProviderEGL.cpp
@@ -16,21 +16,16 @@
 #if defined(XP_UNIX)
     #ifdef MOZ_WIDGET_GONK
         #include "libdisplay/GonkDisplay.h"
         #include "nsWindow.h"
         #include "nsScreenManagerGonk.h"
     #endif
 
     #ifdef ANDROID
-        /* from widget */
-        #ifdef MOZ_WIDGET_ANDROID
-            #include "AndroidBridge.h"
-        #endif
-
         #include <android/log.h>
         #define LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "Gonk" , ## args)
 
         #ifdef MOZ_WIDGET_GONK
             #include "cutils/properties.h"
             #include <ui/GraphicBuffer.h>
 
             using namespace android;
@@ -167,23 +162,22 @@ DestroySurface(EGLSurface oldSurface) {
         sEGLLibrary.fDestroySurface(EGL_DISPLAY(), oldSurface);
     }
 }
 
 static EGLSurface
 CreateSurfaceForWindow(nsIWidget* widget, const EGLConfig& config) {
     EGLSurface newSurface = nullptr;
 
+    MOZ_ASSERT(widget);
 #ifdef MOZ_WIDGET_ANDROID
-        mozilla::AndroidBridge::Bridge()->RegisterCompositor();
-        newSurface = mozilla::AndroidBridge::Bridge()->CreateEGLSurfaceForCompositor();
+    newSurface = EGLSurface(widget->GetNativeData(NS_NATIVE_NEW_EGL_SURFACE));
 #else
-        MOZ_ASSERT(widget != nullptr);
-        newSurface = sEGLLibrary.fCreateWindowSurface(EGL_DISPLAY(), config,
-                                                      GET_NATIVE_WINDOW(widget), 0);
+    newSurface = sEGLLibrary.fCreateWindowSurface(EGL_DISPLAY(), config,
+                                                  GET_NATIVE_WINDOW(widget), 0);
 #endif
     return newSurface;
 }
 
 GLContextEGL::GLContextEGL(
                   const SurfaceCaps& caps,
                   GLContext* shareContext,
                   bool isOffscreen,
--- a/mobile/android/base/java/org/mozilla/gecko/gfx/GLController.java
+++ b/mobile/android/base/java/org/mozilla/gecko/gfx/GLController.java
@@ -117,17 +117,17 @@ public class GLController extends JNIObj
     synchronized void serverSurfaceChanged(int newWidth, int newHeight) {
         ThreadUtils.assertOnUiThread();
 
         mWidth = newWidth;
         mHeight = newHeight;
         mServerSurfaceValid = true;
 
         // we defer to a runnable the task of updating the compositor, because this is going to
-        // call back into createEGLSurfaceForCompositor, which will try to create an EGLSurface
+        // call back into createEGLSurface, which will try to create an EGLSurface
         // against mView, which we suspect might fail if called too early. By posting this to
         // mView, we hope to ensure that it is deferred until mView is actually "ready" for some
         // sense of "ready".
         mView.post(new Runnable() {
             @Override
             public void run() {
                 updateCompositor();
             }
@@ -256,18 +256,19 @@ public class GLController extends JNIObj
             }
         }
         if (mEGLSurfaceForCompositor == null) {
             Log.w(LOGTAG, "eglCreateWindowSurface returned no surface!");
         }
         return mEGLSurfaceForCompositor != null;
     }
 
-    @WrapForJNI(allowMultithread = true, stubName = "CreateEGLSurfaceForCompositorWrapper")
-    private synchronized EGLSurface createEGLSurfaceForCompositor() {
+    @WrapForJNI(allowMultithread = true)
+    private synchronized EGLSurface createEGLSurface() {
+        compositorCreated();
         AttemptPreallocateEGLSurfaceForCompositor();
         EGLSurface result = mEGLSurfaceForCompositor;
         mEGLSurfaceForCompositor = null;
         return result;
     }
 
     private static String getEGLError() {
         return "Error " + (sEGL == null ? "(no sEGL)" : sEGL.eglGetError());
--- a/mobile/android/base/java/org/mozilla/gecko/gfx/LayerView.java
+++ b/mobile/android/base/java/org/mozilla/gecko/gfx/LayerView.java
@@ -504,29 +504,16 @@ public class LayerView extends ScrollVie
 
     public Object getNativeWindow() {
         if (mSurfaceView != null)
             return mSurfaceView.getHolder();
 
         return mTextureView.getSurfaceTexture();
     }
 
-    @WrapForJNI(allowMultithread = true, stubName = "RegisterCompositorWrapper")
-    public static GLController registerCxxCompositor() {
-        try {
-            LayerView layerView = GeckoAppShell.getLayerView();
-            GLController controller = layerView.getGLController();
-            controller.compositorCreated();
-            return controller;
-        } catch (Exception e) {
-            Log.e(LOGTAG, "Error registering compositor!", e);
-            return null;
-        }
-    }
-
     //This method is called on the Gecko main thread.
     @WrapForJNI(allowMultithread = true, stubName = "updateZoomedView")
     public static void updateZoomedView(ByteBuffer data) {
         LayerView layerView = GeckoAppShell.getLayerView();
         if (layerView != null) {
             LayerRenderer layerRenderer = layerView.getRenderer();
             if (layerRenderer != null) {
                 layerRenderer.updateZoomedView(data);
--- a/widget/android/AndroidBridge.cpp
+++ b/widget/android/AndroidBridge.cpp
@@ -203,17 +203,16 @@ AndroidBridge::AndroidBridge()
             jEnv, jEnv->GetObjectClass(mMessageQueue.Get()));
     // mMessageQueueNext must not be null
     mMessageQueueNext = GetMethodID(
             jEnv, msgQueueClass.Get(), "next", "()Landroid/os/Message;");
     // mMessageQueueMessages may be null (e.g. due to proguard optimization)
     mMessageQueueMessages = jEnv->GetFieldID(
             msgQueueClass.Get(), "mMessages", "Landroid/os/Message;");
 
-    mGLControllerObj = nullptr;
     mOpenedGraphicsLibraries = false;
     mHasNativeBitmapAccess = false;
     mHasNativeWindowAccess = false;
     mHasNativeWindowFallback = false;
 
 #ifdef MOZ_WEBSMS_BACKEND
     AutoJNIClass smsMessage(jEnv, "android/telephony/SmsMessage");
     mAndroidSmsMessageClass = smsMessage.getGlobalRef();
@@ -233,26 +232,16 @@ AndroidBridge::AndroidBridge()
         jSurfacePointerField = surface.getField("mSurface", "I");
     } else if (mAPIVersion > 8 && mAPIVersion < 19 /* KitKat */) {
         jSurfacePointerField = surface.getField("mNativeSurface", "I");
     } else {
         // We don't know how to get this, just set it to 0
         jSurfacePointerField = 0;
     }
 
-    AutoJNIClass egl(jEnv, "com/google/android/gles_jni/EGLSurfaceImpl");
-    jclass eglClass = egl.getGlobalRef();
-    if (eglClass) {
-        // The pointer type moved to a 'long' in Android L, API version 20
-        const char* jniType = mAPIVersion >= 20 ? "J" : "I";
-        jEGLSurfacePointerField = egl.getField("mEGLSurface", jniType);
-    } else {
-        jEGLSurfacePointerField = 0;
-    }
-
     AutoJNIClass channels(jEnv, "java/nio/channels/Channels");
     jChannels = channels.getGlobalRef();
     jChannelCreate = channels.getStaticMethod("newChannel", "(Ljava/io/InputStream;)Ljava/nio/channels/ReadableByteChannel;");
 
     AutoJNIClass readableByteChannel(jEnv, "java/nio/channels/ReadableByteChannel");
     jReadableByteChannel = readableByteChannel.getGlobalRef();
     jByteBufferRead = readableByteChannel.getMethod("read", "(Ljava/nio/ByteBuffer;)I");
 
@@ -683,47 +672,16 @@ AndroidBridge::GetIconForExtension(const
 }
 
 void
 AndroidBridge::SetLayerClient(GeckoLayerClient::Param jobj)
 {
     mLayerClient = jobj;
 }
 
-void
-AndroidBridge::RegisterCompositor(JNIEnv *env)
-{
-    if (mGLControllerObj != nullptr) {
-        // we already have this set up, no need to do it again
-        return;
-    }
-
-    mGLControllerObj = GLController::LocalRef(
-            LayerView::RegisterCompositorWrapper());
-}
-
-EGLSurface
-AndroidBridge::CreateEGLSurfaceForCompositor()
-{
-    if (!jEGLSurfacePointerField) {
-        return nullptr;
-    }
-    MOZ_ASSERT(mGLControllerObj, "AndroidBridge::CreateEGLSurfaceForCompositor called with a null GL controller ref");
-
-    auto eglSurface = mGLControllerObj->CreateEGLSurfaceForCompositorWrapper();
-    if (!eglSurface) {
-        return nullptr;
-    }
-
-    JNIEnv* const env = GetEnvForThread(); // called on the compositor thread
-    return reinterpret_cast<EGLSurface>(mAPIVersion >= 20 ?
-            env->GetLongField(eglSurface.Get(), jEGLSurfacePointerField) :
-            env->GetIntField(eglSurface.Get(), jEGLSurfacePointerField));
-}
-
 bool
 AndroidBridge::GetStaticIntField(const char *className, const char *fieldName, int32_t* aInt, JNIEnv* jEnv /* = nullptr */)
 {
     ALOG_BRIDGE("AndroidBridge::GetStaticIntField %s", fieldName);
 
     if (!jEnv) {
         if (!jni::IsAvailable()) {
             return false;
--- a/widget/android/AndroidBridge.h
+++ b/widget/android/AndroidBridge.h
@@ -213,20 +213,16 @@ public:
     int GetScreenDepth();
 
     void Vibrate(const nsTArray<uint32_t>& aPattern);
 
     void GetSystemColors(AndroidSystemColors *aColors);
 
     void GetIconForExtension(const nsACString& aFileExt, uint32_t aIconSize, uint8_t * const aBuf);
 
-    // Switch Java to composite with the Gecko Compositor thread
-    void RegisterCompositor(JNIEnv* env = nullptr);
-    EGLSurface CreateEGLSurfaceForCompositor();
-
     bool GetStaticStringField(const char *classID, const char *field, nsAString &result, JNIEnv* env = nullptr);
 
     bool GetStaticIntField(const char *className, const char *fieldName, int32_t* aInt, JNIEnv* env = nullptr);
 
     // These next four functions are for native Bitmap access in Android 2.2+
     bool HasNativeBitmapAccess();
 
     bool ValidateBitmap(jobject bitmap, int width, int height);
@@ -406,21 +402,16 @@ protected:
     jmethodID jDestroySurface;
 
     jmethodID jCalculateLength;
 
     // For native surface stuff
     jclass jSurfaceClass;
     jfieldID jSurfacePointerField;
 
-    jclass jLayerView;
-
-    jfieldID jEGLSurfacePointerField;
-    widget::GLController::GlobalRef mGLControllerObj;
-
     // some convinient types to have around
     jclass jStringClass;
 
     jni::Object::GlobalRef mClassLoader;
     jmethodID mClassLoaderLoadClass;
 
     jni::Object::GlobalRef mMessageQueue;
     jfieldID mMessageQueueMessages;
--- a/widget/android/GeneratedJNIWrappers.cpp
+++ b/widget/android/GeneratedJNIWrappers.cpp
@@ -1237,22 +1237,22 @@ auto DisplayPortMetrics::Resolution() co
     return mozilla::jni::Field<Resolution_t>::Get(this, nullptr);
 }
 
 constexpr char GLController::name[];
 
 constexpr char GLController::CreateCompositor_t::name[];
 constexpr char GLController::CreateCompositor_t::signature[];
 
-constexpr char GLController::CreateEGLSurfaceForCompositorWrapper_t::name[];
-constexpr char GLController::CreateEGLSurfaceForCompositorWrapper_t::signature[];
+constexpr char GLController::CreateEGLSurface_t::name[];
+constexpr char GLController::CreateEGLSurface_t::signature[];
 
-auto GLController::CreateEGLSurfaceForCompositorWrapper() const -> mozilla::jni::Object::LocalRef
+auto GLController::CreateEGLSurface() const -> mozilla::jni::Object::LocalRef
 {
-    return mozilla::jni::Method<CreateEGLSurfaceForCompositorWrapper_t>::Call(this, nullptr);
+    return mozilla::jni::Method<CreateEGLSurface_t>::Call(this, nullptr);
 }
 
 constexpr char GLController::DisposeNative_t::name[];
 constexpr char GLController::DisposeNative_t::signature[];
 
 constexpr char GLController::PauseCompositor_t::name[];
 constexpr char GLController::PauseCompositor_t::signature[];
 
@@ -1398,24 +1398,16 @@ constexpr char LayerRenderer::Frame::End
 
 auto LayerRenderer::Frame::EndDrawing() const -> void
 {
     return mozilla::jni::Method<EndDrawing_t>::Call(this, nullptr);
 }
 
 constexpr char LayerView::name[];
 
-constexpr char LayerView::RegisterCompositorWrapper_t::name[];
-constexpr char LayerView::RegisterCompositorWrapper_t::signature[];
-
-auto LayerView::RegisterCompositorWrapper() -> mozilla::jni::Object::LocalRef
-{
-    return mozilla::jni::Method<RegisterCompositorWrapper_t>::Call(nullptr, nullptr);
-}
-
 constexpr char LayerView::updateZoomedView_t::name[];
 constexpr char LayerView::updateZoomedView_t::signature[];
 
 auto LayerView::updateZoomedView(mozilla::jni::Object::Param a0) -> void
 {
     return mozilla::jni::Method<updateZoomedView_t>::Call(nullptr, nullptr, a0);
 }
 
--- a/widget/android/GeneratedJNIWrappers.h
+++ b/widget/android/GeneratedJNIWrappers.h
@@ -3348,31 +3348,31 @@ public:
                 "(II)V";
         static const bool isStatic = false;
         static const bool isMultithreaded = false;
         static const mozilla::jni::ExceptionMode exceptionMode =
                 mozilla::jni::ExceptionMode::ABORT;
     };
 
 public:
-    struct CreateEGLSurfaceForCompositorWrapper_t {
+    struct CreateEGLSurface_t {
         typedef GLController Owner;
         typedef mozilla::jni::Object::LocalRef ReturnType;
         typedef mozilla::jni::Object::Param SetterType;
         typedef mozilla::jni::Args<> Args;
-        static constexpr char name[] = "createEGLSurfaceForCompositor";
+        static constexpr char name[] = "createEGLSurface";
         static constexpr char signature[] =
                 "()Ljavax/microedition/khronos/egl/EGLSurface;";
         static const bool isStatic = false;
         static const bool isMultithreaded = true;
         static const mozilla::jni::ExceptionMode exceptionMode =
                 mozilla::jni::ExceptionMode::ABORT;
     };
 
-    auto CreateEGLSurfaceForCompositorWrapper() const -> mozilla::jni::Object::LocalRef;
+    auto CreateEGLSurface() const -> mozilla::jni::Object::LocalRef;
 
 public:
     struct DisposeNative_t {
         typedef GLController Owner;
         typedef void ReturnType;
         typedef void SetterType;
         typedef mozilla::jni::Args<> Args;
         static constexpr char name[] = "disposeNative";
@@ -3861,33 +3861,16 @@ public:
 
     static constexpr char name[] =
             "org/mozilla/gecko/gfx/LayerView";
 
 protected:
     LayerView(jobject instance) : Class(instance) {}
 
 public:
-    struct RegisterCompositorWrapper_t {
-        typedef LayerView Owner;
-        typedef mozilla::jni::Object::LocalRef ReturnType;
-        typedef mozilla::jni::Object::Param SetterType;
-        typedef mozilla::jni::Args<> Args;
-        static constexpr char name[] = "registerCxxCompositor";
-        static constexpr char signature[] =
-                "()Lorg/mozilla/gecko/gfx/GLController;";
-        static const bool isStatic = true;
-        static const bool isMultithreaded = true;
-        static const mozilla::jni::ExceptionMode exceptionMode =
-                mozilla::jni::ExceptionMode::ABORT;
-    };
-
-    static auto RegisterCompositorWrapper() -> mozilla::jni::Object::LocalRef;
-
-public:
     struct updateZoomedView_t {
         typedef LayerView Owner;
         typedef void ReturnType;
         typedef void SetterType;
         typedef mozilla::jni::Args<
                 mozilla::jni::Object::Param> Args;
         static constexpr char name[] = "updateZoomedView";
         static constexpr char signature[] =
--- a/widget/android/nsWindow.cpp
+++ b/widget/android/nsWindow.cpp
@@ -506,16 +506,37 @@ public:
         return mLayerClient;
     }
 
     bool CompositorPaused() const
     {
         return mCompositorPaused;
     }
 
+    EGLSurface CreateEGLSurface()
+    {
+        static jfieldID eglSurfacePointerField;
+
+        JNIEnv* const env = jni::GetEnvForThread();
+
+        if (!eglSurfacePointerField) {
+            AutoJNIClass egl(env, "com/google/android/gles_jni/EGLSurfaceImpl");
+            // The pointer type moved to a 'long' in Android L, API version 20
+            eglSurfacePointerField = egl.getField("mEGLSurface",
+                    AndroidBridge::Bridge()->GetAPIVersion() >= 20 ? "J" : "I");
+        }
+
+        // Called on the compositor thread.
+        auto eglSurface = mGLController->CreateEGLSurface();
+        return reinterpret_cast<EGLSurface>(
+                AndroidBridge::Bridge()->GetAPIVersion() >= 20 ?
+                env->GetLongField(eglSurface.Get(), eglSurfacePointerField) :
+                env->GetIntField(eglSurface.Get(), eglSurfacePointerField));
+    }
+
 private:
     void OnResumedCompositor(int32_t aWidth, int32_t aHeight)
     {
         // When we receive this, the compositor has already been told to
         // resume. (It turns out that waiting till we reach here to tell
         // the compositor to resume takes too long, resulting in a black
         // flash.) This means it's now safe for layer updates to occur.
         // Since we might have prevented one or more draw events from
@@ -1479,16 +1500,21 @@ nsWindow::GetNativeData(uint32_t aDataTy
 
         case NS_NATIVE_WIDGET:
             return (void *) this;
 
         case NS_RAW_NATIVE_IME_CONTEXT:
             // We assume that there is only one context per process on Android
             return NS_ONLY_ONE_NATIVE_IME_CONTEXT;
 
+        case NS_NATIVE_NEW_EGL_SURFACE:
+            if (!mGLControllerSupport) {
+                return nullptr;
+            }
+            return static_cast<void*>(mGLControllerSupport->CreateEGLSurface());
     }
 
     return nullptr;
 }
 
 void
 nsWindow::OnMouseEvent(AndroidGeckoEvent *ae)
 {
--- a/widget/nsIWidget.h
+++ b/widget/nsIWidget.h
@@ -123,16 +123,19 @@ typedef void* nsNativeWidget;
 #define NS_NATIVE_ICOREWINDOW          103 // winrt specific
 #define NS_NATIVE_CHILD_WINDOW         104
 #define NS_NATIVE_CHILD_OF_SHAREABLE_WINDOW 105
 #endif
 #if defined(MOZ_WIDGET_GTK)
 // set/get nsPluginNativeWindowGtk, e10s specific
 #define NS_NATIVE_PLUGIN_OBJECT_PTR    104
 #endif
+#ifdef MOZ_WIDGET_ANDROID
+#define NS_NATIVE_NEW_EGL_SURFACE      100
+#endif
 
 #define NS_IWIDGET_IID \
 { 0xaaa79c8d, 0xc99d, 0x4fe1, \
   { 0xa5, 0x11, 0xd3, 0xeb, 0xb1, 0x61, 0x9e, 0x26 } }
 
 /*
  * Window shadow styles
  * Also used for the -moz-window-shadow CSS property