Bug 1341524 - Fix NotifyDidComposite() and WebRender epoch r=nical
authorsotaro <sotaro.ikeda.g@gmail.com>
Fri, 24 Feb 2017 12:22:59 +0900
changeset 374803 b545b4883b898a78f6071c9ef4cd627037b2fc08
parent 374802 b323a395e46e436062971eda9b675c1dbbcfc55e
child 374804 d4583ab7644efc567dbc412e38c32282a9cb067a
push id10863
push userjlorenzo@mozilla.com
push dateMon, 06 Mar 2017 23:02:23 +0000
treeherdermozilla-aurora@0931190cd725 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnical
bugs1341524
milestone54.0a1
Bug 1341524 - Fix NotifyDidComposite() and WebRender epoch r=nical
gfx/layers/ipc/CompositorBridgeParent.cpp
gfx/layers/ipc/CompositorBridgeParent.h
gfx/layers/ipc/CrossProcessCompositorBridgeParent.cpp
gfx/layers/wr/WebRenderBridgeParent.cpp
gfx/layers/wr/WebRenderBridgeParent.h
gfx/webrender_bindings/RenderThread.cpp
--- a/gfx/layers/ipc/CompositorBridgeParent.cpp
+++ b/gfx/layers/ipc/CompositorBridgeParent.cpp
@@ -1812,18 +1812,54 @@ CompositorBridgeParent::LayerTreeState::
 {
   return mParent;
 }
 
 void
 CompositorBridgeParent::DidComposite(TimeStamp& aCompositeStart,
                                      TimeStamp& aCompositeEnd)
 {
-  NotifyDidComposite(mPendingTransaction, aCompositeStart, aCompositeEnd);
-  mPendingTransaction = 0;
+  if (mWrBridge) {
+    NotifyDidComposite(mWrBridge->FlushPendingTransactionIds(), aCompositeStart, aCompositeEnd);
+  } else {
+    NotifyDidComposite(mPendingTransaction, aCompositeStart, aCompositeEnd);
+    mPendingTransaction = 0;
+  }
+}
+
+void
+CompositorBridgeParent::NotifyDidCompositeToPipeline(const wr::PipelineId& aPipelineId, const wr::Epoch& aEpoch, TimeStamp& aCompositeStart, TimeStamp& aCompositeEnd)
+{
+  if (mPaused) {
+    return;
+  }
+  MOZ_ASSERT(mWrBridge);
+
+  if (mWrBridge->PipelineId() == aPipelineId) {
+    uint64_t transactionId = mWrBridge->FlushTransactionIdsForEpoch(aEpoch);
+    Unused << SendDidComposite(0, transactionId, aCompositeStart, aCompositeEnd);
+
+    nsTArray<ImageCompositeNotificationInfo> notifications;
+    mWrBridge->ExtractImageCompositeNotifications(&notifications);
+    if (!notifications.IsEmpty()) {
+      Unused << ImageBridgeParent::NotifyImageComposites(notifications);
+    }
+    return;
+  }
+
+  MonitorAutoLock lock(*sIndirectLayerTreesLock);
+  ForEachIndirectLayerTree([&] (LayerTreeState* lts, const uint64_t& aLayersId) -> void {
+    if (lts->mCrossProcessParent &&
+        lts->mWrBridge &&
+        lts->mWrBridge->PipelineId() == aPipelineId) {
+      CrossProcessCompositorBridgeParent* cpcp = lts->mCrossProcessParent;
+      uint64_t transactionId = lts->mWrBridge->FlushTransactionIdsForEpoch(aEpoch);
+      Unused << cpcp->SendDidComposite(aLayersId, transactionId, aCompositeStart, aCompositeEnd);
+    }
+  });
 }
 
 void
 CompositorBridgeParent::NotifyDidComposite(uint64_t aTransactionId, TimeStamp& aCompositeStart, TimeStamp& aCompositeEnd)
 {
   Unused << SendDidComposite(0, aTransactionId, aCompositeStart, aCompositeEnd);
 
   if (mLayerManager) {
--- a/gfx/layers/ipc/CompositorBridgeParent.h
+++ b/gfx/layers/ipc/CompositorBridgeParent.h
@@ -31,16 +31,17 @@
 #include "mozilla/layers/CompositorOptions.h"
 #include "mozilla/layers/CompositorVsyncSchedulerOwner.h"
 #include "mozilla/layers/GeckoContentController.h"
 #include "mozilla/layers/ISurfaceAllocator.h" // for ShmemAllocator
 #include "mozilla/layers/LayersMessages.h"  // for TargetConfig
 #include "mozilla/layers/MetricsSharingController.h"
 #include "mozilla/layers/PCompositorBridgeParent.h"
 #include "mozilla/layers/APZTestData.h"
+#include "mozilla/webrender/WebRenderTypes.h"
 #include "mozilla/widget/CompositorWidget.h"
 #include "nsISupportsImpl.h"
 #include "ThreadSafeRefcountingWithMainThreadDestruction.h"
 
 class MessageLoop;
 class nsIWidget;
 
 namespace mozilla {
@@ -113,17 +114,17 @@ public:
   virtual void UpdatePaintTime(LayerTransactionParent* aLayerTree, const TimeDuration& aPaintTime) {}
 
   virtual ShmemAllocator* AsShmemAllocator() override { return this; }
 
   virtual mozilla::ipc::IPCResult RecvSyncWithCompositor() override { return IPC_OK(); }
 
   virtual void ObserveLayerUpdate(uint64_t aLayersId, uint64_t aEpoch, bool aActive) = 0;
 
-  virtual void NotifyDidComposite(uint64_t aTransactionId, TimeStamp& aCompositeStart, TimeStamp& aCompositeEnd) {}
+  virtual void NotifyDidCompositeToPipeline(const wr::PipelineId& aPipelineId, const wr::Epoch& aEpoch, TimeStamp& aCompositeStart, TimeStamp& aCompositeEnd) {}
 
   // HostIPCAllocator
   virtual base::ProcessId GetChildProcessId() override;
   virtual void NotifyNotUsed(PTextureParent* aTexture, uint64_t aTransactionId) override;
   virtual void SendAsyncMessage(const InfallibleTArray<AsyncParentMessageData>& aMessage) override;
 
   // ShmemAllocator
   virtual bool AllocShmem(size_t aSize,
@@ -545,17 +546,19 @@ protected:
   /**
    * Return true if current state allows compositing, that is
    * finishing a layers transaction.
    */
   bool CanComposite();
 
   void DidComposite(TimeStamp& aCompositeStart, TimeStamp& aCompositeEnd);
 
-  virtual void NotifyDidComposite(uint64_t aTransactionId, TimeStamp& aCompositeStart, TimeStamp& aCompositeEnd) override;
+  virtual void NotifyDidCompositeToPipeline(const wr::PipelineId& aPipelineId, const wr::Epoch& aEpoch, TimeStamp& aCompositeStart, TimeStamp& aCompositeEnd) override;
+
+  void NotifyDidComposite(uint64_t aTransactionId, TimeStamp& aCompositeStart, TimeStamp& aCompositeEnd);
 
   // The indirect layer tree lock must be held before calling this function.
   // Callback should take (LayerTreeState* aState, const uint64_t& aLayersId)
   template <typename Lambda>
   inline void ForEachIndirectLayerTree(const Lambda& aCallback);
 
   RefPtr<HostLayerManager> mLayerManager;
   RefPtr<Compositor> mCompositor;
--- a/gfx/layers/ipc/CrossProcessCompositorBridgeParent.cpp
+++ b/gfx/layers/ipc/CrossProcessCompositorBridgeParent.cpp
@@ -320,18 +320,17 @@ CrossProcessCompositorBridgeParent::DidC
   TimeStamp& aCompositeStart,
   TimeStamp& aCompositeEnd)
 {
   sIndirectLayerTreesLock->AssertCurrentThreadOwns();
   if (LayerTransactionParent *layerTree = sIndirectLayerTrees[aId].mLayerTree) {
     Unused << SendDidComposite(aId, layerTree->GetPendingTransactionId(), aCompositeStart, aCompositeEnd);
     layerTree->SetPendingTransactionId(0);
   } else if (WebRenderBridgeParent* wrbridge = sIndirectLayerTrees[aId].mWrBridge) {
-    Unused << SendDidComposite(aId, wrbridge->GetPendingTransactionId(), aCompositeStart, aCompositeEnd);
-    wrbridge->SetPendingTransactionId(0);
+    Unused << SendDidComposite(aId, wrbridge->FlushPendingTransactionIds(), aCompositeStart, aCompositeEnd);
   }
 }
 
 void
 CrossProcessCompositorBridgeParent::ForceComposite(LayerTransactionParent* aLayerTree)
 {
   uint64_t id = aLayerTree->GetId();
   MOZ_ASSERT(id != 0);
--- a/gfx/layers/wr/WebRenderBridgeParent.cpp
+++ b/gfx/layers/wr/WebRenderBridgeParent.cpp
@@ -83,17 +83,17 @@ WebRenderBridgeParent::WebRenderBridgePa
   : mCompositorBridge(aCompositorBridge)
   , mPipelineId(aPipelineId)
   , mWidget(aWidget)
   , mBuilder(Nothing())
   , mApi(aApi)
   , mCompositableHolder(aHolder)
   , mChildLayerObserverEpoch(0)
   , mParentLayerObserverEpoch(0)
-  , mPendingTransactionId(0)
+  , mWrEpoch(0)
   , mDestroyed(false)
 {
   MOZ_ASSERT(mCompositableHolder);
   if (mWidget) {
     mCompositorScheduler = new CompositorVsyncScheduler(this, mWidget);
   }
 }
 
@@ -225,23 +225,19 @@ WebRenderBridgeParent::HandleDPEnd(const
       DestroyActor(op);
     }
     return;
   }
   // This ensures that destroy operations are always processed. It is not safe
   // to early-return from RecvDPEnd without doing so.
   AutoWebRenderBridgeParentAsyncMessageSender autoAsyncMessageSender(this, &aToDestroy);
 
-  ProcessWebrenderCommands(aSize, aCommands, wr::NewEpoch(aTransactionId));
-
-  // The transaction ID might get reset to 1 if the page gets reloaded, see
-  // https://bugzilla.mozilla.org/show_bug.cgi?id=1145295#c41
-  // Otherwise, it should be continually increasing.
-  MOZ_ASSERT(aTransactionId == 1 || aTransactionId > mPendingTransactionId);
-  mPendingTransactionId = aTransactionId;
+  ++mWrEpoch; // Update webrender epoch
+  ProcessWebrenderCommands(aSize, aCommands, wr::NewEpoch(mWrEpoch));
+  HoldPendingTransactionId(mWrEpoch, aTransactionId);
 }
 
 mozilla::ipc::IPCResult
 WebRenderBridgeParent::RecvDPEnd(const gfx::IntSize& aSize,
                                  InfallibleTArray<WebRenderCommand>&& aCommands,
                                  InfallibleTArray<OpDestroy>&& aToDestroy,
                                  const uint64_t& aFwdTransactionId,
                                  const uint64_t& aTransactionId)
@@ -573,19 +569,65 @@ void
 WebRenderBridgeParent::CompositeToTarget(gfx::DrawTarget* aTarget, const gfx::IntRect* aRect)
 {
   // TODO(bug 1328602) With the RenderThread, calling SetRootStackingContext
   // should trigger the composition on the render thread.
   MOZ_ASSERT_UNREACHABLE("unexpected to be called");
 }
 
 void
-WebRenderBridgeParent::DidComposite(uint64_t aTransactionId, TimeStamp aStart, TimeStamp aEnd)
+WebRenderBridgeParent::HoldPendingTransactionId(uint32_t aWrEpoch, uint64_t aTransactionId)
+{
+  // The transaction ID might get reset to 1 if the page gets reloaded, see
+  // https://bugzilla.mozilla.org/show_bug.cgi?id=1145295#c41
+  // Otherwise, it should be continually increasing.
+  MOZ_ASSERT(aTransactionId == 1 || aTransactionId > LastPendingTransactionId());
+  // Handle TransactionIdAllocator(RefreshDriver) change.
+  if (aTransactionId == 1) {
+    FlushPendingTransactionIds();
+  }
+  mPendingTransactionIds.push(PendingTransactionId(wr::NewEpoch(aWrEpoch), aTransactionId));
+}
+
+uint64_t
+WebRenderBridgeParent::LastPendingTransactionId()
 {
-  mCompositorBridge->NotifyDidComposite(aTransactionId, aStart, aEnd);
+  uint64_t id = 0;
+  if (!mPendingTransactionIds.empty()) {
+    id = mPendingTransactionIds.back().mId;
+  }
+  return id;
+}
+
+uint64_t
+WebRenderBridgeParent::FlushPendingTransactionIds()
+{
+  uint64_t id = 0;
+  while (!mPendingTransactionIds.empty()) {
+    id = mPendingTransactionIds.front().mId;
+    mPendingTransactionIds.pop();
+  }
+  return id;
+}
+
+
+
+uint64_t
+WebRenderBridgeParent::FlushTransactionIdsForEpoch(const wr::Epoch& aEpoch)
+{
+  uint64_t id = 0;
+  while (!mPendingTransactionIds.empty()) {
+    id = mPendingTransactionIds.front().mId;
+    if (mPendingTransactionIds.front().mEpoch == aEpoch) {
+      mPendingTransactionIds.pop();
+      break;
+    }
+    mPendingTransactionIds.pop();
+  }
+  return id;
 }
 
 WebRenderBridgeParent::~WebRenderBridgeParent()
 {
 }
 
 void
 WebRenderBridgeParent::DeleteOldImages()
--- a/gfx/layers/wr/WebRenderBridgeParent.h
+++ b/gfx/layers/wr/WebRenderBridgeParent.h
@@ -95,33 +95,33 @@ public:
 
   mozilla::ipc::IPCResult RecvClearCachedResources() override;
 
   void ActorDestroy(ActorDestroyReason aWhy) override;
   void SetWebRenderProfilerEnabled(bool aEnabled);
 
   void Destroy();
 
-  const uint64_t& GetPendingTransactionId() { return mPendingTransactionId; }
-  void SetPendingTransactionId(uint64_t aId) { mPendingTransactionId = aId; }
-
   // CompositorVsyncSchedulerOwner
   bool IsPendingComposite() override { return false; }
   void FinishPendingComposite() override { }
   void CompositeToTarget(gfx::DrawTarget* aTarget, const gfx::IntRect* aRect = nullptr) override;
 
   // CompositableParentManager
   bool IsSameProcess() const override;
   base::ProcessId GetChildProcessId() override;
   void NotifyNotUsed(PTextureParent* aTexture, uint64_t aTransactionId) override;
   void SendAsyncMessage(const InfallibleTArray<AsyncParentMessageData>& aMessage) override;
   void SendPendingAsyncMessages() override;
   void SetAboutToSendAsyncMessages() override;
 
-  void DidComposite(uint64_t aTransactionId, TimeStamp aStart, TimeStamp aEnd);
+  void HoldPendingTransactionId(uint32_t aWrEpoch, uint64_t aTransactionId);
+  uint64_t LastPendingTransactionId();
+  uint64_t FlushPendingTransactionIds();
+  uint64_t FlushTransactionIdsForEpoch(const wr::Epoch& aEpoch);
 
   TextureFactoryIdentifier GetTextureFactoryIdentifier();
 
   void AppendImageCompositeNotification(const ImageCompositeNotificationInfo& aNotification)
   {
     MOZ_ASSERT(mWidget);
     mImageCompositeNotifications.AppendElement(aNotification);
   }
@@ -143,16 +143,25 @@ private:
   bool ShouldParentObserveEpoch();
   void HandleDPEnd(const gfx::IntSize& aSize,
                    InfallibleTArray<WebRenderCommand>&& aCommands,
                    InfallibleTArray<OpDestroy>&& aToDestroy,
                    const uint64_t& aFwdTransactionId,
                    const uint64_t& aTransactionId);
 
 private:
+  struct PendingTransactionId {
+    PendingTransactionId(wr::Epoch aEpoch, uint64_t aId)
+      : mEpoch(aEpoch)
+      , mId(aId)
+    {}
+    wr::Epoch mEpoch;
+    uint64_t mId;
+  };
+
   CompositorBridgeParentBase* MOZ_NON_OWNING_REF mCompositorBridge;
   wr::PipelineId mPipelineId;
   RefPtr<widget::CompositorWidget> mWidget;
   Maybe<wr::DisplayListBuilder> mBuilder;
   RefPtr<wr::WebRenderAPI> mApi;
   RefPtr<WebRenderCompositableHolder> mCompositableHolder;
   RefPtr<CompositorVsyncScheduler> mCompositorScheduler;
   std::vector<wr::ImageKey> mKeysToDelete;
@@ -161,17 +170,18 @@ private:
 
   // These fields keep track of the latest layer observer epoch values in the child and the
   // parent. mChildLayerObserverEpoch is the latest epoch value received from the child.
   // mParentLayerObserverEpoch is the latest epoch value that we have told TabParent about
   // (via ObserveLayerUpdate).
   uint64_t mChildLayerObserverEpoch;
   uint64_t mParentLayerObserverEpoch;
 
-  uint64_t mPendingTransactionId;
+  std::queue<PendingTransactionId> mPendingTransactionIds;
+  uint32_t mWrEpoch;
 
   bool mDestroyed;
 };
 
 } // namespace layers
 } // namespace mozilla
 
 #endif // mozilla_layers_WebRenderBridgeParent_h
--- a/gfx/webrender_bindings/RenderThread.cpp
+++ b/gfx/webrender_bindings/RenderThread.cpp
@@ -155,20 +155,17 @@ static void
 NotifyDidRender(layers::CompositorBridgeParentBase* aBridge,
                 WrRenderedEpochs* aEpochs,
                 TimeStamp aStart,
                 TimeStamp aEnd)
 {
   WrPipelineId pipeline;
   WrEpoch epoch;
   while (wr_rendered_epochs_next(aEpochs, &pipeline, &epoch)) {
-    // TODO - Currently each bridge seems to  only have one pipeline but at some
-    // point we should pass make sure we only notify bridges that have the
-    // corresponding pipeline id.
-    aBridge->NotifyDidComposite(epoch.mHandle, aStart, aEnd);
+    aBridge->NotifyDidCompositeToPipeline(pipeline, epoch, aStart, aEnd);
   }
   wr_rendered_epochs_delete(aEpochs);
 }
 
 void
 RenderThread::UpdateAndRender(wr::WindowId aWindowId)
 {
   MOZ_ASSERT(IsInRenderThread());