Bug 781731 - Use a similar surface for non-blurred shadows to improve performance; r=roc
authorAnthony Jones <ajones@mozilla.com>
Mon, 27 Aug 2012 11:34:33 +0200
changeset 105586 8ac3a7df2b6a64ab5ebe600c91ec0de9ef33d9d4
parent 105585 3b2797ed0518b438b468bac4d1a76f08afc02be7
child 105587 dfdfdf5ae236757f9267dc3a7fae8f951fcc9a92
push id55
push usershu@rfrn.org
push dateThu, 30 Aug 2012 01:33:09 +0000
reviewersroc
bugs781731
milestone17.0a1
Bug 781731 - Use a similar surface for non-blurred shadows to improve performance; r=roc
content/canvas/src/nsCanvasRenderingContext2DAzure.cpp
gfx/2d/2D.h
gfx/2d/DrawTargetCairo.cpp
gfx/2d/DrawTargetCairo.h
--- a/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp
+++ b/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp
@@ -308,17 +308,17 @@ public:
 
     mTempRect.ScaleRoundOut(1.0f);
 
     transform._31 -= mTempRect.x;
     transform._32 -= mTempRect.y;
       
     mTarget =
       mCtx->mTarget->CreateShadowDrawTarget(IntSize(int32_t(mTempRect.width), int32_t(mTempRect.height)),
-                                             FORMAT_B8G8R8A8);
+                                             FORMAT_B8G8R8A8, mSigma);
 
     if (!mTarget) {
       // XXX - Deal with the situation where our temp size is too big to
       // fit in a texture.
       mTarget = ctx->mTarget;
       mCtx = nullptr;
     } else {
       mTarget->SetTransform(transform);
--- a/gfx/2d/2D.h
+++ b/gfx/2d/2D.h
@@ -724,19 +724,25 @@ public:
   /*
    * Create a DrawTarget whose snapshot is optimized for use with this DrawTarget.
    */
   virtual TemporaryRef<DrawTarget>
     CreateSimilarDrawTarget(const IntSize &aSize, SurfaceFormat aFormat) const = 0;
 
   /*
    * Create a draw target optimized for drawing a shadow.
+   *
+   * Note that aSigma is the blur radius that must be used when we draw the
+   * shadow. Also note that this doesn't affect the size of the allocated
+   * surface, the caller is still responsible for including the shadow area in
+   * its size.
    */
   virtual TemporaryRef<DrawTarget>
-    CreateShadowDrawTarget(const IntSize &aSize, SurfaceFormat aFormat) const
+    CreateShadowDrawTarget(const IntSize &aSize, SurfaceFormat aFormat,
+                           float aSigma) const
   {
     return CreateSimilarDrawTarget(aSize, aFormat);
   }
 
   /*
    * Create a path builder with the specified fillmode.
    *
    * We need the fill mode up front because of Direct2D.
--- a/gfx/2d/DrawTargetCairo.cpp
+++ b/gfx/2d/DrawTargetCairo.cpp
@@ -388,26 +388,36 @@ DrawTargetCairo::DrawSurfaceWithShadow(S
     return;
   }
 
   Float width = aSurface->GetSize().width;
   Float height = aSurface->GetSize().height;
  
   SourceSurfaceCairo* source = static_cast<SourceSurfaceCairo*>(aSurface);
   cairo_surface_t* sourcesurf = source->GetSurface();
-  cairo_surface_t* blursurf = cairo_tee_surface_index(sourcesurf, 0);
-  cairo_surface_t* surf = cairo_tee_surface_index(sourcesurf, 1);
- 
-  MOZ_ASSERT(cairo_surface_get_type(blursurf) == CAIRO_SURFACE_TYPE_IMAGE);
-  Rect extents(0, 0, width, height);
-  AlphaBoxBlur blur(cairo_image_surface_get_data(blursurf),
-                    extents,
-                    cairo_image_surface_get_stride(blursurf),
-                    aSigma);
-  blur.Blur();
+  cairo_surface_t* blursurf;
+  cairo_surface_t* surf;
+
+  // We only use the A8 surface for blurred shadows. Unblurred shadows can just
+  // use the RGBA surface directly.
+  if (cairo_surface_get_type(sourcesurf) == CAIRO_SURFACE_TYPE_TEE) {
+    blursurf = cairo_tee_surface_index(sourcesurf, 0);
+    surf = cairo_tee_surface_index(sourcesurf, 1);
+
+    MOZ_ASSERT(cairo_surface_get_type(blursurf) == CAIRO_SURFACE_TYPE_IMAGE);
+    Rect extents(0, 0, width, height);
+    AlphaBoxBlur blur(cairo_image_surface_get_data(blursurf),
+                      extents,
+                      cairo_image_surface_get_stride(blursurf),
+                      aSigma);
+    blur.Blur();
+  } else {
+    blursurf = sourcesurf;
+    surf = sourcesurf;
+  }
 
   WillChange();
   ClearSurfaceForUnboundedSource(aOperator);
   
   cairo_save(mContext);
   cairo_set_operator(mContext, GfxOpToCairoOp(aOperator));
   cairo_identity_matrix(mContext);
   cairo_translate(mContext, aDest.x, aDest.y);
@@ -787,26 +797,35 @@ DrawTargetCairo::InitAlreadyReferenced(c
   mSurface = aSurface;
   mSize = aSize;
   mFormat = CairoContentToGfxFormat(cairo_surface_get_content(aSurface));
 
   return true;
 }
 
 TemporaryRef<DrawTarget>
-DrawTargetCairo::CreateShadowDrawTarget(const IntSize &aSize, SurfaceFormat aFormat) const
+DrawTargetCairo::CreateShadowDrawTarget(const IntSize &aSize, SurfaceFormat aFormat,
+                                        float aSigma) const
 {
   cairo_surface_t* similar = cairo_surface_create_similar(cairo_get_target(mContext),
                                                           GfxFormatToCairoContent(aFormat),
                                                           aSize.width, aSize.height);
 
   if (cairo_surface_status(similar)) {
     return nullptr;
   }
 
+  // If we don't have a blur then we can use the RGBA mask and keep all the
+  // operations in graphics memory.
+  if (aSigma == 0.0F) {
+    RefPtr<DrawTargetCairo> target = new DrawTargetCairo();
+    target->InitAlreadyReferenced(similar, aSize);
+    return target;
+  }
+
   cairo_surface_t* blursurf = cairo_image_surface_create(CAIRO_FORMAT_A8,
                                                          aSize.width,
                                                          aSize.height);
 
   if (cairo_surface_status(blursurf)) {
     return nullptr;
   }
 
--- a/gfx/2d/DrawTargetCairo.h
+++ b/gfx/2d/DrawTargetCairo.h
@@ -111,17 +111,18 @@ public:
                                                             int32_t aStride,
                                                             SurfaceFormat aFormat) const;
   virtual TemporaryRef<SourceSurface> OptimizeSourceSurface(SourceSurface *aSurface) const;
   virtual TemporaryRef<SourceSurface>
     CreateSourceSurfaceFromNativeSurface(const NativeSurface &aSurface) const;
   virtual TemporaryRef<DrawTarget>
     CreateSimilarDrawTarget(const IntSize &aSize, SurfaceFormat aFormat) const;
   virtual TemporaryRef<DrawTarget>
-    CreateShadowDrawTarget(const IntSize &aSize, SurfaceFormat aFormat) const;
+    CreateShadowDrawTarget(const IntSize &aSize, SurfaceFormat aFormat,
+                           float aSigma) const;
 
   virtual TemporaryRef<GradientStops>
     CreateGradientStops(GradientStop *aStops,
                         uint32_t aNumStops,
                         ExtendMode aExtendMode = EXTEND_CLAMP) const;
 
   virtual void *GetNativeSurface(NativeSurfaceType aType);