Bug 675474 - Draw all ThebesLayer content before compositing and synchronize with glXWaitX on GLX. r=bjacob,roc
authorMatt Woodrow <mwoodrow@mozilla.com>
Sat, 20 Aug 2011 14:04:24 +1200
changeset 76079 58147380793b71cadae0ed29930b30f4a76e135a
parent 76078 96e052b3e845f99e91bac5783ba94fc029870b80
child 76080 0a920411e64c019db924a46ae617074f868df3b1
push idunknown
push userunknown
push dateunknown
reviewersbjacob, roc
bugs675474
milestone9.0a1
Bug 675474 - Draw all ThebesLayer content before compositing and synchronize with glXWaitX on GLX. r=bjacob,roc
gfx/layers/opengl/ContainerLayerOGL.cpp
gfx/layers/opengl/ContainerLayerOGL.h
gfx/layers/opengl/LayerManagerOGL.cpp
gfx/layers/opengl/LayerManagerOGL.h
gfx/layers/opengl/ThebesLayerOGL.cpp
gfx/layers/opengl/ThebesLayerOGL.h
gfx/thebes/GLContext.h
gfx/thebes/GLContextProviderGLX.cpp
gfx/thebes/GLXLibrary.h
--- a/gfx/layers/opengl/ContainerLayerOGL.cpp
+++ b/gfx/layers/opengl/ContainerLayerOGL.cpp
@@ -327,16 +327,26 @@ ContainerLayerOGL::GetFirstChildOGL()
 {
   if (!mFirstChild) {
     return nsnull;
   }
   return static_cast<LayerOGL*>(mFirstChild->ImplData());
 }
 
 void
+ContainerLayerOGL::Validate()
+{
+  for (LayerOGL* child = GetFirstChildOGL();
+       child != nsnull;
+       child = mozilla::layers::GetNextSibling(child)) {
+    child->Validate();
+  }
+}
+
+void
 ContainerLayerOGL::RenderLayer(int aPreviousFrameBuffer,
                                const nsIntPoint& aOffset)
 {
   ContainerRender(this, aPreviousFrameBuffer, aOffset, mOGLManager);
 }
 
 
 ShadowContainerLayerOGL::ShadowContainerLayerOGL(LayerManagerOGL *aManager)
--- a/gfx/layers/opengl/ContainerLayerOGL.h
+++ b/gfx/layers/opengl/ContainerLayerOGL.h
@@ -84,16 +84,17 @@ public:
 
   /** LayerOGL implementation */
   Layer* GetLayer() { return this; }
 
   void Destroy();
 
   LayerOGL* GetFirstChildOGL();
 
+  virtual void Validate();
   virtual void RenderLayer(int aPreviousFrameBuffer,
                            const nsIntPoint& aOffset);
 
   virtual void ComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface)
   {
     DefaultComputeEffectiveTransforms(aTransformToSurface);
   }
 };
--- a/gfx/layers/opengl/LayerManagerOGL.cpp
+++ b/gfx/layers/opengl/LayerManagerOGL.cpp
@@ -786,16 +786,19 @@ LayerManagerOGL::Render()
     mGLContext->fScissor(0, 0, width, height);
   }
 
   mGLContext->fEnable(LOCAL_GL_SCISSOR_TEST);
 
   mGLContext->fClearColor(0.0, 0.0, 0.0, 0.0);
   mGLContext->fClear(LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT);
 
+  RootLayer()->Validate();
+  mGLContext->WaitForDrawing();
+
   // Render our layers.
   RootLayer()->RenderLayer(mGLContext->IsDoubleBuffered() ? 0 : mBackBufferFBO,
                            nsIntPoint(0, 0));
                            
   mWidget->DrawOver(this, rect);
 
   if (mTarget) {
     CopyToTarget();
--- a/gfx/layers/opengl/LayerManagerOGL.h
+++ b/gfx/layers/opengl/LayerManagerOGL.h
@@ -526,16 +526,18 @@ public:
 
   /* Do NOT call this from the generic LayerOGL destructor.  Only from the
    * concrete class destructor
    */
   virtual void Destroy() = 0;
 
   virtual Layer* GetLayer() = 0;
 
+  virtual void Validate() {}
+
   virtual void RenderLayer(int aPreviousFrameBuffer,
                            const nsIntPoint& aOffset) = 0;
 
   typedef mozilla::gl::GLContext GLContext;
 
   LayerManagerOGL* OGLManager() const { return mOGLManager; }
   GLContext *gl() const { return mOGLManager->gl(); }
 
--- a/gfx/layers/opengl/ThebesLayerOGL.cpp
+++ b/gfx/layers/opengl/ThebesLayerOGL.cpp
@@ -729,38 +729,31 @@ ThebesLayerOGL::SetVisibleRegion(const n
 
 void
 ThebesLayerOGL::InvalidateRegion(const nsIntRegion &aRegion)
 {
   mValidRegion.Sub(mValidRegion, aRegion);
 }
 
 void
-ThebesLayerOGL::RenderLayer(int aPreviousFrameBuffer,
-                            const nsIntPoint& aOffset)
+ThebesLayerOGL::Validate()
 {
   if (!mBuffer && !CreateSurface()) {
     return;
   }
   NS_ABORT_IF_FALSE(mBuffer, "should have a buffer here");
 
-  mOGLManager->MakeCurrent();
-  gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
-
   TextureImage::ContentType contentType =
     CanUseOpaqueSurface() ? gfxASurface::CONTENT_COLOR :
                             gfxASurface::CONTENT_COLOR_ALPHA;
 
   gfxMatrix transform2d;
   PRUint32 flags = 0;
-  if (GetEffectiveTransform().Is2D(&transform2d)) {
-    if (transform2d.HasNonIntegerTranslation()) {
-      flags |= ThebesLayerBufferOGL::PAINT_WILL_RESAMPLE;
-    }
-  } else {
+  if (!GetEffectiveTransform().Is2D(&transform2d) ||
+      transform2d.HasNonIntegerTranslation()) {
     flags |= ThebesLayerBufferOGL::PAINT_WILL_RESAMPLE;
   }
 
   Buffer::PaintState state = mBuffer->BeginPaint(contentType, flags);
   mValidRegion.Sub(mValidRegion, state.mRegionToInvalidate);
 
   if (state.mContext) {
     state.mRegionToInvalidate.And(state.mRegionToInvalidate, mVisibleRegion);
@@ -778,19 +771,33 @@ ThebesLayerOGL::RenderLayer(int aPreviou
       // OR-ing with aRegionToDraw, since that can lead to a very complex region
       // here (OR doesn't automatically simplify to the simplest possible
       // representation of a region.)
       nsIntRegion tmp;
       tmp.Or(mVisibleRegion, state.mRegionToDraw);
       mValidRegion.Or(mValidRegion, tmp);
     }
   }
+}
 
-  // Drawing thebes layers can change the current context, reset it.
+void
+ThebesLayerOGL::RenderLayer(int aPreviousFrameBuffer,
+                            const nsIntPoint& aOffset)
+{
+  NS_ABORT_IF_FALSE(mBuffer, "should have a buffer here");
+  
+  gfxMatrix transform2d;
+  PRUint32 flags = 0;
+  if (!GetEffectiveTransform().Is2D(&transform2d) ||
+      transform2d.HasNonIntegerTranslation()) {
+    flags |= ThebesLayerBufferOGL::PAINT_WILL_RESAMPLE;
+  }
+
   gl()->MakeCurrent();
+  gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
 
   gl()->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, aPreviousFrameBuffer);
   mBuffer->RenderTo(aOffset, mOGLManager, flags);
 }
 
 Layer*
 ThebesLayerOGL::GetLayer()
 {
--- a/gfx/layers/opengl/ThebesLayerOGL.h
+++ b/gfx/layers/opengl/ThebesLayerOGL.h
@@ -68,16 +68,17 @@ public:
 
   /** ThebesLayer implementation */
   void InvalidateRegion(const nsIntRegion& aRegion);
 
   /** LayerOGL implementation */
   void Destroy();
   Layer* GetLayer();
   virtual PRBool IsEmpty();
+  virtual void Validate();
   virtual void RenderLayer(int aPreviousFrameBuffer,
                            const nsIntPoint& aOffset);
 
 private:
   friend class BasicBufferOGL;
 
   PRBool CreateSurface();
 
--- a/gfx/thebes/GLContext.h
+++ b/gfx/thebes/GLContext.h
@@ -645,16 +645,22 @@ public:
     /**
      * If this context wraps a double-buffered target, swap the back
      * and front buffers.  It should be assumed that after a swap, the
      * contents of the new back buffer are undefined.
      */
     virtual PRBool SwapBuffers() { return PR_FALSE; }
 
     /**
+     * Insert a sync point to wait for any platform specific
+     * drawing to soure surfaces to complete.
+     */
+    virtual void WaitForDrawing() {}
+
+    /**
      * Defines a two-dimensional texture image for context target surface
      */
     virtual PRBool BindTexImage() { return PR_FALSE; }
     /*
      * Releases a color buffer that is being used as a texture
      */
     virtual PRBool ReleaseTexImage() { return PR_FALSE; }
 
--- a/gfx/thebes/GLContextProviderGLX.cpp
+++ b/gfx/thebes/GLContextProviderGLX.cpp
@@ -119,16 +119,17 @@ GLXLibrary::EnsureInitialized()
     LibrarySymbolLoader::SymLoadStruct symbols[] = {
         /* functions that were in GLX 1.0 */
         { (PRFuncPtr*) &xDestroyContextInternal, { "glXDestroyContext", NULL } },
         { (PRFuncPtr*) &xMakeCurrentInternal, { "glXMakeCurrent", NULL } },
         { (PRFuncPtr*) &xSwapBuffersInternal, { "glXSwapBuffers", NULL } },
         { (PRFuncPtr*) &xQueryVersionInternal, { "glXQueryVersion", NULL } },
         { (PRFuncPtr*) &xGetCurrentContextInternal, { "glXGetCurrentContext", NULL } },
         { (PRFuncPtr*) &xWaitGLInternal, { "glXWaitGL", NULL } },
+        { (PRFuncPtr*) &xWaitXInternal, { "glXWaitX", NULL } },
         /* functions introduced in GLX 1.1 */
         { (PRFuncPtr*) &xQueryExtensionsStringInternal, { "glXQueryExtensionsString", NULL } },
         { (PRFuncPtr*) &xGetClientStringInternal, { "glXGetClientString", NULL } },
         { (PRFuncPtr*) &xQueryServerStringInternal, { "glXQueryServerString", NULL } },
         { NULL, { NULL } }
     };
 
     LibrarySymbolLoader::SymLoadStruct symbols13[] = {
@@ -292,16 +293,17 @@ GLXLibrary::CreatePixmap(gfxASurface* aS
                                                  &numFormats));
     if (!cfg) {
         return 0;
     }
     NS_ABORT_IF_FALSE(numFormats > 0,
                  "glXChooseFBConfig() failed to match our requested format and violated its spec (!)");
 
     gfxXlibSurface *xs = static_cast<gfxXlibSurface*>(aSurface);
+    NS_ABORT_IF_FALSE(xs->XDisplay() == display, "This is bad");
 
     int pixmapAttribs[] = { GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT,
                             GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGBA_EXT,
                             None};
 
     GLXPixmap glxpixmap = xCreatePixmap(display,
                                         cfg[0],
                                         xs->XDrawable(),
@@ -325,17 +327,16 @@ void
 GLXLibrary::BindTexImage(GLXPixmap aPixmap)
 {    
     if (!mHasTextureFromPixmap) {
         return;
     }
 
     Display *display = DefaultXDisplay();
     // Make sure all X drawing to the surface has finished before binding to a texture.
-    XSync(DefaultXDisplay(), False);
     xBindTexImage(display, aPixmap, GLX_FRONT_LEFT_EXT, NULL);
 }
 
 void
 GLXLibrary::ReleaseTexImage(GLXPixmap aPixmap)
 {
     if (!mHasTextureFromPixmap) {
         return;
@@ -613,16 +614,24 @@ GLXLibrary::xReleaseTexImage(Display *di
 void 
 GLXLibrary::xWaitGL()
 {
     BEFORE_GLX_CALL;
     xWaitGLInternal();
     AFTER_GLX_CALL;
 }
 
+void
+GLXLibrary::xWaitX()
+{
+    BEFORE_GLX_CALL;
+    xWaitXInternal();
+    AFTER_GLX_CALL;
+}
+
 GLXLibrary sGLXLibrary;
 
 class GLContextGLX : public GLContext
 {
 public:
     static already_AddRefed<GLContextGLX>
     CreateGLContext(const ContextFormat& format,
                     Display *display,
@@ -770,16 +779,21 @@ TRY_AGAIN_NO_SHARING:
     {
         if (!mDoubleBuffered)
             return PR_FALSE;
         sGLXLibrary.xSwapBuffers(mDisplay, mDrawable);
         sGLXLibrary.xWaitGL();
         return PR_TRUE;
     }
 
+    void WaitForDrawing()
+    {
+        sGLXLibrary.xWaitX();
+    }
+
     PRBool TextureImageSupportsGetBackingSurface()
     {
         return sGLXLibrary.HasTextureFromPixmap();
     }
 
     virtual already_AddRefed<TextureImage>
     CreateTextureImage(const nsIntSize& aSize,
                        TextureImage::ContentType aContentType,
--- a/gfx/thebes/GLXLibrary.h
+++ b/gfx/thebes/GLXLibrary.h
@@ -101,16 +101,17 @@ public:
     void xBindTexImage(Display *display,
                        GLXDrawable drawable,
                        int buffer,
                        const int *attrib_list);
     void xReleaseTexImage(Display *display,
                           GLXDrawable drawable,
                           int buffer);
     void xWaitGL();
+    void xWaitX();
 
     PRBool EnsureInitialized();
 
     GLXPixmap CreatePixmap(gfxASurface* aSurface);
     void DestroyPixmap(GLXPixmap aPixmap);
     void BindTexImage(GLXPixmap aPixmap);
     void ReleaseTexImage(GLXPixmap aPixmap);
 
@@ -199,16 +200,19 @@ private:
 
     typedef void (GLAPIENTRY * PFNGLXRELEASETEXIMAGE) (Display *,
                                                        GLXDrawable,
                                                        int);
     PFNGLXRELEASETEXIMAGE xReleaseTexImageInternal;
 
     typedef void (GLAPIENTRY * PFNGLXWAITGL) ();
     PFNGLXWAITGL xWaitGLInternal;
+    
+    typedef void (GLAPIENTRY * PFNGLXWAITX) ();
+    PFNGLXWAITGL xWaitXInternal;
 
 #ifdef DEBUG
     void BeforeGLXCall();
     void AfterGLXCall();
 #endif
 
     PRBool mInitialized;
     PRBool mTriedInitializing;