Bug 607936 - Make possible to apply transform on topLevel LayerManager scene r=matt,roc a=joe
authorOleg Romashin <romaxa@gmail.com>
Fri, 04 Feb 2011 14:47:06 -0500
changeset 61955 c8a2a8063a1cb47a343b8fffed522d4b1eb83e9b
parent 61954 beb7483fcb5d1236d46a399f4e35cb5471d53ade
child 61956 261614faec16fd03500260004219bda4bd341b66
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmatt, roc, joe
bugs607936
milestone2.0b12pre
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 607936 - Make possible to apply transform on topLevel LayerManager scene r=matt,roc a=joe
gfx/layers/opengl/ContainerLayerOGL.cpp
gfx/layers/opengl/LayerManagerOGL.cpp
gfx/layers/opengl/LayerManagerOGL.h
gfx/thebes/gfxMatrix.h
--- a/gfx/layers/opengl/ContainerLayerOGL.cpp
+++ b/gfx/layers/opengl/ContainerLayerOGL.cpp
@@ -206,17 +206,18 @@ ContainerRender(Container* aContainer,
     aManager->CreateFBOWithTexture(framebufferRect,
                                    mode,
                                    &frameBuffer,
                                    &containerSurface);
     childOffset.x = visibleRect.x;
     childOffset.y = visibleRect.y;
 
     aContainer->gl()->PushViewportRect();
-    aManager->SetupPipeline(visibleRect.width, visibleRect.height);
+    aManager->SetupPipeline(visibleRect.width, visibleRect.height,
+                            LayerManagerOGL::DontApplyWorldTransform);
 
   } else {
     frameBuffer = aPreviousFrameBuffer;
     aContainer->mSupportsComponentAlphaChildren = (aContainer->GetContentFlags() & Layer::CONTENT_OPAQUE) ||
       (aContainer->GetParent() && aContainer->GetParent()->SupportsComponentAlphaChildren());
 #ifdef DEBUG
     PRBool is2d =
 #endif
@@ -251,16 +252,21 @@ ContainerRender(Container* aContainer,
           scissorRect = visibleRect;
         }
       }
     }
 
     if (needsFramebuffer) {
       scissorRect.MoveBy(- visibleRect.TopLeft());
     } else {
+      if (!frameBuffer) {
+        // Transform scissorRect here
+        aManager->WorldTransformRect(scissorRect);
+      }
+
       if (!aPreviousFrameBuffer) {
         /**
          * glScissor coordinates are oriented with 0,0 being at the bottom left,
          * the opposite to layout (0,0 at the top left).
          * All rendering to an FBO is upside-down, making the coordinate systems
          * match.
          * When rendering directly to a window (No current or previous FBO),
          * we need to flip the scissor rect.
@@ -293,17 +299,18 @@ ContainerRender(Container* aContainer,
   aContainer->gl()->PopScissorRect();
 
   if (needsFramebuffer) {
     // Unbind the current framebuffer and rebind the previous one.
     
     // Restore the viewport
     aContainer->gl()->PopViewportRect();
     nsIntRect viewport = aContainer->gl()->ViewportRect();
-    aManager->SetupPipeline(viewport.width, viewport.height);
+    aManager->SetupPipeline(viewport.width, viewport.height,
+                            LayerManagerOGL::ApplyWorldTransform);
 
     aContainer->gl()->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, aPreviousFrameBuffer);
     aContainer->gl()->fDeleteFramebuffers(1, &frameBuffer);
 
     aContainer->gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
 
     aContainer->gl()->fBindTexture(aManager->FBOTextureTarget(), containerSurface);
 
--- a/gfx/layers/opengl/LayerManagerOGL.cpp
+++ b/gfx/layers/opengl/LayerManagerOGL.cpp
@@ -545,16 +545,17 @@ LayerManagerOGL::Render()
 {
   if (mDestroyed) {
     NS_WARNING("Call on destroyed layer manager");
     return;
   }
 
   nsIntRect rect;
   mWidget->GetClientBounds(rect);
+  WorldTransformRect(rect);
 
   GLint width = rect.width;
   GLint height = rect.height;
 
   // We can't draw anything to something with no area
   // so just return
   if (width == 0 || height == 0)
     return;
@@ -570,29 +571,30 @@ LayerManagerOGL::Render()
     mWidgetSize.height = height;
   } else {
     MakeCurrent();
   }
 
   DEBUG_GL_ERROR_CHECK(mGLContext);
 
   SetupBackBuffer(width, height);
-  SetupPipeline(width, height);
+  SetupPipeline(width, height, ApplyWorldTransform);
 
   // Default blend function implements "OVER"
   mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA,
                                  LOCAL_GL_ONE, LOCAL_GL_ONE);
   mGLContext->fEnable(LOCAL_GL_BLEND);
 
   DEBUG_GL_ERROR_CHECK(mGLContext);
 
   const nsIntRect *clipRect = mRoot->GetClipRect();
 
   if (clipRect) {
     nsIntRect r = *clipRect;
+    WorldTransformRect(r);
     if (!mGLContext->IsDoubleBuffered() && !mTarget)
       mGLContext->FixWindowCoordinateRect(r, mWidgetSize.height);
     mGLContext->fScissor(r.x, r.y, r.width, r.height);
   } else {
     mGLContext->fScissor(0, 0, width, height);
   }
 
   mGLContext->fEnable(LOCAL_GL_SCISSOR_TEST);
@@ -657,16 +659,18 @@ LayerManagerOGL::Render()
 
   mGLContext->fEnableVertexAttribArray(vcattr);
   mGLContext->fEnableVertexAttribArray(tcattr);
 
   const nsIntRect *r;
   nsIntRegionRectIterator iter(mClippingRegion);
 
   while ((r = iter.Next()) != nsnull) {
+    nsIntRect cRect = *r; r = &cRect;
+    WorldTransformRect(cRect);
     float left = (GLfloat)r->x / width;
     float right = (GLfloat)r->XMost() / width;
     float top = (GLfloat)r->y / height;
     float bottom = (GLfloat)r->YMost() / height;
 
     float vertices[] = { left * 2.0f - 1.0f,
                          -(top * 2.0f - 1.0f),
                          right * 2.0f - 1.0f,
@@ -701,17 +705,42 @@ LayerManagerOGL::Render()
   DEBUG_GL_ERROR_CHECK(mGLContext);
 
   mGLContext->fFlush();
 
   DEBUG_GL_ERROR_CHECK(mGLContext);
 }
 
 void
-LayerManagerOGL::SetupPipeline(int aWidth, int aHeight)
+LayerManagerOGL::SetWorldTransform(const gfxMatrix& aMatrix)
+{
+  NS_ASSERTION(aMatrix.PreservesAxisAlignedRectangles(),
+               "SetWorldTransform only accepts matrices that satisfy PreservesAxisAlignedRectangles");
+  NS_ASSERTION(!aMatrix.HasNonIntegerScale(),
+               "SetWorldTransform only accepts matrices with integer scale");
+
+  mWorldMatrix = aMatrix;
+}
+
+gfxMatrix&
+LayerManagerOGL::GetWorldTransform(void)
+{
+  return mWorldMatrix;
+}
+
+void
+LayerManagerOGL::WorldTransformRect(nsIntRect& aRect)
+{
+  gfxRect grect(aRect.x, aRect.y, aRect.width, aRect.height);
+  grect = mWorldMatrix.TransformBounds(grect);
+  aRect.SetRect(grect.pos.x, grect.pos.y, grect.size.width, grect.size.height);
+}
+
+void
+LayerManagerOGL::SetupPipeline(int aWidth, int aHeight, WorldTransforPolicy aTransformPolicy)
 {
   // Set the viewport correctly. 
   //
   // When we're not double buffering, we use a FBO as our backbuffer.
   // We use a normal view transform in that case, meaning that our FBO
   // and all other FBOs look upside down.  We then do a Y-flip when
   // we draw it into the window.
   mGLContext->fViewport(0, 0, aWidth, aHeight);
@@ -739,16 +768,20 @@ LayerManagerOGL::SetupPipeline(int aWidt
     viewMatrix._42 = 1.0f;
   } else {
     viewMatrix._11 = 2.0f / float(aWidth);
     viewMatrix._22 = 2.0f / float(aHeight);
     viewMatrix._41 = -1.0f;
     viewMatrix._42 = -1.0f;
   }
 
+  if (aTransformPolicy == ApplyWorldTransform) {
+    viewMatrix = gfx3DMatrix::From2D(mWorldMatrix) * viewMatrix;
+  }
+
   SetLayerProgramProjectionMatrix(viewMatrix);
 }
 
 void
 LayerManagerOGL::SetupBackBuffer(int aWidth, int aHeight)
 {
   if (mGLContext->IsDoubleBuffered() && !mTarget) {
     mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
--- a/gfx/layers/opengl/LayerManagerOGL.h
+++ b/gfx/layers/opengl/LayerManagerOGL.h
@@ -367,21 +367,35 @@ public:
 #ifdef MOZ_LAYERS_HAVE_LOG
   virtual const char* Name() const { return "OGL"; }
 #endif // MOZ_LAYERS_HAVE_LOG
 
   const nsIntSize& GetWigetSize() {
     return mWidgetSize;
   }
 
+  enum WorldTransforPolicy {
+    ApplyWorldTransform,
+    DontApplyWorldTransform
+  };
+
   /**
    * Setup the viewport and projection matrix for rendering
    * to a window of the given dimensions.
    */
-  void SetupPipeline(int aWidth, int aHeight);
+  void SetupPipeline(int aWidth, int aHeight, WorldTransforPolicy aTransformPolicy);
+
+  /**
+   * Setup World transform matrix.
+   * Transform will be ignored if it is not PreservesAxisAlignedRectangles
+   * or has non integer scale
+   */
+  void SetWorldTransform(const gfxMatrix& aMatrix);
+  gfxMatrix& GetWorldTransform(void);
+  void WorldTransformRect(nsIntRect& aRect);
 
 private:
   /** Widget associated with this layer manager */
   nsIWidget *mWidget;
   nsIntSize mWidgetSize;
 
   /** 
    * Context target, NULL when drawing directly to our swap chain.
@@ -450,16 +464,17 @@ private:
    * If we have any more similar updates, then we should delay.
    */
   void SetLayerProgramProjectionMatrix(const gfx3DMatrix& aMatrix);
 
   /* Thebes layer callbacks; valid at the end of a transaciton,
    * while rendering */
   DrawThebesLayerCallback mThebesLayerCallback;
   void *mThebesLayerCallbackData;
+  gfxMatrix mWorldMatrix;
 };
 
 /**
  * General information and tree management for OGL layers.
  */
 class LayerOGL
 {
 public:
--- a/gfx/thebes/gfxMatrix.h
+++ b/gfx/thebes/gfxMatrix.h
@@ -276,15 +276,23 @@ public:
      * Returns true if matrix is multiple of 90 degrees rotation with flipping,
      * scaling and translation.
      */
     PRBool PreservesAxisAlignedRectangles() const {
         return ((FuzzyEqual(xx, 0.0) && FuzzyEqual(yy, 0.0))
             || (FuzzyEqual(xy, 0.0) && FuzzyEqual(yx, 0.0)));
     }
 
+    /**
+     * Returns true if the matrix has non-integer scale
+     */
+    PRBool HasNonIntegerScale() const {
+        return !FuzzyEqual(xx, NS_floor(xx + 0.5)) ||
+               !FuzzyEqual(yy, NS_floor(yy + 0.5));
+    }
+
 private:
     static PRBool FuzzyEqual(gfxFloat aV1, gfxFloat aV2) {
         return fabs(aV2 - aV1) < 1e-6;
     }
 };
 
 #endif /* GFX_MATRIX_H */