Bug 599507. Propagate opacity and transform from single-child ContainerLayerOGL to child. r=joe, a=blocker
authorMatt Woodrow <mattwoodrow@gmail.com>
Mon, 08 Nov 2010 22:06:14 +1300
changeset 57096 362567eee98261c00a8544f714eeaa0b436c12a7
parent 57095 5d82a6476d531687a32d60a3472f5151bcdb7ff7
child 57097 f35c89eac3923034bc4a373d05b9772c6a05afc0
push idunknown
push userunknown
push dateunknown
reviewersjoe, blocker
bugs599507
milestone2.0b8pre
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 599507. Propagate opacity and transform from single-child ContainerLayerOGL to child. r=joe, a=blocker
gfx/layers/opengl/CanvasLayerOGL.cpp
gfx/layers/opengl/CanvasLayerOGL.h
gfx/layers/opengl/ColorLayerOGL.cpp
gfx/layers/opengl/ColorLayerOGL.h
gfx/layers/opengl/ContainerLayerOGL.cpp
gfx/layers/opengl/ContainerLayerOGL.h
gfx/layers/opengl/ImageLayerOGL.cpp
gfx/layers/opengl/ImageLayerOGL.h
gfx/layers/opengl/LayerManagerOGL.cpp
gfx/layers/opengl/LayerManagerOGL.h
gfx/layers/opengl/ThebesLayerOGL.cpp
gfx/layers/opengl/ThebesLayerOGL.h
--- a/gfx/layers/opengl/CanvasLayerOGL.cpp
+++ b/gfx/layers/opengl/CanvasLayerOGL.cpp
@@ -226,17 +226,19 @@ CanvasLayerOGL::Updated(const nsIntRect&
 
   // sanity
   NS_ASSERTION(mBounds.Contains(mUpdatedRect),
                "CanvasLayer: Updated rect bigger than bounds!");
 }
 
 void
 CanvasLayerOGL::RenderLayer(int aPreviousDestination,
-                            const nsIntPoint& aOffset)
+                            const nsIntPoint& aOffset,
+                            float aOpacity,
+                            const gfx3DMatrix& aMatrix)
 {
   mOGLManager->MakeCurrent();
 
   // XXX We're going to need a different program depending on if
   // mGLBufferIsPremultiplied is TRUE or not.  The RGBLayerProgram
   // assumes that it's true.
 
   ColorTextureLayerProgram *program = nsnull;
@@ -261,18 +263,18 @@ CanvasLayerOGL::RenderLayer(int aPreviou
   program =
     mOGLManager->GetBasicLayerProgram(CanUseOpaqueSurface(),
                                       useGLContext != 0);
 
   ApplyFilter(mFilter);
 
   program->Activate();
   program->SetLayerQuadRect(mBounds);
-  program->SetLayerTransform(GetEffectiveTransform());
-  program->SetLayerOpacity(GetOpacity());
+  program->SetLayerTransform(GetEffectiveTransform() * aMatrix);
+  program->SetLayerOpacity(GetOpacity() * aOpacity);
   program->SetRenderOffset(aOffset);
   program->SetTextureUnit(0);
 
   mOGLManager->BindAndDrawQuad(program, mNeedsYFlip ? true : false);
 
   DEBUG_GL_ERROR_CHECK(gl());
 
   if (useGLContext) {
@@ -347,32 +349,34 @@ ShadowCanvasLayerOGL::Destroy()
 Layer*
 ShadowCanvasLayerOGL::GetLayer()
 {
   return this;
 }
 
 void
 ShadowCanvasLayerOGL::RenderLayer(int aPreviousFrameBuffer,
-                                  const nsIntPoint& aOffset)
+                                  const nsIntPoint& aOffset,
+                                  float aOpacity,
+                                  const gfx3DMatrix& aMatrix)
 {
   mOGLManager->MakeCurrent();
 
   gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
   gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexImage->Texture());
   ColorTextureLayerProgram *program =
     mOGLManager->GetBasicLayerProgram(CanUseOpaqueSurface(),
                                       mTexImage->IsRGB());
 
   ApplyFilter(mFilter);
 
   program->Activate();
   program->SetLayerQuadRect(nsIntRect(nsIntPoint(0, 0), mTexImage->GetSize()));
-  program->SetLayerTransform(mTransform);
-  program->SetLayerOpacity(GetOpacity());
+  program->SetLayerTransform(mTransform * aMatrix);
+  program->SetLayerOpacity(GetOpacity() * aOpacity);
   program->SetRenderOffset(aOffset);
   program->SetTextureUnit(0);
 
   mOGLManager->BindAndDrawQuad(program);
 
   DEBUG_GL_ERROR_CHECK(gl());
 }
 
--- a/gfx/layers/opengl/CanvasLayerOGL.h
+++ b/gfx/layers/opengl/CanvasLayerOGL.h
@@ -66,17 +66,19 @@ public:
   // CanvasLayer implementation
   virtual void Initialize(const Data& aData);
   virtual void Updated(const nsIntRect& aRect);
 
   // LayerOGL implementation
   virtual void Destroy();
   virtual Layer* GetLayer() { return this; }
   virtual void RenderLayer(int aPreviousFrameBuffer,
-                           const nsIntPoint& aOffset);
+                           const nsIntPoint& aOffset,
+                           float aOpacity,
+                           const gfx3DMatrix& aMatrix);
 
 protected:
   nsRefPtr<gfxASurface> mCanvasSurface;
   nsRefPtr<GLContext> mCanvasGLContext;
 
   void MakeTexture();
   GLuint mTexture;
 
@@ -110,17 +112,19 @@ public:
   Swap(gfxSharedImageSurface* aNewFront);
 
   virtual void DestroyFrontBuffer();
 
   // LayerOGL impl
   void Destroy();
   Layer* GetLayer();
   virtual void RenderLayer(int aPreviousFrameBuffer,
-                           const nsIntPoint& aOffset);
+                           const nsIntPoint& aOffset,
+                           float aOpacity,
+                           const gfx3DMatrix& aMatrix);
 
 private:
   nsRefPtr<TextureImage> mTexImage;
 
 
   // XXX FIXME holding to free
   nsRefPtr<gfxSharedImageSurface> mDeadweight;
 
--- a/gfx/layers/opengl/ColorLayerOGL.cpp
+++ b/gfx/layers/opengl/ColorLayerOGL.cpp
@@ -38,59 +38,64 @@
 
 #include "ColorLayerOGL.h"
 
 namespace mozilla {
 namespace layers {
 
 static void
 RenderColorLayer(ColorLayer* aLayer, LayerManagerOGL *aManager,
-                 const nsIntPoint& aOffset)
+                 const nsIntPoint& aOffset, float aOpacity,
+                 const gfx3DMatrix& aMatrix)
 {
   aManager->MakeCurrent();
 
   // XXX we might be able to improve performance by using glClear
 
   nsIntRect visibleRect = aLayer->GetEffectiveVisibleRegion().GetBounds();
   
   /* Multiply color by the layer opacity, as the shader
    * ignores layer opacity and expects a final color to
    * write to the color buffer.  This saves a needless
    * multiply in the fragment shader.
    */
-  float opacity = aLayer->GetOpacity();
+  float opacity = aLayer->GetOpacity() * aOpacity;
   gfxRGBA color(aLayer->GetColor());
   color.r *= opacity;
   color.g *= opacity;
   color.b *= opacity;
   color.a *= opacity;
 
   SolidColorLayerProgram *program = aManager->GetColorLayerProgram();
   program->Activate();
   program->SetLayerQuadRect(visibleRect);
-  program->SetLayerTransform(aLayer->GetEffectiveTransform());
+  program->SetLayerTransform(aLayer->GetEffectiveTransform() * aMatrix);
   program->SetRenderOffset(aOffset);
   program->SetRenderColor(color);
 
   aManager->BindAndDrawQuad(program);
 
   DEBUG_GL_ERROR_CHECK(aManager->gl());
 }
 
 void
 ColorLayerOGL::RenderLayer(int,
-                           const nsIntPoint& aOffset)
+                           const nsIntPoint& aOffset,
+                           float aOpacity,
+                           const gfx3DMatrix& aMatrix)
 {
-  return RenderColorLayer(this, mOGLManager, aOffset);
+  return RenderColorLayer(this, mOGLManager, aOffset, aOpacity, aMatrix);
 }
 
 #ifdef MOZ_IPC
 void
 ShadowColorLayerOGL::RenderLayer(int,
-                                 const nsIntPoint& aOffset)
+                                 const nsIntPoint& aOffset,
+                                 float aOpacity,
+                                 const gfx3DMatrix& aMatrix)
 {
-  return RenderColorLayer(this, mOGLManager, aOffset);
+  return RenderColorLayer(this, mOGLManager, aOffset, aOpacity, aMatrix);
 }
 #endif  // MOZ_IPC
 
 
 } /* layers */
 } /* mozilla */
--- a/gfx/layers/opengl/ColorLayerOGL.h
+++ b/gfx/layers/opengl/ColorLayerOGL.h
@@ -61,17 +61,19 @@ public:
   ~ColorLayerOGL() { Destroy(); }
 
   // LayerOGL Implementation
   virtual Layer* GetLayer() { return this; }
 
   virtual void Destroy() { mDestroyed = PR_TRUE; }
 
   virtual void RenderLayer(int aPreviousFrameBuffer,
-                           const nsIntPoint& aOffset);
+                           const nsIntPoint& aOffset,
+                           float aOpacity,
+                           const gfx3DMatrix& aMatrix);
 };
 
 #ifdef MOZ_IPC
 class ShadowColorLayerOGL : public ShadowColorLayer,
                             public LayerOGL
 {
 public:
   ShadowColorLayerOGL(LayerManagerOGL *aManager)
@@ -83,15 +85,17 @@ public:
   ~ShadowColorLayerOGL() { Destroy(); }
 
   // LayerOGL Implementation
   virtual Layer* GetLayer() { return this; }
 
   virtual void Destroy() { mDestroyed = PR_TRUE; }
 
   virtual void RenderLayer(int aPreviousFrameBuffer,
-                           const nsIntPoint& aOffset);
+                           const nsIntPoint& aOffset,
+                           float aOpacity,
+                           const gfx3DMatrix& aMatrix);
 };
 #endif  // MOZ_IPC
 
 } /* layers */
 } /* mozilla */
 #endif /* GFX_COLORLAYEROGL_H */
--- a/gfx/layers/opengl/ContainerLayerOGL.cpp
+++ b/gfx/layers/opengl/ContainerLayerOGL.cpp
@@ -116,36 +116,75 @@ ContainerDestroy(Container* aContainer)
       aContainer->GetFirstChildOGL()->Destroy();
       aContainer->RemoveChild(aContainer->mFirstChild);
     }
     aContainer->mDestroyed = PR_TRUE;
   }
 }
 
 template<class Container>
+static bool
+ShouldUseIntermediate(Container* aContainer,
+                      float aOpacity, 
+                      const gfx3DMatrix& aMatrix)
+{
+  if (aOpacity == 1.0f && aMatrix.IsIdentity()) {
+    return false;
+  }
+
+  Layer *firstChild = aContainer->GetFirstChild();
+  if (!firstChild) {
+    return false;
+  }
+
+  /* We always require an intermediate layer for opacity */
+  if (aOpacity != 1.0f) {
+    return true;
+  }
+
+  do {
+    const nsIntRect *clipRect = firstChild->GetClipRect();
+    /* We can't (easily) forward our transform to children with a non-emtpy clip 
+     * rect since it would need to be adjusted for the transform.
+     * TODO: This is easily solvable for translation/scaling transforms.
+     */
+    if (clipRect && !clipRect->IsEmpty() && !firstChild->GetVisibleRegion().IsEmpty()) {
+      return true;
+    }
+
+  } while ((firstChild = firstChild->GetNextSibling()) != nsnull);
+
+  /* All children have no clip or are invisible */
+  return false;
+}
+
+template<class Container>
 static void
 ContainerRender(Container* aContainer,
                 int aPreviousFrameBuffer,
                 const nsIntPoint& aOffset,
+                float aOpacity,
+                const gfx3DMatrix& aMatrix,
                 LayerManagerOGL* aManager)
 {
   /**
    * Setup our temporary texture for rendering the contents of this container.
    */
   GLuint containerSurface;
   GLuint frameBuffer;
 
   nsIntPoint childOffset(aOffset);
   nsIntRect visibleRect = aContainer->GetEffectiveVisibleRegion().GetBounds();
-  const gfx3DMatrix& transform = aContainer->GetEffectiveTransform();
+  const gfx3DMatrix& transform = aContainer->GetEffectiveTransform() * aMatrix;
 
+  nsIntRect cachedScissor = aContainer->gl()->ScissorRect();
   aContainer->gl()->PushScissorRect();
 
-  float opacity = aContainer->GetOpacity();
-  bool needsFramebuffer = (opacity != 1.0) || !transform.IsIdentity();
+  float opacity = aContainer->GetOpacity() * aOpacity;
+  bool needsFramebuffer = ShouldUseIntermediate(aContainer, opacity, transform);
   if (needsFramebuffer) {
     aManager->CreateFBOWithTexture(visibleRect.width,
                                    visibleRect.height,
                                    &frameBuffer,
                                    &containerSurface);
     childOffset.x = visibleRect.x;
     childOffset.y = visibleRect.y;
 
@@ -170,23 +209,44 @@ ContainerRender(Container* aContainer,
     if (clipRect) {
       scissorRect = *clipRect;
     }
 
     if (needsFramebuffer) {
       scissorRect.MoveBy(- visibleRect.TopLeft());
     }
 
-    if (aPreviousFrameBuffer == 0) {
-      aContainer->gl()->FixWindowCoordinateRect(scissorRect, aManager->GetWigetSize().height);
+    if (!needsFramebuffer && aPreviousFrameBuffer) {
+      scissorRect.IntersectRect(scissorRect, cachedScissor);
+    } else if (!needsFramebuffer) {
+      aContainer->gl()->FixWindowCoordinateRect(scissorRect, 
+                                                aManager->GetWigetSize().height);
+      scissorRect.IntersectRect(scissorRect, cachedScissor);
     }
 
-    aManager->gl()->fScissor(scissorRect.x, scissorRect.y, scissorRect.width, scissorRect.height);
+    /**
+     *  We can't clip to a visible region if theres no framebuffer since we might be transformed
+     */
+    if (needsFramebuffer || clipRect) {
+      aContainer->gl()->fScissor(scissorRect.x, 
+                                 scissorRect.y, 
+                                 scissorRect.width, 
+                                 scissorRect.height);
+    } else {
+      aContainer->gl()->fScissor(cachedScissor.x, 
+                                 cachedScissor.y, 
+                                 cachedScissor.width, 
+                                 cachedScissor.height);
+    }
 
-    layerToRender->RenderLayer(frameBuffer, childOffset);
+    if (!needsFramebuffer) {
+      layerToRender->RenderLayer(frameBuffer, childOffset, opacity, transform);
+    } else {
+      layerToRender->RenderLayer(frameBuffer, childOffset, 1.0, gfx3DMatrix());
+     }
 
     Layer *nextSibling = layerToRender->GetLayer()->GetNextSibling();
     layerToRender = nextSibling ? static_cast<LayerOGL*>(nextSibling->
                                                          ImplData())
                                 : nsnull;
   }
 
   aContainer->gl()->PopScissorRect();
@@ -271,19 +331,21 @@ ContainerLayerOGL::GetFirstChildOGL()
   if (!mFirstChild) {
     return nsnull;
   }
   return static_cast<LayerOGL*>(mFirstChild->ImplData());
 }
 
 void
 ContainerLayerOGL::RenderLayer(int aPreviousFrameBuffer,
-                               const nsIntPoint& aOffset)
+                               const nsIntPoint& aOffset,
+                               float aOpacity,
+                               const gfx3DMatrix& aMatrix)
 {
-  ContainerRender(this, aPreviousFrameBuffer, aOffset, mOGLManager);
+  ContainerRender(this, aPreviousFrameBuffer, aOffset, aOpacity, aMatrix, mOGLManager);
 }
 
 
 #ifdef MOZ_IPC
 
 ShadowContainerLayerOGL::ShadowContainerLayerOGL(LayerManagerOGL *aManager)
   : ShadowContainerLayer(aManager, NULL)
   , LayerOGL(aManager)
@@ -320,18 +382,20 @@ ShadowContainerLayerOGL::GetFirstChildOG
   if (!mFirstChild) {
     return nsnull;
    }
   return static_cast<LayerOGL*>(mFirstChild->ImplData());
 }
  
 void
 ShadowContainerLayerOGL::RenderLayer(int aPreviousFrameBuffer,
-                                     const nsIntPoint& aOffset)
+                                     const nsIntPoint& aOffset,
+                                     float aOpacity,
+                                     const gfx3DMatrix& aMatrix)
 {
-  ContainerRender(this, aPreviousFrameBuffer, aOffset, mOGLManager);
+  ContainerRender(this, aPreviousFrameBuffer, aOffset, aOpacity, aMatrix, mOGLManager);
 }
 
 #endif  // MOZ_IPC
 
 
 } /* layers */
 } /* mozilla */
--- a/gfx/layers/opengl/ContainerLayerOGL.h
+++ b/gfx/layers/opengl/ContainerLayerOGL.h
@@ -55,31 +55,39 @@ template<class Container>
 static void ContainerRemoveChild(Container* aContainer, Layer* aChild);
 template<class Container>
 static void ContainerDestroy(Container* aContainer);
 template<class Container>
 static void ContainerRender(Container* aContainer,
                             int aPreviousFrameBuffer,
                             const nsIntPoint& aOffset,
                             LayerManagerOGL* aManager);
+template<class Container>
+static bool ShouldUseIntermediate(Container* aContainer,
+                                  float aOpacity,
+                                  const gfx3DMatrix& aMatrix);
 
 class ContainerLayerOGL : public ContainerLayer, 
                           public LayerOGL
 {
   template<class Container>
   friend void ContainerInsertAfter(Container* aContainer, Layer* aChild, Layer* aAfter);
   template<class Container>
   friend void ContainerRemoveChild(Container* aContainer, Layer* aChild);
   template<class Container>
   friend void ContainerDestroy(Container* aContainer);
   template<class Container>
   friend void ContainerRender(Container* aContainer,
                               int aPreviousFrameBuffer,
                               const nsIntPoint& aOffset,
                               LayerManagerOGL* aManager);
+  template<class Container>
+  friend bool ShouldUseIntermediate(Container* aContainer,
+                                    float aOpacity,
+                                    const gfx3DMatrix& aMatrix);
 
 public:
   ContainerLayerOGL(LayerManagerOGL *aManager);
   ~ContainerLayerOGL();
 
   void InsertAfter(Layer* aChild, Layer* aAfter);
 
   void RemoveChild(Layer* aChild);
@@ -87,17 +95,19 @@ public:
   /** LayerOGL implementation */
   Layer* GetLayer() { return this; }
 
   void Destroy();
 
   LayerOGL* GetFirstChildOGL();
 
   virtual void RenderLayer(int aPreviousFrameBuffer,
-                           const nsIntPoint& aOffset);
+                           const nsIntPoint& aOffset,
+                           float aOpacity,
+                           const gfx3DMatrix& aMatrix);
 };
 
 #ifdef MOZ_IPC
 class ShadowContainerLayerOGL : public ShadowContainerLayer,
                                 public LayerOGL
 {
   template<class Container>
   friend void ContainerInsertAfter(Container* aContainer, Layer* aChild, Layer* aAfter);
@@ -105,16 +115,20 @@ class ShadowContainerLayerOGL : public S
   friend void ContainerRemoveChild(Container* aContainer, Layer* aChild);
   template<class Container>
   friend void ContainerDestroy(Container* aContainer);
   template<class Container>
   friend void ContainerRender(Container* aContainer,
                               int aPreviousFrameBuffer,
                               const nsIntPoint& aOffset,
                               LayerManagerOGL* aManager);
+  template<class Container>
+  friend bool ShouldUseIntermediate(Container* aContainer,
+                                    float aOpacity,
+                                    const gfx3DMatrix& aMatrix);
 
 public:
   ShadowContainerLayerOGL(LayerManagerOGL *aManager);
   ~ShadowContainerLayerOGL();
 
   void InsertAfter(Layer* aChild, Layer* aAfter);
 
   void RemoveChild(Layer* aChild);
@@ -122,16 +136,18 @@ public:
   // LayerOGL Implementation
   virtual Layer* GetLayer() { return this; }
 
   virtual void Destroy();
 
   LayerOGL* GetFirstChildOGL();
 
   virtual void RenderLayer(int aPreviousFrameBuffer,
-                           const nsIntPoint& aOffset);
+                           const nsIntPoint& aOffset,
+                           float aOpacity,
+                           const gfx3DMatrix& aMatrix);
 };
 #endif  // MOZ_IPC
 
 } /* layers */
 } /* mozilla */
 
 #endif /* GFX_CONTAINERLAYEROGL_H */
--- a/gfx/layers/opengl/ImageLayerOGL.cpp
+++ b/gfx/layers/opengl/ImageLayerOGL.cpp
@@ -366,17 +366,19 @@ ImageContainerOGL::SetLayerManager(Layer
 Layer*
 ImageLayerOGL::GetLayer()
 {
   return this;
 }
 
 void
 ImageLayerOGL::RenderLayer(int,
-                           const nsIntPoint& aOffset)
+                           const nsIntPoint& aOffset,
+                           float aOpacity,
+                           const gfx3DMatrix& aMatrix)
 {
   if (!GetContainer())
     return;
 
   mOGLManager->MakeCurrent();
 
   nsRefPtr<Image> image = GetContainer()->GetCurrentImage();
 
@@ -405,18 +407,18 @@ ImageLayerOGL::RenderLayer(int,
     ApplyFilter(mFilter);
 
     YCbCrTextureLayerProgram *program = mOGLManager->GetYCbCrLayerProgram();
 
     program->Activate();
     program->SetLayerQuadRect(nsIntRect(0, 0,
                                         yuvImage->mSize.width,
                                         yuvImage->mSize.height));
-    program->SetLayerTransform(GetEffectiveTransform());
-    program->SetLayerOpacity(GetOpacity());
+    program->SetLayerTransform(GetEffectiveTransform() * aMatrix);
+    program->SetLayerOpacity(GetOpacity() * aOpacity);
     program->SetRenderOffset(aOffset);
     program->SetYCbCrTextureUnits(0, 1, 2);
 
     DEBUG_GL_ERROR_CHECK(gl());
 
     mOGLManager->BindAndDrawQuad(program);
 
     // We shouldn't need to do this, but do it anyway just in case
@@ -434,18 +436,18 @@ ImageLayerOGL::RenderLayer(int,
                                         cairoImage->mASurfaceAsGLContext != 0);
 
     ApplyFilter(mFilter);
 
     program->Activate();
     program->SetLayerQuadRect(nsIntRect(0, 0,
                                         cairoImage->mSize.width,
                                         cairoImage->mSize.height));
-    program->SetLayerTransform(GetEffectiveTransform());
-    program->SetLayerOpacity(GetOpacity());
+    program->SetLayerTransform(GetEffectiveTransform() * aMatrix);
+    program->SetLayerOpacity(GetOpacity() * aOpacity);
     program->SetRenderOffset(aOffset);
     program->SetTextureUnit(0);
 
     mOGLManager->BindAndDrawQuad(program);
   }
 
   DEBUG_GL_ERROR_CHECK(gl());
 }
@@ -782,32 +784,34 @@ ShadowImageLayerOGL::Destroy()
 Layer*
 ShadowImageLayerOGL::GetLayer()
 {
   return this;
 }
 
 void
 ShadowImageLayerOGL::RenderLayer(int aPreviousFrameBuffer,
-                                 const nsIntPoint& aOffset)
+                                 const nsIntPoint& aOffset,
+                                 float aOpacity,
+                                 const gfx3DMatrix& aMatrix)
 {
   mOGLManager->MakeCurrent();
 
   gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
   gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexImage->Texture());
   ColorTextureLayerProgram *program =
     mOGLManager->GetBasicLayerProgram(CanUseOpaqueSurface(),
                                       mTexImage->IsRGB());
 
   ApplyFilter(mFilter);
 
   program->Activate();
   program->SetLayerQuadRect(nsIntRect(nsIntPoint(0, 0), mTexImage->GetSize()));
-  program->SetLayerTransform(mTransform);
-  program->SetLayerOpacity(GetOpacity());
+  program->SetLayerTransform(mTransform * aMatrix);
+  program->SetLayerOpacity(GetOpacity() * aOpacity);
   program->SetRenderOffset(aOffset);
   program->SetTextureUnit(0);
 
   mOGLManager->BindAndDrawQuad(program);
 
   DEBUG_GL_ERROR_CHECK(gl());
 }
 
--- a/gfx/layers/opengl/ImageLayerOGL.h
+++ b/gfx/layers/opengl/ImageLayerOGL.h
@@ -179,17 +179,19 @@ public:
   }
   ~ImageLayerOGL() { Destroy(); }
 
   // LayerOGL Implementation
   virtual void Destroy() { mDestroyed = PR_TRUE; }
   virtual Layer* GetLayer();
 
   virtual void RenderLayer(int aPreviousFrameBuffer,
-                           const nsIntPoint& aOffset);
+                           const nsIntPoint& aOffset,
+                           float aOpacity,
+                           const gfx3DMatrix& aMatrix);
 };
 
 class THEBES_API PlanarYCbCrImageOGL : public PlanarYCbCrImage
 {
   typedef mozilla::gl::GLContext GLContext;
 
 public:
   PlanarYCbCrImageOGL(LayerManagerOGL *aManager,
@@ -257,17 +259,19 @@ public:
   virtual void DestroyFrontBuffer();
 
   // LayerOGL impl
   virtual void Destroy();
 
   virtual Layer* GetLayer();
 
   virtual void RenderLayer(int aPreviousFrameBuffer,
-                           const nsIntPoint& aOffset);
+                           const nsIntPoint& aOffset,
+                           float aOpacity,
+                           const gfx3DMatrix& aMatrix);
 
 private:
   nsRefPtr<TextureImage> mTexImage;
 
 
   // XXX FIXME holding to free
   nsRefPtr<gfxSharedImageSurface> mDeadweight;
 
--- a/gfx/layers/opengl/LayerManagerOGL.cpp
+++ b/gfx/layers/opengl/LayerManagerOGL.cpp
@@ -586,17 +586,17 @@ LayerManagerOGL::Render()
 
   DEBUG_GL_ERROR_CHECK(mGLContext);
 
   mGLContext->fClearColor(0.0, 0.0, 0.0, 0.0);
   mGLContext->fClear(LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT);
 
   // Render our layers.
   RootLayer()->RenderLayer(mGLContext->IsDoubleBuffered() ? 0 : mBackBufferFBO,
-                           nsIntPoint(0, 0));
+                           nsIntPoint(0, 0), 1.0, gfx3DMatrix());
 
   DEBUG_GL_ERROR_CHECK(mGLContext);
 
   if (mTarget) {
     CopyToTarget();
     return;
   }
 
--- a/gfx/layers/opengl/LayerManagerOGL.h
+++ b/gfx/layers/opengl/LayerManagerOGL.h
@@ -457,17 +457,19 @@ 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 RenderLayer(int aPreviousFrameBuffer,
-                           const nsIntPoint& aOffset) = 0;
+                           const nsIntPoint& aOffset,
+                           float aOpacity,
+                           const gfx3DMatrix& aMatrix) = 0;
 
   typedef mozilla::gl::GLContext GLContext;
 
   LayerManagerOGL* OGLManager() const { return mOGLManager; }
   GLContext *gl() const { return mOGLManager->gl(); }
 
   void ApplyFilter(gfxPattern::GraphicsFilter aFilter);
 protected:
--- a/gfx/layers/opengl/ThebesLayerOGL.cpp
+++ b/gfx/layers/opengl/ThebesLayerOGL.cpp
@@ -128,17 +128,18 @@ public:
   ThebesLayerBufferOGL(ThebesLayer* aLayer, LayerOGL* aOGLLayer)
     : mLayer(aLayer)
     , mOGLLayer(aOGLLayer)
   {}
   virtual ~ThebesLayerBufferOGL() {}
 
   virtual PaintState BeginPaint(ContentType aContentType) = 0;
 
-  void RenderTo(const nsIntPoint& aOffset, LayerManagerOGL* aManager);
+  void RenderTo(const nsIntPoint& aOffset, LayerManagerOGL* aManager,
+                float aOpacity, const gfx3DMatrix& aMatrix);
 
   nsIntSize GetSize() {
     if (mTexImage)
       return mTexImage->GetSize();
     return nsIntSize(0, 0);
   }
 
 protected:
@@ -148,17 +149,19 @@ protected:
 
   ThebesLayer* mLayer;
   LayerOGL* mOGLLayer;
   nsRefPtr<TextureImage> mTexImage;
 };
 
 void
 ThebesLayerBufferOGL::RenderTo(const nsIntPoint& aOffset,
-                               LayerManagerOGL* aManager)
+                               LayerManagerOGL* aManager,
+                               float aOpacity,
+                               const gfx3DMatrix& aMatrix)
 {
   if (!mTexImage)
     return;
 
   // Note BGR: Cairo's image surfaces are always in what
   // OpenGL and our shaders consider BGR format.
   ColorTextureLayerProgram *program =
     aManager->GetBasicLayerProgram(mLayer->CanUseOpaqueSurface(),
@@ -173,18 +176,18 @@ ThebesLayerBufferOGL::RenderTo(const nsI
   float xres = mLayer->GetXResolution();
   float yres = mLayer->GetYResolution();
 
   nsIntRegionRectIterator iter(mLayer->GetEffectiveVisibleRegion());
   while (const nsIntRect *iterRect = iter.Next()) {
     nsIntRect quadRect = *iterRect;
     program->Activate();
     program->SetLayerQuadRect(quadRect);
-    program->SetLayerOpacity(mLayer->GetOpacity());
-    program->SetLayerTransform(mLayer->GetEffectiveTransform());
+    program->SetLayerOpacity(mLayer->GetOpacity() * aOpacity);
+    program->SetLayerTransform(mLayer->GetEffectiveTransform() * aMatrix);
     program->SetRenderOffset(aOffset);
     program->SetTextureUnit(0);
     DEBUG_GL_ERROR_CHECK(gl());
 
     quadRect.MoveBy(-GetOriginOffset());
 
     // The buffer rect and rotation are resolution-neutral; with a
     // non-1.0 resolution, only the texture size is scaled by the
@@ -504,17 +507,19 @@ ThebesLayerOGL::SetVisibleRegion(const n
 void
 ThebesLayerOGL::InvalidateRegion(const nsIntRegion &aRegion)
 {
   mValidRegion.Sub(mValidRegion, aRegion);
 }
 
 void
 ThebesLayerOGL::RenderLayer(int aPreviousFrameBuffer,
-                            const nsIntPoint& aOffset)
+                            const nsIntPoint& aOffset,
+                            float aOpacity,
+                            const gfx3DMatrix& aMatrix)
 {
   if (!mBuffer && !CreateSurface()) {
     return;
   }
   NS_ABORT_IF_FALSE(mBuffer, "should have a buffer here");
 
   mOGLManager->MakeCurrent();
   gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
@@ -534,17 +539,17 @@ ThebesLayerOGL::RenderLayer(int aPreviou
     callback(this, state.mContext, state.mRegionToDraw,
              state.mRegionToInvalidate, callbackData);
     mValidRegion.Or(mValidRegion, state.mRegionToDraw);
   }
 
   DEBUG_GL_ERROR_CHECK(gl());
 
   gl()->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, aPreviousFrameBuffer);
-  mBuffer->RenderTo(aOffset, mOGLManager);
+  mBuffer->RenderTo(aOffset, mOGLManager, aOpacity, aMatrix);
   DEBUG_GL_ERROR_CHECK(gl());
 }
 
 Layer*
 ThebesLayerOGL::GetLayer()
 {
   return this;
 }
@@ -694,29 +699,31 @@ ShadowThebesLayerOGL::GetLayer()
 PRBool
 ShadowThebesLayerOGL::IsEmpty()
 {
   return !mBuffer;
 }
 
 void
 ShadowThebesLayerOGL::RenderLayer(int aPreviousFrameBuffer,
-                                  const nsIntPoint& aOffset)
+                                  const nsIntPoint& aOffset,
+                                  float aOpacity,
+                                  const gfx3DMatrix& aMatrix)
 {
   if (!mBuffer) {
     return;
   }
   NS_ABORT_IF_FALSE(mBuffer, "should have a buffer here");
 
   mOGLManager->MakeCurrent();
   gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
   DEBUG_GL_ERROR_CHECK(gl());
 
   gl()->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, aPreviousFrameBuffer);
-  mBuffer->RenderTo(aOffset, mOGLManager);
+  mBuffer->RenderTo(aOffset, mOGLManager, aOpacity, aMatrix);
   DEBUG_GL_ERROR_CHECK(gl());
 }
 
 #endif  // MOZ_IPC
 
 
 } /* layers */
 } /* mozilla */
--- a/gfx/layers/opengl/ThebesLayerOGL.h
+++ b/gfx/layers/opengl/ThebesLayerOGL.h
@@ -71,17 +71,19 @@ public:
   /** ThebesLayer implementation */
   void InvalidateRegion(const nsIntRegion& aRegion);
 
   /** LayerOGL implementation */
   void Destroy();
   Layer* GetLayer();
   virtual PRBool IsEmpty();
   virtual void RenderLayer(int aPreviousFrameBuffer,
-                           const nsIntPoint& aOffset);
+                           const nsIntPoint& aOffset,
+                           float aOpacity,
+                           const gfx3DMatrix& aMatrix);
 
 private:
   friend class BasicBufferOGL;
 
   PRBool CreateSurface();
 
   nsRefPtr<Buffer> mBuffer;
 };
@@ -105,17 +107,19 @@ public:
        OptionalThebesBuffer* aReadOnlyFront, nsIntRegion* aFrontUpdatedRegion);
   virtual void DestroyFrontBuffer();
 
   // LayerOGL impl
   void Destroy();
   Layer* GetLayer();
   virtual PRBool IsEmpty();
   virtual void RenderLayer(int aPreviousFrameBuffer,
-                           const nsIntPoint& aOffset);
+                           const nsIntPoint& aOffset,
+                           float aOpacity,
+                           const gfx3DMatrix& aMatrix);
 
 private:
   nsRefPtr<ShadowBufferOGL> mBuffer;
 
 
   // XXX FIXME TEMP: hold on to this so that we can free it in DestroyFrontBuffer()
   SurfaceDescriptor mDeadweight;