Bug 689501 - Use an offscreen surface for rendering 3d transformed content instead of PushGroup in BasicLayers. r=roc
authorMatt Woodrow <mwoodrow@mozilla.com>
Fri, 30 Sep 2011 14:13:50 +1300
changeset 77898 a08928f32bce
parent 77897 06a077444292
child 77899 730a82c21c53
push id3
push userfelipc@gmail.com
push dateFri, 30 Sep 2011 20:09:13 +0000
reviewersroc
bugs689501
milestone10.0a1
Bug 689501 - Use an offscreen surface for rendering 3d transformed content instead of PushGroup in BasicLayers. r=roc
gfx/layers/basic/BasicLayers.cpp
gfx/layers/basic/BasicLayers.h
--- a/gfx/layers/basic/BasicLayers.cpp
+++ b/gfx/layers/basic/BasicLayers.cpp
@@ -1361,28 +1361,16 @@ BasicLayerManager::PopGroupToSourceWithC
     aTarget->IdentityMatrix();
     aTarget->SetSource(current);
     mCachedSurfaceInUse = PR_FALSE;
   } else {
     aTarget->PopGroupToSource();
   }
 }
 
-already_AddRefed<gfxASurface>
-BasicLayerManager::PopGroupToSurface(gfxContext *aTarget, gfxContext *aPushed)
-{
-  if (!aTarget)
-    return nsnull;
-  nsRefPtr<gfxASurface> current = aPushed->CurrentSurface();
-  NS_ASSERTION(!mCachedSurface.IsSurface(current), "Should never be popping cached surface here!");
-  nsRefPtr<gfxPattern> pat = aTarget->PopGroup();
-  current = pat->GetSurface();
-  return current.forget();
-}
-
 void
 BasicLayerManager::BeginTransactionWithTarget(gfxContext* aTarget)
 {
 #ifdef MOZ_LAYERS_HAVE_LOG
   MOZ_LAYERS_LOG(("[----- BeginTransaction"));
   Log();
 #endif
 
@@ -1840,45 +1828,50 @@ BasicLayerManager::PaintLayer(gfxContext
   gfxMatrix transform;
   // Will return an identity matrix for 3d transforms, and is handled separately below.
   bool is2D = effectiveTransform.CanDraw2D(&transform);
   NS_ABORT_IF_FALSE(is2D || needsGroup || !aLayer->GetFirstChild(), "Must PushGroup for 3d transforms!");
   if (is2D) {
     aTarget->SetMatrix(transform);
   } else {
     aTarget->SetMatrix(gfxMatrix());
-    // Save so we can restore clipping after PushGroupForLayer changes it.
-    aTarget->Save();
   }
 
   const nsIntRegion& visibleRegion = aLayer->GetEffectiveVisibleRegion();
   // If needsGroup is true, we'll clip to the visible region after we've popped the group
   if (needsClipToVisibleRegion && !needsGroup) {
     gfxUtils::ClipToRegion(aTarget, visibleRegion);
     // Don't need to clip to visible region again
     needsClipToVisibleRegion = PR_FALSE;
   }
 
   bool pushedTargetOpaqueRect = false;
   nsRefPtr<gfxASurface> currentSurface = aTarget->CurrentSurface();
   const gfxRect& targetOpaqueRect = currentSurface->GetOpaqueRect();
 
   // Try to annotate currentSurface with a region of pixels that have been
   // (or will be) painted opaque, if no such region is currently set.
+  const nsIntRect& bounds = visibleRegion.GetBounds();
   if (targetOpaqueRect.IsEmpty() && visibleRegion.GetNumRects() == 1 &&
       (aLayer->GetContentFlags() & Layer::CONTENT_OPAQUE) &&
       !transform.HasNonAxisAlignedTransform()) {
-    const nsIntRect& bounds = visibleRegion.GetBounds();
     currentSurface->SetOpaqueRect(
         aTarget->UserToDevice(gfxRect(bounds.x, bounds.y, bounds.width, bounds.height)));
     pushedTargetOpaqueRect = PR_TRUE;
   }
 
   nsRefPtr<gfxContext> groupTarget;
-  if (needsGroup) {
+  nsRefPtr<gfxASurface> untransformedSurface;
+  if (!is2D) {
+    untransformedSurface = 
+      gfxPlatform::GetPlatform()->CreateOffscreenSurface(gfxIntSize(bounds.width, bounds.height), 
+                                                         gfxASurface::CONTENT_COLOR_ALPHA);
+    untransformedSurface->SetDeviceOffset(gfxPoint(-bounds.x, -bounds.y));
+    groupTarget = new gfxContext(untransformedSurface);
+  } else if (needsGroup) {
     groupTarget = PushGroupForLayer(aTarget, aLayer, aLayer->GetEffectiveVisibleRegion(),
                                     &needsClipToVisibleRegion);
   } else {
     groupTarget = aTarget;
   }
 
   /* Only paint ourself, or our children - This optimization relies on this! */
   Layer* child = aLayer->GetFirstChild();
@@ -1906,26 +1899,24 @@ BasicLayerManager::PaintLayer(gfxContext
     }
   }
 
   if (needsGroup) {
     bool blitComplete = false;
     if (is2D) {
       PopGroupToSourceWithCachedSurface(aTarget, groupTarget);
     } else {
-      nsRefPtr<gfxASurface> sourceSurface = PopGroupToSurface(aTarget, groupTarget);
-      aTarget->Restore();
-      NS_ABORT_IF_FALSE(sourceSurface, "PopGroup should always return a surface pattern");
-      gfxRect bounds = visibleRegion.GetBounds();
+      NS_ABORT_IF_FALSE(untransformedSurface, 
+                        "We should always allocate an untransformed surface with 3d transforms!");
 
       gfxPoint offset;
       bool dontBlit = needsClipToVisibleRegion || mTransactionIncomplete || 
                         aLayer->GetEffectiveOpacity() != 1.0f;
       nsRefPtr<gfxASurface> result = 
-        Transform3D(sourceSurface, aTarget, bounds,
+        Transform3D(untransformedSurface, aTarget, bounds,
                     effectiveTransform, offset, dontBlit);
 
       blitComplete = !result;
       if (result) {
         aTarget->SetSource(result, offset);
       }
     }
     // If we're doing our own double-buffering, we need to avoid drawing
--- a/gfx/layers/basic/BasicLayers.h
+++ b/gfx/layers/basic/BasicLayers.h
@@ -167,17 +167,16 @@ public:
   void SetTransactionIncomplete() { mTransactionIncomplete = true; }
 
   already_AddRefed<gfxContext> PushGroupForLayer(gfxContext* aContext, Layer* aLayer,
                                                  const nsIntRegion& aRegion,
                                                  bool* aNeedsClipToVisibleRegion);
   already_AddRefed<gfxContext> PushGroupWithCachedSurface(gfxContext *aTarget,
                                                           gfxASurface::gfxContentType aContent);
   void PopGroupToSourceWithCachedSurface(gfxContext *aTarget, gfxContext *aPushed);
-  already_AddRefed<gfxASurface> PopGroupToSurface(gfxContext *aTarget, gfxContext *aPushed);
 
   virtual bool IsCompositingCheap() { return false; }
   virtual bool HasShadowManagerInternal() const { return false; }
   bool HasShadowManager() const { return HasShadowManagerInternal(); }
 
 protected:
 #ifdef DEBUG
   enum TransactionPhase {