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 id17664
push userromaxa@gmail.com
push dateTue, 21 Dec 2010 18:45:33 +0000
treeherdermozilla-central@722ffb1a0920 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc, approval2.0
bugs607653
milestone2.0b9pre
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 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,