Bug 1436058 - Remove async image pipelines when the renderer notifies pipelines removed. r=kats draft
authorNicolas Silva <nsilva@mozilla.com>
Mon, 12 Feb 2018 11:37:02 -0500
changeset 753903 78336e265760bae888c9fa807d4a5fa0cf370bf2
parent 753902 9790131af6798bf61b373102514a19c5256aaf70
child 753904 4aeaee920195eb886bab2c58547170110477e372
push id98716
push userkgupta@mozilla.com
push dateMon, 12 Feb 2018 16:43:47 +0000
reviewerskats
bugs1436058, 1432708
milestone60.0a1
Bug 1436058 - Remove async image pipelines when the renderer notifies pipelines removed. r=kats Patch originally attached to - and reviewed by sotaro on - bug 1432708. MozReview-Commit-ID: LNWHtuFTPG5
gfx/layers/ipc/CompositorBridgeParent.cpp
gfx/layers/ipc/CompositorBridgeParent.h
gfx/layers/wr/AsyncImagePipelineManager.cpp
gfx/layers/wr/AsyncImagePipelineManager.h
gfx/webrender_bindings/RenderThread.cpp
gfx/webrender_bindings/RendererOGL.cpp
gfx/webrender_bindings/RendererOGL.h
gfx/webrender_bindings/src/bindings.rs
gfx/webrender_bindings/webrender_ffi_generated.h
--- a/gfx/layers/ipc/CompositorBridgeParent.cpp
+++ b/gfx/layers/ipc/CompositorBridgeParent.cpp
@@ -1978,22 +1978,30 @@ CompositorBridgeParent::DidComposite(Tim
     mTxnStartTime = TimeStamp();
     mFwdTime = TimeStamp();
 #endif
     mPendingTransaction = 0;
   }
 }
 
 void
+CompositorBridgeParent::NotifyPipelineRemoved(const wr::PipelineId& aPipelineId)
+{
+  if (mAsyncImageManager) {
+    mAsyncImageManager->PipelineRemoved(aPipelineId);
+  }
+}
+
+void
 CompositorBridgeParent::NotifyDidCompositeToPipeline(const wr::PipelineId& aPipelineId, const wr::Epoch& aEpoch, TimeStamp& aCompositeStart, TimeStamp& aCompositeEnd)
 {
   if (!mWrBridge || !mAsyncImageManager) {
     return;
   }
-  mAsyncImageManager->Update(aPipelineId, aEpoch);
+  mAsyncImageManager->PipelineRendered(aPipelineId, aEpoch);
 
   if (mPaused) {
     return;
   }
 
   if (mWrBridge->PipelineId() == aPipelineId) {
     uint64_t transactionId = mWrBridge->FlushTransactionIdsForEpoch(aEpoch, aCompositeEnd);
     Unused << SendDidComposite(0, transactionId, aCompositeStart, aCompositeEnd);
--- a/gfx/layers/ipc/CompositorBridgeParent.h
+++ b/gfx/layers/ipc/CompositorBridgeParent.h
@@ -127,17 +127,21 @@ public:
   mozilla::ipc::IPCResult RecvSyncWithCompositor() override { return IPC_OK(); }
 
   mozilla::ipc::IPCResult Recv__delete__() override { return IPC_OK(); }
 
   virtual void ObserveLayerUpdate(uint64_t aLayersId, uint64_t aEpoch, bool aActive) = 0;
 
   virtual void DidComposite(uint64_t aId, TimeStamp& aCompositeStart, TimeStamp& aCompositeEnd) {}
 
-  virtual void NotifyDidCompositeToPipeline(const wr::PipelineId& aPipelineId, const wr::Epoch& aEpoch, TimeStamp& aCompositeStart, TimeStamp& aCompositeEnd) {}
+  virtual void NotifyDidCompositeToPipeline(const wr::PipelineId& aPipelineId,
+                                            const wr::Epoch& aEpoch,
+                                            TimeStamp& aCompositeStart,
+                                            TimeStamp& aCompositeEnd) { MOZ_ASSERT_UNREACHABLE("WebRender only"); }
+  virtual void NotifyPipelineRemoved(const wr::PipelineId& aPipelineId) { MOZ_ASSERT_UNREACHABLE("WebRender only"); }
 
   // HostIPCAllocator
   base::ProcessId GetChildProcessId() override;
   void NotifyNotUsed(PTextureParent* aTexture, uint64_t aTransactionId) override;
   void SendAsyncMessage(const InfallibleTArray<AsyncParentMessageData>& aMessage) override;
 
   // ShmemAllocator
   bool AllocShmem(size_t aSize,
@@ -557,17 +561,21 @@ protected:
    * Return true if current state allows compositing, that is
    * finishing a layers transaction.
    */
   bool CanComposite();
 
   using CompositorBridgeParentBase::DidComposite;
   void DidComposite(TimeStamp& aCompositeStart, TimeStamp& aCompositeEnd);
 
-  void NotifyDidCompositeToPipeline(const wr::PipelineId& aPipelineId, const wr::Epoch& aEpoch, TimeStamp& aCompositeStart, TimeStamp& aCompositeEnd) override;
+  void NotifyDidCompositeToPipeline(const wr::PipelineId& aPipelineId,
+                                    const wr::Epoch& aEpoch,
+                                    TimeStamp& aCompositeStart,
+                                    TimeStamp& aCompositeEnd) override;
+  void NotifyPipelineRemoved(const wr::PipelineId& aPipelineId) 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);
 
--- a/gfx/layers/wr/AsyncImagePipelineManager.cpp
+++ b/gfx/layers/wr/AsyncImagePipelineManager.cpp
@@ -378,33 +378,39 @@ AsyncImagePipelineManager::HoldExternalI
   if (!holder) {
     return;
   }
   // Hold WebRenderTextureHost until end of its usage on RenderThread
   holder->mTextureHosts.push(ForwardingTextureHost(aEpoch, aTexture));
 }
 
 void
-AsyncImagePipelineManager::Update(const wr::PipelineId& aPipelineId, const wr::Epoch& aEpoch)
+AsyncImagePipelineManager::PipelineRendered(const wr::PipelineId& aPipelineId, const wr::Epoch& aEpoch)
 {
   if (mDestroyed) {
     return;
   }
   if (auto entry = mPipelineTexturesHolders.Lookup(wr::AsUint64(aPipelineId))) {
     PipelineTexturesHolder* holder = entry.Data();
-    // Remove Pipeline
-    if (holder->mDestroyedEpoch.isSome() && holder->mDestroyedEpoch.ref() <= aEpoch) {
-      entry.Remove();
-      return;
-    }
-
     // Release TextureHosts based on Epoch
     while (!holder->mTextureHosts.empty()) {
       if (aEpoch <= holder->mTextureHosts.front().mEpoch) {
         break;
       }
       holder->mTextureHosts.pop();
     }
   }
 }
 
+void
+AsyncImagePipelineManager::PipelineRemoved(const wr::PipelineId& aPipelineId)
+{
+  if (mDestroyed) {
+    return;
+  }
+  if (auto entry = mPipelineTexturesHolders.Lookup(wr::AsUint64(aPipelineId))) {
+    // Remove Pipeline
+    entry.Remove();
+  }
+}
+
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/wr/AsyncImagePipelineManager.h
+++ b/gfx/layers/wr/AsyncImagePipelineManager.h
@@ -43,17 +43,18 @@ protected:
 
 public:
   void Destroy();
 
   void AddPipeline(const wr::PipelineId& aPipelineId);
   void RemovePipeline(const wr::PipelineId& aPipelineId, const wr::Epoch& aEpoch);
 
   void HoldExternalImage(const wr::PipelineId& aPipelineId, const wr::Epoch& aEpoch, WebRenderTextureHost* aTexture);
-  void Update(const wr::PipelineId& aPipelineId, const wr::Epoch& aEpoch);
+  void PipelineRendered(const wr::PipelineId& aPipelineId, const wr::Epoch& aEpoch);
+  void PipelineRemoved(const wr::PipelineId& aPipelineId);
 
   TimeStamp GetCompositionTime() const {
     return mCompositionTime;
   }
   void SetCompositionTime(TimeStamp aTimeStamp) {
     mCompositionTime = aTimeStamp;
     if (!mCompositionTime.IsNull() && !mCompositeUntilTime.IsNull() &&
         mCompositionTime >= mCompositeUntilTime) {
--- a/gfx/webrender_bindings/RenderThread.cpp
+++ b/gfx/webrender_bindings/RenderThread.cpp
@@ -190,26 +190,30 @@ RenderThread::RunEvent(wr::WindowId aWin
   }
 
   aEvent->Run(*this, aWindowId);
   aEvent = nullptr;
 }
 
 static void
 NotifyDidRender(layers::CompositorBridgeParentBase* aBridge,
-                wr::WrRenderedEpochs* aEpochs,
+                wr::WrPipelineInfo* aInfo,
                 TimeStamp aStart,
                 TimeStamp aEnd)
 {
   wr::WrPipelineId pipeline;
   wr::WrEpoch epoch;
-  while (wr_rendered_epochs_next(aEpochs, &pipeline, &epoch)) {
+  while (wr_pipeline_info_next_epoch(aInfo, &pipeline, &epoch)) {
     aBridge->NotifyDidCompositeToPipeline(pipeline, epoch, aStart, aEnd);
   }
-  wr_rendered_epochs_delete(aEpochs);
+  while (wr_pipeline_info_next_removed_pipeline(aInfo, &pipeline)) {
+    aBridge->NotifyPipelineRemoved(pipeline);
+  }
+
+  wr_pipeline_info_delete(aInfo);
 }
 
 void
 RenderThread::UpdateAndRender(wr::WindowId aWindowId)
 {
   AUTO_PROFILER_TRACING("Paint", "Composite");
   MOZ_ASSERT(IsInRenderThread());
 
@@ -225,22 +229,22 @@ RenderThread::UpdateAndRender(wr::Window
   bool ret = renderer->UpdateAndRender();
   if (!ret) {
     // Render did not happen, do not call NotifyDidRender.
     return;
   }
 
   TimeStamp end = TimeStamp::Now();
 
-  auto epochs = renderer->FlushRenderedEpochs();
+  auto info = renderer->FlushPipelineInfo();
   layers::CompositorThreadHolder::Loop()->PostTask(NewRunnableFunction(
     "NotifyDidRenderRunnable",
     &NotifyDidRender,
     renderer->GetCompositorBridge(),
-    epochs,
+    info,
     start, end
   ));
 }
 
 void
 RenderThread::Pause(wr::WindowId aWindowId)
 {
   MOZ_ASSERT(IsInRenderThread());
--- a/gfx/webrender_bindings/RendererOGL.cpp
+++ b/gfx/webrender_bindings/RendererOGL.cpp
@@ -168,20 +168,20 @@ RendererOGL::SetFrameStartTime(const Tim
   if (mFrameStartTime) {
     // frame start time is already set. This could happen when multiple
     // generate frame requests are merged by webrender.
     return;
   }
   mFrameStartTime = aTime;
 }
 
-wr::WrRenderedEpochs*
-RendererOGL::FlushRenderedEpochs()
+wr::WrPipelineInfo*
+RendererOGL::FlushPipelineInfo()
 {
-  return wr_renderer_flush_rendered_epochs(mRenderer);
+  return wr_renderer_flush_pipeline_info(mRenderer);
 }
 
 RenderTextureHost*
 RendererOGL::GetRenderTexture(wr::WrExternalImageId aExternalImageId)
 {
   return mThread->GetRenderTexture(aExternalImageId);
 }
 
--- a/gfx/webrender_bindings/RendererOGL.h
+++ b/gfx/webrender_bindings/RendererOGL.h
@@ -76,17 +76,17 @@ public:
 
   /// This can be called on the render thread only.
   bool Resume();
 
   layers::SyncObjectHost* GetSyncObject() const;
 
   layers::CompositorBridgeParentBase* GetCompositorBridge() { return mBridge; }
 
-  wr::WrRenderedEpochs* FlushRenderedEpochs();
+  wr::WrPipelineInfo* FlushPipelineInfo();
 
   RenderTextureHost* GetRenderTexture(wr::WrExternalImageId aExternalImageId);
 
   wr::Renderer* GetRenderer() { return mRenderer; }
 
   gl::GLContext* gl() const;
 
 protected:
--- a/gfx/webrender_bindings/src/bindings.rs
+++ b/gfx/webrender_bindings/src/bindings.rs
@@ -585,46 +585,63 @@ pub extern "C" fn wr_renderer_current_ep
 /// cbindgen:postfix=WR_DESTRUCTOR_SAFE_FUNC
 #[no_mangle]
 pub unsafe extern "C" fn wr_renderer_delete(renderer: *mut Renderer) {
     let renderer = Box::from_raw(renderer);
     renderer.deinit();
     // let renderer go out of scope and get dropped
 }
 
-pub struct WrRenderedEpochs {
-    data: Vec<(WrPipelineId, WrEpoch)>,
+pub struct WrPipelineInfo {
+    epochs: Vec<(WrPipelineId, WrEpoch)>,
+    removed_pipelines: Vec<PipelineId>,
 }
 
 #[no_mangle]
-pub unsafe extern "C" fn wr_renderer_flush_rendered_epochs(renderer: &mut Renderer) -> *mut WrRenderedEpochs {
-    let map = renderer.flush_rendered_epochs();
-    let pipeline_epochs = Box::new(WrRenderedEpochs {
-                                       data: map.into_iter().collect(),
-                                   });
+pub unsafe extern "C" fn wr_renderer_flush_pipeline_info(renderer: &mut Renderer) -> *mut WrPipelineInfo {
+    let info = renderer.flush_pipeline_info();
+    let pipeline_epochs = Box::new(
+        WrPipelineInfo {
+            epochs: info.epochs.into_iter().collect(),
+            removed_pipelines: info.removed_pipelines,
+        }
+    );
     return Box::into_raw(pipeline_epochs);
 }
 
 #[no_mangle]
-pub unsafe extern "C" fn wr_rendered_epochs_next(pipeline_epochs: &mut WrRenderedEpochs,
-                                                 out_pipeline: &mut WrPipelineId,
-                                                 out_epoch: &mut WrEpoch)
-                                                 -> bool {
-    if let Some((pipeline, epoch)) = pipeline_epochs.data.pop() {
+pub unsafe extern "C" fn wr_pipeline_info_next_epoch(
+    info: &mut WrPipelineInfo,
+    out_pipeline: &mut WrPipelineId,
+    out_epoch: &mut WrEpoch
+) -> bool {
+    if let Some((pipeline, epoch)) = info.epochs.pop() {
         *out_pipeline = pipeline;
         *out_epoch = epoch;
         return true;
     }
     return false;
 }
 
+#[no_mangle]
+pub unsafe extern "C" fn wr_pipeline_info_next_removed_pipeline(
+    info: &mut WrPipelineInfo,
+    out_pipeline: &mut WrPipelineId,
+) -> bool {
+    if let Some(pipeline) = info.removed_pipelines.pop() {
+        *out_pipeline = pipeline;
+        return true;
+    }
+    return false;
+}
+
 /// cbindgen:postfix=WR_DESTRUCTOR_SAFE_FUNC
 #[no_mangle]
-pub unsafe extern "C" fn wr_rendered_epochs_delete(pipeline_epochs: *mut WrRenderedEpochs) {
-    Box::from_raw(pipeline_epochs);
+pub unsafe extern "C" fn wr_pipeline_info_delete(info: *mut WrPipelineInfo) {
+    Box::from_raw(info);
 }
 
 extern "C" {
     fn gecko_profiler_register_thread(name: *const ::std::os::raw::c_char);
     fn gecko_profiler_unregister_thread();
 }
 
 struct GeckoProfilerThreadListener {}
--- a/gfx/webrender_bindings/webrender_ffi_generated.h
+++ b/gfx/webrender_bindings/webrender_ffi_generated.h
@@ -268,19 +268,19 @@ struct Transaction;
 struct UnknownUnit;
 
 template<typename T>
 struct Vec;
 
 // Geometry in the document's coordinate space (logical pixels).
 struct WorldPixel;
 
-struct WrProgramCache;
+struct WrPipelineInfo;
 
-struct WrRenderedEpochs;
+struct WrProgramCache;
 
 struct WrState;
 
 struct WrThreadPool;
 
 struct IdNamespace {
   uint32_t mHandle;
 
@@ -1354,45 +1354,50 @@ extern void wr_notifier_external_event(W
 extern void wr_notifier_new_frame_ready(WrWindowId aWindowId);
 
 extern void wr_notifier_new_scroll_frame_ready(WrWindowId aWindowId,
                                                bool aCompositeNeeded);
 
 extern void wr_notifier_wake_up(WrWindowId aWindowId);
 
 WR_INLINE
+void wr_pipeline_info_delete(WrPipelineInfo *aInfo)
+WR_DESTRUCTOR_SAFE_FUNC;
+
+WR_INLINE
+bool wr_pipeline_info_next_epoch(WrPipelineInfo *aInfo,
+                                 WrPipelineId *aOutPipeline,
+                                 WrEpoch *aOutEpoch)
+WR_FUNC;
+
+WR_INLINE
+bool wr_pipeline_info_next_removed_pipeline(WrPipelineInfo *aInfo,
+                                            WrPipelineId *aOutPipeline)
+WR_FUNC;
+
+WR_INLINE
 void wr_program_cache_delete(WrProgramCache *aProgramCache)
 WR_DESTRUCTOR_SAFE_FUNC;
 
 WR_INLINE
 WrProgramCache *wr_program_cache_new()
 WR_FUNC;
 
 WR_INLINE
-void wr_rendered_epochs_delete(WrRenderedEpochs *aPipelineEpochs)
-WR_DESTRUCTOR_SAFE_FUNC;
-
-WR_INLINE
-bool wr_rendered_epochs_next(WrRenderedEpochs *aPipelineEpochs,
-                             WrPipelineId *aOutPipeline,
-                             WrEpoch *aOutEpoch)
-WR_FUNC;
-
-WR_INLINE
 bool wr_renderer_current_epoch(Renderer *aRenderer,
                                WrPipelineId aPipelineId,
                                WrEpoch *aOutEpoch)
 WR_FUNC;
 
 WR_INLINE
 void wr_renderer_delete(Renderer *aRenderer)
 WR_DESTRUCTOR_SAFE_FUNC;
 
 WR_INLINE
-WrRenderedEpochs *wr_renderer_flush_rendered_epochs(Renderer *aRenderer)
+WrPipelineInfo *wr_renderer_flush_pipeline_info(Renderer *aRenderer)
 WR_FUNC;
 
 WR_INLINE
 WrDebugFlags wr_renderer_get_debug_flags(Renderer *aRenderer)
 WR_FUNC;
 
 WR_INLINE
 void wr_renderer_readback(Renderer *aRenderer,