Bug 607653 - avoid temporary fbos/textures on transformed layers, when possible. r=roc a=approval2.0
authorOleg Romashin <romaxa@gmail.com>
Tue, 30 Nov 2010 08:02:46 +0200
changeset 59559 ab173acf8a1f751ba485980e032d4fe18be4b05d
parent 59558 d538a677628e71f1de7de056a93d195a08f6112b
child 59560 722ffb1a0920773fc92adac27244e13f3c5a1c95
push id1
push usershaver@mozilla.com
push dateTue, 04 Jan 2011 17:58:04 +0000
reviewersroc, approval2
bugs607653
milestone2.0b9pre
Bug 607653 - avoid temporary fbos/textures on transformed layers, when possible. r=roc a=approval2.0
gfx/layers/Layers.cpp
gfx/layers/d3d10/ContainerLayerD3D10.cpp
gfx/layers/d3d9/ContainerLayerD3D9.cpp
gfx/layers/opengl/ContainerLayerOGL.cpp
--- a/gfx/layers/Layers.cpp
+++ b/gfx/layers/Layers.cpp
@@ -327,17 +327,19 @@ ContainerLayer::DefaultComputeEffectiveT
   mEffectiveTransform = SnapTransform(idealTransform, gfxRect(0, 0, 0, 0), &residual);
 
   PRBool useIntermediateSurface;
   float opacity = GetEffectiveOpacity();
   if (opacity != 1.0f && HasMultipleChildren()) {
     useIntermediateSurface = PR_TRUE;
   } else {
     useIntermediateSurface = PR_FALSE;
-    if (!mEffectiveTransform.IsIdentity()) {
+    gfxMatrix contTransform;
+    if (!mEffectiveTransform.Is2D(&contTransform) ||
+        !contTransform.PreservesAxisAlignedRectangles()) {
       for (Layer* child = GetFirstChild(); child; child = child->GetNextSibling()) {
         const nsIntRect *clipRect = child->GetEffectiveClipRect();
         /* We can't (easily) forward our transform to children with a non-empty 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() && !child->GetVisibleRegion().IsEmpty()) {
           useIntermediateSurface = PR_TRUE;
--- a/gfx/layers/d3d10/ContainerLayerD3D10.cpp
+++ b/gfx/layers/d3d10/ContainerLayerD3D10.cpp
@@ -166,16 +166,17 @@ ContainerLayerD3D10::RenderLayer()
   nsRefPtr<ID3D10RenderTargetView> previousRTView;
   nsRefPtr<ID3D10Texture2D> renderTexture;
   nsRefPtr<ID3D10RenderTargetView> rtView;
   float previousRenderTargetOffset[2];
   nsIntSize previousViewportSize;
 
   gfx3DMatrix oldViewMatrix;
 
+  gfxMatrix contTransform;
   if (useIntermediate) {
     device()->OMGetRenderTargets(1, getter_AddRefs(previousRTView), NULL);
  
     D3D10_TEXTURE2D_DESC desc;
     memset(&desc, 0, sizeof(D3D10_TEXTURE2D_DESC));
     desc.ArraySize = 1;
     desc.MipLevels = 1;
     desc.Width = visibleRect.width;
@@ -198,16 +199,22 @@ ContainerLayerD3D10::RenderLayer()
 
     renderTargetOffset[0] = (float)visibleRect.x;
     renderTargetOffset[1] = (float)visibleRect.y;
     effect()->GetVariableByName("vRenderTargetOffset")->
       SetRawValue(renderTargetOffset, 0, 8);
 
     previousViewportSize = mD3DManager->GetViewport();
     mD3DManager->SetViewport(nsIntSize(visibleRect.Size()));
+  } else {
+#ifdef DEBUG
+    PRBool is2d =
+#endif
+    GetEffectiveTransform().Is2D(&contTransform);
+    NS_ASSERTION(is2d, "Transform must be 2D");
   }
 
   /*
    * Render this container's contents.
    */
   for (LayerD3D10* layerToRender = GetFirstChildD3D10();
        layerToRender != nsnull;
        layerToRender = GetNextSiblingD3D10(layerToRender)) {
@@ -234,16 +241,34 @@ ContainerLayerD3D10::RenderLayer()
         r.left = 0;
         r.top = 0;
         r.right = visibleRect.width;
         r.bottom = visibleRect.height;
       }
 
       D3D10_RECT d3drect;
       if (!useIntermediate) {
+        if (clipRect) {
+          gfxRect cliprect(r.left, r.top, r.right - r.left, r.bottom - r.top);
+          gfxRect trScissor = contTransform.TransformBounds(cliprect);
+          trScissor.Round();
+          nsIntRect trIntScissor;
+          if (gfxUtils::GfxRectToIntRect(trScissor, &trIntScissor)) {
+            r.left = trIntScissor.x;
+            r.top = trIntScissor.y;
+            r.right = trIntScissor.XMost();
+            r.bottom = trIntScissor.YMost();
+          } else {
+            r.left = 0;
+            r.top = 0;
+            r.right = visibleRect.width;
+            r.bottom = visibleRect.height;
+            clipRect = nsnull;
+          }
+        }
         // Scissor rect should be an intersection of the old and current scissor.
         r.left = NS_MAX<PRInt32>(oldScissor.left, r.left);
         r.right = NS_MIN<PRInt32>(oldScissor.right, r.right);
         r.top = NS_MAX<PRInt32>(oldScissor.top, r.top);
         r.bottom = NS_MIN<PRInt32>(oldScissor.bottom, r.bottom);
       }
 
       if (r.left >= r.right || r.top >= r.bottom) {
--- a/gfx/layers/d3d9/ContainerLayerD3D9.cpp
+++ b/gfx/layers/d3d9/ContainerLayerD3D9.cpp
@@ -161,16 +161,17 @@ ContainerLayerD3D9::RenderLayer()
   float previousRenderTargetOffset[4];
   RECT oldClipRect;
   float renderTargetOffset[] = { 0, 0, 0, 0 };
   float oldViewMatrix[4][4];
 
   nsIntRect visibleRect = mVisibleRegion.GetBounds();
   PRBool useIntermediate = UseIntermediateSurface();
 
+  gfxMatrix contTransform;
   if (useIntermediate) {
     device()->GetRenderTarget(0, getter_AddRefs(previousRenderTarget));
     device()->CreateTexture(visibleRect.width, visibleRect.height, 1,
                             D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8,
                             D3DPOOL_DEFAULT, getter_AddRefs(renderTexture),
                             NULL);
     nsRefPtr<IDirect3DSurface9> renderSurface;
     renderTexture->GetSurfaceLevel(0, getter_AddRefs(renderSurface));
@@ -188,16 +189,22 @@ ContainerLayerD3D9::RenderLayer()
      */
     viewMatrix._11 = 2.0f / visibleRect.width;
     viewMatrix._22 = -2.0f / visibleRect.height;
     viewMatrix._41 = -1.0f;
     viewMatrix._42 = 1.0f;
 
     device()->GetVertexShaderConstantF(CBmProjection, &oldViewMatrix[0][0], 4);
     device()->SetVertexShaderConstantF(CBmProjection, &viewMatrix._11, 4);
+  } else {
+#ifdef DEBUG
+    PRBool is2d =
+#endif
+    GetEffectiveTransform().Is2D(&contTransform);
+    NS_ASSERTION(is2d, "Transform must be 2D");
   }
 
   /*
    * Render this container's contents.
    */
   for (LayerD3D9* layerToRender = GetFirstChildD3D9();
        layerToRender != nsnull;
        layerToRender = GetNextSiblingD3D9(layerToRender)) {
@@ -225,16 +232,35 @@ ContainerLayerD3D9::RenderLayer()
 
       nsRefPtr<IDirect3DSurface9> renderSurface;
       device()->GetRenderTarget(0, getter_AddRefs(renderSurface));
 
       D3DSURFACE_DESC desc;
       renderSurface->GetDesc(&desc);
 
       if (!useIntermediate) {
+        // Transform clip rect
+        if (clipRect) {
+          gfxRect cliprect(r.left, r.top, r.right - r.left, r.bottom - r.top);
+          gfxRect trScissor = contTransform.TransformBounds(cliprect);
+          trScissor.Round();
+          nsIntRect trIntScissor;
+          if (gfxUtils::GfxRectToIntRect(trScissor, &trIntScissor)) {
+            r.left = trIntScissor.x;
+            r.top = trIntScissor.y;
+            r.right = trIntScissor.XMost();
+            r.bottom = trIntScissor.YMost();
+          } else {
+            r.left = 0;
+            r.top = 0;
+            r.right = visibleRect.width;
+            r.bottom = visibleRect.height;
+            clipRect = nsnull;
+          }
+        }
         // Intersect with current clip rect.
         r.left = NS_MAX<PRInt32>(oldClipRect.left, r.left);
         r.right = NS_MIN<PRInt32>(oldClipRect.right, r.right);
         r.top = NS_MAX<PRInt32>(oldClipRect.top, r.top);
         r.bottom = NS_MIN<PRInt32>(oldClipRect.bottom, r.bottom);
       } else {
         // > 0 is implied during the intersection when useIntermediate == true;
         r.left = NS_MAX<LONG>(0, r.left);
--- a/gfx/layers/opengl/ContainerLayerOGL.cpp
+++ b/gfx/layers/opengl/ContainerLayerOGL.cpp
@@ -155,32 +155,38 @@ ContainerRender(Container* aContainer,
   nsIntRect visibleRect = aContainer->GetEffectiveVisibleRegion().GetBounds();
 
   nsIntRect cachedScissor = aContainer->gl()->ScissorRect();
   aContainer->gl()->PushScissorRect();
 
   float opacity = aContainer->GetEffectiveOpacity();
   const gfx3DMatrix& transform = aContainer->GetEffectiveTransform();
   bool needsFramebuffer = aContainer->UseIntermediateSurface();
+  gfxMatrix contTransform;
   if (needsFramebuffer) {
     aManager->CreateFBOWithTexture(visibleRect.width,
                                    visibleRect.height,
                                    &frameBuffer,
                                    &containerSurface);
     childOffset.x = visibleRect.x;
     childOffset.y = visibleRect.y;
 
     aContainer->gl()->PushViewportRect();
     aManager->SetupPipeline(visibleRect.width, visibleRect.height);
 
     aContainer->gl()->fScissor(0, 0, visibleRect.width, visibleRect.height);
     aContainer->gl()->fClearColor(0.0, 0.0, 0.0, 0.0);
     aContainer->gl()->fClear(LOCAL_GL_COLOR_BUFFER_BIT);
   } else {
     frameBuffer = aPreviousFrameBuffer;
+#ifdef DEBUG
+    PRBool is2d =
+#endif
+    transform.Is2D(&contTransform);
+    NS_ASSERTION(is2d, "Transform must be 2D");
   }
 
   /**
    * Render this container's contents.
    */
   for (LayerOGL* layerToRender = aContainer->GetFirstChildOGL();
        layerToRender != nsnull;
        layerToRender = GetNextSibling(layerToRender)) {
@@ -192,16 +198,24 @@ ContainerRender(Container* aContainer,
     nsIntRect scissorRect(visibleRect);
 
     const nsIntRect *clipRect = layerToRender->GetLayer()->GetEffectiveClipRect();
     if (clipRect) {
       if (clipRect->IsEmpty()) {
         continue;
       }
       scissorRect = *clipRect;
+      if (!needsFramebuffer) {
+        gfxRect r(scissorRect.x, scissorRect.y, scissorRect.width, scissorRect.height);
+        gfxRect trScissor = contTransform.TransformBounds(r);
+        trScissor.Round();
+        if (!gfxUtils::GfxRectToIntRect(trScissor, &scissorRect)) {
+          scissorRect = visibleRect;
+        }
+      }
     }
 
     if (needsFramebuffer) {
       scissorRect.MoveBy(- visibleRect.TopLeft());
     } else {
       if (!aPreviousFrameBuffer) {
         /**
          * glScissor coordinates are oriented with 0,0 being at the bottom left,