Bug 1337761 - Implement WebRenderLayerManager::EndEmptyTransaction. r=mattwoodrow
authorMason Chang <mchang@mozilla.com>
Wed, 19 Apr 2017 15:39:44 -0700
changeset 403268 8a3a9bb423224f0d662947aa9fa11bbabdff78ba
parent 403267 9cdad15bc911aad38b40d5be9a740d4d83fb9b3d
child 403269 73569501177174b1022ed18e439b1c397d5ebe3b
push id7391
push usermtabara@mozilla.com
push dateMon, 12 Jun 2017 13:08:53 +0000
treeherdermozilla-beta@2191d7f87e2e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmattwoodrow
bugs1337761
milestone55.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 1337761 - Implement WebRenderLayerManager::EndEmptyTransaction. r=mattwoodrow
gfx/layers/wr/WebRenderDisplayItemLayer.cpp
gfx/layers/wr/WebRenderLayerManager.cpp
gfx/layers/wr/WebRenderLayerManager.h
gfx/layers/wr/WebRenderPaintedLayer.cpp
gfx/layers/wr/WebRenderPaintedLayer.h
--- a/gfx/layers/wr/WebRenderDisplayItemLayer.cpp
+++ b/gfx/layers/wr/WebRenderDisplayItemLayer.cpp
@@ -43,19 +43,29 @@ WebRenderDisplayItemLayer::RenderLayer(w
   }
 
   if (mItem) {
     wr::DisplayListBuilder builder(WrBridge()->GetPipeline());
     // We might have recycled this layer. Throw away the old commands.
     mParentCommands.Clear();
     mItem->CreateWebRenderCommands(builder, mParentCommands, this);
     mBuiltDisplayList = builder.Finalize();
+  } else {
+    // else we have an empty transaction and just use the
+    // old commands.
+    WebRenderLayerManager* manager = static_cast<WebRenderLayerManager*>(Manager());
+    MOZ_ASSERT(manager);
+
+    // Since our recording relies on our parent layer's transform and stacking context
+    // If this layer or our parent changed, this empty transaction won't work.
+    if (manager->IsMutatedLayer(this) || manager->IsMutatedLayer(GetParent())) {
+      manager->SetTransactionIncomplete();
+      return;
+    }
   }
-  // else we have an empty transaction and just use the
-  // old commands.
 
   aBuilder.PushBuiltDisplayList(Move(mBuiltDisplayList));
   WrBridge()->AddWebRenderParentCommands(mParentCommands);
 
   if (imageMask) {
     aBuilder.PopClip();
   }
 }
--- a/gfx/layers/wr/WebRenderLayerManager.cpp
+++ b/gfx/layers/wr/WebRenderLayerManager.cpp
@@ -326,40 +326,52 @@ bool
 WebRenderLayerManager::BeginTransaction()
 {
   return true;
 }
 
 bool
 WebRenderLayerManager::EndEmptyTransaction(EndTransactionFlags aFlags)
 {
-  return false;
+  if (!mRoot) {
+    return false;
+  }
+
+  return EndTransactionInternal(nullptr, nullptr, aFlags);
 }
 
 void
 WebRenderLayerManager::EndTransaction(DrawPaintedLayerCallback aCallback,
                                       void* aCallbackData,
                                       EndTransactionFlags aFlags)
 {
   DiscardImages();
   WrBridge()->RemoveExpiredFontKeys();
+  EndTransactionInternal(aCallback, aCallbackData, aFlags);
+}
 
+bool
+WebRenderLayerManager::EndTransactionInternal(DrawPaintedLayerCallback aCallback,
+                                              void* aCallbackData,
+                                              EndTransactionFlags aFlags)
+{
   mPaintedLayerCallback = aCallback;
   mPaintedLayerCallbackData = aCallbackData;
+  mTransactionIncomplete = false;
 
   if (gfxPrefs::LayersDump()) {
     this->Dump();
   }
 
   // Since we don't do repeat transactions right now, just set the time
   mAnimationReadyTime = TimeStamp::Now();
 
   LayoutDeviceIntSize size = mWidget->GetClientSize();
   if (!WrBridge()->DPBegin(size.ToUnknownSize())) {
-    return;
+    return false;
   }
   DiscardCompositorAnimations();
   mRoot->StartPendingAnimations(mAnimationReadyTime);
 
   wr::DisplayListBuilder builder(WrBridge()->GetPipeline());
   WebRenderLayer::ToWebRenderLayer(mRoot)->RenderLayer(builder);
 
   bool sync = mTarget != nullptr;
@@ -370,16 +382,19 @@ WebRenderLayerManager::EndTransaction(Dr
   MakeSnapshotIfRequired(size);
   mNeedsComposite = false;
 
   ClearDisplayItemLayers();
 
   // this may result in Layers being deleted, which results in
   // PLayer::Send__delete__() and DeallocShmem()
   mKeepAlive.Clear();
+  ClearMutatedLayers();
+
+  return !mTransactionIncomplete;
 }
 
 void
 WebRenderLayerManager::MakeSnapshotIfRequired(LayoutDeviceIntSize aSize)
 {
   if (!mTarget || aSize.IsEmpty()) {
     return;
   }
@@ -464,16 +479,46 @@ void
 WebRenderLayerManager::DiscardCompositorAnimations()
 {
   for (auto id : mDiscardedCompositorAnimationsIds) {
     WrBridge()->AddWebRenderParentCommand(OpRemoveCompositorAnimations(id));
   }
   mDiscardedCompositorAnimationsIds.clear();
 }
 
+WebRenderLayerManager::Mutated(Layer* aLayer)
+{
+  LayerManager::Mutated(aLayer);
+  AddMutatedLayer(aLayer);
+}
+
+void
+WebRenderLayerManager::MutatedSimple(Layer* aLayer)
+{
+  LayerManager::Mutated(aLayer);
+  AddMutatedLayer(aLayer);
+}
+
+void
+WebRenderLayerManager::AddMutatedLayer(Layer* aLayer)
+{
+  mMutatedLayers.AppendElement(aLayer);
+}
+
+void
+WebRenderLayerManager::ClearMutatedLayers()
+{
+  mMutatedLayers.Clear();
+}
+
+bool
+WebRenderLayerManager::IsMutatedLayer(Layer* aLayer)
+{
+  return mMutatedLayers.Contains(aLayer);
+}
 
 void
 WebRenderLayerManager::Hold(Layer* aLayer)
 {
   mKeepAlive.AppendElement(aLayer);
 }
 
 void
--- a/gfx/layers/wr/WebRenderLayerManager.h
+++ b/gfx/layers/wr/WebRenderLayerManager.h
@@ -157,27 +157,37 @@ public:
 
   // Before destroying a layer with animations, add its compositorAnimationsId
   // to a list of ids that will be discarded on the next transaction
   void AddCompositorAnimationsIdForDiscard(uint64_t aId);
   void DiscardCompositorAnimations();
 
   WebRenderBridgeChild* WrBridge() const { return mWrChild; }
 
+  virtual void Mutated(Layer* aLayer) override;
+  virtual void MutatedSimple(Layer* aLayer) override;
+
   void Hold(Layer* aLayer);
+  void SetTransactionIncomplete() { mTransactionIncomplete = true; }
+  bool IsMutatedLayer(Layer* aLayer);
 
 private:
   /**
    * Take a snapshot of the parent context, and copy
    * it into mTarget.
    */
   void MakeSnapshotIfRequired(LayoutDeviceIntSize aSize);
 
   void ClearLayer(Layer* aLayer);
 
+  bool EndTransactionInternal(DrawPaintedLayerCallback aCallback,
+                              void* aCallbackData,
+                              EndTransactionFlags aFlags);
+
+
 private:
   nsIWidget* MOZ_NON_OWNING_REF mWidget;
   std::vector<wr::ImageKey> mImageKeys;
   std::vector<uint64_t> mDiscardedCompositorAnimationsIds;
 
   /* PaintedLayer callbacks; valid at the end of a transaciton,
    * while rendering */
   DrawPaintedLayerCallback mPaintedLayerCallback;
@@ -187,16 +197,24 @@ private:
 
   RefPtr<TransactionIdAllocator> mTransactionIdAllocator;
   uint64_t mLatestTransactionId;
 
   nsTArray<DidCompositeObserver*> mDidCompositeObservers;
 
   LayerRefArray mKeepAlive;
 
+  // Layers that have been mutated. If we have an empty transaction
+  // then a display item layer will no longer be valid
+  // if it was a mutated layers.
+  void AddMutatedLayer(Layer* aLayer);
+  void ClearMutatedLayers();
+  LayerRefArray mMutatedLayers;
+  bool mTransactionIncomplete;
+
   bool mNeedsComposite;
 
  // When we're doing a transaction in order to draw to a non-default
  // target, the layers transaction is only performed in order to send
  // a PLayers:Update.  We save the original non-default target to
  // mTarget, and then perform the transaction. After the transaction ends,
  // we send a message to our remote side to capture the actual pixels
  // being drawn to the default target, and then copy those pixels
--- a/gfx/layers/wr/WebRenderPaintedLayer.cpp
+++ b/gfx/layers/wr/WebRenderPaintedLayer.cpp
@@ -13,159 +13,65 @@
 #include "gfxPrefs.h"
 #include "gfxUtils.h"
 
 namespace mozilla {
 namespace layers {
 
 using namespace mozilla::gfx;
 
-void
-WebRenderPaintedLayer::PaintThebes(nsTArray<ReadbackProcessor::Update>* aReadbackUpdates)
-{
-  PROFILER_LABEL("WebRenderPaintedLayer", "PaintThebes",
-    js::ProfileEntry::Category::GRAPHICS);
-
-  mContentClient->BeginPaint();
-
-  uint32_t flags = RotatedContentBuffer::PAINT_CAN_DRAW_ROTATED;
-
-  PaintState state =
-    mContentClient->BeginPaintBuffer(this, flags);
-  mValidRegion.Sub(mValidRegion, state.mRegionToInvalidate);
-
-  if (!state.mRegionToDraw.IsEmpty() && !Manager()->GetPaintedLayerCallback()) {
-    return;
-  }
-
-  // The area that became invalid and is visible needs to be repainted
-  // (this could be the whole visible area if our buffer switched
-  // from RGB to RGBA, because we might need to repaint with
-  // subpixel AA)
-  state.mRegionToInvalidate.And(state.mRegionToInvalidate,
-                                GetLocalVisibleRegion().ToUnknownRegion());
-
-  bool didUpdate = false;
-  RotatedContentBuffer::DrawIterator iter;
-  while (DrawTarget* target = mContentClient->BorrowDrawTargetForPainting(state, &iter)) {
-    if (!target || !target->IsValid()) {
-      if (target) {
-        mContentClient->ReturnDrawTargetToBuffer(target);
-      }
-      continue;
-    }
-
-    SetAntialiasingFlags(this, target);
-
-    RefPtr<gfxContext> ctx = gfxContext::CreatePreservingTransformOrNull(target);
-    MOZ_ASSERT(ctx); // already checked the target above
-    Manager()->GetPaintedLayerCallback()(this,
-                                              ctx,
-                                              iter.mDrawRegion,
-                                              iter.mDrawRegion,
-                                              state.mClip,
-                                              state.mRegionToInvalidate,
-                                              Manager()->GetPaintedLayerCallbackData());
-
-    ctx = nullptr;
-    mContentClient->ReturnDrawTargetToBuffer(target);
-    didUpdate = true;
-  }
-
-  mContentClient->EndPaint(aReadbackUpdates);
-
-  if (didUpdate) {
-    Mutated();
-
-    // XXX It will cause reftests failures. See Bug 1340798.
-    //mValidRegion.Or(mValidRegion, state.mRegionToDraw);
-
-    ContentClientRemote* contentClientRemote = static_cast<ContentClientRemote*>(mContentClient.get());
-
-    // Hold(this) ensures this layer is kept alive through the current transaction
-    // The ContentClient assumes this layer is kept alive (e.g., in CreateBuffer),
-    // so deleting this Hold for whatever reason will break things.
-    Manager()->Hold(this);
-
-    contentClientRemote->Updated(state.mRegionToDraw,
-                                 mVisibleRegion.ToUnknownRegion(),
-                                 state.mDidSelfCopy);
-  }
-}
-
-void
-WebRenderPaintedLayer::RenderLayerWithReadback(ReadbackProcessor *aReadback)
-{
-  if (!mContentClient) {
-    mContentClient = ContentClient::CreateContentClient(Manager()->WrBridge());
-    if (!mContentClient) {
-      return;
-    }
-    mContentClient->Connect();
-    MOZ_ASSERT(mContentClient->GetForwarder());
-  }
-
-  nsTArray<ReadbackProcessor::Update> readbackUpdates;
-  nsIntRegion readbackRegion;
-  if (aReadback && UsedForReadback()) {
-    aReadback->GetPaintedLayerUpdates(this, &readbackUpdates);
-  }
-
-  PaintThebes(&readbackUpdates);
-}
-
-void
-WebRenderPaintedLayer::RenderLayer(wr::DisplayListBuilder& aBuilder)
+bool
+WebRenderPaintedLayer::SetupExternalImages()
 {
   // XXX We won't keep using ContentClient for WebRenderPaintedLayer in the future and
   // there is a crash problem for ContentClient on MacOS. So replace ContentClient with
   // ImageClient. See bug 1341001.
-  //RenderLayerWithReadback(nullptr);
 
   if (!mImageContainer) {
     mImageContainer = LayerManager::CreateImageContainer();
   }
 
   if (!mImageClient) {
     mImageClient = ImageClient::CreateImageClient(CompositableType::IMAGE,
                                                   WrBridge(),
                                                   TextureFlags::DEFAULT);
     if (!mImageClient) {
-      return;
+      return false;
     }
     mImageClient->Connect();
   }
 
   if (mExternalImageId.isNothing()) {
     mExternalImageId = Some(WrBridge()->AllocExternalImageIdForCompositable(mImageClient));
   }
 
+  return true;
+}
+
+bool
+WebRenderPaintedLayer::UpdateImageClient()
+{
+  MOZ_ASSERT(Manager()->GetPaintedLayerCallback());
   LayerIntRegion visibleRegion = GetVisibleRegion();
   LayerIntRect bounds = visibleRegion.GetBounds();
   LayerIntSize size = bounds.Size();
-  if (size.IsEmpty()) {
-      if (gfxPrefs::LayersDump()) {
-        printf_stderr("PaintedLayer %p skipping\n", this->GetLayer());
-      }
-      return;
-  }
-
   IntSize imageSize(size.width, size.height);
 
   UpdateImageHelper helper(mImageContainer, mImageClient, imageSize);
 
   {
     RefPtr<DrawTarget> target = helper.GetDrawTarget();
     if (!target) {
-      return;
+      return false;
     }
 
     target->ClearRect(Rect(0, 0, imageSize.width, imageSize.height));
     target->SetTransform(Matrix().PreTranslate(-bounds.x, -bounds.y));
-    RefPtr<gfxContext> ctx = gfxContext::CreatePreservingTransformOrNull(target);
+    RefPtr<gfxContext> ctx =
+        gfxContext::CreatePreservingTransformOrNull(target);
     MOZ_ASSERT(ctx); // already checked the target above
 
     Manager()->GetPaintedLayerCallback()(this,
                                          ctx,
                                          visibleRegion.ToUnknownRegion(), visibleRegion.ToUnknownRegion(),
                                          DrawRegionClip::DRAW, nsIntRegion(), Manager()->GetPaintedLayerCallbackData());
 
     if (gfxPrefs::WebRenderHighlightPaintedLayers()) {
@@ -173,16 +79,26 @@ WebRenderPaintedLayer::RenderLayer(wr::D
       target->FillRect(Rect(0, 0, imageSize.width, imageSize.height), ColorPattern(Color(1.0, 0.0, 0.0, 0.5)));
     }
   }
 
   if (!helper.UpdateImage()) {
     return;
   }
 
+  return true;
+}
+
+void
+WebRenderPaintedLayer::CreateWebRenderDisplayList(wr::DisplayListBuilder& aBuilder)
+{
+  LayerIntRegion visibleRegion = GetVisibleRegion();
+  LayerIntRect bounds = visibleRegion.GetBounds();
+  LayerIntSize size = bounds.Size();
+
   gfx::Matrix4x4 transform = GetTransform();
   gfx::Rect relBounds = GetWrRelBounds();
   gfx::Rect rect(0, 0, size.width, size.height);
 
   gfx::Rect clipRect = GetWrClipRect(rect);
   Maybe<WrImageMask> mask = BuildWrMaskLayer(true);
   WrClipRegion clip = aBuilder.BuildClipRegion(wr::ToWrRect(clipRect), mask.ptrOr(nullptr));
 
@@ -198,10 +114,48 @@ WebRenderPaintedLayer::RenderLayer(wr::D
                               1.0f,
                               //GetAnimations(),
                               transform,
                               mixBlendMode);
   aBuilder.PushImage(wr::ToWrRect(rect), clip, wr::ImageRendering::Auto, key);
   aBuilder.PopStackingContext();
 }
 
+void
+WebRenderPaintedLayer::RenderLayer(wr::DisplayListBuilder& aBuilder)
+{
+  if (!SetupExternalImages()) {
+    return;
+  }
+
+  if (GetVisibleRegion().IsEmpty()) {
+    if (gfxPrefs::LayersDump()) {
+      printf_stderr("PaintedLayer %p skipping\n", this->GetLayer());
+    }
+    return;
+  }
+
+  nsIntRegion regionToPaint;
+  regionToPaint.Sub(mVisibleRegion.ToUnknownRegion(), mValidRegion);
+
+  // We have something to paint but can't. This usually happens only in
+  // empty transactions
+  if (!regionToPaint.IsEmpty() && !Manager()->GetPaintedLayerCallback()) {
+    Manager()->SetTransactionIncomplete();
+    return;
+  }
+
+  if (!regionToPaint.IsEmpty() && Manager()->GetPaintedLayerCallback()) {
+    if (!UpdateImageClient()) {
+      return;
+    }
+  } else {
+    // We have an empty transaction, just reuse the old image we had before.
+    MOZ_ASSERT(mExternalImageId);
+    MOZ_ASSERT(mImageContainer->HasCurrentImage());
+    MOZ_ASSERT(GetInvalidRegion().IsEmpty());
+  }
+
+  CreateWebRenderDisplayList(aBuilder);
+}
+
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/wr/WebRenderPaintedLayer.h
+++ b/gfx/layers/wr/WebRenderPaintedLayer.h
@@ -46,19 +46,21 @@ public:
   virtual void InvalidateRegion(const nsIntRegion& aRegion) override
   {
     mInvalidRegion.Add(aRegion);
     mValidRegion.Sub(mValidRegion, mInvalidRegion.GetRegion());
   }
 
   Layer* GetLayer() override { return this; }
   void RenderLayer(wr::DisplayListBuilder& aBuilder) override;
-  void PaintThebes(nsTArray<ReadbackProcessor::Update>* aReadbackUpdates);
-  void RenderLayerWithReadback(ReadbackProcessor *aReadback);
-  RefPtr<ContentClient> mContentClient;
   RefPtr<ImageContainer> mImageContainer;
   RefPtr<ImageClient> mImageClient;
+
+private:
+  bool SetupExternalImages();
+  bool UpdateImageClient();
+  void CreateWebRenderDisplayList(wr::DisplayListBuilder& aBuilder);
 };
 
 } // namespace layers
 } // namespace mozilla
 
 #endif // GFX_WEBRENDERPAINTEDLAYER_H