Bug 1405481 - Push canvas updates to the compositor on empty transactions r=jrmuizel
authorsotaro <sotaro.ikeda.g@gmail.com>
Thu, 12 Oct 2017 10:13:10 +0900
changeset 385833 86c487f84974c727365d6cc266d7a8949ba253bb
parent 385832 1d25638f204d30d3e1d23f93cfea93c65fc5e70f
child 385834 077b6ec36d84589557e581742abf7557974a8463
push id32669
push userarchaeopteryx@coole-files.de
push dateThu, 12 Oct 2017 21:58:56 +0000
treeherdermozilla-central@25aad10380b1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjrmuizel
bugs1405481
milestone58.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 1405481 - Push canvas updates to the compositor on empty transactions r=jrmuizel
gfx/layers/ipc/PWebRenderBridge.ipdl
gfx/layers/wr/WebRenderBridgeChild.cpp
gfx/layers/wr/WebRenderBridgeChild.h
gfx/layers/wr/WebRenderBridgeParent.cpp
gfx/layers/wr/WebRenderBridgeParent.h
gfx/layers/wr/WebRenderCommandBuilder.cpp
gfx/layers/wr/WebRenderCommandBuilder.h
gfx/layers/wr/WebRenderLayerManager.cpp
--- a/gfx/layers/ipc/PWebRenderBridge.ipdl
+++ b/gfx/layers/ipc/PWebRenderBridge.ipdl
@@ -54,16 +54,19 @@ parent:
                        WebRenderScrollData aScrollData,
                        OpUpdateResource[] aResourceUpdates, Shmem[] aSmallShmems, Shmem[] aLargeShmems,
                        IdNamespace aIdNamespace, TimeStamp txnStartTime, TimeStamp fwdTime);
   sync SetDisplayListSync(IntSize aSize, WebRenderParentCommand[] commands, OpDestroy[] toDestroy, uint64_t fwdTransactionId, uint64_t transactionId,
                           LayoutSize aContentSize, ByteBuffer aDL, BuiltDisplayListDescriptor aDLDesc,
                           WebRenderScrollData aScrollData,
                           OpUpdateResource[] aResourceUpdates, Shmem[] aSmallShmems, Shmem[] aLargeShmems,
                           IdNamespace aIdNamespace, TimeStamp txnStartTime, TimeStamp fwdTime);
+  async EmptyTransaction(FocusTarget focusTarget,
+                         WebRenderParentCommand[] commands, OpDestroy[] toDestroy, uint64_t fwdTransactionId, uint64_t transactionId,
+                         IdNamespace aIdNamespace, TimeStamp txnStartTime, TimeStamp fwdTime);
   async SetFocusTarget(FocusTarget focusTarget);
   async UpdateResources(OpUpdateResource[] aResourceUpdates, Shmem[] aSmallShmems, Shmem[] aLargeShmems);
   async ParentCommands(WebRenderParentCommand[] commands);
   sync GetSnapshot(PTexture texture);
   async AddPipelineIdForCompositable(PipelineId aImageId, CompositableHandle aHandle, bool aAsync);
   async RemovePipelineIdForCompositable(PipelineId aPipelineId);
   async AddExternalImageIdForCompositable(ExternalImageId aImageId, CompositableHandle aHandle);
   async RemoveExternalImageId(ExternalImageId aImageId);
--- a/gfx/layers/wr/WebRenderBridgeChild.cpp
+++ b/gfx/layers/wr/WebRenderBridgeChild.cpp
@@ -153,16 +153,38 @@ WebRenderBridgeChild::EndTransaction(con
   }
 
   mParentCommands.Clear();
   mDestroyedActors.Clear();
   mIsInTransaction = false;
 }
 
 void
+WebRenderBridgeChild::EndEmptyTransaction(const FocusTarget& aFocusTarget,
+                                          uint64_t aTransactionId,
+                                          const mozilla::TimeStamp& aTxnStartTime)
+{
+  MOZ_ASSERT(!mDestroyed);
+  MOZ_ASSERT(mIsInTransaction);
+
+  TimeStamp fwdTime;
+#if defined(ENABLE_FRAME_LATENCY_LOG)
+  fwdTime = TimeStamp::Now();
+#endif
+
+  this->SendEmptyTransaction(aFocusTarget,
+                             mParentCommands, mDestroyedActors,
+                             GetFwdTransactionId(), aTransactionId,
+                             mIdNamespace, aTxnStartTime, fwdTime);
+  mParentCommands.Clear();
+  mDestroyedActors.Clear();
+  mIsInTransaction = false;
+}
+
+void
 WebRenderBridgeChild::ProcessWebRenderParentCommands()
 {
   MOZ_ASSERT(!mDestroyed);
 
   if (mParentCommands.IsEmpty()) {
     return;
   }
   this->SendParentCommands(mParentCommands);
--- a/gfx/layers/wr/WebRenderBridgeChild.h
+++ b/gfx/layers/wr/WebRenderBridgeChild.h
@@ -70,16 +70,19 @@ public:
   void BeginTransaction();
   void EndTransaction(const wr::LayoutSize& aContentSize,
                       wr::BuiltDisplayList& dl,
                       wr::IpcResourceUpdateQueue& aResources,
                       const gfx::IntSize& aSize,
                       bool aIsSync, uint64_t aTransactionId,
                       const WebRenderScrollData& aScrollData,
                       const mozilla::TimeStamp& aTxnStartTime);
+  void EndEmptyTransaction(const FocusTarget& aFocusTarget,
+                           uint64_t aTransactionId,
+                           const mozilla::TimeStamp& aTxnStartTime);
   void ProcessWebRenderParentCommands();
 
   CompositorBridgeChild* GetCompositorBridgeChild();
 
   wr::PipelineId GetPipeline() { return mPipelineId; }
 
   // KnowsCompositor
   TextureForwarder* GetTextureForwarder() override;
--- a/gfx/layers/wr/WebRenderBridgeParent.cpp
+++ b/gfx/layers/wr/WebRenderBridgeParent.cpp
@@ -610,16 +610,58 @@ WebRenderBridgeParent::RecvSetDisplayLis
   return RecvSetDisplayList(aSize, Move(aCommands), Move(aToDestroy),
                             aFwdTransactionId, aTransactionId,
                             aContentSize, dl, dlDesc, aScrollData,
                             Move(aResourceUpdates), Move(aSmallShmems), Move(aLargeShmems),
                             aIdNamespace, aTxnStartTime, aFwdTime);
 }
 
 mozilla::ipc::IPCResult
+WebRenderBridgeParent::RecvEmptyTransaction(const FocusTarget& aFocusTarget,
+                                            InfallibleTArray<WebRenderParentCommand>&& aCommands,
+                                            InfallibleTArray<OpDestroy>&& aToDestroy,
+                                            const uint64_t& aFwdTransactionId,
+                                            const uint64_t& aTransactionId,
+                                            const wr::IdNamespace& aIdNamespace,
+                                            const TimeStamp& aTxnStartTime,
+                                            const TimeStamp& aFwdTime)
+{
+  if (mDestroyed) {
+    for (const auto& op : aToDestroy) {
+      DestroyActor(op);
+    }
+    return IPC_OK();
+  }
+
+  AutoProfilerTracing tracing("Paint", "EmptyTransaction");
+  UpdateFwdTransactionId(aFwdTransactionId);
+  AutoClearReadLocks clearLocks(mReadLocks);
+
+  // This ensures that destroy operations are always processed. It is not safe
+  // to early-return without doing so.
+  AutoWebRenderBridgeParentAsyncMessageSender autoAsyncMessageSender(this, &aToDestroy);
+
+  if (!aCommands.IsEmpty()) {
+    mAsyncImageManager->SetCompositionTime(TimeStamp::Now());
+    ProcessWebRenderParentCommands(aCommands);
+    mCompositorScheduler->ScheduleComposition();
+  }
+
+  mScrollData.SetFocusTarget(aFocusTarget);
+  UpdateAPZ(false);
+
+  // XXX Call DidComposite at correct timing.
+  TimeStamp now = TimeStamp::Now();
+  HoldPendingTransactionId(mWrEpoch, aTransactionId, aTxnStartTime, aFwdTime);
+  mCompositorBridge->DidComposite(wr::AsUint64(mPipelineId), now, now);
+
+  return IPC_OK();
+}
+
+mozilla::ipc::IPCResult
 WebRenderBridgeParent::RecvSetFocusTarget(const FocusTarget& aFocusTarget)
 {
   mScrollData.SetFocusTarget(aFocusTarget);
   UpdateAPZ(false);
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
--- a/gfx/layers/wr/WebRenderBridgeParent.h
+++ b/gfx/layers/wr/WebRenderBridgeParent.h
@@ -101,16 +101,24 @@ public:
                                                  const wr::BuiltDisplayListDescriptor& dlDesc,
                                                  const WebRenderScrollData& aScrollData,
                                                  nsTArray<OpUpdateResource>&& aResourceUpdates,
                                                  nsTArray<ipc::Shmem>&& aSmallShmems,
                                                  nsTArray<ipc::Shmem>&& aLargeShmems,
                                                  const wr::IdNamespace& aIdNamespace,
                                                  const TimeStamp& aTxnStartTime,
                                                  const TimeStamp& aFwdTime) override;
+  mozilla::ipc::IPCResult RecvEmptyTransaction(const FocusTarget& aFocusTarget,
+                                               InfallibleTArray<WebRenderParentCommand>&& aCommands,
+                                               InfallibleTArray<OpDestroy>&& aToDestroy,
+                                               const uint64_t& aFwdTransactionId,
+                                               const uint64_t& aTransactionId,
+                                               const wr::IdNamespace& aIdNamespace,
+                                               const TimeStamp& aTxnStartTime,
+                                               const TimeStamp& aFwdTime) override;
   mozilla::ipc::IPCResult RecvSetFocusTarget(const FocusTarget& aFocusTarget) override;
   mozilla::ipc::IPCResult RecvParentCommands(nsTArray<WebRenderParentCommand>&& commands) override;
   mozilla::ipc::IPCResult RecvGetSnapshot(PTextureParent* aTexture) override;
 
   mozilla::ipc::IPCResult RecvAddPipelineIdForCompositable(const wr::PipelineId& aPipelineIds,
                                                            const CompositableHandle& aHandle,
                                                            const bool& aAsync) override;
   mozilla::ipc::IPCResult RecvRemovePipelineIdForCompositable(const wr::PipelineId& aPipelineId) override;
--- a/gfx/layers/wr/WebRenderCommandBuilder.cpp
+++ b/gfx/layers/wr/WebRenderCommandBuilder.cpp
@@ -27,16 +27,27 @@ namespace layers {
 
 void WebRenderCommandBuilder::Destroy()
 {
   mLastCanvasDatas.Clear();
   RemoveUnusedAndResetWebRenderUserData();
 }
 
 void
+WebRenderCommandBuilder::EmptyTransaction()
+{
+  // We need to update canvases that might have changed.
+  for (auto iter = mLastCanvasDatas.Iter(); !iter.Done(); iter.Next()) {
+    RefPtr<WebRenderCanvasData> canvasData = iter.Get()->GetKey();
+    WebRenderCanvasRendererAsync* canvas = canvasData->GetCanvasRenderer();
+    canvas->UpdateCompositableClient();
+  }
+}
+
+void
 WebRenderCommandBuilder::BuildWebRenderCommands(wr::DisplayListBuilder& aBuilder,
                                                 wr::IpcResourceUpdateQueue& aResourceUpdates,
                                                 nsDisplayList* aDisplayList,
                                                 nsDisplayListBuilder* aDisplayListBuilder,
                                                 WebRenderScrollData& aScrollData,
                                                 wr::LayoutSize& aContentSize)
 {
   { // scoping for StackingContextHelper RAII
--- a/gfx/layers/wr/WebRenderCommandBuilder.h
+++ b/gfx/layers/wr/WebRenderCommandBuilder.h
@@ -35,16 +35,18 @@ class WebRenderCommandBuilder {
 public:
   explicit WebRenderCommandBuilder(WebRenderLayerManager* aManager)
   : mManager(aManager)
   , mLastAsr(nullptr)
   {}
 
   void Destroy();
 
+  void EmptyTransaction();
+
   void BuildWebRenderCommands(wr::DisplayListBuilder& aBuilder,
                               wr::IpcResourceUpdateQueue& aResourceUpdates,
                               nsDisplayList* aDisplayList,
                               nsDisplayListBuilder* aDisplayListBuilder,
                               WebRenderScrollData& aScrollData,
                               wr::LayoutSize& aContentSize);
 
   Maybe<wr::ImageKey> CreateImageKey(nsDisplayItem* aItem,
--- a/gfx/layers/wr/WebRenderLayerManager.cpp
+++ b/gfx/layers/wr/WebRenderLayerManager.cpp
@@ -169,35 +169,45 @@ WebRenderLayerManager::BeginTransaction(
     mApzTestData.StartNewPaint(mPaintSequenceNumber);
   }
   return true;
 }
 
 bool
 WebRenderLayerManager::EndEmptyTransaction(EndTransactionFlags aFlags)
 {
+  LayoutDeviceIntSize size = mWidget->GetClientSize();
+  WrBridge()->BeginTransaction();
+
   // With the WebRenderLayerManager we reject attempts to set most kind of
   // "pending data" for empty transactions. Any place that attempts to update
   // transforms or scroll offset, for example, will get failure return values
   // back, and will fall back to a full transaction. Therefore the only piece
-  // of "pending" information we need to send in an empty transaction is the
-  // APZ focus state.
-  WrBridge()->SendSetFocusTarget(mFocusTarget);
+  // of "pending" information we need to send in an empty transaction are the
+  // APZ focus state and canvases's CompositableOperations.
+
+  mWebRenderCommandBuilder.EmptyTransaction();
+
+  WrBridge()->ClearReadLocks();
+
+  mLatestTransactionId = mTransactionIdAllocator->GetTransactionId(/*aThrottle*/ true);
+  TimeStamp transactionStart = mTransactionIdAllocator->GetTransactionStart();
 
-  // We also need to update canvases that might have changed, but this code
-  // as-is causes crashes so comment it out for now.
-  //for (auto iter = mLastCanvasDatas.Iter(); !iter.Done(); iter.Next()) {
-  //  RefPtr<WebRenderCanvasData> canvasData = iter.Get()->GetKey();
-  //  WebRenderCanvasRendererAsync* canvas = canvasData->GetCanvasRenderer();
-  //  canvas->UpdateCompositableClient();
-  //}
+  // Skip the synchronization for buffer since we also skip the painting during
+  // device-reset status.
+  if (!gfxPlatform::GetPlatform()->DidRenderingDeviceReset()) {
+    if (WrBridge()->GetSyncObject() &&
+        WrBridge()->GetSyncObject()->IsSyncObjectValid()) {
+      WrBridge()->GetSyncObject()->Synchronize();
+    }
+  }
 
-  if (!(aFlags & EndTransactionFlags::END_NO_COMPOSITE)) {
-    ScheduleComposite();
-  }
+  WrBridge()->EndEmptyTransaction(mFocusTarget, mLatestTransactionId, transactionStart);
+
+  MakeSnapshotIfRequired(size);
   return true;
 }
 
 /*static*/ int32_t
 PopulateScrollData(WebRenderScrollData& aTarget, Layer* aLayer)
 {
   MOZ_ASSERT(aLayer);