Bug 659832 - Make WebGL working on Maemo r=joe
authorOleg Romashin <romaxa@gmail.com>
Thu, 09 Jun 2011 21:18:43 -0400
changeset 70841 1619d8fc6416
parent 70840 9f18296db571
child 70842 443c7cd5bdf8
push id20427
push userromaxa@gmail.com
push dateFri, 10 Jun 2011 04:18:10 +0000
treeherdermozilla-central@1619d8fc6416 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjoe
bugs659832
milestone7.0a1
first release with
nightly linux32
1619d8fc6416 / 7.0a1 / 20110610030736 / files
nightly linux64
1619d8fc6416 / 7.0a1 / 20110610030736 / files
nightly mac
1619d8fc6416 / 7.0a1 / 20110610030736 / files
nightly win32
1619d8fc6416 / 7.0a1 / 20110610030736 / files
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
Bug 659832 - Make WebGL working on Maemo r=joe
gfx/thebes/GLContextProviderEGL.cpp
--- a/gfx/thebes/GLContextProviderEGL.cpp
+++ b/gfx/thebes/GLContextProviderEGL.cpp
@@ -189,17 +189,17 @@ typedef void *GLeglImageOES;
 } while (0)
 
 EGLSurface
 CreateSurfaceForWindow(nsIWidget *aWidget, EGLConfig config);
 EGLConfig
 CreateConfig();
 #ifdef MOZ_X11
 static EGLConfig
-CreateEGLSurfaceForXSurface(gfxASurface* aSurface, EGLConfig* aConfig = nsnull);
+CreateEGLSurfaceForXSurface(gfxASurface* aSurface, EGLConfig* aConfig = nsnull, EGLenum aDepth = 0);
 #endif
 
 static int
 next_power_of_two(int v)
 {
     v--;
     v |= v >> 1;
     v |= v >> 2;
@@ -604,16 +604,57 @@ private:
     PRPackedBool mHave_EGL_KHR_lock_surface;
     PRPackedBool mHave_EGL_ANGLE_surface_d3d_share_handle;
 } sEGLLibrary;
 
 class GLContextEGL : public GLContext
 {
     friend class TextureImageEGL;
 
+    static already_AddRefed<GLContextEGL>
+    CreateGLContext(const ContextFormat& format,
+                    EGLSurface surface,
+                    EGLConfig config,
+                    GLContextEGL *shareContext,
+                    PRBool aIsOffscreen = PR_FALSE)
+    {
+        EGLContext context;
+        static EGLint cxattribs[] = {
+            LOCAL_EGL_CONTEXT_CLIENT_VERSION, 2,
+            LOCAL_EGL_NONE
+        };
+
+        context = sEGLLibrary.fCreateContext(EGL_DISPLAY(),
+                                             config,
+                                             shareContext ? shareContext->mContext : EGL_NO_CONTEXT,
+                                             cxattribs);
+        if (!context) {
+            if (shareContext) {
+                shareContext = nsnull;
+                context = sEGLLibrary.fCreateContext(EGL_DISPLAY(),
+                                                     config,
+                                                     EGL_NO_CONTEXT,
+                                                     cxattribs);
+                if (!context) {
+                    NS_WARNING("Failed to create EGLContext!");
+                    return nsnull;
+                }
+            }
+        }
+
+        nsRefPtr<GLContextEGL> glContext =
+            new GLContextEGL(format, shareContext, config,
+                             surface, context, aIsOffscreen);
+
+        if (!glContext->Init())
+            return nsnull;
+
+        return glContext.forget();
+    }
+
 public:
     GLContextEGL(const ContextFormat& aFormat,
                  GLContext *aShareContext,
                  EGLConfig aConfig,
                  EGLSurface aSurface,
                  EGLContext aContext,
                  PRBool aIsOffscreen = PR_FALSE)
         : GLContext(aFormat, aIsOffscreen, aShareContext)
@@ -808,17 +849,18 @@ public:
 
     PRBool BindTex2DOffscreen(GLContext *aOffscreen);
     void UnbindTex2DOffscreen(GLContext *aOffscreen);
     PRBool ResizeOffscreen(const gfxIntSize& aNewSize);
     void BindOffscreenFramebuffer();
 
     static already_AddRefed<GLContextEGL>
     CreateEGLPixmapOffscreenContext(const gfxIntSize& aSize,
-                                    const ContextFormat& aFormat);
+                                    const ContextFormat& aFormat,
+                                    PRBool aShare);
 
     static already_AddRefed<GLContextEGL>
     CreateEGLPBufferOffscreenContext(const gfxIntSize& aSize,
                                      const ContextFormat& aFormat);
 
     void SetOffscreenSize(const gfxIntSize &aRequestedSize,
                           const gfxIntSize &aActualSize)
     {
@@ -977,16 +1019,52 @@ GLContextEGL::ResizeOffscreen(const gfxI
         mSurface = surface;
 
         MakeCurrent(PR_TRUE);
         ClearSafely();
 
         return PR_TRUE;
     }
 
+#ifdef MOZ_X11
+    if (gUseBackingSurface && mThebesSurface) {
+        if (aNewSize == mThebesSurface->GetSize()) {
+            return PR_TRUE;
+        }
+
+        EGLNativePixmapType pixmap = 0;
+        nsRefPtr<gfxXlibSurface> xsurface =
+            gfxXlibSurface::Create(DefaultScreenOfDisplay(DefaultXDisplay()),
+                                   gfxXlibSurface::FindRenderFormat(DefaultXDisplay(),
+                                                                    gfxASurface::ImageFormatRGB24),
+                                   aNewSize);
+        // Make sure that pixmap created and ready for GL rendering
+        XSync(DefaultXDisplay(), False);
+
+        if (xsurface->CairoStatus() != 0) {
+            return PR_FALSE;
+        }
+        pixmap = xsurface->XDrawable();
+        if (!pixmap) {
+            return PR_FALSE;
+        }
+
+        EGLSurface surface;
+        EGLConfig config = 0;
+        int depth = gfxUtils::ImageFormatToDepth(gfxPlatform::GetPlatform()->GetOffscreenFormat());
+        surface = CreateEGLSurfaceForXSurface(xsurface, &config, depth);
+        if (!config) {
+            return PR_FALSE;
+        }
+        mThebesSurface = xsurface;
+
+        return PR_TRUE;
+    }
+#endif
+
     return ResizeOffscreenFBO(aNewSize);
 }
 
 
 static GLContextEGL *
 GetGlobalContextEGL()
 {
     return static_cast<GLContextEGL*>(GLContextProviderEGL::GetGlobalContext());
@@ -1567,17 +1645,19 @@ GLContextProviderEGL::CreateForWindow(ns
 
     if (viewport->paintEngine()->type() == QPaintEngine::OpenGL2) {
         // Qt widget viewport already have GL context created by Qt
         // Create dummy GLContextEGL class
         nsRefPtr<GLContextEGL> glContext =
             new GLContextEGL(ContextFormat(DepthToGLFormat(viewport->depth())),
                              NULL,
                              NULL, NULL,
-                             sEGLLibrary.fGetCurrentContext());
+                             sEGLLibrary.fGetCurrentContext(),
+                             PR_FALSE);
+
         if (!glContext->Init())
             return nsnull;
 
         glContext->SetIsDoubleBuffered(PR_TRUE);
 
         glContext->SetQtGLWidget(viewport);
 
         return glContext.forget();
@@ -1712,47 +1792,29 @@ GLContextProviderEGL::CreateForWindow(ns
         return nsnull;
     }
 
     if (!sEGLLibrary.fBindAPI(LOCAL_EGL_OPENGL_ES_API)) {
         sEGLLibrary.fDestroySurface(EGL_DISPLAY(), surface);
         return nsnull;
     }
 
-    EGLint cxattribs[] = {
-        LOCAL_EGL_CONTEXT_CLIENT_VERSION, 2,
-        LOCAL_EGL_NONE
-    };
-
     GLContextEGL *shareContext = GetGlobalContextEGL();
 
-TRY_AGAIN_NO_SHARING:
-    context = sEGLLibrary.fCreateContext(EGL_DISPLAY(),
-                                         config,
-                                         shareContext ? shareContext->mContext : EGL_NO_CONTEXT,
-                                         cxattribs);
-    if (!context) {
-        if (shareContext) {
-            NS_WARNING("CreateForWindow -- couldn't share, trying again");
-            shareContext = nsnull;
-            goto TRY_AGAIN_NO_SHARING;
-        }
+    nsRefPtr<GLContextEGL> glContext =
+        GLContextEGL::CreateGLContext(ContextFormat(ContextFormat::BasicRGB24),
+                                      surface,
+                                      config,
+                                      shareContext,
+                                      PR_FALSE);
 
-        NS_WARNING("CreateForWindow -- no context, giving up");
-        sEGLLibrary.fDestroySurface(EGL_DISPLAY(), surface);
+    if (!glContext) {
         return nsnull;
     }
 
-    nsRefPtr<GLContextEGL> glContext = new GLContextEGL(ContextFormat(ContextFormat::BasicRGB24),
-                                                        shareContext,
-                                                        config, surface, context);
-
-    if (!glContext->Init())
-        return nsnull;
-
 #if defined(XP_WIN) || defined(ANDROID) || defined(MOZ_PLATFORM_MAEMO)
     glContext->SetIsDoubleBuffered(PR_TRUE);
 #endif
 
     return glContext.forget();
 }
 #endif
 
@@ -1904,17 +1966,17 @@ TRY_ATTRIBS_AGAIN:
     glContext->mIsPBuffer = PR_TRUE;
     glContext->mPBufferCanBindToTexture = configCanBindToTexture;
 
     return glContext.forget();
 }
 
 #ifdef MOZ_X11
 EGLSurface
-CreateEGLSurfaceForXSurface(gfxASurface* aSurface, EGLConfig* aConfig)
+CreateEGLSurfaceForXSurface(gfxASurface* aSurface, EGLConfig* aConfig, EGLenum aDepth)
 {
     gfxXlibSurface* xsurface = static_cast<gfxXlibSurface*>(aSurface);
     PRBool opaque =
         aSurface->GetContentType() == gfxASurface::CONTENT_COLOR;
 
     static EGLint pixmap_config_rgb[] = {
         LOCAL_EGL_TEXTURE_TARGET,       LOCAL_EGL_TEXTURE_2D,
         LOCAL_EGL_TEXTURE_FORMAT,       LOCAL_EGL_TEXTURE_RGB,
@@ -1943,25 +2005,25 @@ CreateEGLSurfaceForXSurface(gfxASurface*
     }
 
     EGLConfig configs[32];
     int numConfigs = 32;
 
     static EGLint pixmap_config[] = {
         LOCAL_EGL_SURFACE_TYPE,         LOCAL_EGL_PIXMAP_BIT,
         LOCAL_EGL_RENDERABLE_TYPE,      LOCAL_EGL_OPENGL_ES2_BIT,
-        LOCAL_EGL_DEPTH_SIZE,           0,
+        LOCAL_EGL_DEPTH_SIZE,           aDepth,
         LOCAL_EGL_BIND_TO_TEXTURE_RGB,  LOCAL_EGL_TRUE,
         LOCAL_EGL_NONE
     };
 
     static EGLint pixmap_lock_config[] = {
         LOCAL_EGL_SURFACE_TYPE,         LOCAL_EGL_PIXMAP_BIT | LOCAL_EGL_LOCK_SURFACE_BIT_KHR,
         LOCAL_EGL_RENDERABLE_TYPE,      LOCAL_EGL_OPENGL_ES2_BIT,
-        LOCAL_EGL_DEPTH_SIZE,           0,
+        LOCAL_EGL_DEPTH_SIZE,           aDepth,
         LOCAL_EGL_BIND_TO_TEXTURE_RGB,  LOCAL_EGL_TRUE,
         LOCAL_EGL_NONE
     };
 
     if (!sEGLLibrary.fChooseConfig(EGL_DISPLAY(),
                                    sEGLLibrary.HasKHRLockSurface() ?
                                        pixmap_lock_config : pixmap_config,
                                    configs, numConfigs, &numConfigs))
@@ -1993,37 +2055,28 @@ CreateEGLSurfaceForXSurface(gfxASurface*
         *aConfig = configs[i];
 
     return surface;
 }
 #endif
 
 already_AddRefed<GLContextEGL>
 GLContextEGL::CreateEGLPixmapOffscreenContext(const gfxIntSize& aSize,
-                                              const ContextFormat& aFormat)
+                                              const ContextFormat& aFormat,
+                                              PRBool aShare)
 {
-    // XXX -- write me.
-    // This needs to find a FBConfig/Visual that matches aFormat, and allocate
-    // a gfxXlibSurface of the appropriat format, and then create a context
-    // for it.
-    //
-    // The code below is almost correct, except it doesn't do the format-FBConfig
-    // matching, instead just creating a random gfxXlibSurface.  The code below just
-    // uses context sharing and a FBO target, when instead it should avoid context
-    // sharing if some form of texture-from-pixmap functionality is available.
-
     gfxASurface *thebesSurface = nsnull;
     EGLNativePixmapType pixmap = 0;
 
 #ifdef MOZ_X11
     nsRefPtr<gfxXlibSurface> xsurface =
         gfxXlibSurface::Create(DefaultScreenOfDisplay(DefaultXDisplay()),
                                gfxXlibSurface::FindRenderFormat(DefaultXDisplay(),
                                                                 gfxASurface::ImageFormatRGB24),
-                               gfxIntSize(16, 16));
+                               gUseBackingSurface ? aSize : gfxIntSize(16, 16));
 
     // XSync required after gfxXlibSurface::Create, otherwise EGL will fail with BadDrawable error
     XSync(DefaultXDisplay(), False);
     if (xsurface->CairoStatus() != 0)
         return nsnull;
 
     thebesSurface = xsurface;
     pixmap = xsurface->XDrawable();
@@ -2032,50 +2085,31 @@ GLContextEGL::CreateEGLPixmapOffscreenCo
     if (!pixmap) {
         return nsnull;
     }
 
     EGLSurface surface = 0;
     EGLConfig config = 0;
 
 #ifdef MOZ_X11
-    surface = CreateEGLSurfaceForXSurface(thebesSurface, &config);
+    int depth = gfxUtils::ImageFormatToDepth(gfxPlatform::GetPlatform()->GetOffscreenFormat());
+    surface = CreateEGLSurfaceForXSurface(thebesSurface, &config, gUseBackingSurface ? depth : 0);
 #endif
     if (!config) {
         return nsnull;
     }
 
-    EGLint cxattribs[] = {
-        LOCAL_EGL_CONTEXT_CLIENT_VERSION, 2,
-        LOCAL_EGL_NONE
-    };
-
-    GLContextEGL *shareContext = GetGlobalContextEGL();
-    if (!shareContext) {
-        // we depend on context sharing currently
-        sEGLLibrary.fDestroySurface(EGL_DISPLAY(), surface);
-        return nsnull;
-    }
+    GLContextEGL *shareContext = aShare ? GetGlobalContextEGL() : nsnull;
 
-    EGLContext context = sEGLLibrary.fCreateContext(EGL_DISPLAY(),
-                                                    config,
-                                                    shareContext->Context(),
-                                                    cxattribs);
-    if (!context) {
-        sEGLLibrary.fDestroySurface(EGL_DISPLAY(), surface);
-        return nsnull;
-    }
-
-    nsRefPtr<GLContextEGL> glContext = new GLContextEGL(aFormat, shareContext,
-                                                        config, surface, context,
-                                                        PR_TRUE);
-
-    if (!glContext->Init() ||
-        !glContext->ResizeOffscreenFBO(aSize))
-        return nsnull;
+    nsRefPtr<GLContextEGL> glContext =
+        GLContextEGL::CreateGLContext(aFormat,
+                                      surface,
+                                      config,
+                                      shareContext,
+                                      PR_TRUE);
 
     glContext->HoldSurface(thebesSurface);
 
     return glContext.forget();
 }
 
 // Under EGL, if we're under X11, then we have to create a Pixmap
 // because Maemo's EGL implementation doesn't support pbuffers at all
@@ -2087,17 +2121,33 @@ GLContextProviderEGL::CreateOffscreen(co
 {
     if (!sEGLLibrary.EnsureInitialized()) {
         return nsnull;
     }
 
 #if defined(ANDROID) || defined(XP_WIN)
     return GLContextEGL::CreateEGLPBufferOffscreenContext(aSize, aFormat);
 #elif defined(MOZ_X11)
-    return GLContextEGL::CreateEGLPixmapOffscreenContext(aSize, aFormat);
+    nsRefPtr<GLContextEGL> glContext =
+        GLContextEGL::CreateEGLPixmapOffscreenContext(aSize, aFormat, PR_TRUE);
+
+    if (!glContext) {
+        return nsnull;
+    }
+    if (!glContext->GetSharedContext()) {
+        // no point in returning anything if sharing failed, we can't
+        // render from this
+        return nsnull;
+    }
+    if (!gUseBackingSurface && !glContext->ResizeOffscreenFBO(aSize)) {
+        // we weren't able to create the initial
+        // offscreen FBO, so this is dead
+        return nsnull;
+    }
+    return glContext.forget();
 #else
     return nsnull;
 #endif
 }
 
 static ContextFormat
 ContentTypeToGLFormat(gfxASurface::gfxContentType aCType)
 {
@@ -2132,33 +2182,23 @@ GLContextProviderEGL::CreateForNativePix
         return nsnull;
     }
 
     surface = CreateEGLSurfaceForXSurface(aSurface, &config);
     if (!config) {
         return nsnull;
     }
 
-    EGLint cxattribs[] = {
-        LOCAL_EGL_CONTEXT_CLIENT_VERSION, 2,
-        LOCAL_EGL_NONE
-    };
-
-    context = sEGLLibrary.fCreateContext(EGL_DISPLAY(),
-                                         config,
-                                         EGL_NO_SURFACE,
-                                         cxattribs);
-    if (!context) {
-        sEGLLibrary.fDestroySurface(EGL_DISPLAY(), surface);
-        return nsnull;
-    }
+    GLContextEGL *shareContext = GetGlobalContextEGL();
+    gfxXlibSurface* xsurface = static_cast<gfxXlibSurface*>(aSurface);
 
     nsRefPtr<GLContextEGL> glContext =
-        new GLContextEGL(ContextFormat(ContentTypeToGLFormat(aSurface->GetContentType())),
-                         nsnull, config, surface, context, PR_FALSE);
+        GLContextEGL::CreateGLContext(DepthToGLFormat(xsurface->XRenderFormat()->depth),
+                                      surface, config, shareContext, PR_FALSE);
+
     glContext->HoldSurface(aSurface);
 
     return glContext.forget().get();
 #else
     (void)surface;
     (void)context;
 
     // Not implemented
@@ -2169,17 +2209,20 @@ GLContextProviderEGL::CreateForNativePix
 static nsRefPtr<GLContext> gGlobalContext;
 
 GLContext *
 GLContextProviderEGL::GetGlobalContext()
 {
     static bool triedToCreateContext = false;
     if (!triedToCreateContext && !gGlobalContext) {
         triedToCreateContext = true;
-        gGlobalContext = CreateOffscreen(gfxIntSize(16, 16));
+        gGlobalContext =
+            GLContextEGL::CreateEGLPixmapOffscreenContext(gfxIntSize(16, 16),
+                                                          ContextFormat(ContextFormat::BasicRGB24),
+                                                          PR_FALSE);
         if (gGlobalContext)
             gGlobalContext->SetIsGlobalSharedContext(PR_TRUE);
     }
 
     return gGlobalContext;
 }
 
 void