Bug 801918. OpenGL: Avoid doing extra invalidation when unrotating a buffer. r=mwoodrow
authorJeff Muizelaar <jmuizelaar@mozilla.com>
Wed, 07 Nov 2012 21:35:54 -0500
changeset 112662 b5c86318a3eea414659dd660afe06c373ad2d584
parent 112661 6cafbe512866905f9a9e33019901e193df1147fa
child 112663 1626c61ba11b788a7cf47520e8a00062aa46a612
push id23833
push useremorley@mozilla.com
push dateThu, 08 Nov 2012 10:20:57 +0000
treeherdermozilla-central@e0d7b394462b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmwoodrow
bugs801918
milestone19.0a1
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 801918. OpenGL: Avoid doing extra invalidation when unrotating a buffer. r=mwoodrow This approach ends up calling BlitTextureImage three extra times instead of changing BlitTextureImage to support rotated buffers. Supporting rotated buffers in BlitTextureImage is somewhat tricky because of TiledTextureImage, and calling it three more times shouldn't be too bad (it should be better than having to repaint) Unfortunately, the rectangle manipulation code is a bit hairy.
gfx/layers/opengl/ThebesLayerOGL.cpp
--- a/gfx/layers/opengl/ThebesLayerOGL.cpp
+++ b/gfx/layers/opengl/ThebesLayerOGL.cpp
@@ -582,73 +582,118 @@ BasicBufferOGL::BeginPaint(ContentType a
   }
 
   if (destBuffer) {
     if (mTexImage && (mode != Layer::SURFACE_COMPONENT_ALPHA || mTexImageOnWhite)) {
       // BlitTextureImage depends on the FBO texture target being
       // TEXTURE_2D.  This isn't the case on some older X1600-era Radeons.
       if (mOGLLayer->OGLManager()->FBOTextureTarget() == LOCAL_GL_TEXTURE_2D) {
         nsIntRect overlap;
+
+        // The buffer looks like:
+        //  ______
+        // |1  |2 |  Where the center point is offset by mBufferRotation from the top-left corner.
+        // |___|__|
+        // |3  |4 |
+        // |___|__|
+        //
+        // This is drawn to the screen as:
+        //  ______
+        // |4  |3 |  Where the center point is { width - mBufferRotation.x, height - mBufferRotation.y } from
+        // |___|__|  from the top left corner - rotationPoint.
+        // |2  |1 |
+        // |___|__|
+        //
+
+        // The basic idea below is to take all quadrant rectangles from the src and transform them into rectangles
+        // in the destination. Unfortunately, it seems it is overly complex and could perhaps be simplified.
+
+        nsIntRect srcBufferSpaceBottomRight(mBufferRotation.x, mBufferRotation.y, mBufferRect.width - mBufferRotation.x, mBufferRect.height - mBufferRotation.y);
+        nsIntRect srcBufferSpaceTopRight(mBufferRotation.x, 0, mBufferRect.width - mBufferRotation.x, mBufferRotation.y);
+        nsIntRect srcBufferSpaceTopLeft(0, 0, mBufferRotation.x, mBufferRotation.y);
+        nsIntRect srcBufferSpaceBottomLeft(0, mBufferRotation.y, mBufferRotation.x, mBufferRect.height - mBufferRotation.y);
+
         overlap.IntersectRect(mBufferRect, destBufferRect);
 
         nsIntRect srcRect(overlap), dstRect(overlap);
         srcRect.MoveBy(- mBufferRect.TopLeft() + mBufferRotation);
-        dstRect.MoveBy(- destBufferRect.TopLeft());
-        
-        if (mBufferRotation != nsIntPoint(0, 0)) {
-          // If mBuffer is rotated, then BlitTextureImage will only be copying the bottom-right section
-          // of the buffer. We need to invalidate the remaining sections so that they get redrawn too.
-          // Alternatively we could teach BlitTextureImage to rearrange the rotated segments onto
-          // the new buffer.
-          
-          // When the rotated buffer is reorganised, the bottom-right section will be drawn in the top left.
-          // Find the point where this content ends.
-          nsIntPoint rotationPoint(mBufferRect.x + mBufferRect.width - mBufferRotation.x, 
-                                   mBufferRect.y + mBufferRect.height - mBufferRotation.y);
+
+        nsIntRect srcRectDrawTopRight(srcRect);
+        nsIntRect srcRectDrawTopLeft(srcRect);
+        nsIntRect srcRectDrawBottomLeft(srcRect);
+        // transform into the different quadrants
+        srcRectDrawTopRight  .MoveBy(-nsIntPoint(0, mBufferRect.height));
+        srcRectDrawTopLeft   .MoveBy(-nsIntPoint(mBufferRect.width, mBufferRect.height));
+        srcRectDrawBottomLeft.MoveBy(-nsIntPoint(mBufferRect.width, 0));
+
+        // Intersect with the quadrant
+        srcRect               = srcRect              .Intersect(srcBufferSpaceBottomRight);
+        srcRectDrawTopRight   = srcRectDrawTopRight  .Intersect(srcBufferSpaceTopRight);
+        srcRectDrawTopLeft    = srcRectDrawTopLeft   .Intersect(srcBufferSpaceTopLeft);
+        srcRectDrawBottomLeft = srcRectDrawBottomLeft.Intersect(srcBufferSpaceBottomLeft);
 
-          // The buffer looks like:
-          //  ______
-          // |1  |2 |  Where the center point is offset by mBufferRotation from the top-left corner.
-          // |___|__|
-          // |3  |4 |
-          // |___|__|
-          //
-          // This is drawn to the screen as:
-          //  ______
-          // |4  |3 |  Where the center point is { width - mBufferRotation.x, height - mBufferRotation.y } from
-          // |___|__|  from the top left corner - rotationPoint. Since only quadrant 4 will actually be copied, 
-          // |2  |1 |  we need to invalidate the others.
-          // |___|__|
-          //
-          // Quadrants 2 and 1
-          nsIntRect bottom(mBufferRect.x, rotationPoint.y, mBufferRect.width, mBufferRotation.y);
-          // Quadrant 3
-          nsIntRect topright(rotationPoint.x, mBufferRect.y, mBufferRotation.x, rotationPoint.y - mBufferRect.y);
+        dstRect = srcRect;
+        nsIntRect dstRectDrawTopRight(srcRectDrawTopRight);
+        nsIntRect dstRectDrawTopLeft(srcRectDrawTopLeft);
+        nsIntRect dstRectDrawBottomLeft(srcRectDrawBottomLeft);
+
+        // transform back to src buffer space
+        dstRect              .MoveBy(-mBufferRotation);
+        dstRectDrawTopRight  .MoveBy(-mBufferRotation + nsIntPoint(0, mBufferRect.height));
+        dstRectDrawTopLeft   .MoveBy(-mBufferRotation + nsIntPoint(mBufferRect.width, mBufferRect.height));
+        dstRectDrawBottomLeft.MoveBy(-mBufferRotation + nsIntPoint(mBufferRect.width, 0));
 
-          if (!bottom.IsEmpty()) {
-            nsIntRegion temp;
-            temp.And(destBufferRect, bottom);
-            result.mRegionToDraw.Or(result.mRegionToDraw, temp);
-          }
-          if (!topright.IsEmpty()) {
-            nsIntRegion temp;
-            temp.And(destBufferRect, topright);
-            result.mRegionToDraw.Or(result.mRegionToDraw, temp);
-          }
-        }
+        // transform back to draw coordinates
+        dstRect              .MoveBy(mBufferRect.TopLeft());
+        dstRectDrawTopRight  .MoveBy(mBufferRect.TopLeft());
+        dstRectDrawTopLeft   .MoveBy(mBufferRect.TopLeft());
+        dstRectDrawBottomLeft.MoveBy(mBufferRect.TopLeft());
+
+        // transform to destBuffer space
+        dstRect              .MoveBy(-destBufferRect.TopLeft());
+        dstRectDrawTopRight  .MoveBy(-destBufferRect.TopLeft());
+        dstRectDrawTopLeft   .MoveBy(-destBufferRect.TopLeft());
+        dstRectDrawBottomLeft.MoveBy(-destBufferRect.TopLeft());
 
         destBuffer->Resize(destBufferRect.Size());
 
         gl()->BlitTextureImage(mTexImage, srcRect,
                                destBuffer, dstRect);
+        if (mBufferRotation != nsIntPoint(0, 0)) {
+          // Draw the remaining quadrants. We call BlitTextureImage 3 extra
+          // times instead of doing a single draw call because supporting that
+          // with a tiled source is quite tricky.
+          if (!srcRectDrawTopRight.IsEmpty())
+            gl()->BlitTextureImage(mTexImage, srcRectDrawTopRight,
+                                   destBuffer, dstRectDrawTopRight);
+          if (!srcRectDrawTopLeft.IsEmpty())
+            gl()->BlitTextureImage(mTexImage, srcRectDrawTopLeft,
+                                   destBuffer, dstRectDrawTopLeft);
+          if (!srcRectDrawBottomLeft.IsEmpty())
+            gl()->BlitTextureImage(mTexImage, srcRectDrawBottomLeft,
+                                   destBuffer, dstRectDrawBottomLeft);
+        }
         destBuffer->MarkValid();
         if (mode == Layer::SURFACE_COMPONENT_ALPHA) {
           destBufferOnWhite->Resize(destBufferRect.Size());
           gl()->BlitTextureImage(mTexImageOnWhite, srcRect,
                                  destBufferOnWhite, dstRect);
+          if (mBufferRotation != nsIntPoint(0, 0)) {
+            // draw the remaining quadrants
+            if (!srcRectDrawTopRight.IsEmpty())
+              gl()->BlitTextureImage(mTexImage, srcRectDrawTopRight,
+                                     destBuffer, dstRectDrawTopRight);
+            if (!srcRectDrawTopLeft.IsEmpty())
+              gl()->BlitTextureImage(mTexImage, srcRectDrawTopLeft,
+                                     destBuffer, dstRectDrawTopLeft);
+            if (!srcRectDrawBottomLeft.IsEmpty())
+              gl()->BlitTextureImage(mTexImage, srcRectDrawBottomLeft,
+                                     destBuffer, dstRectDrawBottomLeft);
+          }
+
           destBufferOnWhite->MarkValid();
         }
       } else {
         // can't blit, just draw everything
         destBuffer = CreateClampOrRepeatTextureImage(gl(), destBufferRect.Size(), contentType, bufferFlags);
         if (mode == Layer::SURFACE_COMPONENT_ALPHA) {
           destBufferOnWhite = 
             CreateClampOrRepeatTextureImage(gl(), destBufferRect.Size(), contentType, bufferFlags);