Bug 1521008: Defer OptimizeSourceSurface to the paint thread if possible. r=rhunt
authorBas Schouten <bschouten@mozilla.com>
Fri, 18 Jan 2019 06:45:17 +0100
changeset 511723 bd3e08ada630ea0051c778a5cbdb4af33e8471ae
parent 511721 8a6882cfdfe50002f294e8e6609893e7f364168b
child 511724 965622da5962b6cfd9e9e8b5332896e1634070e1
push id10547
push userffxbld-merge
push dateMon, 21 Jan 2019 13:03:58 +0000
treeherdermozilla-beta@24ec1916bffe [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersrhunt
bugs1521008
milestone66.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 1521008: Defer OptimizeSourceSurface to the paint thread if possible. r=rhunt Differential Revision: https://phabricator.services.mozilla.com/D16943
gfx/2d/DrawTargetCapture.cpp
gfx/2d/DrawTargetD2D1.cpp
gfx/2d/SourceSurfaceCapture.cpp
gfx/2d/SourceSurfaceCapture.h
--- a/gfx/2d/DrawTargetCapture.cpp
+++ b/gfx/2d/DrawTargetCapture.cpp
@@ -108,17 +108,19 @@ already_AddRefed<SourceSurface> DrawTarg
 already_AddRefed<SourceSurface> DrawTargetCaptureImpl::OptimizeSourceSurface(
     SourceSurface* aSurface) const {
   // If the surface is a recording, make sure it gets resolved on the paint
   // thread.
   if (aSurface->GetType() == SurfaceType::CAPTURE) {
     RefPtr<SourceSurface> surface = aSurface;
     return surface.forget();
   }
-  return mRefDT->OptimizeSourceSurface(aSurface);
+  RefPtr<SourceSurfaceCapture> surface = new SourceSurfaceCapture(
+      const_cast<DrawTargetCaptureImpl*>(this), aSurface);
+  return surface.forget();
 }
 
 void DrawTargetCaptureImpl::DetachAllSnapshots() { MarkChanged(); }
 
 #define AppendCommand(arg) new (AppendToCommandList<arg>()) arg
 #define ReuseOrAppendCommand(arg) new (ReuseOrAppendToCommandList<arg>()) arg
 
 void DrawTargetCaptureImpl::SetPermitSubpixelAA(bool aPermitSubpixelAA) {
--- a/gfx/2d/DrawTargetD2D1.cpp
+++ b/gfx/2d/DrawTargetD2D1.cpp
@@ -1970,21 +1970,32 @@ already_AddRefed<ID2D1Brush> DrawTargetD
       return CreateTransparentBlackBrush();
     }
 
     D2D1_RECT_F samplingBounds;
     Matrix mat = pat->mMatrix;
 
     MOZ_ASSERT(pat->mSurface->IsValid());
 
+    RefPtr<SourceSurface> surf = pat->mSurface;
+
+    if (pat->mSurface->GetType() == SurfaceType::CAPTURE) {
+      SourceSurfaceCapture *capture =
+          static_cast<SourceSurfaceCapture *>(pat->mSurface.get());
+      RefPtr<SourceSurface> resolved = capture->Resolve(GetBackendType());
+      if (resolved) {
+        surf = resolved;
+      }
+    }
+
     RefPtr<ID2D1Image> image = GetImageForSurface(
-        pat->mSurface, mat, pat->mExtendMode,
+        surf, mat, pat->mExtendMode,
         !pat->mSamplingRect.IsEmpty() ? &pat->mSamplingRect : nullptr);
 
-    if (pat->mSurface->GetFormat() == SurfaceFormat::A8) {
+    if (surf->GetFormat() == SurfaceFormat::A8) {
       // See bug 1251431, at least FillOpacityMask does not appear to allow a
       // source bitmapbrush with source format A8. This creates a BGRA surface
       // with the same alpha values that the A8 surface has.
       RefPtr<ID2D1Bitmap> bitmap;
       HRESULT hr =
           image->QueryInterface((ID2D1Bitmap **)getter_AddRefs(bitmap));
       if (SUCCEEDED(hr) && bitmap) {
         RefPtr<ID2D1Image> oldTarget;
@@ -2038,17 +2049,17 @@ already_AddRefed<ID2D1Brush> DrawTargetD
         return bitmapBrush.forget();
       }
     }
 
     RefPtr<ID2D1ImageBrush> imageBrush;
     if (pat->mSamplingRect.IsEmpty()) {
       samplingBounds = D2D1::RectF(0, 0, Float(pat->mSurface->GetSize().width),
                                    Float(pat->mSurface->GetSize().height));
-    } else if (pat->mSurface->GetType() == SurfaceType::D2D1_1_IMAGE) {
+    } else if (surf->GetType() == SurfaceType::D2D1_1_IMAGE) {
       samplingBounds = D2DRect(pat->mSamplingRect);
       mat.PreTranslate(pat->mSamplingRect.X(), pat->mSamplingRect.Y());
     } else {
       // We will do a partial upload of the sampling restricted area from
       // GetImageForSurface.
       samplingBounds = D2D1::RectF(0, 0, pat->mSamplingRect.Width(),
                                    pat->mSamplingRect.Height());
     }
--- a/gfx/2d/SourceSurfaceCapture.cpp
+++ b/gfx/2d/SourceSurfaceCapture.cpp
@@ -43,50 +43,69 @@ SourceSurfaceCapture::SourceSurfaceCaptu
   mStride = mOwner->mStride;
   mSurfaceAllocationSize = mOwner->mSurfaceAllocationSize;
 
   // In this case our DrawTarget will not track us, so copy its drawing
   // commands.
   DrawTargetWillChange();
 }
 
+SourceSurfaceCapture::SourceSurfaceCapture(DrawTargetCaptureImpl* aOwner,
+                                           SourceSurface* aSurfToOptimize)
+    : mOwner{aOwner},
+      mHasCommandList{false},
+      mShouldResolveToLuminance{false},
+      mLuminanceType{LuminanceType::LUMINANCE},
+      mOpacity{1.0f},
+      mLock{"SourceSurfaceCapture.mLock"},
+      mSurfToOptimize(aSurfToOptimize) {
+  mSize = aSurfToOptimize->GetSize();
+  mFormat = aSurfToOptimize->GetFormat();
+  mRefDT = mOwner->mRefDT;
+}
+
 SourceSurfaceCapture::~SourceSurfaceCapture() {}
 
 bool SourceSurfaceCapture::IsValid() const {
   // We must either be able to source a command list, or we must have a cached
   // and rasterized surface.
   MutexAutoLock lock(mLock);
-  return (mOwner || mHasCommandList) || mResolved;
+  return (mOwner || mHasCommandList || mSurfToOptimize) || mResolved;
 }
 
 RefPtr<SourceSurface> SourceSurfaceCapture::Resolve(BackendType aBackendType) {
   MutexAutoLock lock(mLock);
 
-  if (!mOwner && !mHasCommandList) {
-    // There is no way we can rasterize anything, we don't have a source
-    // DrawTarget and we don't have a command list. Return whatever our
-    // cached surface is.
+  if (mSurfToOptimize) {
+    mResolved = mRefDT->OptimizeSourceSurface(mSurfToOptimize);
+    mSurfToOptimize = nullptr;
+  }
+
+  if (mResolved || (!mOwner && !mHasCommandList)) {
+    // We are already resolved, or there is no way we can rasterize
+    // anything, we don't have a source DrawTarget and we don't have
+    // a command list. Return whatever our cached surface is.
     return mResolved;
   }
 
   BackendType backendType = aBackendType;
   if (backendType == BackendType::NONE) {
     backendType = mRefDT->GetBackendType();
   }
 
   // If on the paint thread, we require that the owning DrawTarget be detached
   // from this snapshot. This roughly approximates an assert that nothing can
   // mutate the snapshot.
   MOZ_RELEASE_ASSERT(NS_IsMainThread() || !mOwner);
 
   // Note: SurfaceType is not 1:1 with BackendType, so we can't easily decide
   // that they match. Instead we just cache the first thing to be requested.
-  if (!mResolved) {
-    mResolved = ResolveImpl(backendType);
-  }
+  // We ensured no mResolved existed before.
+  mResolved = ResolveImpl(backendType);
+
   return mResolved;
 }
 
 RefPtr<SourceSurface> SourceSurfaceCapture::ResolveImpl(
     BackendType aBackendType) {
   RefPtr<DrawTarget> dt;
   uint8_t* data = nullptr;
   if (!mSurfaceAllocationSize) {
--- a/gfx/2d/SourceSurfaceCapture.h
+++ b/gfx/2d/SourceSurfaceCapture.h
@@ -20,16 +20,18 @@ class SourceSurfaceCapture : public Sour
   friend class DrawTargetCaptureImpl;
 
  public:
   MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SourceSurfaceCapture, override)
 
   explicit SourceSurfaceCapture(DrawTargetCaptureImpl* aOwner);
   explicit SourceSurfaceCapture(DrawTargetCaptureImpl* aOwner,
                                 LuminanceType aLuminanceType, float aOpacity);
+  explicit SourceSurfaceCapture(DrawTargetCaptureImpl* aOwner,
+                                SourceSurface* aSurfToOptimize);
   ~SourceSurfaceCapture();
 
   SurfaceType GetType() const override { return SurfaceType::CAPTURE; }
   IntSize GetSize() const override { return mSize; }
   SurfaceFormat GetFormat() const override { return mFormat; }
 
   bool IsValid() const override;
   already_AddRefed<DataSourceSurface> GetDataSurface() override;
@@ -57,14 +59,15 @@ class SourceSurfaceCapture : public Sour
   LuminanceType mLuminanceType;
   float mOpacity;
 
   // Note that we have to keep a reference around. Internal methods like
   // GetSkImageForSurface expect their callers to hold a reference, which
   // isn't easily possible for nested surfaces.
   mutable Mutex mLock;
   RefPtr<SourceSurface> mResolved;
+  RefPtr<SourceSurface> mSurfToOptimize;
 };
 
 }  // namespace gfx
 }  // namespace mozilla
 
 #endif  // mozilla_gfx_2d_SourceSurfaceCapture_h