Bug 1440937 - Change PaintTask to be a UniquePtr. r=mattwoodrow
authorRyan Hunt <rhunt@eqrion.net>
Wed, 12 Sep 2018 10:28:59 -0500
changeset 436805 ad3db6015cec0f903f45f7a5095e3373a3592170
parent 436804 a1c1e2f201a73f1e82701d08b42dc9ae3da24ee0
child 436806 9c3d3afc75aa265ac5e6aa92b2cf6f7faa3762cf
push id34660
push userbtara@mozilla.com
push dateMon, 17 Sep 2018 21:58:52 +0000
treeherdermozilla-central@87a95e1b7ec6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmattwoodrow
bugs1440937
milestone64.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 1440937 - Change PaintTask to be a UniquePtr. r=mattwoodrow Now that we have C++14 support we can capture a move only object in a lambda expression.
gfx/layers/PaintThread.cpp
gfx/layers/PaintThread.h
gfx/layers/client/ClientPaintedLayer.cpp
gfx/layers/client/ContentClient.cpp
gfx/layers/client/ContentClient.h
gfx/layers/client/MultiTiledContentClient.cpp
gfx/layers/client/MultiTiledContentClient.h
gfx/layers/client/SingleTiledContentClient.cpp
--- a/gfx/layers/PaintThread.cpp
+++ b/gfx/layers/PaintThread.cpp
@@ -192,35 +192,35 @@ PaintThread::UpdateRenderMode()
       mPaintWorkers = nullptr;
     } else {
       InitPaintWorkers();
     }
   }
 }
 
 void
-PaintThread::QueuePaintTask(PaintTask* aTask)
+PaintThread::QueuePaintTask(UniquePtr<PaintTask>&& aTask)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aTask);
 
   if (gfxPrefs::LayersOMTPDumpCapture() && aTask->mCapture) {
     aTask->mCapture->Dump();
   }
 
+  MOZ_RELEASE_ASSERT(aTask->mCapture->hasOneRef());
+
   RefPtr<CompositorBridgeChild> cbc(CompositorBridgeChild::Get());
-  RefPtr<PaintTask> state(aTask);
-
-  cbc->NotifyBeginAsyncPaint(state);
+  cbc->NotifyBeginAsyncPaint(aTask.get());
 
   RefPtr<PaintThread> self = this;
   RefPtr<Runnable> task = NS_NewRunnableFunction("PaintThread::AsyncPaintTask",
-    [self, cbc, state]() -> void
+    [self, cbc, task = std::move(aTask)]() -> void
   {
-    self->AsyncPaintTask(cbc, state);
+    self->AsyncPaintTask(cbc, task.get());
   });
 
   nsIEventTarget* paintThread = mPaintWorkers ?
     static_cast<nsIEventTarget*>(mPaintWorkers.get()) :
     static_cast<nsIEventTarget*>(sThread.get());
 
 #ifndef OMTP_FORCE_SYNC
   paintThread->Dispatch(task.forget());
--- a/gfx/layers/PaintThread.h
+++ b/gfx/layers/PaintThread.h
@@ -29,28 +29,25 @@ namespace layers {
 // on the paint thread or paint worker pool.
 //
 // More specifically it contains:
 // 1. A capture command list of drawing commands
 // 2. A destination draw target to replay the draw commands upon
 // 3. A list of dependent texture clients that must be kept alive for the
 //    task's duration, and then destroyed on the main thread
 class PaintTask {
-  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(PaintTask)
 public:
   PaintTask() {}
+  ~PaintTask() {}
 
   void DropTextureClients();
 
   RefPtr<gfx::DrawTarget> mTarget;
   RefPtr<gfx::DrawTargetCapture> mCapture;
   AutoTArray<RefPtr<TextureClient>, 4> mClients;
-
-protected:
-  virtual ~PaintTask() {}
 };
 
 class CompositorBridgeChild;
 
 class PaintThread final
 {
   friend void DestroyPaintThread(UniquePtr<PaintThread>&& aPaintThread);
 
@@ -68,17 +65,17 @@ public:
 
   // This allows the paint thread to dynamically toggle between a paint worker
   // thread pool used with tiling, and a single paint thread used with rotated
   // buffer.
   void UpdateRenderMode();
 
   // Must be called on the main thread. Queues an async paint
   // task to be completed on the paint thread.
-  void QueuePaintTask(PaintTask* aTask);
+  void QueuePaintTask(UniquePtr<PaintTask>&& aTask);
 
   // Must be called on the main thread. Signifies that the current
   // layer tree transaction has been finished and any async paints
   // for it have been queued on the paint thread. This MUST be called
   // at the end of a layer transaction as it will be used to do an optional
   // texture sync and then unblock the main thread if it is waiting to paint
   // a new frame.
   void QueueEndLayerTransaction(SyncObjectClient* aSyncObject);
--- a/gfx/layers/client/ClientPaintedLayer.cpp
+++ b/gfx/layers/client/ClientPaintedLayer.cpp
@@ -91,17 +91,17 @@ ClientPaintedLayer::UpdatePaintRegion(Pa
   return true;
 }
 
 void
 ClientPaintedLayer::FinishPaintState(PaintState& aState)
 {
   if (aState.mAsyncTask && !aState.mAsyncTask->mCapture->IsEmpty()) {
     ClientManager()->SetQueuedAsyncPaints();
-    PaintThread::Get()->QueuePaintTask(aState.mAsyncTask);
+    PaintThread::Get()->QueuePaintTask(std::move(aState.mAsyncTask));
   }
 }
 
 uint32_t
 ClientPaintedLayer::GetPaintFlags(ReadbackProcessor* aReadback)
 {
   uint32_t flags = ContentClient::PAINT_CAN_DRAW_ROTATED;
   #ifndef MOZ_IGNORE_PAINT_WILL_RESAMPLE
--- a/gfx/layers/client/ContentClient.cpp
+++ b/gfx/layers/client/ContentClient.cpp
@@ -158,17 +158,17 @@ ContentClient::BeginPaint(PaintedLayer* 
   OpenMode readMode = result.mAsyncPaint ? OpenMode::OPEN_READ_ASYNC
                                          : OpenMode::OPEN_READ;
   OpenMode writeMode = result.mAsyncPaint ? OpenMode::OPEN_READ_WRITE_ASYNC
                                           : OpenMode::OPEN_READ_WRITE;
 
   IntRect drawBounds = result.mRegionToDraw.GetBounds();
 
   if (result.mAsyncPaint) {
-    result.mAsyncTask = new PaintTask();
+    result.mAsyncTask.reset(new PaintTask());
   }
 
   // Try to acquire the back buffer, copy over contents if we are using a new buffer,
   // and rotate or unrotate the buffer as necessary
   if (mBuffer && dest.mCanReuseBuffer) {
     if (mBuffer->Lock(writeMode)) {
       auto newParameters = mBuffer->AdjustedParameters(dest.mBufferRect);
 
--- a/gfx/layers/client/ContentClient.h
+++ b/gfx/layers/client/ContentClient.h
@@ -20,16 +20,17 @@
 #include "mozilla/layers/CompositorTypes.h"  // for TextureInfo, etc
 #include "mozilla/layers/ISurfaceAllocator.h"
 #include "mozilla/layers/LayersSurfaces.h"  // for SurfaceDescriptor
 #include "mozilla/layers/LayersTypes.h"  // for TextureDumpMode
 #include "mozilla/layers/TextureClient.h"  // for TextureClient
 #include "mozilla/layers/PaintThread.h"  // for PaintTask
 #include "mozilla/Maybe.h"              // for Maybe
 #include "mozilla/mozalloc.h"           // for operator delete
+#include "mozilla/UniquePtr.h"          // for UniquePtr
 #include "ReadbackProcessor.h"          // For ReadbackProcessor::Update
 #include "nsCOMPtr.h"                   // for already_AddRefed
 #include "nsPoint.h"                    // for nsIntPoint
 #include "nsRect.h"                     // for mozilla::gfx::IntRect
 #include "nsRegion.h"                   // for nsIntRegion
 #include "nsTArray.h"                   // for nsTArray
 
 namespace mozilla {
@@ -112,17 +113,17 @@ public:
     {}
 
     nsIntRegion mRegionToDraw;
     nsIntRegion mRegionToInvalidate;
     SurfaceMode mMode;
     DrawRegionClip mClip;
     gfxContentType mContentType;
     bool mAsyncPaint;
-    RefPtr<PaintTask> mAsyncTask;
+    UniquePtr<PaintTask> mAsyncTask;
   };
 
   enum {
     PAINT_WILL_RESAMPLE = 0x01,
     PAINT_NO_ROTATION = 0x02,
     PAINT_CAN_DRAW_ROTATED = 0x04,
     PAINT_ASYNC = 0x08,
   };
--- a/gfx/layers/client/MultiTiledContentClient.cpp
+++ b/gfx/layers/client/MultiTiledContentClient.cpp
@@ -147,17 +147,17 @@ void ClientMultiTiledLayerBuffer::MaybeS
     AutoTArray<uint64_t, 10> syncTextureSerials;
     SurfaceMode mode;
     Unused << GetContentType(&mode);
 
     // Pre-pass through the tiles (mirroring the filter logic below) to gather
     // texture IDs that we need to ensure are unused by the GPU before we
     // continue.
     if (!aPaintRegion.IsEmpty()) {
-      MOZ_ASSERT(mPaintTasks.size() == 0);
+      MOZ_ASSERT(mPaintTasks.IsEmpty());
       for (size_t i = 0; i < mRetainedTiles.Length(); ++i) {
         const TileCoordIntPoint tileCoord = aNewTiles.TileCoord(i);
 
         IntPoint tileOffset = GetTileOffset(tileCoord);
         nsIntRegion tileDrawRegion = IntRect(tileOffset, aScaledTileSize);
         tileDrawRegion.AndWith(aPaintRegion);
 
         if (tileDrawRegion.IsEmpty()) {
@@ -215,17 +215,17 @@ void ClientMultiTiledLayerBuffer::Update
   oldRetainedTiles.Clear();
 
   nsIntRegion paintRegion = aPaintRegion;
   nsIntRegion dirtyRegion = aDirtyRegion;
 
   MaybeSyncTextures(paintRegion, newTiles, scaledTileSize);
 
   if (!paintRegion.IsEmpty()) {
-    MOZ_ASSERT(mPaintTasks.size() == 0);
+    MOZ_ASSERT(mPaintTasks.IsEmpty());
 
     for (size_t i = 0; i < newTileCount; ++i) {
       const TileCoordIntPoint tileCoord = newTiles.TileCoord(i);
 
       IntPoint tileOffset = GetTileOffset(tileCoord);
       nsIntRegion tileDrawRegion = IntRect(tileOffset, scaledTileSize);
       tileDrawRegion.AndWith(paintRegion);
 
@@ -238,24 +238,24 @@ void ClientMultiTiledLayerBuffer::Update
         gfxCriticalError() << "ValidateTile failed";
       }
 
       // Validating the tile may have required more to be painted.
       paintRegion.OrWith(tileDrawRegion);
       dirtyRegion.OrWith(tileDrawRegion);
     }
 
-    if (!mPaintTiles.empty()) {
+    if (!mPaintTiles.IsEmpty()) {
       // Create a tiled draw target
       gfx::TileSet tileset;
-      for (size_t i = 0; i < mPaintTiles.size(); ++i) {
+      for (size_t i = 0; i < mPaintTiles.Length(); ++i) {
         mPaintTiles[i].mTileOrigin -= mTilingOrigin;
       }
-      tileset.mTiles = &mPaintTiles[0];
-      tileset.mTileCount = mPaintTiles.size();
+      tileset.mTiles = mPaintTiles.Elements();
+      tileset.mTileCount = mPaintTiles.Length();
       RefPtr<DrawTarget> drawTarget = gfx::Factory::CreateTiledDrawTarget(tileset);
       if (!drawTarget || !drawTarget->IsValid()) {
         gfxDevCrash(LogReason::InvalidContext) << "Invalid tiled draw target";
         return;
       }
       drawTarget->SetTransform(Matrix());
 
       // Draw into the tiled draw target
@@ -269,37 +269,38 @@ void ClientMultiTiledLayerBuffer::Update
       ctx = nullptr;
 
       // Edge padding allows us to avoid resampling artifacts
       if (gfxPrefs::TileEdgePaddingEnabled() && mResolution == 1) {
         drawTarget->PadEdges(newValidRegion.MovedBy(-mTilingOrigin));
       }
 
       // Reset
-      mPaintTiles.clear();
+      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) {
-        if (!state->mCapture->IsEmpty()) {
-          PaintThread::Get()->QueuePaintTask(state);
+      while (!mPaintTasks.IsEmpty()) {
+        UniquePtr<PaintTask> task = mPaintTasks.PopLastElement();
+        if (!task->mCapture->IsEmpty()) {
+          PaintThread::Get()->QueuePaintTask(std::move(task));
           queuedTask = true;
         }
       }
 
       if (queuedTask) {
         mManager->SetQueuedAsyncPaints();
       }
 
-      mPaintTasks.clear();
+      mPaintTasks.Clear();
     }
 
     for (uint32_t i = 0; i < mRetainedTiles.Length(); ++i) {
       TileClient& tile = mRetainedTiles[i];
       UnlockTile(tile);
     }
   }
 
@@ -381,24 +382,24 @@ ClientMultiTiledLayerBuffer::ValidateTil
                                iter.Get().Width(), iter.Get().Height());
       backBuffer->mTarget->ClearRect(drawRect);
     }
   }
 
   gfx::Tile paintTile;
   paintTile.mTileOrigin = gfx::IntPoint(aTileOrigin.x, aTileOrigin.y);
   paintTile.mDrawTarget = backBuffer->mTarget;
-  mPaintTiles.push_back(paintTile);
+  mPaintTiles.AppendElement(paintTile);
 
   if (aFlags & TilePaintFlags::Async) {
-    RefPtr<PaintTask> task = new PaintTask();
+    UniquePtr<PaintTask> task(new PaintTask());
     task->mCapture = backBuffer->mCapture;
     task->mTarget = backBuffer->mBackBuffer;
     task->mClients = std::move(backBuffer->mTextureClients);
-    mPaintTasks.push_back(task);
+    mPaintTasks.AppendElement(std::move(task));
   } else {
     MOZ_RELEASE_ASSERT(backBuffer->mTarget == backBuffer->mBackBuffer);
     MOZ_RELEASE_ASSERT(backBuffer->mCapture == nullptr);
   }
 
   mTilingOrigin.x = std::min(mTilingOrigin.x, paintTile.mTileOrigin.x);
   mTilingOrigin.y = std::min(mTilingOrigin.y, paintTile.mTileOrigin.y);
 
--- a/gfx/layers/client/MultiTiledContentClient.h
+++ b/gfx/layers/client/MultiTiledContentClient.h
@@ -9,16 +9,17 @@
 
 #include "ClientLayerManager.h"                 // for ClientLayerManager
 #include "nsRegion.h"                           // for nsIntRegion
 #include "mozilla/gfx/2D.h"                     // for gfx::Tile
 #include "mozilla/gfx/Point.h"                  // for IntPoint
 #include "mozilla/layers/CompositableClient.h"  // for CompositableClient
 #include "mozilla/layers/LayersMessages.h"      // for TileDescriptor
 #include "mozilla/layers/TiledContentClient.h"  // for ClientTiledPaintedLayer
+#include "mozilla/UniquePtr.h"                  // for UniquePtr
 #include "TiledLayerBuffer.h"                   // for TiledLayerBuffer
 
 namespace mozilla {
 namespace layers {
 
 class ClientLayerManager;
 
 class ClientMultiTiledLayerBuffer
@@ -116,18 +117,18 @@ private:
   // The region that will be made valid during Update(). Once Update() is
   // completed then this is identical to mValidRegion.
   nsIntRegion mNewValidRegion;
 
   SharedFrameMetricsHelper*  mSharedFrameMetricsHelper;
 
   // Parameters that are collected during Update for a paint before they
   // are either executed or replayed on the paint thread.
-  std::vector<gfx::Tile> mPaintTiles;
-  std::vector<RefPtr<PaintTask>> mPaintTasks;
+  AutoTArray<gfx::Tile, 4> mPaintTiles;
+  AutoTArray<UniquePtr<PaintTask>, 4> mPaintTasks;
 
   /**
    * While we're adding tiles, this is used to keep track of the position of
    * the top-left of the top-left-most tile.  When we come to wrap the tiles in
    * TiledDrawTarget we subtract the value of this member from each tile's
    * offset so that all the tiles have a positive offset, then add a
    * translation to the TiledDrawTarget to compensate.  This is important so
    * that the mRect of the TiledDrawTarget is always at a positive x/y
--- a/gfx/layers/client/SingleTiledContentClient.cpp
+++ b/gfx/layers/client/SingleTiledContentClient.cpp
@@ -3,16 +3,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/layers/SingleTiledContentClient.h"
 
 #include "ClientTiledPaintedLayer.h"
 #include "mozilla/Maybe.h"
+#include "mozilla/UniquePtr.h"
 
 namespace mozilla {
 namespace layers {
 
 
 SingleTiledContentClient::SingleTiledContentClient(ClientTiledPaintedLayer& aPaintedLayer,
                                                    ClientLayerManager* aManager)
   : TiledContentClient(aManager, "Single")
@@ -231,21 +232,27 @@ ClientSingleTiledLayerBuffer::PaintThebe
     }
     ctx->SetMatrix(ctx->CurrentMatrix().PreTranslate(-mTilingOrigin.x, -mTilingOrigin.y));
 
     aCallback(&mPaintedLayer, ctx, paintRegion, paintRegion, DrawRegionClip::DRAW, nsIntRegion(), aCallbackData);
   }
 
   if (asyncPaint) {
     if (!backBuffer->mCapture->IsEmpty()) {
-      RefPtr<PaintTask> task = new PaintTask();
+      UniquePtr<PaintTask> task(new PaintTask());
       task->mCapture = backBuffer->mCapture;
       task->mTarget = backBuffer->mBackBuffer;
       task->mClients = std::move(backBuffer->mTextureClients);
-      PaintThread::Get()->QueuePaintTask(task);
+
+      // The target is an alias for the capture, and the paint thread expects
+      // to be the only one with a reference to the capture
+      backBuffer->mTarget = nullptr;
+      backBuffer->mCapture = nullptr;
+
+      PaintThread::Get()->QueuePaintTask(std::move(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.