diff --git a/gfx/layers/wr/WebRenderBridgeParent.cpp b/gfx/layers/wr/WebRenderBridgeParent.cpp index 9a85d8285898..0bda2e6a81e3 100644 --- a/gfx/layers/wr/WebRenderBridgeParent.cpp +++ b/gfx/layers/wr/WebRenderBridgeParent.cpp @@ -122,6 +122,7 @@ WebRenderBridgeParent::WebRenderBridgeParent(CompositorBridgeParentBase* aCompos , mIdNameSpace(AllocIdNameSpace()) , mPaused(false) , mDestroyed(false) + , mIsSnapshotting(false) { MOZ_ASSERT(mCompositableHolder); mCompositableHolder->AddPipeline(mPipelineId); @@ -616,6 +617,8 @@ WebRenderBridgeParent::RecvDPGetSnapshot(PTextureParent* aTexture) // Assert the stride of the buffer is what webrender expects MOZ_ASSERT((uint32_t)(size.width * 4) == stride); + mIsSnapshotting = true; + if (mCompositorScheduler->NeedsComposite()) { mCompositorScheduler->CancelCurrentCompositeTask(); mCompositorScheduler->ForceComposeToTarget(nullptr, nullptr); @@ -623,6 +626,8 @@ WebRenderBridgeParent::RecvDPGetSnapshot(PTextureParent* aTexture) mApi->Readback(size, buffer, buffer_size); + mIsSnapshotting = false; + return IPC_OK(); } @@ -762,6 +767,15 @@ WebRenderBridgeParent::CompositeToTarget(gfx::DrawTarget* aTarget, const gfx::In return; } + const uint32_t maxPendingFrameCount = 2; + + if (!mIsSnapshotting && + wr::RenderThread::Get()->GetPendingFrameCount(mApi->GetId()) > maxPendingFrameCount) { + // Render thread is busy, try next time. + ScheduleComposition(); + return; + } + if (PushAPZStateToWR()) { ScheduleComposition(); } diff --git a/gfx/layers/wr/WebRenderBridgeParent.h b/gfx/layers/wr/WebRenderBridgeParent.h index d6c039f17ac2..d367cdcdf701 100644 --- a/gfx/layers/wr/WebRenderBridgeParent.h +++ b/gfx/layers/wr/WebRenderBridgeParent.h @@ -236,6 +236,7 @@ private: bool mPaused; bool mDestroyed; + bool mIsSnapshotting; // Can only be accessed on the compositor thread. WebRenderScrollData mScrollData; diff --git a/gfx/webrender_bindings/RenderThread.cpp b/gfx/webrender_bindings/RenderThread.cpp index 4d4b58912c2d..6b1d5031a7c2 100644 --- a/gfx/webrender_bindings/RenderThread.cpp +++ b/gfx/webrender_bindings/RenderThread.cpp @@ -20,6 +20,7 @@ static StaticRefPtr sRenderThread; RenderThread::RenderThread(base::Thread* aThread) : mThread(aThread) + , mPendingFrameCountMapLock("RenderThread.mPendingFrameCountMapLock") , mRenderTextureMapLock("RenderThread.mRenderTextureMapLock") { @@ -88,6 +89,9 @@ RenderThread::AddRenderer(wr::WindowId aWindowId, UniquePtr aRender { MOZ_ASSERT(IsInRenderThread()); mRenderers[aWindowId] = Move(aRenderer); + + MutexAutoLock lock(mPendingFrameCountMapLock); + mPendingFrameCounts.Put(AsUint64(aWindowId), 0); } void @@ -95,6 +99,9 @@ RenderThread::RemoveRenderer(wr::WindowId aWindowId) { MOZ_ASSERT(IsInRenderThread()); mRenderers.erase(aWindowId); + + MutexAutoLock lock(mPendingFrameCountMapLock); + mPendingFrameCounts.Remove(AsUint64(aWindowId)); } RendererOGL* @@ -123,6 +130,7 @@ RenderThread::NewFrameReady(wr::WindowId aWindowId) } UpdateAndRender(aWindowId); + DecPendingFrameCount(aWindowId); } void @@ -224,6 +232,48 @@ RenderThread::Resume(wr::WindowId aWindowId) return renderer->Resume(); } +uint32_t +RenderThread::GetPendingFrameCount(wr::WindowId aWindowId) +{ + MutexAutoLock lock(mPendingFrameCountMapLock); + uint32_t count = 0; + MOZ_ASSERT(mPendingFrameCounts.Get(AsUint64(aWindowId), &count)); + mPendingFrameCounts.Get(AsUint64(aWindowId), &count); + return count; +} + +void +RenderThread::IncPendingFrameCount(wr::WindowId aWindowId) +{ + MutexAutoLock lock(mPendingFrameCountMapLock); + // Get the old count. + uint32_t oldCount = 0; + if (!mPendingFrameCounts.Get(AsUint64(aWindowId), &oldCount)) { + MOZ_ASSERT(false); + return; + } + // Update pending frame count. + mPendingFrameCounts.Put(AsUint64(aWindowId), oldCount + 1); +} + +void +RenderThread::DecPendingFrameCount(wr::WindowId aWindowId) +{ + MutexAutoLock lock(mPendingFrameCountMapLock); + // Get the old count. + uint32_t oldCount = 0; + if (!mPendingFrameCounts.Get(AsUint64(aWindowId), &oldCount)) { + MOZ_ASSERT(false); + return; + } + MOZ_ASSERT(oldCount > 0); + if (oldCount <= 0) { + return; + } + // Update pending frame count. + mPendingFrameCounts.Put(AsUint64(aWindowId), oldCount - 1); +} + void RenderThread::RegisterExternalImage(uint64_t aExternalImageId, RenderTextureHost* aTexture) { @@ -255,6 +305,7 @@ extern "C" { void wr_notifier_new_frame_ready(WrWindowId aWindowId) { + mozilla::wr::RenderThread::Get()->IncPendingFrameCount(aWindowId); mozilla::wr::RenderThread::Get()->NewFrameReady(mozilla::wr::WindowId(aWindowId)); } diff --git a/gfx/webrender_bindings/RenderThread.h b/gfx/webrender_bindings/RenderThread.h index 250aae2d7183..fb4f031abbe8 100644 --- a/gfx/webrender_bindings/RenderThread.h +++ b/gfx/webrender_bindings/RenderThread.h @@ -111,16 +111,25 @@ public: RenderTextureHost* GetRenderTexture(WrExternalImageId aExternalImageId); + /// Can be called from any thread. + uint32_t GetPendingFrameCount(wr::WindowId aWindowId); + /// Can be called from any thread. + void IncPendingFrameCount(wr::WindowId aWindowId); + /// Can be called from any thread. + void DecPendingFrameCount(wr::WindowId aWindowId); + private: explicit RenderThread(base::Thread* aThread); ~RenderThread(); - base::Thread* const mThread; std::map> mRenderers; + Mutex mPendingFrameCountMapLock; + nsDataHashtable mPendingFrameCounts; + Mutex mRenderTextureMapLock; nsDataHashtable > mRenderTextures; }; diff --git a/gfx/webrender_bindings/WebRenderTypes.h b/gfx/webrender_bindings/WebRenderTypes.h index 810359bb8e9b..e1756d01485e 100644 --- a/gfx/webrender_bindings/WebRenderTypes.h +++ b/gfx/webrender_bindings/WebRenderTypes.h @@ -103,6 +103,11 @@ struct ImageDescriptor: public WrImageDescriptor { } }; +// Whenever possible, use wr::WindowId instead of manipulating uint64_t. +inline uint64_t AsUint64(const WindowId& aId) { + return static_cast(aId.mHandle); +} + // Whenever possible, use wr::ImageKey instead of manipulating uint64_t. inline uint64_t AsUint64(const ImageKey& aId) { return (static_cast(aId.mNamespace) << 32)