diff --git a/gfx/webrender_bindings/RenderThread.cpp b/gfx/webrender_bindings/RenderThread.cpp index e6473da9b87c..dc5914da1217 100644 --- a/gfx/webrender_bindings/RenderThread.cpp +++ b/gfx/webrender_bindings/RenderThread.cpp @@ -310,6 +310,8 @@ void RenderThread::AddRenderer(wr::WindowId aWindowId, auto windows = mWindowInfos.Lock(); windows->emplace(AsUint64(aWindowId), new WindowInfo()); + mWrNotifierEventsQueues.emplace(AsUint64(aWindowId), + new std::queue); } void RenderThread::RemoveRenderer(wr::WindowId aWindowId) { @@ -338,6 +340,19 @@ void RenderThread::RemoveRenderer(wr::WindowId aWindowId) { auto it = windows->find(AsUint64(aWindowId)); MOZ_ASSERT(it != windows->end()); windows->erase(it); + + // Defer std::deque remove, RemoveRenderer() is called in + // HandleWrNotifierEvents(). + RefPtr runnable = + NS_NewRunnableFunction("RenderThread::RemoveRenderer", [aWindowId]() { + auto* self = RenderThread::Get(); + auto it = self->mWrNotifierEventsQueues.find(AsUint64(aWindowId)); + if (it == self->mWrNotifierEventsQueues.end()) { + return; + } + self->mWrNotifierEventsQueues.erase(it); + }); + RenderThread::Get()->PostRunnable(runnable.forget()); } RendererOGL* RenderThread::GetRenderer(wr::WindowId aWindowId) { @@ -369,6 +384,167 @@ size_t RenderThread::ActiveRendererCount() const { return num_active; } +void RenderThread::WrNotifierEvent_WakeUp(WrWindowId aWindowId, + bool aCompositeNeeded) { + auto windows = mWindowInfos.Lock(); + auto it = windows->find(AsUint64(aWindowId)); + if (it == windows->end()) { + MOZ_ASSERT(false); + return; + } + + WindowInfo* info = it->second.get(); + + info->mPendingWrNotifierEvents.emplace( + WrNotifierEvent::WakeUp(aCompositeNeeded)); + PostWrNotifierEvents(aWindowId, info); +} + +void RenderThread::WrNotifierEvent_NewFrameReady(WrWindowId aWindowId, + bool aCompositeNeeded, + FramePublishId aPublishId) { + auto windows = mWindowInfos.Lock(); + auto it = windows->find(AsUint64(aWindowId)); + if (it == windows->end()) { + MOZ_ASSERT(false); + return; + } + WindowInfo* info = it->second.get(); + + info->mPendingWrNotifierEvents.emplace( + WrNotifierEvent::NewFrameReady(aCompositeNeeded, aPublishId)); + PostWrNotifierEvents(aWindowId, info); +} + +void RenderThread::WrNotifierEvent_ExternalEvent(WrWindowId aWindowId, + size_t aRawEvent) { + UniquePtr evt(reinterpret_cast(aRawEvent)); + { + auto windows = mWindowInfos.Lock(); + auto it = windows->find(AsUint64(aWindowId)); + if (it == windows->end()) { + MOZ_ASSERT(false); + return; + } + WindowInfo* info = it->second.get(); + + info->mPendingWrNotifierEvents.emplace( + WrNotifierEvent::ExternalEvent(std::move(evt))); + PostWrNotifierEvents(aWindowId, info); + } +} + +void RenderThread::PostWrNotifierEvents(WrWindowId aWindowId) { + { + auto windows = mWindowInfos.Lock(); + auto it = windows->find(AsUint64(aWindowId)); + if (it == windows->end()) { + MOZ_ASSERT(false); + return; + } + WindowInfo* info = it->second.get(); + PostWrNotifierEvents(aWindowId, info); + } +} + +void RenderThread::PostWrNotifierEvents(WrWindowId aWindowId, + WindowInfo* aInfo) { + // Runnable has already been triggered. + if (aInfo->mWrNotifierEventsRunnable) { + return; + } + + // Runnable has not been triggered yet. + RefPtr runnable = NewRunnableMethod( + "RenderThread::HandleWrNotifierEvents", this, + &RenderThread::HandleWrNotifierEvents, aWindowId); + aInfo->mWrNotifierEventsRunnable = runnable; + PostRunnable(runnable.forget()); +} + +void RenderThread::HandleWrNotifierEvents(WrWindowId aWindowId) { + MOZ_ASSERT(IsInRenderThread()); + + auto eventsIt = mWrNotifierEventsQueues.find(AsUint64(aWindowId)); + if (eventsIt == mWrNotifierEventsQueues.end()) { + return; + } + auto* events = eventsIt->second.get(); + + { + auto windows = mWindowInfos.Lock(); + auto infoIt = windows->find(AsUint64(aWindowId)); + if (infoIt == windows->end()) { + MOZ_ASSERT(false); + return; + } + WindowInfo* info = infoIt->second.get(); + info->mWrNotifierEventsRunnable = nullptr; + + if (events->empty() && !info->mPendingWrNotifierEvents.empty()) { + events->swap(info->mPendingWrNotifierEvents); + } + } + + bool handleNext = true; + + while (!events->empty() && handleNext) { + auto& front = events->front(); + switch (front.mTag) { + case WrNotifierEvent::Tag::WakeUp: + WrNotifierEvent_HandleWakeUp(aWindowId, front.CompositeNeeded()); + handleNext = false; + break; + case WrNotifierEvent::Tag::NewFrameReady: + WrNotifierEvent_HandleNewFrameReady(aWindowId, front.CompositeNeeded(), + front.PublishId()); + handleNext = false; + break; + case WrNotifierEvent::Tag::ExternalEvent: + WrNotifierEvent_HandleExternalEvent(aWindowId, front.ExternalEvent()); + break; + } + events->pop(); + } + + { + auto windows = mWindowInfos.Lock(); + auto it = windows->find(AsUint64(aWindowId)); + if (it == windows->end()) { + return; + } + WindowInfo* info = it->second.get(); + + if (!events->empty() || !info->mPendingWrNotifierEvents.empty()) { + PostWrNotifierEvents(aWindowId, info); + } + } +} + +void RenderThread::WrNotifierEvent_HandleWakeUp(wr::WindowId aWindowId, + bool aCompositeNeeded) { + MOZ_ASSERT(IsInRenderThread()); + + bool isTrackedFrame = false; + HandleFrameOneDoc(aWindowId, aCompositeNeeded, isTrackedFrame, Nothing()); +} + +void RenderThread::WrNotifierEvent_HandleNewFrameReady( + wr::WindowId aWindowId, bool aCompositeNeeded, FramePublishId aPublishId) { + MOZ_ASSERT(IsInRenderThread()); + + bool isTrackedFrame = true; + HandleFrameOneDoc(aWindowId, aCompositeNeeded, isTrackedFrame, + Some(aPublishId)); +} + +void RenderThread::WrNotifierEvent_HandleExternalEvent( + wr::WindowId aWindowId, UniquePtr aRendererEvent) { + MOZ_ASSERT(IsInRenderThread()); + + RunEvent(aWindowId, std::move(aRendererEvent)); +} + void RenderThread::BeginRecordingForWindow(wr::WindowId aWindowId, const TimeStamp& aRecordingStart, wr::PipelineId aRootPipelineId) { @@ -388,22 +564,16 @@ Maybe RenderThread::EndRecordingForWindow( return renderer->EndRecording(); } -void RenderThread::PostHandleFrameOneDoc(wr::WindowId aWindowId, bool aRender, - bool aTrackedFrame) { - PostRunnable(NewRunnableMethod( - "wr::RenderThread::HandleFrameOneDoc", this, - &RenderThread::HandleFrameOneDoc, aWindowId, aRender, aTrackedFrame)); -} - void RenderThread::HandleFrameOneDoc(wr::WindowId aWindowId, bool aRender, - bool aTrackedFrame) { + bool aTrackedFrame, + Maybe aPublishId) { MOZ_ASSERT(IsInRenderThread()); if (mHasShutdown) { return; } - HandleFrameOneDocInner(aWindowId, aRender, aTrackedFrame); + HandleFrameOneDocInner(aWindowId, aRender, aTrackedFrame, aPublishId); if (aTrackedFrame) { DecPendingFrameCount(aWindowId); @@ -411,7 +581,8 @@ void RenderThread::HandleFrameOneDoc(wr::WindowId aWindowId, bool aRender, } void RenderThread::HandleFrameOneDocInner(wr::WindowId aWindowId, bool aRender, - bool aTrackedFrame) { + bool aTrackedFrame, + Maybe aPublishId) { if (IsDestroyed(aWindowId)) { return; } @@ -451,6 +622,10 @@ void RenderThread::HandleFrameOneDocInner(wr::WindowId aWindowId, bool aRender, // RenderTextureHost::Lock(). HandleRenderTextureOps(); + if (aPublishId.isSome()) { + SetFramePublishId(aWindowId, aPublishId.ref()); + } + UpdateAndRender(aWindowId, frame.mStartId, frame.mStartTime, render, /* aReadbackSize */ Nothing(), /* aReadbackFormat */ Nothing(), @@ -556,6 +731,20 @@ static void NotifyDidStartRender(layers::CompositorBridgeParent* aBridge) { } } +void RenderThread::SetFramePublishId(wr::WindowId aWindowId, + FramePublishId aPublishId) { + MOZ_ASSERT(IsInRenderThread()); + + auto it = mRenderers.find(aWindowId); + MOZ_ASSERT(it != mRenderers.end()); + if (it == mRenderers.end()) { + return; + } + auto& renderer = it->second; + + renderer->SetFramePublishId(aPublishId); +} + void RenderThread::UpdateAndRender( wr::WindowId aWindowId, const VsyncId& aStartId, const TimeStamp& aStartTime, bool aRender, @@ -1406,9 +1595,8 @@ void wr_notifier_wake_up(mozilla::wr::WrWindowId aWindowId, bool aCompositeNeeded) { // wake_up is used for things like propagating debug options or memory // pressure events, so we are not tracking pending frame counts. - bool isTrackedFrame = false; - mozilla::wr::RenderThread::Get()->PostHandleFrameOneDoc( - aWindowId, aCompositeNeeded, isTrackedFrame); + mozilla::wr::RenderThread::Get()->WrNotifierEvent_WakeUp(aWindowId, + aCompositeNeeded); } void wr_notifier_new_frame_ready(mozilla::wr::WrWindowId aWindowId, @@ -1417,17 +1605,14 @@ void wr_notifier_new_frame_ready(mozilla::wr::WrWindowId aWindowId, auto* renderThread = mozilla::wr::RenderThread::Get(); renderThread->DecPendingFrameBuildCount(aWindowId); - bool isTrackedFrame = true; - renderThread->PostHandleFrameOneDoc(aWindowId, aCompositeNeeded, - isTrackedFrame); + renderThread->WrNotifierEvent_NewFrameReady(aWindowId, aCompositeNeeded, + aPublishId); } void wr_notifier_external_event(mozilla::wr::WrWindowId aWindowId, size_t aRawEvent) { - mozilla::UniquePtr evt( - reinterpret_cast(aRawEvent)); - mozilla::wr::RenderThread::Get()->PostEvent(mozilla::wr::WindowId(aWindowId), - std::move(evt)); + mozilla::wr::RenderThread::Get()->WrNotifierEvent_ExternalEvent( + mozilla::wr::WindowId(aWindowId), aRawEvent); } static void NotifyScheduleRender(mozilla::wr::WrWindowId aWindowId, diff --git a/gfx/webrender_bindings/RenderThread.h b/gfx/webrender_bindings/RenderThread.h index e9db594e9eb8..91c4a2114537 100644 --- a/gfx/webrender_bindings/RenderThread.h +++ b/gfx/webrender_bindings/RenderThread.h @@ -165,14 +165,6 @@ class RenderThread final { /// Can only be called from the render thread. RendererOGL* GetRenderer(wr::WindowId aWindowId); - // RenderNotifier implementation - - /// Forwarded to the render thread. Will trigger a render for - /// the current pending frame once one call per document in that pending - /// frame has been received. - void PostHandleFrameOneDoc(wr::WindowId aWindowId, bool aRender, - bool aTrackedFrame); - /// Automatically forwarded to the render thread. void SetClearColor(wr::WindowId aWindowId, wr::ColorF aColor); @@ -186,6 +178,9 @@ class RenderThread final { /// Post RendererEvent to the render thread. void PostEvent(wr::WindowId aWindowId, UniquePtr aEvent); + /// Can only be called from the render thread. + void SetFramePublishId(wr::WindowId aWindowId, FramePublishId aPublishId); + /// Can only be called from the render thread. void UpdateAndRender(wr::WindowId aWindowId, const VsyncId& aStartId, const TimeStamp& aStartTime, bool aRender, @@ -240,6 +235,13 @@ class RenderThread final { void DecPendingFrameBuildCount(wr::WindowId aWindowId); void DecPendingFrameCount(wr::WindowId aWindowId); + // RenderNotifier implementation + void WrNotifierEvent_WakeUp(WrWindowId aWindowId, bool aCompositeNeeded); + void WrNotifierEvent_NewFrameReady(WrWindowId aWindowId, + bool aCompositeNeeded, + FramePublishId aPublishId); + void WrNotifierEvent_ExternalEvent(WrWindowId aWindowId, size_t aRawEvent); + /// Can be called from any thread. WebRenderThreadPool& ThreadPool() { return mThreadPool; } @@ -306,17 +308,85 @@ class RenderThread final { NotifyForUse, NotifyNotUsed, }; + class WrNotifierEvent { + public: + enum class Tag { + WakeUp, + NewFrameReady, + ExternalEvent, + }; + const Tag mTag; + + private: + WrNotifierEvent(const Tag aTag, const bool aCompositeNeeded) + : mTag(aTag), mCompositeNeeded(aCompositeNeeded) { + MOZ_ASSERT(mTag == Tag::WakeUp); + } + WrNotifierEvent(const Tag aTag, bool aCompositeNeeded, + FramePublishId aPublishId) + : mTag(aTag), + mCompositeNeeded(aCompositeNeeded), + mPublishId(aPublishId) { + MOZ_ASSERT(mTag == Tag::NewFrameReady); + } + WrNotifierEvent(const Tag aTag, UniquePtr aRendererEvent) + : mTag(aTag), mRendererEvent(std::move(aRendererEvent)) { + MOZ_ASSERT(mTag == Tag::ExternalEvent); + } + + const bool mCompositeNeeded = false; + UniquePtr mRendererEvent; + const FramePublishId mPublishId = FramePublishId::INVALID; + + public: + static WrNotifierEvent WakeUp(const bool aCompositeNeeded) { + return WrNotifierEvent(Tag::WakeUp, aCompositeNeeded); + } + + static WrNotifierEvent NewFrameReady(const bool aCompositeNeeded, + const FramePublishId aPublishId) { + return WrNotifierEvent(Tag::NewFrameReady, aCompositeNeeded, aPublishId); + } + + static WrNotifierEvent ExternalEvent( + UniquePtr aRendererEvent) { + return WrNotifierEvent(Tag::ExternalEvent, std::move(aRendererEvent)); + } + + bool CompositeNeeded() { + if (mTag == Tag::WakeUp || mTag == Tag::NewFrameReady) { + return mCompositeNeeded; + } + MOZ_ASSERT_UNREACHABLE("unexpected to be called"); + return false; + } + FramePublishId PublishId() { + if (mTag == Tag::NewFrameReady) { + return mPublishId; + } + MOZ_ASSERT_UNREACHABLE("unexpected to be called"); + return FramePublishId::INVALID; + } + UniquePtr ExternalEvent() { + if (mTag == Tag::ExternalEvent) { + return std::move(mRendererEvent); + } + MOZ_ASSERT_UNREACHABLE("unexpected to be called"); + return nullptr; + } + }; explicit RenderThread(RefPtr aThread); void HandleFrameOneDocInner(wr::WindowId aWindowId, bool aRender, - bool aTrackedFrame); + bool aTrackedFrame, + Maybe aPublishId); void DeferredRenderTextureHostDestroy(); void ShutDownTask(); void InitDeviceTask(); void HandleFrameOneDoc(wr::WindowId aWindowId, bool aRender, - bool aTrackedFrame); + bool aTrackedFrame, Maybe aPublishId); void RunEvent(wr::WindowId aWindowId, UniquePtr aEvent); void PostRunnable(already_AddRefed aRunnable); @@ -330,6 +400,19 @@ class RenderThread final { void DestroyExternalImages(const std::vector&& aIds); + struct WindowInfo; + + void PostWrNotifierEvents(WrWindowId aWindowId); + void PostWrNotifierEvents(WrWindowId aWindowId, WindowInfo* aInfo); + void HandleWrNotifierEvents(WrWindowId aWindowId); + void WrNotifierEvent_HandleWakeUp(wr::WindowId aWindowId, + bool aCompositeNeeded); + void WrNotifierEvent_HandleNewFrameReady(wr::WindowId aWindowId, + bool aCompositeNeeded, + FramePublishId aPublishId); + void WrNotifierEvent_HandleExternalEvent( + wr::WindowId aWindowId, UniquePtr aRendererEvent); + ~RenderThread(); RefPtr const mThread; @@ -361,10 +444,15 @@ class RenderThread final { std::queue mPendingFrames; uint8_t mPendingFrameBuild = 0; bool mIsDestroyed = false; + RefPtr mWrNotifierEventsRunnable; + std::queue mPendingWrNotifierEvents; }; DataMutex>> mWindowInfos; + std::unordered_map>> + mWrNotifierEventsQueues; + struct ExternalImageIdHashFn { std::size_t operator()(const wr::ExternalImageId& aId) const { return HashGeneric(wr::AsUint64(aId)); diff --git a/gfx/webrender_bindings/RendererOGL.cpp b/gfx/webrender_bindings/RendererOGL.cpp index 0248fc676be4..3c4d13e376cb 100644 --- a/gfx/webrender_bindings/RendererOGL.cpp +++ b/gfx/webrender_bindings/RendererOGL.cpp @@ -130,6 +130,10 @@ wr::WrExternalImageHandler RendererOGL::GetExternalImageHandler() { }; } +void RendererOGL::SetFramePublishId(FramePublishId aPublishId) { + wr_renderer_set_target_frame_publish_id(mRenderer, aPublishId); +} + void RendererOGL::Update() { mCompositor->Update(); if (mCompositor->MakeCurrent()) { diff --git a/gfx/webrender_bindings/RendererOGL.h b/gfx/webrender_bindings/RendererOGL.h index 930d7cb07834..bf79f70d1658 100644 --- a/gfx/webrender_bindings/RendererOGL.h +++ b/gfx/webrender_bindings/RendererOGL.h @@ -55,6 +55,8 @@ class RendererOGL { public: wr::WrExternalImageHandler GetExternalImageHandler(); + void SetFramePublishId(FramePublishId aPublishId); + /// This can be called on the render thread only. void Update();