Bug 994856 - Add support for Gecko rendering via GLScreenBuffer into external GL Context. r=bjacob,jgilbert
authorTatiana Meshkova <tanya.meshkova@gmail.com>
Tue, 15 Apr 2014 07:57:26 -0700
changeset 197259 5d7dd6086a5a78f283cdf7f979395cd5cb357c25
parent 197258 d8d1d9108f5617de45888431d458a72b1d635fa1
child 197260 c724358ef43f69356318292ea6346e102b7a3468
push id3624
push userasasaki@mozilla.com
push dateMon, 09 Jun 2014 21:49:01 +0000
treeherdermozilla-beta@b1a5da15899a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbjacob, jgilbert
bugs994856
milestone31.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 994856 - Add support for Gecko rendering via GLScreenBuffer into external GL Context. r=bjacob,jgilbert
gfx/gl/GLContext.h
gfx/gl/GLContextCGL.h
gfx/gl/GLContextEGL.h
gfx/gl/GLContextGLX.h
gfx/gl/GLContextProviderCGL.mm
gfx/gl/GLContextProviderEGL.cpp
gfx/gl/GLContextProviderGLX.cpp
gfx/gl/GLContextProviderImpl.h
gfx/gl/GLContextProviderNull.cpp
gfx/gl/GLContextProviderWGL.cpp
gfx/gl/GLContextWGL.h
--- a/gfx/gl/GLContext.h
+++ b/gfx/gl/GLContext.h
@@ -2518,16 +2518,18 @@ public:
         // support contexts used on multiple threads.
         NS_ASSERTION(IsOwningThreadCurrent(),
                      "MakeCurrent() called on different thread than this context was created on!");
 #endif
 #endif
         return MakeCurrentImpl(aForce);
     }
 
+    virtual bool Init() = 0;
+
     virtual bool SetupLookupFunction() = 0;
 
     virtual void ReleaseSurface() {}
 
     // Mark this context as destroyed.  This will nullptr out all
     // the GL function pointers!
     void MarkDestroyed();
 
--- a/gfx/gl/GLContextCGL.h
+++ b/gfx/gl/GLContextCGL.h
@@ -37,17 +37,17 @@ public:
 
     virtual GLContextType GetContextType() const MOZ_OVERRIDE { return GLContextType::CGL; }
 
     static GLContextCGL* Cast(GLContext* gl) {
         MOZ_ASSERT(gl->GetContextType() == GLContextType::CGL);
         return static_cast<GLContextCGL*>(gl);
     }
 
-    bool Init();
+    bool Init() MOZ_OVERRIDE;
 
     NSOpenGLContext* GetNSOpenGLContext() const { return mContext; }
     CGLContextObj GetCGLContext() const;
 
     virtual bool MakeCurrentImpl(bool aForce) MOZ_OVERRIDE;
 
     virtual bool IsCurrent() MOZ_OVERRIDE;
 
--- a/gfx/gl/GLContextEGL.h
+++ b/gfx/gl/GLContextEGL.h
@@ -41,17 +41,17 @@ public:
 
     virtual GLContextType GetContextType() const MOZ_OVERRIDE { return GLContextType::EGL; }
 
     static GLContextEGL* Cast(GLContext* gl) {
         MOZ_ASSERT(gl->GetContextType() == GLContextType::EGL);
         return static_cast<GLContextEGL*>(gl);
     }
 
-    bool Init();
+    bool Init() MOZ_OVERRIDE;
 
     virtual bool IsDoubleBuffered() const MOZ_OVERRIDE {
         return mIsDoubleBuffered;
     }
 
     void SetIsDoubleBuffered(bool aIsDB) {
         mIsDoubleBuffered = aIsDB;
     }
@@ -112,16 +112,17 @@ protected:
 
     bool mIsPBuffer;
     bool mIsDoubleBuffered;
     bool mCanBindToTexture;
     bool mShareWithEGLImage;
 #ifdef MOZ_WIDGET_GONK
     nsRefPtr<HwcComposer2D> mHwc;
 #endif
+    bool mOwnsContext;
 
     static EGLSurface CreatePBufferSurfaceTryingPowerOfTwo(EGLConfig config,
                                                            EGLenum bindToTextureFormat,
                                                            gfxIntSize& pbsize);
 };
 
 }
 }
--- a/gfx/gl/GLContextGLX.h
+++ b/gfx/gl/GLContextGLX.h
@@ -31,17 +31,17 @@ public:
 
     virtual GLContextType GetContextType() const MOZ_OVERRIDE { return GLContextType::GLX; }
 
     static GLContextGLX* Cast(GLContext* gl) {
         MOZ_ASSERT(gl->GetContextType() == GLContextType::GLX);
         return static_cast<GLContextGLX*>(gl);
     }
 
-    bool Init();
+    bool Init() MOZ_OVERRIDE;
 
     virtual bool MakeCurrentImpl(bool aForce) MOZ_OVERRIDE;
 
     virtual bool IsCurrent() MOZ_OVERRIDE;
 
     virtual bool SetupLookupFunction() MOZ_OVERRIDE;
 
     virtual bool IsDoubleBuffered() const MOZ_OVERRIDE;
@@ -67,14 +67,15 @@ private:
     Display *mDisplay;
     GLXDrawable mDrawable;
     bool mDeleteDrawable;
     bool mDoubleBuffered;
 
     GLXLibrary* mGLX;
 
     nsRefPtr<gfxXlibSurface> mPixmap;
+    bool mOwnsContext;
 };
 
 }
 }
 
 #endif // GLCONTEXTGLX_H_
--- a/gfx/gl/GLContextProviderCGL.mm
+++ b/gfx/gl/GLContextProviderCGL.mm
@@ -182,22 +182,24 @@ GLContextCGL::SwapBuffers()
 
 static GLContextCGL *
 GetGlobalContextCGL()
 {
     return static_cast<GLContextCGL*>(GLContextProviderCGL::GetGlobalContext());
 }
 
 already_AddRefed<GLContext>
+GLContextProviderCGL::CreateWrappingExisting(void*, void*)
+{
+    return nullptr;
+}
+
+already_AddRefed<GLContext>
 GLContextProviderCGL::CreateForWindow(nsIWidget *aWidget)
 {
-    if (!sCGLLibrary.EnsureInitialized()) {
-        return nullptr;
-    }
-
     GLContextCGL *shareContext = GetGlobalContextCGL();
 
     NSOpenGLContext *context = [[NSOpenGLContext alloc]
                                 initWithFormat:sCGLLibrary.PixelFormat()
                                 shareContext:(shareContext ? shareContext->mContext : NULL)];
     if (!context) {
         return nullptr;
     }
--- a/gfx/gl/GLContextProviderEGL.cpp
+++ b/gfx/gl/GLContextProviderEGL.cpp
@@ -228,16 +228,17 @@ GLContextEGL::GLContextEGL(
     , mSurfaceOverride(EGL_NO_SURFACE)
     , mContext(context)
     , mThebesSurface(nullptr)
     , mBound(false)
     , mIsPBuffer(false)
     , mIsDoubleBuffered(false)
     , mCanBindToTexture(false)
     , mShareWithEGLImage(false)
+    , mOwnsContext(true)
 {
     // any EGL contexts will always be GLESv2
     SetProfileVersion(ContextProfile::OpenGLES, 200);
 
 #ifdef DEBUG
     printf_stderr("Initializing context %p surface %p on display %p\n", mContext, mSurface, EGL_DISPLAY());
 #endif
 #if defined(MOZ_WIDGET_GONK)
@@ -252,16 +253,21 @@ GLContextEGL::GLContextEGL(
     }
 #endif
 }
 
 GLContextEGL::~GLContextEGL()
 {
     MarkDestroyed();
 
+    // Wrapped context should not destroy eglContext/Surface
+    if (!mOwnsContext) {
+        return;
+    }
+
 #ifdef DEBUG
     printf_stderr("Destroying context %p surface %p on display %p\n", mContext, mSurface, EGL_DISPLAY());
 #endif
 
     sEGLLibrary.fDestroyContext(EGL_DISPLAY(), mContext);
 
 #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION < 17
     if (!mIsOffscreen) {
@@ -404,16 +410,19 @@ GLContextEGL::MakeCurrentImpl(bool aForc
 
 bool
 GLContextEGL::IsCurrent() {
     return sEGLLibrary.fGetCurrentContext() == mContext;
 }
 
 bool
 GLContextEGL::RenewSurface() {
+    if (!mOwnsContext) {
+        return false;
+    }
 #ifndef MOZ_WIDGET_ANDROID
     MOZ_CRASH("unimplemented");
     // to support this on non-Android platforms, need to keep track of the nsIWidget that
     // this GLContext was created for (with CreateForWindow) so that we know what to
     // pass again to CreateSurfaceForWindow below.
     // The reason why Android doesn't need this is that it delegates EGLSurface creation to
     // Java code which is the only thing that knows about our actual widget.
 #endif
@@ -424,17 +433,19 @@ GLContextEGL::RenewSurface() {
     if (mSurface == EGL_NO_SURFACE) {
         return false;
     }
     return MakeCurrent(true);
 }
 
 void
 GLContextEGL::ReleaseSurface() {
-    DestroySurface(mSurface);
+    if (mOwnsContext) {
+        DestroySurface(mSurface);
+    }
     mSurface = EGL_NO_SURFACE;
 }
 
 bool
 GLContextEGL::SetupLookupFunction()
 {
     mLookupFunc = (PlatformLookupFunction)sEGLLibrary.mSymbols.fGetProcAddress;
     return true;
@@ -677,16 +688,41 @@ CreateConfig(EGLConfig* aConfig)
 #endif
         return false;
     } else {
         return true;
     }
 }
 
 already_AddRefed<GLContext>
+GLContextProviderEGL::CreateWrappingExisting(void* aContext, void* aSurface)
+{
+    if (!sEGLLibrary.EnsureInitialized()) {
+        MOZ_CRASH("Failed to load EGL library!\n");
+        return nullptr;
+    }
+
+    if (aContext && aSurface) {
+        SurfaceCaps caps = SurfaceCaps::Any();
+        EGLConfig config = EGL_NO_CONFIG;
+        nsRefPtr<GLContextEGL> glContext =
+            new GLContextEGL(caps,
+                             nullptr, false,
+                             config, (EGLSurface)aSurface, (EGLContext)aContext);
+
+        glContext->SetIsDoubleBuffered(true);
+        glContext->mOwnsContext = false;
+
+        return glContext.forget();
+    }
+
+    return nullptr;
+}
+
+already_AddRefed<GLContext>
 GLContextProviderEGL::CreateForWindow(nsIWidget *aWidget)
 {
     if (!sEGLLibrary.EnsureInitialized()) {
         MOZ_CRASH("Failed to load EGL library!\n");
         return nullptr;
     }
 
     bool doubleBuffered = true;
--- a/gfx/gl/GLContextProviderGLX.cpp
+++ b/gfx/gl/GLContextProviderGLX.cpp
@@ -819,16 +819,21 @@ TRY_AGAIN_NO_SHARING:
 
     return glContext.forget();
 }
 
 GLContextGLX::~GLContextGLX()
 {
     MarkDestroyed();
 
+    // Wrapped context should not destroy glxContext/Surface
+    if (!mOwnsContext) {
+        return;
+    }
+
     // see bug 659842 comment 76
 #ifdef DEBUG
     bool success =
 #endif
     mGLX->xMakeCurrent(mDisplay, None, nullptr);
     NS_ABORT_IF_FALSE(success,
         "glXMakeCurrent failed to release GL context before we call glXDestroyContext!");
 
@@ -918,17 +923,18 @@ GLContextGLX::GLContextGLX(
                   gfxXlibSurface *aPixmap)
     : GLContext(caps, shareContext, isOffscreen),//aDeleteDrawable ? true : false, aShareContext, ),
       mContext(aContext),
       mDisplay(aDisplay),
       mDrawable(aDrawable),
       mDeleteDrawable(aDeleteDrawable),
       mDoubleBuffered(aDoubleBuffered),
       mGLX(&sGLXLibrary),
-      mPixmap(aPixmap)
+      mPixmap(aPixmap),
+      mOwnsContext(true)
 {
     MOZ_ASSERT(mGLX);
     // See 899855
     SetProfileVersion(ContextProfile::OpenGLCompatibility, 200);
 }
 
 
 static GLContextGLX *
@@ -952,31 +958,66 @@ AreCompatibleVisuals(Visual *one, Visual
 
     if (one->bits_per_rgb != two->bits_per_rgb) {
         return false;
     }
 
     return true;
 }
 
+static StaticRefPtr<GLContext> gGlobalContext;
+
+already_AddRefed<GLContext>
+GLContextProviderGLX::CreateWrappingExisting(void* aContext, void* aSurface)
+{
+    if (!sGLXLibrary.EnsureInitialized()) {
+        return nullptr;
+    }
+
+    if (aContext && aSurface) {
+        SurfaceCaps caps = SurfaceCaps::Any();
+        nsRefPtr<GLContextGLX> glContext =
+            new GLContextGLX(caps,
+                             nullptr, // SharedContext
+                             false, // Offscreen
+                             (Display*)DefaultXDisplay(), // Display
+                             (GLXDrawable)aSurface, (GLXContext)aContext,
+                             false, // aDeleteDrawable,
+                             true,
+                             (gfxXlibSurface*)nullptr);
+
+        glContext->mOwnsContext = false;
+        gGlobalContext = glContext;
+
+        return glContext.forget();
+    }
+
+    return nullptr;
+}
+
 already_AddRefed<GLContext>
 GLContextProviderGLX::CreateForWindow(nsIWidget *aWidget)
 {
     if (!sGLXLibrary.EnsureInitialized()) {
         return nullptr;
     }
 
     // Currently, we take whatever Visual the window already has, and
     // try to create an fbconfig for that visual.  This isn't
     // necessarily what we want in the long run; an fbconfig may not
     // be available for the existing visual, or if it is, the GL
     // performance might be suboptimal.  But using the existing visual
     // is a relatively safe intermediate step.
 
     Display *display = (Display*)aWidget->GetNativeData(NS_NATIVE_DISPLAY);
+    if (!display) {
+        NS_ERROR("X Display required for GLX Context provider");
+        return nullptr;
+    }
+
     int xscreen = DefaultScreen(display);
     Window window = GET_NATIVE_WINDOW(aWidget);
 
     int numConfigs;
     ScopedXFree<GLXFBConfig> cfgs;
     if (sGLXLibrary.IsATI() ||
         !sGLXLibrary.GLXVersionCheck(1, 3)) {
         const int attribs[] = {
@@ -1183,18 +1224,16 @@ GLContextProviderGLX::CreateOffscreen(co
         return nullptr;
 
     if (!glContext->InitOffscreen(ToIntSize(size), caps))
         return nullptr;
 
     return glContext.forget();
 }
 
-static StaticRefPtr<GLContext> gGlobalContext;
-
 GLContext*
 GLContextProviderGLX::GetGlobalContext()
 {
     static bool checkedContextSharing = false;
     static bool useContextSharing = false;
 
     if (!checkedContextSharing) {
         useContextSharing = getenv("MOZ_DISABLE_CONTEXT_SHARING_GLX") == 0;
--- a/gfx/gl/GLContextProviderImpl.h
+++ b/gfx/gl/GLContextProviderImpl.h
@@ -57,16 +57,27 @@ public:
      *
      * @return Context to use for offscreen rendering
      */
     static already_AddRefed<GLContext>
     CreateOffscreen(const gfxIntSize& size,
                     const SurfaceCaps& caps);
 
     /**
+     * Create wrapping Gecko GLContext for external gl context.
+     *
+     * @param aContext External context which will be wrapped by Gecko GLContext.
+     * @param aSurface External surface which is used for external context.
+     *
+     * @return Wrapping Context to use for rendering
+     */
+    static already_AddRefed<GLContext>
+    CreateWrappingExisting(void* aContext, void* aSurface);
+
+    /**
      * Get a pointer to the global context, creating it if it doesn't exist.
      */
     static GLContext*
     GetGlobalContext();
 
     /**
      * Free any resources held by this Context Provider.
      */
--- a/gfx/gl/GLContextProviderNull.cpp
+++ b/gfx/gl/GLContextProviderNull.cpp
@@ -10,16 +10,22 @@ namespace gl {
 
 already_AddRefed<GLContext>
 GLContextProviderNull::CreateForWindow(nsIWidget*)
 {
     return nullptr;
 }
 
 already_AddRefed<GLContext>
+GLContextProviderNull::CreateWrappingExisting(void*, void*)
+{
+    return nullptr;
+}
+
+already_AddRefed<GLContext>
 GLContextProviderNull::CreateOffscreen(const gfxIntSize&,
                                        const SurfaceCaps&,
                                        ContextFlags)
 {
     return nullptr;
 }
 
 GLContext*
--- a/gfx/gl/GLContextProviderWGL.cpp
+++ b/gfx/gl/GLContextProviderWGL.cpp
@@ -394,16 +394,22 @@ IsValidSizeForFormat(HDC hDC, int format
 
 static GLContextWGL *
 GetGlobalContextWGL()
 {
     return static_cast<GLContextWGL*>(GLContextProviderWGL::GetGlobalContext());
 }
 
 already_AddRefed<GLContext>
+GLContextProviderWGL::CreateWrappingExisting(void*, void*)
+{
+    return nullptr;
+}
+
+already_AddRefed<GLContext>
 GLContextProviderWGL::CreateForWindow(nsIWidget *aWidget)
 {
     if (!sWGLLib.EnsureInitialized()) {
         return nullptr;
     }
 
     /**
        * We need to make sure we call SetPixelFormat -after- calling
--- a/gfx/gl/GLContextWGL.h
+++ b/gfx/gl/GLContextWGL.h
@@ -38,17 +38,17 @@ public:
 
     virtual GLContextType GetContextType() const MOZ_OVERRIDE { return GLContextType::WGL; }
 
     static GLContextWGL* Cast(GLContext* gl) {
         MOZ_ASSERT(gl->GetContextType() == GLContextType::WGL);
         return static_cast<GLContextWGL*>(gl);
     }
 
-    bool Init();
+    bool Init() MOZ_OVERRIDE;
 
     virtual bool MakeCurrentImpl(bool aForce) MOZ_OVERRIDE;
 
     virtual bool IsCurrent() MOZ_OVERRIDE;
 
     void SetIsDoubleBuffered(bool aIsDB);
 
     virtual bool IsDoubleBuffered() const MOZ_OVERRIDE;