Bug 1478815 part 10 - Don't submit PaintTask's if the DrawTargetCapture is empty. r=bas
authorRyan Hunt <rhunt@eqrion.net>
Tue, 31 Jul 2018 17:47:51 -0500
changeset 486012 423c08523aa92bcbd5587771ca1dd6720c6d2884
parent 486011 2b95cb0f33ea440b0301d25b462b033a01e81c75
child 486013 b807f63147aeb40dc4139b258d630cc1739662e0
push id9719
push userffxbld-merge
push dateFri, 24 Aug 2018 17:49:46 +0000
treeherdermozilla-beta@719ec98fba77 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbas
bugs1478815
milestone63.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 1478815 part 10 - Don't submit PaintTask's if the DrawTargetCapture is empty. r=bas This commit exposes a method on DrawTargetCapture to see if it has captured any drawing commands. This allows us to not dispatch paint tasks if they will do nothing. Ideally these tasks would execute instantly on the PaintThread, and we would never delay sending the layer transaction or block on the next paint, but with thread starvation and context switches it's best to just not send them. MozReview-Commit-ID: 7ywkEDBw6EX
gfx/2d/2D.h
gfx/2d/CaptureCommandList.h
gfx/2d/DrawTargetCapture.cpp
gfx/2d/DrawTargetCapture.h
gfx/layers/client/ClientPaintedLayer.cpp
gfx/layers/client/MultiTiledContentClient.cpp
gfx/layers/client/SingleTiledContentClient.cpp
--- a/gfx/2d/2D.h
+++ b/gfx/2d/2D.h
@@ -1542,16 +1542,17 @@ protected:
   SurfaceFormat mFormat;
 };
 
 class DrawTargetCapture : public DrawTarget
 {
 public:
   virtual bool IsCaptureDT() const override { return true; }
 
+  virtual bool IsEmpty() const = 0;
   virtual void Dump() = 0;
 };
 
 class DrawEventRecorder : public RefCounted<DrawEventRecorder>
 {
 public:
   MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DrawEventRecorder)
   // returns true if there were any items in the recording
--- a/gfx/2d/CaptureCommandList.h
+++ b/gfx/2d/CaptureCommandList.h
@@ -59,16 +59,20 @@ public:
       if (mLastCommand != nullptr &&
         mLastCommand->GetType() == T::Type) {
         return reinterpret_cast<T*>(mLastCommand);
       }
     }
     return Append<T>();
   }
 
+  bool IsEmpty() const {
+    return mStorage.empty();
+  }
+
   template <typename T>
   bool BufferWillAlloc() const {
     return mStorage.size() + sizeof(uint32_t) + sizeof(T) > mStorage.capacity();
   }
 
   size_t BufferCapacity() const {
     return mStorage.capacity();
   }
--- a/gfx/2d/DrawTargetCapture.cpp
+++ b/gfx/2d/DrawTargetCapture.cpp
@@ -414,16 +414,22 @@ DrawTargetCaptureImpl::CreateFilter(Filt
 {
   if (mRefDT->GetBackendType() == BackendType::DIRECT2D1_1) {
     return MakeRefPtr<FilterNodeCapture>(aType).forget();
   } else {
     return mRefDT->CreateFilter(aType);
   }
 }
 
+bool
+DrawTargetCaptureImpl::IsEmpty() const
+{
+  return mCommands.IsEmpty();
+}
+
 void
 DrawTargetCaptureImpl::Dump()
 {
   TreeLog output;
   output << "DrawTargetCapture(" << (void*)(this) << ")\n";
   TreeAutoIndent indent(output);
   mCommands.Log(output);
   output << "\n";
--- a/gfx/2d/DrawTargetCapture.h
+++ b/gfx/2d/DrawTargetCapture.h
@@ -146,16 +146,17 @@ public:
                         ExtendMode aExtendMode = ExtendMode::CLAMP) const override
   {
     return mRefDT->CreateGradientStops(aStops, aNumStops, aExtendMode);
   }
   virtual already_AddRefed<FilterNode> CreateFilter(FilterType aType) override;
 
   void ReplayToDrawTarget(DrawTarget* aDT, const Matrix& aTransform);
 
+  bool IsEmpty() const override;
   void Dump() override;
 
 protected:
   virtual ~DrawTargetCaptureImpl();
 
   void MarkChanged();
 
 private:
--- a/gfx/layers/client/ClientPaintedLayer.cpp
+++ b/gfx/layers/client/ClientPaintedLayer.cpp
@@ -88,17 +88,17 @@ ClientPaintedLayer::UpdatePaintRegion(Pa
   aState.mRegionToInvalidate.And(aState.mRegionToInvalidate,
                                  GetLocalVisibleRegion().ToUnknownRegion());
   return true;
 }
 
 void
 ClientPaintedLayer::FinishPaintState(PaintState& aState)
 {
-  if (aState.mAsyncTask) {
+  if (aState.mAsyncTask && !aState.mAsyncTask->mCapture->IsEmpty()) {
     ClientManager()->SetQueuedAsyncPaints();
     PaintThread::Get()->QueuePaintTask(aState.mAsyncTask);
   }
 }
 
 uint32_t
 ClientPaintedLayer::GetPaintFlags(ReadbackProcessor* aReadback)
 {
--- a/gfx/layers/client/MultiTiledContentClient.cpp
+++ b/gfx/layers/client/MultiTiledContentClient.cpp
@@ -276,20 +276,29 @@ void ClientMultiTiledLayerBuffer::Update
       // Reset
       mPaintTiles.clear();
       mTilingOrigin = IntPoint(std::numeric_limits<int32_t>::max(),
                                std::numeric_limits<int32_t>::max());
     }
 
     // Dispatch to the paint thread
     if (aFlags & TilePaintFlags::Async) {
+      bool queuedTask = false;
+
       for (const auto& state : mPaintTasks) {
-        PaintThread::Get()->QueuePaintTask(state);
+        if (!state->mCapture->IsEmpty()) {
+          PaintThread::Get()->QueuePaintTask(state);
+          queuedTask = true;
+        }
       }
-      mManager->SetQueuedAsyncPaints();
+
+      if (queuedTask) {
+        mManager->SetQueuedAsyncPaints();
+      }
+
       mPaintTasks.clear();
     }
 
     for (uint32_t i = 0; i < mRetainedTiles.Length(); ++i) {
       TileClient& tile = mRetainedTiles[i];
       UnlockTile(tile);
     }
   }
--- a/gfx/layers/client/SingleTiledContentClient.cpp
+++ b/gfx/layers/client/SingleTiledContentClient.cpp
@@ -230,22 +230,24 @@ ClientSingleTiledLayerBuffer::PaintThebe
       return;
     }
     ctx->SetMatrix(ctx->CurrentMatrix().PreTranslate(-mTilingOrigin.x, -mTilingOrigin.y));
 
     aCallback(&mPaintedLayer, ctx, paintRegion, paintRegion, DrawRegionClip::DRAW, nsIntRegion(), aCallbackData);
   }
 
   if (asyncPaint) {
-    RefPtr<PaintTask> task = new PaintTask();
-    task->mCapture = backBuffer->mCapture;
-    task->mTarget = backBuffer->mBackBuffer;
-    task->mClients = std::move(backBuffer->mTextureClients);
-    PaintThread::Get()->QueuePaintTask(task);
-    mManager->SetQueuedAsyncPaints();
+    if (!backBuffer->mCapture->IsEmpty()) {
+      RefPtr<PaintTask> task = new PaintTask();
+      task->mCapture = backBuffer->mCapture;
+      task->mTarget = backBuffer->mBackBuffer;
+      task->mClients = std::move(backBuffer->mTextureClients);
+      PaintThread::Get()->QueuePaintTask(task);
+      mManager->SetQueuedAsyncPaints();
+    }
   } else {
     MOZ_ASSERT(backBuffer->mTarget == backBuffer->mBackBuffer);
     MOZ_ASSERT(!backBuffer->mCapture);
   }
 
   // The new buffer is now validated, remove the dirty region from it.
   mTile.mInvalidBack.SubOut(tileDirtyRegion);