diff --git a/gfx/layers/ipc/CompositorBridgeParent.cpp b/gfx/layers/ipc/CompositorBridgeParent.cpp index a86b3011b1bb..bbe81a395821 100644 --- a/gfx/layers/ipc/CompositorBridgeParent.cpp +++ b/gfx/layers/ipc/CompositorBridgeParent.cpp @@ -904,7 +904,11 @@ CompositorBridgeParent::ScheduleComposition() return; } - mCompositorScheduler->ScheduleComposition(); + if (mWrBridge) { + mWrBridge->ScheduleGenerateFrame(); + } else { + mCompositorScheduler->ScheduleComposition(); + } } // Go down the composite layer tree, setting properties to match their diff --git a/gfx/layers/wr/AsyncImagePipelineManager.cpp b/gfx/layers/wr/AsyncImagePipelineManager.cpp index 0223c94aef2b..e608229dd344 100644 --- a/gfx/layers/wr/AsyncImagePipelineManager.cpp +++ b/gfx/layers/wr/AsyncImagePipelineManager.cpp @@ -9,6 +9,7 @@ #include "CompositableHost.h" #include "gfxEnv.h" #include "mozilla/gfx/gfxVars.h" +#include "mozilla/layers/CompositorThread.h" #include "mozilla/layers/WebRenderImageHost.h" #include "mozilla/layers/WebRenderTextureHost.h" #include "mozilla/webrender/WebRenderAPI.h" @@ -30,6 +31,7 @@ AsyncImagePipelineManager::AsyncImagePipelineManager(already_AddRefedGetNamespace()) , mResourceId(0) , mAsyncImageEpoch(0) + , mWillGenerateFrame(false) , mDestroyed(false) { MOZ_COUNT_CTOR(AsyncImagePipelineManager); @@ -48,6 +50,24 @@ AsyncImagePipelineManager::Destroy() mDestroyed = true; } +void +AsyncImagePipelineManager::SetWillGenerateFrame() +{ + MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); + + mWillGenerateFrame = true; +} + +bool +AsyncImagePipelineManager::GetAndResetWillGenerateFrame() +{ + MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); + + bool ret = mWillGenerateFrame; + mWillGenerateFrame = false; + return ret; +} + void AsyncImagePipelineManager::AddPipeline(const wr::PipelineId& aPipelineId) { @@ -270,6 +290,11 @@ AsyncImagePipelineManager::ApplyAsyncImages() (pipeline->mIsChanged || op == Some(TextureHost::ADD_IMAGE)) && !!pipeline->mCurrentTexture; + // Request to generate frame if there is an update. + if (updateDisplayList || !op.isNothing()) { + SetWillGenerateFrame(); + } + if (!updateDisplayList) { // We don't need to update the display list, either because we can't or because // the previous one is still up to date. diff --git a/gfx/layers/wr/AsyncImagePipelineManager.h b/gfx/layers/wr/AsyncImagePipelineManager.h index 35680798dd92..c712aad02914 100644 --- a/gfx/layers/wr/AsyncImagePipelineManager.h +++ b/gfx/layers/wr/AsyncImagePipelineManager.h @@ -91,6 +91,9 @@ public: aNotifications->AppendElements(Move(mImageCompositeNotifications)); } + void SetWillGenerateFrame(); + bool GetAndResetWillGenerateFrame(); + private: uint32_t GetNextResourceId() { return ++mResourceId; } @@ -168,6 +171,7 @@ private: nsClassHashtable mPipelineTexturesHolders; nsClassHashtable mAsyncImagePipelines; uint32_t mAsyncImageEpoch; + bool mWillGenerateFrame; bool mDestroyed; // Render time for the current composition. diff --git a/gfx/layers/wr/WebRenderBridgeParent.cpp b/gfx/layers/wr/WebRenderBridgeParent.cpp index 0766a8c71e97..7e577b4a65a2 100644 --- a/gfx/layers/wr/WebRenderBridgeParent.cpp +++ b/gfx/layers/wr/WebRenderBridgeParent.cpp @@ -612,7 +612,7 @@ WebRenderBridgeParent::RecvSetDisplayList(const gfx::IntSize& aSize, dlDesc, dl.mData, dl.mLen, resources); - ScheduleComposition(); + ScheduleGenerateFrame(); if (ShouldParentObserveEpoch()) { mCompositorBridge->ObserveLayerUpdate(GetLayersId(), GetChildLayerObserverEpoch(), true); @@ -664,7 +664,7 @@ WebRenderBridgeParent::RecvEmptyTransaction(const FocusTarget& aFocusTarget, if (!aCommands.IsEmpty()) { mAsyncImageManager->SetCompositionTime(TimeStamp::Now()); ProcessWebRenderParentCommands(aCommands); - mCompositorScheduler->ScheduleComposition(); + ScheduleGenerateFrame(); } mScrollData.SetFocusTarget(aFocusTarget); @@ -940,8 +940,8 @@ WebRenderBridgeParent::RecvClearCachedResources() // Clear resources mApi->ClearDisplayList(wr::NewEpoch(GetNextWrEpoch()), mPipelineId); - // Schedule composition to clean up Pipeline - mCompositorScheduler->ScheduleComposition(); + // Schedule generate frame to clean up Pipeline + ScheduleGenerateFrame(); // Remove animations. for (std::unordered_set::iterator iter = mActiveAnimations.begin(); iter != mActiveAnimations.end(); iter++) { mAnimStorage->ClearById(*iter); @@ -998,7 +998,7 @@ WebRenderBridgeParent::RecvForceComposite() if (mDestroyed) { return IPC_OK(); } - ScheduleComposition(); + ScheduleGenerateFrame(); return IPC_OK(); } @@ -1189,24 +1189,36 @@ WebRenderBridgeParent::CompositeToTarget(gfx::DrawTarget* aTarget, const gfx::In if (!mForceRendering && wr::RenderThread::Get()->TooManyPendingFrames(mApi->GetId())) { // Render thread is busy, try next time. - ScheduleComposition(); + mCompositorScheduler->ScheduleComposition(); return; } - bool scheduleComposite = false; - nsTArray opacityArray; - nsTArray transformArray; - mAsyncImageManager->SetCompositionTime(TimeStamp::Now()); mAsyncImageManager->ApplyAsyncImages(); + if (!mAsyncImageManager->GetCompositeUntilTime().IsNull()) { + // Trigger another CompositeToTarget() call because there might be another + // frame that we want to generate after this one. + // It will check if we actually want to generate the frame or not. + mCompositorScheduler->ScheduleComposition(); + } + + if (!mAsyncImageManager->GetAndResetWillGenerateFrame() && + !mForceRendering) { + // Could skip generating frame now. + return; + } + + nsTArray opacityArray; + nsTArray transformArray; + SampleAnimations(opacityArray, transformArray); if (!transformArray.IsEmpty() || !opacityArray.IsEmpty()) { - scheduleComposite = true; + ScheduleGenerateFrame(); } if (PushAPZStateToWR(transformArray)) { - scheduleComposite = true; + ScheduleGenerateFrame(); } wr::RenderThread::Get()->IncPendingFrameCount(mApi->GetId()); @@ -1221,14 +1233,6 @@ WebRenderBridgeParent::CompositeToTarget(gfx::DrawTarget* aTarget, const gfx::In } else { mApi->GenerateFrame(); } - - if (!mAsyncImageManager->GetCompositeUntilTime().IsNull()) { - scheduleComposite = true; - } - - if (scheduleComposite) { - ScheduleComposition(); - } } void @@ -1302,9 +1306,10 @@ WebRenderBridgeParent::GetLayersId() const } void -WebRenderBridgeParent::ScheduleComposition() +WebRenderBridgeParent::ScheduleGenerateFrame() { if (mCompositorScheduler) { + mAsyncImageManager->SetWillGenerateFrame(); mCompositorScheduler->ScheduleComposition(); } } @@ -1368,8 +1373,8 @@ WebRenderBridgeParent::ClearResources() uint32_t wrEpoch = GetNextWrEpoch(); mApi->ClearDisplayList(wr::NewEpoch(wrEpoch), mPipelineId); - // Schedule composition to clean up Pipeline - mCompositorScheduler->ScheduleComposition(); + // Schedule generate frame to clean up Pipeline + ScheduleGenerateFrame(); // WrFontKeys and WrImageKeys are deleted during WebRenderAPI destruction. for (auto iter = mExternalImageIds.Iter(); !iter.Done(); iter.Next()) { iter.Data()->ClearWrBridge(); diff --git a/gfx/layers/wr/WebRenderBridgeParent.h b/gfx/layers/wr/WebRenderBridgeParent.h index 94339b6ab954..fd845e00dc15 100644 --- a/gfx/layers/wr/WebRenderBridgeParent.h +++ b/gfx/layers/wr/WebRenderBridgeParent.h @@ -173,7 +173,18 @@ public: void FlushRendering(bool aIsSync); - void ScheduleComposition(); + /** + * Schedule generating WebRender frame definitely at next composite timing. + * + * WebRenderBridgeParent uses composite timing to check if there is an update + * to AsyncImagePipelines. If there is no update, WebRenderBridgeParent skips + * to generate frame. If we need to generate new frame at next composite timing, + * call this method. + * + * Call CompositorVsyncScheduler::ScheduleComposition() directly, if we just + * want to trigger AsyncImagePipelines update checks. + */ + void ScheduleGenerateFrame(); void UpdateWebRender(CompositorVsyncScheduler* aScheduler, wr::WebRenderAPI* aApi, diff --git a/gfx/layers/wr/WebRenderImageHost.cpp b/gfx/layers/wr/WebRenderImageHost.cpp index 3228e22d66e5..469e02fb2a14 100644 --- a/gfx/layers/wr/WebRenderImageHost.cpp +++ b/gfx/layers/wr/WebRenderImageHost.cpp @@ -70,8 +70,9 @@ WebRenderImageHost::UseTextureHost(const nsTArray& aTextures) mImages.SwapElements(newImages); newImages.Clear(); - if (mWrBridge && GetAsyncRef()) { - mWrBridge->ScheduleComposition(); + if (mWrBridge && mWrBridge->CompositorScheduler() && GetAsyncRef()) { + // Will check if we will generate frame. + mWrBridge->CompositorScheduler()->ScheduleComposition(); } // Video producers generally send replacement images with the same frameID but