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
--- 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,