Bug 848482 - Make SourceSurface work with SkiaGL r=mattwoodrow
authorJames Willcox <snorp@snorp.net>
Thu, 06 Jun 2013 10:58:45 -0400
changeset 134243 3a1d47b8501dd9b2b6b4f6cf03df842f8cc5ebff
parent 134242 18bb116f6a7599795f89fe40af4542ab20d333ce
child 134244 7b39c8bec2953f105393a71855ccfe6f5398daa2
push id29116
push userjwillcox@mozilla.com
push dateThu, 06 Jun 2013 15:00:18 +0000
treeherdermozilla-inbound@3a1d47b8501d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmattwoodrow
bugs848482
milestone24.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 848482 - Make SourceSurface work with SkiaGL r=mattwoodrow
content/canvas/src/CanvasRenderingContext2D.cpp
gfx/layers/CopyableCanvasLayer.cpp
gfx/layers/CopyableCanvasLayer.h
--- a/content/canvas/src/CanvasRenderingContext2D.cpp
+++ b/content/canvas/src/CanvasRenderingContext2D.cpp
@@ -616,17 +616,16 @@ CanvasRenderingContext2D::Reset()
   if (mTarget && IsTargetValid() && !mDocShell) {
     gCanvasAzureMemoryUsed -= mWidth * mHeight * 4;
   }
 
   mTarget = nullptr;
 
   // Since the target changes the backing texture will change, and this will
   // no longer be valid.
-  mThebesSurface = nullptr;
   mIsEntireFrameInvalid = false;
   mPredictManyRedrawCalls = false;
 
   return NS_OK;
 }
 
 static void
 WarnAboutUnexpectedStyle(HTMLCanvasElement* canvasElement)
@@ -708,21 +707,16 @@ CanvasRenderingContext2D::Redraw()
 
   mIsEntireFrameInvalid = true;
 
   if (!mCanvasElement) {
     NS_ASSERTION(mDocShell, "Redraw with no canvas element or docshell!");
     return NS_OK;
   }
 
-  if (!mThebesSurface)
-    mThebesSurface =
-      gfxPlatform::GetPlatform()->GetThebesSurfaceForDrawTarget(mTarget);
-  mThebesSurface->MarkDirty();
-
   nsSVGEffects::InvalidateDirectRenderingObservers(mCanvasElement);
 
   mCanvasElement->InvalidateCanvasContent(nullptr);
 
   return NS_OK;
 }
 
 void
@@ -740,21 +734,16 @@ CanvasRenderingContext2D::Redraw(const m
     return;
   }
 
   if (!mCanvasElement) {
     NS_ASSERTION(mDocShell, "Redraw with no canvas element or docshell!");
     return;
   }
 
-  if (!mThebesSurface)
-    mThebesSurface =
-      gfxPlatform::GetPlatform()->GetThebesSurfaceForDrawTarget(mTarget);
-  mThebesSurface->MarkDirty();
-
   nsSVGEffects::InvalidateDirectRenderingObservers(mCanvasElement);
 
   mCanvasElement->InvalidateCanvasContent(&r);
 }
 
 void
 CanvasRenderingContext2D::RedrawUser(const gfxRect& r)
 {
@@ -886,17 +875,16 @@ CanvasRenderingContext2D::ClearTarget()
 
 NS_IMETHODIMP
 CanvasRenderingContext2D::InitializeWithSurface(nsIDocShell *shell,
                                                 gfxASurface *surface,
                                                 int32_t width,
                                                 int32_t height)
 {
   mDocShell = shell;
-  mThebesSurface = surface;
 
   SetDimensions(width, height);
   mTarget = gfxPlatform::GetPlatform()->
     CreateDrawTargetForSurface(surface, IntSize(width, height));
   if (!mTarget) {
     EnsureErrorTarget();
     mTarget = sErrorTarget;
   }
@@ -3207,28 +3195,49 @@ CanvasRenderingContext2D::DrawWindow(nsI
   if (flags & nsIDOMCanvasRenderingContext2D::DRAWWINDOW_ASYNC_DECODE_IMAGES) {
     renderDocFlags |= nsIPresShell::RENDER_ASYNC_DECODE_IMAGES;
   }
 
   // gfxContext-over-Azure may modify the DrawTarget's transform, so
   // save and restore it
   Matrix matrix = mTarget->GetTransform();
   nsRefPtr<gfxContext> thebes;
+  nsRefPtr<gfxASurface> drawSurf;
   if (gfxPlatform::GetPlatform()->SupportsAzureContentForDrawTarget(mTarget)) {
     thebes = new gfxContext(mTarget);
+    thebes->SetMatrix(gfxMatrix(matrix._11, matrix._12, matrix._21,
+                                matrix._22, matrix._31, matrix._32));
   } else {
-    nsRefPtr<gfxASurface> drawSurf;
-    GetThebesSurface(getter_AddRefs(drawSurf));
+    drawSurf =
+      gfxPlatform::GetPlatform()->CreateOffscreenSurface(gfxIntSize(ceil(w), ceil(h)),
+                                                         gfxASurface::CONTENT_COLOR_ALPHA);
+
+    drawSurf->SetDeviceOffset(gfxPoint(-floor(x), -floor(y)));
     thebes = new gfxContext(drawSurf);
+    thebes->Translate(gfxPoint(floor(x), floor(y)));
   }
-  thebes->SetMatrix(gfxMatrix(matrix._11, matrix._12, matrix._21,
-                              matrix._22, matrix._31, matrix._32));
+
   nsCOMPtr<nsIPresShell> shell = presContext->PresShell();
   unused << shell->RenderDocument(r, renderDocFlags, backgroundColor, thebes);
-  mTarget->SetTransform(matrix);
+  if (drawSurf) {
+    gfxIntSize size = drawSurf->GetSize();
+
+    drawSurf->SetDeviceOffset(gfxPoint(0, 0));
+    nsRefPtr<gfxImageSurface> img = drawSurf->GetAsReadableARGB32ImageSurface();
+    RefPtr<SourceSurface> data =
+      mTarget->CreateSourceSurfaceFromData(img->Data(),
+                                           IntSize(size.width, size.height),
+                                           img->Stride(),
+                                           FORMAT_B8G8R8A8);
+    mgfx::Rect rect(0, 0, w, h);
+    mTarget->DrawSurface(data, rect, rect);
+    mTarget->Flush();
+  } else {
+    mTarget->SetTransform(matrix);
+  }
 
   // note that x and y are coordinates in the document that
   // we're drawing; x and y are drawn to 0,0 in current user
   // space.
   RedrawUser(gfxRect(0, 0, w, h));
 }
 
 void
@@ -3662,30 +3671,25 @@ CanvasRenderingContext2D::PutImageData_e
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 CanvasRenderingContext2D::GetThebesSurface(gfxASurface **surface)
 {
   EnsureTarget();
-  if (!mThebesSurface) {
-    mThebesSurface =
+
+  nsRefPtr<gfxASurface> thebesSurface =
       gfxPlatform::GetPlatform()->GetThebesSurfaceForDrawTarget(mTarget);
 
-    if (!mThebesSurface) {
-      return NS_ERROR_FAILURE;
-    }
-  } else {
-    // Normally GetThebesSurfaceForDrawTarget will handle the flush, when
-    // we're returning a cached ThebesSurface we need to flush here.
-    mTarget->Flush();
+  if (!thebesSurface) {
+    return NS_ERROR_FAILURE;
   }
 
-  *surface = mThebesSurface;
+  *surface = thebesSurface;
   NS_ADDREF(*surface);
 
   return NS_OK;
 }
 
 static already_AddRefed<ImageData>
 CreateImageData(JSContext* cx, CanvasRenderingContext2D* context,
                 uint32_t w, uint32_t h, ErrorResult& error)
--- a/gfx/layers/CopyableCanvasLayer.cpp
+++ b/gfx/layers/CopyableCanvasLayer.cpp
@@ -56,24 +56,17 @@ void
 CopyableCanvasLayer::UpdateSurface(gfxASurface* aDestSurface, Layer* aMaskLayer)
 {
   if (!IsDirty())
     return;
   Painted();
 
   if (mDrawTarget) {
     mDrawTarget->Flush();
-    if (mDrawTarget->GetType() == BACKEND_COREGRAPHICS_ACCELERATED) {
-      // We have an accelerated CG context which has changed, unlike a bitmap surface
-      // where we can alias the bits on initializing the mDrawTarget, we need to readback
-      // and copy the accelerated surface each frame. We want to support this for quick
-      // thumbnail but if we're going to be doing this every frame it likely is better
-      // to use a non accelerated (bitmap) canvas.
-      mSurface = gfxPlatform::GetPlatform()->GetThebesSurfaceForDrawTarget(mDrawTarget);
-    }
+    mSurface = gfxPlatform::GetPlatform()->GetThebesSurfaceForDrawTarget(mDrawTarget);
   }
 
   if (!mGLContext && aDestSurface) {
     nsRefPtr<gfxContext> tmpCtx = new gfxContext(aDestSurface);
     tmpCtx->SetOperator(gfxContext::OPERATOR_SOURCE);
     CopyableCanvasLayer::PaintWithOpacity(tmpCtx, 1.0f, aMaskLayer);
     return;
   }
--- a/gfx/layers/CopyableCanvasLayer.h
+++ b/gfx/layers/CopyableCanvasLayer.h
@@ -47,17 +47,17 @@ protected:
                         Layer* aMaskLayer,
                         gfxContext::GraphicsOperator aOperator = gfxContext::OPERATOR_OVER);
 
   void UpdateSurface(gfxASurface* aDestSurface = nullptr, Layer* aMaskLayer = nullptr);
 
   nsRefPtr<gfxASurface> mSurface;
   nsRefPtr<mozilla::gl::GLContext> mGLContext;
   mozilla::RefPtr<mozilla::gfx::DrawTarget> mDrawTarget;
-  
+
   uint32_t mCanvasFramebuffer;
 
   bool mIsGLAlphaPremult;
   bool mNeedsYFlip;
   bool mForceReadback;
 
   nsRefPtr<gfxImageSurface> mCachedTempSurface;
   gfxIntSize mCachedSize;