From 62a86ac73d2d4aa87fd46078f7b84b9928a50300 Mon Sep 17 00:00:00 2001 From: sotaro Date: Tue, 18 Apr 2023 20:38:20 +0000 Subject: [PATCH] Bug 1828088 - Handle wait of async RemoteTexture at WebRenderAPI r=gfx-reviewers,lsalzman In current m-c, async RemoteTexture wait at RenderThread stops window update when the wait is too long. If async RemoteTexture is handled by WebRenderAPI, window could be updated during long async RemoteTexture wait. async RemoteTexture wait of root WebRenderBridgeParent are disabled to simplify WebRenderAPI's wait handling. offscreen canvas case is handled by WebRenderImageHost by Bug 1827578. Differential Revision: https://phabricator.services.mozilla.com/D175590 --- dom/canvas/ClientWebGLContext.cpp | 3 +- gfx/layers/RemoteTextureMap.cpp | 58 ++++++++- gfx/layers/RemoteTextureMap.h | 11 +- gfx/layers/ipc/CompositorBridgeParent.cpp | 20 +++ gfx/layers/ipc/CompositorBridgeParent.h | 2 + gfx/layers/wr/AsyncImagePipelineManager.cpp | 70 +++-------- gfx/layers/wr/AsyncImagePipelineManager.h | 10 +- gfx/layers/wr/WebRenderBridgeParent.cpp | 59 ++++----- gfx/layers/wr/WebRenderBridgeParent.h | 2 + gfx/webrender_bindings/RenderThread.cpp | 63 ---------- gfx/webrender_bindings/RenderThread.h | 32 ----- gfx/webrender_bindings/WebRenderAPI.cpp | 131 +++++++++++++++++++- gfx/webrender_bindings/WebRenderAPI.h | 102 +++++++++++++++ 13 files changed, 370 insertions(+), 193 deletions(-) diff --git a/dom/canvas/ClientWebGLContext.cpp b/dom/canvas/ClientWebGLContext.cpp index 97c43950c1e2..a131f70495a4 100644 --- a/dom/canvas/ClientWebGLContext.cpp +++ b/dom/canvas/ClientWebGLContext.cpp @@ -474,7 +474,8 @@ Maybe ClientWebGLContext::GetFrontBuffer( const auto& textureId = fb ? fb->mLastRemoteTextureId : mLastRemoteTextureId; auto& needsSync = fb ? fb->mNeedsRemoteTextureSync : mNeedsRemoteTextureSync; if (ownerId && textureId) { - if (gfx::gfxVars::WebglOopAsyncPresentForceSync() || needsSync) { + if (XRE_IsParentProcess() || + gfx::gfxVars::WebglOopAsyncPresentForceSync() || needsSync) { needsSync = false; // Request the front buffer from IPDL to cause a sync, even though we // will continue to use the remote texture descriptor after. diff --git a/gfx/layers/RemoteTextureMap.cpp b/gfx/layers/RemoteTextureMap.cpp index af0668675acd..75f1c75020be 100644 --- a/gfx/layers/RemoteTextureMap.cpp +++ b/gfx/layers/RemoteTextureMap.cpp @@ -108,7 +108,7 @@ void RemoteTextureOwnerClient::PushDummyTexture( } void RemoteTextureOwnerClient::GetLatestBufferSnapshot( - const RemoteTextureOwnerId aOwnerId, const ipc::Shmem& aDestShmem, + const RemoteTextureOwnerId aOwnerId, const mozilla::ipc::Shmem& aDestShmem, const gfx::IntSize& aSize) { MOZ_ASSERT(IsRegistered(aOwnerId)); RemoteTextureMap::Get()->GetLatestBufferSnapshot(aOwnerId, mForPid, @@ -252,7 +252,7 @@ void RemoteTextureMap::PushTexture( void RemoteTextureMap::GetLatestBufferSnapshot( const RemoteTextureOwnerId aOwnerId, const base::ProcessId aForPid, - const ipc::Shmem& aDestShmem, const gfx::IntSize& aSize) { + const mozilla::ipc::Shmem& aDestShmem, const gfx::IntSize& aSize) { // The compositable ref of remote texture should be updated in mMonitor lock. CompositableTextureHostRef textureHostRef; RefPtr releasingTexture; // Release outside the monitor @@ -835,7 +835,7 @@ void RemoteTextureMap::UnregisterRemoteTexturePushListener( bool RemoteTextureMap::CheckRemoteTextureReady( const RemoteTextureInfo& aInfo, std::function&& aCallback) { - MOZ_ASSERT(wr::RenderThread::IsInRenderThread()); + MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); MonitorAutoLock lock(mMonitor); @@ -872,6 +872,58 @@ bool RemoteTextureMap::CheckRemoteTextureReady( return false; } +bool RemoteTextureMap::WaitRemoteTextureReady(const RemoteTextureInfo& aInfo) { + MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); + + MonitorAutoLock lock(mMonitor); + + auto* owner = GetTextureOwner(lock, aInfo.mOwnerId, aInfo.mForPid); + if (!owner) { + // Owner is already removed. + return false; + } + + const auto key = std::pair(aInfo.mForPid, aInfo.mTextureId); + auto it = mRemoteTextureHostWrapperHolders.find(key); + if (it == mRemoteTextureHostWrapperHolders.end()) { + MOZ_ASSERT_UNREACHABLE("unexpected to be called"); + gfxCriticalNoteOnce << "Remote texture does not exist id:" + << uint64_t(aInfo.mTextureId); + return false; + } + + const TimeDuration timeout = TimeDuration::FromMilliseconds(1000); + TextureHost* remoteTexture = it->second->mAsyncRemoteTextureHost; + + while (!remoteTexture) { + CVStatus status = mMonitor.Wait(timeout); + if (status == CVStatus::Timeout) { + MOZ_ASSERT_UNREACHABLE("unexpected to be called"); + gfxCriticalNoteOnce << "Remote texture wait time out id:" + << uint64_t(aInfo.mTextureId); + return false; + } + + auto it = mRemoteTextureHostWrapperHolders.find(key); + if (it == mRemoteTextureHostWrapperHolders.end()) { + MOZ_ASSERT_UNREACHABLE("unexpected to be called"); + return false; + } + + remoteTexture = it->second->mAsyncRemoteTextureHost; + if (!remoteTexture) { + auto* owner = GetTextureOwner(lock, aInfo.mOwnerId, aInfo.mForPid); + // When owner is alreay unregistered, remote texture will not be pushed. + if (!owner) { + // This could happen with IPC abnormal shutdown + return false; + } + } + } + + return true; +} + UniquePtr RemoteTextureMap::GetRecycledBufferTextureData( const RemoteTextureOwnerId aOwnerId, const base::ProcessId aForPid, gfx::IntSize aSize, gfx::SurfaceFormat aFormat) { diff --git a/gfx/layers/RemoteTextureMap.h b/gfx/layers/RemoteTextureMap.h index c8064c0565db..5ff25df32048 100644 --- a/gfx/layers/RemoteTextureMap.h +++ b/gfx/layers/RemoteTextureMap.h @@ -16,8 +16,9 @@ #include #include -#include "mozilla/gfx/Point.h" // for IntSize -#include "mozilla/gfx/Types.h" // for SurfaceFormat +#include "mozilla/gfx/Point.h" // for IntSize +#include "mozilla/gfx/Types.h" // for SurfaceFormat +#include "mozilla/ipc/Shmem.h" #include "mozilla/layers/CompositorTypes.h" // for TextureFlags, etc #include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor #include "mozilla/layers/TextureHost.h" @@ -78,7 +79,7 @@ class RemoteTextureOwnerClient final { void PushDummyTexture(const RemoteTextureId aTextureId, const RemoteTextureOwnerId aOwnerId); void GetLatestBufferSnapshot(const RemoteTextureOwnerId aOwnerId, - const ipc::Shmem& aDestShmem, + const mozilla::ipc::Shmem& aDestShmem, const gfx::IntSize& aSize); UniquePtr CreateOrRecycleBufferTextureData( const RemoteTextureOwnerId aOwnerId, gfx::IntSize aSize, @@ -122,7 +123,7 @@ class RemoteTextureMap { void GetLatestBufferSnapshot(const RemoteTextureOwnerId aOwnerId, const base::ProcessId aForPid, - const ipc::Shmem& aDestShmem, + const mozilla::ipc::Shmem& aDestShmem, const gfx::IntSize& aSize); // aIsSyncMode defines if RemoteTextureMap::GetRemoteTextureForDisplayList() @@ -175,6 +176,8 @@ class RemoteTextureMap { const RemoteTextureInfo& aInfo, std::function&& aCallback); + bool WaitRemoteTextureReady(const RemoteTextureInfo& aInfo); + UniquePtr GetRecycledBufferTextureData( const RemoteTextureOwnerId aOwnerId, const base::ProcessId aForPid, gfx::IntSize aSize, gfx::SurfaceFormat aFormat); diff --git a/gfx/layers/ipc/CompositorBridgeParent.cpp b/gfx/layers/ipc/CompositorBridgeParent.cpp index 89f168d14932..ba93988190fd 100644 --- a/gfx/layers/ipc/CompositorBridgeParent.cpp +++ b/gfx/layers/ipc/CompositorBridgeParent.cpp @@ -1901,6 +1901,26 @@ mozilla::ipc::IPCResult CompositorBridgeParent::RecvEndRecording( return IPC_OK(); } +void CompositorBridgeParent::FlushPendingWrTransactionEventsWithWait() { + if (!mWrBridge) { + return; + } + + std::vector> bridgeParents; + { // scope lock + MonitorAutoLock lock(*sIndirectLayerTreesLock); + ForEachIndirectLayerTree([&](LayerTreeState* lts, LayersId) -> void { + if (lts->mWrBridge) { + bridgeParents.emplace_back(lts->mWrBridge); + } + }); + } + + for (auto& bridge : bridgeParents) { + bridge->FlushPendingWrTransactionEventsWithWait(); + } +} + void RecordCompositionPayloadsPresented( const TimeStamp& aCompositionEndTime, const nsTArray& aPayloads) { diff --git a/gfx/layers/ipc/CompositorBridgeParent.h b/gfx/layers/ipc/CompositorBridgeParent.h index 76b641628a83..228675d27bcc 100644 --- a/gfx/layers/ipc/CompositorBridgeParent.h +++ b/gfx/layers/ipc/CompositorBridgeParent.h @@ -506,6 +506,8 @@ class CompositorBridgeParent final : public CompositorBridgeParentBase, WebRenderBridgeParent* GetWrBridge() { return mWrBridge; } + void FlushPendingWrTransactionEventsWithWait(); + private: void Initialize(); diff --git a/gfx/layers/wr/AsyncImagePipelineManager.cpp b/gfx/layers/wr/AsyncImagePipelineManager.cpp index cb6f409eacd3..4849b651a315 100644 --- a/gfx/layers/wr/AsyncImagePipelineManager.cpp +++ b/gfx/layers/wr/AsyncImagePipelineManager.cpp @@ -17,7 +17,6 @@ #include "mozilla/layers/SharedSurfacesParent.h" #include "mozilla/layers/WebRenderImageHost.h" #include "mozilla/layers/WebRenderTextureHost.h" -#include "mozilla/StaticPrefs_webgl.h" #include "mozilla/webrender/RenderThread.h" #include "mozilla/webrender/WebRenderAPI.h" #include "mozilla/webrender/WebRenderTypes.h" @@ -212,7 +211,7 @@ Maybe AsyncImagePipelineManager::UpdateImageKeys( const wr::Epoch& aEpoch, const wr::PipelineId& aPipelineId, AsyncImagePipeline* aPipeline, nsTArray& aKeys, wr::TransactionBuilder& aSceneBuilderTxn, - wr::TransactionBuilder& aMaybeFastTxn) { + wr::TransactionBuilder& aMaybeFastTxn, RemoteTextureInfoList* aList) { MOZ_ASSERT(aKeys.IsEmpty()); MOZ_ASSERT(aPipeline); @@ -233,6 +232,13 @@ Maybe AsyncImagePipelineManager::UpdateImageKeys( return Nothing(); } + // Check if pending Remote texture exists. + auto* wrapper = texture->AsRemoteTextureHostWrapper(); + if (aList && wrapper && wrapper->IsReadyForRendering()) { + aList->mList.emplace(wrapper->mTextureId, wrapper->mOwnerId, + wrapper->mForPid); + } + aPipeline->mCurrentTexture = texture; WebRenderTextureHost* wrTexture = texture->AsWebRenderTextureHost(); @@ -366,7 +372,7 @@ void AsyncImagePipelineManager::ApplyAsyncImagesOfImageBridge( continue; } ApplyAsyncImageForPipeline(epoch, pipelineId, pipeline, aSceneBuilderTxn, - aFastTxn); + aFastTxn, /* aList */ nullptr); } } @@ -387,10 +393,10 @@ wr::WrRotation ToWrRotation(VideoInfo::Rotation aRotation) { void AsyncImagePipelineManager::ApplyAsyncImageForPipeline( const wr::Epoch& aEpoch, const wr::PipelineId& aPipelineId, AsyncImagePipeline* aPipeline, wr::TransactionBuilder& aSceneBuilderTxn, - wr::TransactionBuilder& aMaybeFastTxn) { + wr::TransactionBuilder& aMaybeFastTxn, RemoteTextureInfoList* aList) { nsTArray keys; auto op = UpdateImageKeys(aEpoch, aPipelineId, aPipeline, keys, - aSceneBuilderTxn, aMaybeFastTxn); + aSceneBuilderTxn, aMaybeFastTxn, aList); bool updateDisplayList = aPipeline->mInitialised && @@ -481,12 +487,19 @@ void AsyncImagePipelineManager::ApplyAsyncImageForPipeline( void AsyncImagePipelineManager::ApplyAsyncImageForPipeline( const wr::PipelineId& aPipelineId, wr::TransactionBuilder& aTxn, - wr::TransactionBuilder& aTxnForImageBridge) { + wr::TransactionBuilder& aTxnForImageBridge, RemoteTextureInfoList* aList) { AsyncImagePipeline* pipeline = mAsyncImagePipelines.Get(wr::AsUint64(aPipelineId)); if (!pipeline) { return; } + + // ready event of RemoteTexture that uses ImageBridge do not need to be + // checked here. + if (pipeline->mImageHost->GetAsyncRef()) { + aList = nullptr; + } + wr::TransactionBuilder fastTxn(mApi, /* aUseSceneBuilderThread */ false); wr::AutoTransactionSender sender(mApi, &fastTxn); @@ -507,7 +520,7 @@ void AsyncImagePipelineManager::ApplyAsyncImageForPipeline( wr::Epoch epoch = GetNextImageEpoch(); ApplyAsyncImageForPipeline(epoch, aPipelineId, pipeline, sceneBuilderTxn, - maybeFastTxn); + maybeFastTxn, aList); } void AsyncImagePipelineManager::SetEmptyDisplayList( @@ -746,49 +759,6 @@ wr::Epoch AsyncImagePipelineManager::GetNextImageEpoch() { return mAsyncImageEpoch; } -UniquePtr -AsyncImagePipelineManager::GetPendingRemoteTextures() { - if (!gfx::gfxVars::UseCanvasRenderThread() || - !StaticPrefs::webgl_out_of_process_async_present() || - gfx::gfxVars::WebglOopAsyncPresentForceSync()) { - return nullptr; - } - - // async remote texture is enabled - MOZ_ASSERT(gfx::gfxVars::UseCanvasRenderThread()); - MOZ_ASSERT(StaticPrefs::webgl_out_of_process_async_present()); - MOZ_ASSERT(!gfx::gfxVars::WebglOopAsyncPresentForceSync()); - - auto list = MakeUnique(); - - for (const auto& entry : mAsyncImagePipelines) { - AsyncImagePipeline* pipeline = entry.GetWeak(); - - if (pipeline->mImageHost->GetAsyncRef()) { - continue; - } - - if (!pipeline->mImageHost->GetCurrentTextureHost()) { - continue; - } - - auto* wrapper = pipeline->mImageHost->GetCurrentTextureHost() - ->AsRemoteTextureHostWrapper(); - if (!wrapper || !wrapper->IsReadyForRendering()) { - continue; - } - - list->mList.emplace(wrapper->mTextureId, wrapper->mOwnerId, - wrapper->mForPid); - } - - if (list->mList.empty()) { - return nullptr; - } - - return list; -} - AsyncImagePipelineManager::WebRenderPipelineInfoHolder:: WebRenderPipelineInfoHolder(RefPtr&& aInfo, ipc::FileDescriptor&& aFenceFd) diff --git a/gfx/layers/wr/AsyncImagePipelineManager.h b/gfx/layers/wr/AsyncImagePipelineManager.h index 8dabc32884d6..1ed144c5484f 100644 --- a/gfx/layers/wr/AsyncImagePipelineManager.h +++ b/gfx/layers/wr/AsyncImagePipelineManager.h @@ -111,7 +111,8 @@ class AsyncImagePipelineManager final { wr::TransactionBuilder& aFastTxn); void ApplyAsyncImageForPipeline(const wr::PipelineId& aPipelineId, wr::TransactionBuilder& aTxn, - wr::TransactionBuilder& aTxnForImageBridge); + wr::TransactionBuilder& aTxnForImageBridge, + RemoteTextureInfoList* aList); void SetEmptyDisplayList(const wr::PipelineId& aPipelineId, wr::TransactionBuilder& aTxn, @@ -130,8 +131,6 @@ class AsyncImagePipelineManager final { void SetWillGenerateFrame(); bool GetAndResetWillGenerateFrame(); - UniquePtr GetPendingRemoteTextures(); - static wr::ExternalImageId GetNextExternalImageId(); private: @@ -213,12 +212,13 @@ class AsyncImagePipelineManager final { const wr::PipelineId& aPipelineId, AsyncImagePipeline* aPipeline, wr::TransactionBuilder& aSceneBuilderTxn, - wr::TransactionBuilder& aMaybeFastTxn); + wr::TransactionBuilder& aMaybeFastTxn, + RemoteTextureInfoList* aList); Maybe UpdateImageKeys( const wr::Epoch& aEpoch, const wr::PipelineId& aPipelineId, AsyncImagePipeline* aPipeline, nsTArray& aKeys, wr::TransactionBuilder& aSceneBuilderTxn, - wr::TransactionBuilder& aMaybeFastTxn); + wr::TransactionBuilder& aMaybeFastTxn, RemoteTextureInfoList* aList); Maybe UpdateWithoutExternalImage( TextureHost* aTexture, wr::ImageKey aKey, TextureHost::ResourceUpdateOp, wr::TransactionBuilder& aTxn); diff --git a/gfx/layers/wr/WebRenderBridgeParent.cpp b/gfx/layers/wr/WebRenderBridgeParent.cpp index a2a17da10ad4..5c92d66cc265 100644 --- a/gfx/layers/wr/WebRenderBridgeParent.cpp +++ b/gfx/layers/wr/WebRenderBridgeParent.cpp @@ -18,6 +18,7 @@ #include "mozilla/Range.h" #include "mozilla/EnumeratedRange.h" #include "mozilla/StaticPrefs_gfx.h" +#include "mozilla/StaticPrefs_webgl.h" #include "mozilla/UniquePtr.h" #include "mozilla/gfx/gfxVars.h" #include "mozilla/gfx/GPUParent.h" @@ -1495,16 +1496,20 @@ bool WebRenderBridgeParent::ProcessWebRenderParentCommands( mAsyncImageManager->UpdateAsyncImagePipeline( op.pipelineId(), op.scBounds(), op.rotation(), op.filter(), op.mixBlendMode()); + auto* list = mApi->GetPendingRemoteTextureInfoList(); + MOZ_ASSERT_IF(IsRootWebRenderBridgeParent(), !list); mAsyncImageManager->ApplyAsyncImageForPipeline(op.pipelineId(), aTxn, - txnForImageBridge); + txnForImageBridge, list); break; } case WebRenderParentCommand::TOpUpdatedAsyncImagePipeline: { const OpUpdatedAsyncImagePipeline& op = cmd.get_OpUpdatedAsyncImagePipeline(); aTxn.InvalidateRenderedFrame(wr::RenderReasons::ASYNC_IMAGE); + auto* list = mApi->GetPendingRemoteTextureInfoList(); + MOZ_ASSERT_IF(IsRootWebRenderBridgeParent(), !list); mAsyncImageManager->ApplyAsyncImageForPipeline(op.pipelineId(), aTxn, - txnForImageBridge); + txnForImageBridge, list); break; } case WebRenderParentCommand::TCompositableOperation: { @@ -1665,6 +1670,10 @@ void WebRenderBridgeParent::MaybeCaptureScreenPixels() { return; } + if (auto* cbp = GetRootCompositorBridgeParent()) { + cbp->FlushPendingWrTransactionEventsWithWait(); + } + // This function should only get called in the root WRBP. MOZ_ASSERT(IsRootWebRenderBridgeParent()); # ifdef DEBUG @@ -1705,6 +1714,10 @@ mozilla::ipc::IPCResult WebRenderBridgeParent::RecvGetSnapshot( return IPC_OK(); } + if (auto* cbp = GetRootCompositorBridgeParent()) { + cbp->FlushPendingWrTransactionEventsWithWait(); + } + LOG("WebRenderBridgeParent::RecvGetSnapshot() PipelineId %" PRIx64 " Id %" PRIx64 " root %d", wr::AsUint64(mPipelineId), wr::AsUint64(mApi->GetId()), @@ -2282,29 +2295,6 @@ TimeDuration WebRenderBridgeParent::GetVsyncInterval() const { return TimeDuration(); } -class SchedulePendingRemoteTextures : public wr::NotificationHandler { - public: - SchedulePendingRemoteTextures( - wr::WindowId aWindowId, - UniquePtr&& aPendingRemoteTextures) - : mWindowId(aWindowId), - mPendingRemoteTextures(std::move(aPendingRemoteTextures)) {} - - virtual void Notify(wr::Checkpoint aCheckpoint) override { - if (aCheckpoint == wr::Checkpoint::FrameBuilt) { - wr::RenderThread::Get()->PushPendingRemoteTexture( - mWindowId, std::move(mPendingRemoteTextures)); - - } else { - MOZ_ASSERT(aCheckpoint == wr::Checkpoint::TransactionDropped); - } - } - - protected: - wr::WindowId mWindowId; - UniquePtr mPendingRemoteTextures; -}; - void WebRenderBridgeParent::MaybeGenerateFrame(VsyncId aId, bool aForceGenerateFrame, wr::RenderReasons aReasons) { @@ -2378,14 +2368,6 @@ void WebRenderBridgeParent::MaybeGenerateFrame(VsyncId aId, SetOMTASampleTime(); SetAPZSampleTime(); - auto pendingTextures = mAsyncImageManager->GetPendingRemoteTextures(); - if (pendingTextures) { - MOZ_ASSERT(!pendingTextures->mList.empty()); - fastTxn.Notify(wr::Checkpoint::FrameBuilt, - MakeUnique( - mApi->GetId(), std::move(pendingTextures))); - } - #if defined(ENABLE_FRAME_LATENCY_LOG) auto startTime = TimeStamp::Now(); mApi->SetFrameStartTime(startTime); @@ -2691,6 +2673,10 @@ void WebRenderBridgeParent::ClearResources() { return; } + if (!IsRootWebRenderBridgeParent()) { + mApi->FlushPendingWrTransactionEventsWithoutWait(); + } + LOG("WebRenderBridgeParent::ClearResources() PipelineId %" PRIx64 " Id %" PRIx64 " root %d", wr::AsUint64(mPipelineId), wr::AsUint64(mApi->GetId()), @@ -2843,6 +2829,13 @@ void WebRenderBridgeParent::ExtractImageCompositeNotifications( mAsyncImageManager->FlushImageNotifications(aNotifications); } +void WebRenderBridgeParent::FlushPendingWrTransactionEventsWithWait() { + if (mDestroyed || IsRootWebRenderBridgeParent()) { + return; + } + mApi->FlushPendingWrTransactionEventsWithWait(); +} + RefPtr WebRenderBridgeParent::GetWebRenderBridgeParentRef() { if (mDestroyed) { diff --git a/gfx/layers/wr/WebRenderBridgeParent.h b/gfx/layers/wr/WebRenderBridgeParent.h index dad4e2c683a8..672e8fb7cd08 100644 --- a/gfx/layers/wr/WebRenderBridgeParent.h +++ b/gfx/layers/wr/WebRenderBridgeParent.h @@ -311,6 +311,8 @@ class WebRenderBridgeParent final : public PWebRenderBridgeParent, RefPtr GetWebRenderBridgeParentRef(); + void FlushPendingWrTransactionEventsWithWait(); + private: class ScheduleSharedSurfaceRelease; diff --git a/gfx/webrender_bindings/RenderThread.cpp b/gfx/webrender_bindings/RenderThread.cpp index e715f2f7d200..dc5914da1217 100644 --- a/gfx/webrender_bindings/RenderThread.cpp +++ b/gfx/webrender_bindings/RenderThread.cpp @@ -26,7 +26,6 @@ #include "mozilla/layers/SurfacePool.h" #include "mozilla/layers/SynchronousTask.h" #include "mozilla/PerfStats.h" -#include "mozilla/StaticPrefs_webgl.h" #include "mozilla/StaticPtr.h" #include "mozilla/Telemetry.h" #include "mozilla/webrender/RendererOGL.h" @@ -385,56 +384,6 @@ size_t RenderThread::ActiveRendererCount() const { return num_active; } -void RenderThread::PushPendingRemoteTexture( - wr::WindowId aWindowId, - UniquePtr&& aPendingRemoteTextures) { - 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::PendingRemoteTextures( - std::move(aPendingRemoteTextures))); -} - -bool RenderThread::CheckIsRemoteTextureReady( - WrWindowId aWindowId, layers::RemoteTextureInfoList* aList) { - MOZ_ASSERT(aList); - MOZ_ASSERT(gfx::gfxVars::UseCanvasRenderThread()); - MOZ_ASSERT(StaticPrefs::webgl_out_of_process_async_present()); - MOZ_ASSERT(!gfx::gfxVars::WebglOopAsyncPresentForceSync()); - - auto callback = [windowId = aWindowId](const layers::RemoteTextureInfo&) { - RefPtr runnable = NewRunnableMethod( - "RenderThread::HandleWrNotifierEvents", RenderThread::Get(), - &RenderThread::HandleWrNotifierEvents, windowId); - RenderThread::Get()->PostRunnable(runnable.forget()); - }; - - bool isReady = true; - while (!aList->mList.empty() && isReady) { - auto& front = aList->mList.front(); - isReady &= layers::RemoteTextureMap::Get()->CheckRemoteTextureReady( - front, callback); - if (isReady) { - aList->mList.pop(); - } - } - - { - auto windows = mWindowInfos.Lock(); - auto it = windows->find(AsUint64(aWindowId)); - MOZ_RELEASE_ASSERT(it != windows->end()); - WindowInfo* info = it->second.get(); - info->mIsWaitingRemoteTextureReady = !isReady; - } - - return isReady; -} - void RenderThread::WrNotifierEvent_WakeUp(WrWindowId aWindowId, bool aCompositeNeeded) { auto windows = mWindowInfos.Lock(); @@ -505,11 +454,6 @@ void RenderThread::PostWrNotifierEvents(WrWindowId aWindowId, return; } - // Waitig callback from RemoteTextureMap - if (aInfo->mIsWaitingRemoteTextureReady) { - return; - } - // Runnable has not been triggered yet. RefPtr runnable = NewRunnableMethod( "RenderThread::HandleWrNotifierEvents", this, @@ -559,13 +503,6 @@ void RenderThread::HandleWrNotifierEvents(WrWindowId aWindowId) { case WrNotifierEvent::Tag::ExternalEvent: WrNotifierEvent_HandleExternalEvent(aWindowId, front.ExternalEvent()); break; - case WrNotifierEvent::Tag::PendingRemoteTextures: - bool isReady = - CheckIsRemoteTextureReady(aWindowId, front.RemoteTextureInfoList()); - if (!isReady) { - return; - } - break; } events->pop(); } diff --git a/gfx/webrender_bindings/RenderThread.h b/gfx/webrender_bindings/RenderThread.h index db5d3cc47ee1..fc6e2a2752a6 100644 --- a/gfx/webrender_bindings/RenderThread.h +++ b/gfx/webrender_bindings/RenderThread.h @@ -21,7 +21,6 @@ #include "mozilla/UniquePtr.h" #include "mozilla/webrender/WebRenderTypes.h" #include "mozilla/layers/CompositionRecorder.h" -#include "mozilla/layers/RemoteTextureMap.h" #include "mozilla/layers/SynchronousTask.h" #include "mozilla/UniquePtr.h" #include "mozilla/VsyncDispatcher.h" @@ -236,10 +235,6 @@ class RenderThread final { void DecPendingFrameBuildCount(wr::WindowId aWindowId); void DecPendingFrameCount(wr::WindowId aWindowId); - void PushPendingRemoteTexture( - wr::WindowId aWindowId, - UniquePtr&& aPendingRemoteTextures); - // RenderNotifier implementation void WrNotifierEvent_WakeUp(WrWindowId aWindowId, bool aCompositeNeeded); void WrNotifierEvent_NewFrameReady(WrWindowId aWindowId, @@ -319,7 +314,6 @@ class RenderThread final { WakeUp, NewFrameReady, ExternalEvent, - PendingRemoteTextures, }; const Tag mTag; @@ -339,18 +333,10 @@ class RenderThread final { : mTag(aTag), mRendererEvent(std::move(aRendererEvent)) { MOZ_ASSERT(mTag == Tag::ExternalEvent); } - WrNotifierEvent( - const Tag aTag, - UniquePtr&& aPendingRemoteTextures) - : mTag(aTag), - mPendingRemoteTextures(std::move(aPendingRemoteTextures)) { - MOZ_ASSERT(mTag == Tag::PendingRemoteTextures); - } const bool mCompositeNeeded = false; const FramePublishId mPublishId = FramePublishId::INVALID; UniquePtr mRendererEvent; - UniquePtr mPendingRemoteTextures; public: static WrNotifierEvent WakeUp(const bool aCompositeNeeded) { @@ -367,12 +353,6 @@ class RenderThread final { return WrNotifierEvent(Tag::ExternalEvent, std::move(aRendererEvent)); } - static WrNotifierEvent PendingRemoteTextures( - UniquePtr&& aPendingRemoteTextures) { - return WrNotifierEvent(Tag::PendingRemoteTextures, - std::move(aPendingRemoteTextures)); - } - bool CompositeNeeded() { if (mTag == Tag::WakeUp || mTag == Tag::NewFrameReady) { return mCompositeNeeded; @@ -395,15 +375,6 @@ class RenderThread final { MOZ_ASSERT_UNREACHABLE("unexpected to be called"); return nullptr; } - - layers::RemoteTextureInfoList* RemoteTextureInfoList() { - if (mTag == Tag::PendingRemoteTextures) { - MOZ_ASSERT(mPendingRemoteTextures); - return mPendingRemoteTextures.get(); - } - MOZ_ASSERT_UNREACHABLE("unexpected to be called"); - return nullptr; - } }; explicit RenderThread(RefPtr aThread); @@ -442,8 +413,6 @@ class RenderThread final { FramePublishId aPublishId); void WrNotifierEvent_HandleExternalEvent( wr::WindowId aWindowId, UniquePtr aRendererEvent); - bool CheckIsRemoteTextureReady(WrWindowId aWindowId, - layers::RemoteTextureInfoList* aList); ~RenderThread(); @@ -478,7 +447,6 @@ class RenderThread final { bool mIsDestroyed = false; RefPtr mWrNotifierEventsRunnable; std::queue mPendingWrNotifierEvents; - bool mIsWaitingRemoteTextureReady = false; }; DataMutex>> mWindowInfos; diff --git a/gfx/webrender_bindings/WebRenderAPI.cpp b/gfx/webrender_bindings/WebRenderAPI.cpp index 0cd92437e866..1afdd03ea585 100644 --- a/gfx/webrender_bindings/WebRenderAPI.cpp +++ b/gfx/webrender_bindings/WebRenderAPI.cpp @@ -6,15 +6,17 @@ #include "WebRenderAPI.h" -#include "mozilla/StaticPrefs_gfx.h" #include "mozilla/ipc/ByteBuf.h" #include "mozilla/webrender/RendererOGL.h" #include "mozilla/gfx/gfxVars.h" #include "mozilla/layers/CompositorThread.h" +#include "mozilla/StaticPrefs_gfx.h" +#include "mozilla/StaticPrefs_webgl.h" #include "mozilla/ToString.h" #include "mozilla/webrender/RenderCompositor.h" #include "mozilla/widget/CompositorWidget.h" #include "mozilla/layers/SynchronousTask.h" +#include "nsThreadUtils.h" #include "TextDrawTarget.h" #include "malloc_decls.h" #include "GLContext.h" @@ -436,7 +438,126 @@ void WebRenderAPI::SendTransaction(TransactionBuilder& aTxn) { if (mRootApi && mRootApi->mRendererDestroyed) { return; } - wr_api_send_transaction(mDocHandle, aTxn.Raw(), aTxn.UseSceneBuilderThread()); + + if (mPendingRemoteTextureInfoList && + !mPendingRemoteTextureInfoList->mList.empty()) { + mPendingWrTransactionEvents.emplace( + WrTransactionEvent::PendingRemoteTextures( + std::move(mPendingRemoteTextureInfoList))); + } + + if (!mPendingWrTransactionEvents.empty()) { + mPendingWrTransactionEvents.emplace(WrTransactionEvent::Transaction( + aTxn.Take(), aTxn.UseSceneBuilderThread())); + HandleWrTransactionEvents(RemoteTextureWaitType::AsyncWait); + } else { + wr_api_send_transaction(mDocHandle, aTxn.Raw(), + aTxn.UseSceneBuilderThread()); + } +} + +layers::RemoteTextureInfoList* WebRenderAPI::GetPendingRemoteTextureInfoList() { + if (!mRootApi) { + // root api does not support async wait RemoteTexture. + return nullptr; + } + + if (!gfx::gfxVars::UseCanvasRenderThread() || + !StaticPrefs::webgl_out_of_process_async_present() || + gfx::gfxVars::WebglOopAsyncPresentForceSync()) { + return nullptr; + } + + // async remote texture is enabled + MOZ_ASSERT(gfx::gfxVars::UseCanvasRenderThread()); + MOZ_ASSERT(StaticPrefs::webgl_out_of_process_async_present()); + MOZ_ASSERT(!gfx::gfxVars::WebglOopAsyncPresentForceSync()); + + if (!mPendingRemoteTextureInfoList) { + mPendingRemoteTextureInfoList = MakeUnique(); + } + return mPendingRemoteTextureInfoList.get(); +} + +bool WebRenderAPI::CheckIsRemoteTextureReady( + layers::RemoteTextureInfoList* aList) { + MOZ_ASSERT(layers::CompositorThreadHolder::IsInCompositorThread()); + MOZ_ASSERT(aList); + MOZ_ASSERT(gfx::gfxVars::UseCanvasRenderThread()); + MOZ_ASSERT(StaticPrefs::webgl_out_of_process_async_present()); + MOZ_ASSERT(!gfx::gfxVars::WebglOopAsyncPresentForceSync()); + + RefPtr self = this; + auto callback = [self](const layers::RemoteTextureInfo&) { + RefPtr runnable = NewRunnableMethod( + "WebRenderAPI::HandleWrTransactionEvents", self, + &WebRenderAPI::HandleWrTransactionEvents, + RemoteTextureWaitType::AsyncWait); + layers::CompositorThread()->Dispatch(runnable.forget()); + }; + + bool isReady = true; + while (!aList->mList.empty() && isReady) { + auto& front = aList->mList.front(); + isReady &= layers::RemoteTextureMap::Get()->CheckRemoteTextureReady( + front, callback); + if (isReady) { + aList->mList.pop(); + } + } + + return isReady; +} + +void WebRenderAPI::WaitRemoteTextureReady( + layers::RemoteTextureInfoList* aList) { + MOZ_ASSERT(layers::CompositorThreadHolder::IsInCompositorThread()); + MOZ_ASSERT(aList); + MOZ_ASSERT(gfx::gfxVars::UseCanvasRenderThread()); + MOZ_ASSERT(StaticPrefs::webgl_out_of_process_async_present()); + MOZ_ASSERT(!gfx::gfxVars::WebglOopAsyncPresentForceSync()); + + while (!aList->mList.empty()) { + auto& front = aList->mList.front(); + layers::RemoteTextureMap::Get()->WaitRemoteTextureReady(front); + aList->mList.pop(); + } +} + +void WebRenderAPI::FlushPendingWrTransactionEventsWithoutWait() { + HandleWrTransactionEvents(RemoteTextureWaitType::FlushWithoutWait); +} + +void WebRenderAPI::FlushPendingWrTransactionEventsWithWait() { + HandleWrTransactionEvents(RemoteTextureWaitType::FlushWithWait); +} + +void WebRenderAPI::HandleWrTransactionEvents(RemoteTextureWaitType aType) { + auto& events = mPendingWrTransactionEvents; + + while (!events.empty()) { + auto& front = events.front(); + switch (front.mTag) { + case WrTransactionEvent::Tag::Transaction: + wr_api_send_transaction(mDocHandle, front.Transaction(), + front.UseSceneBuilderThread()); + break; + case WrTransactionEvent::Tag::PendingRemoteTextures: + bool isReady = true; + if (aType == RemoteTextureWaitType::AsyncWait) { + isReady = CheckIsRemoteTextureReady(front.RemoteTextureInfoList()); + } else if (aType == RemoteTextureWaitType::FlushWithWait) { + WaitRemoteTextureReady(front.RemoteTextureInfoList()); + } else { + MOZ_ASSERT(aType == RemoteTextureWaitType::FlushWithoutWait); + } + if (!isReady) { + return; + } + break; + } + events.pop(); + } } std::vector WebRenderAPI::HitTest(const wr::WorldPoint& aPoint) { @@ -733,6 +854,12 @@ RefPtr WebRenderAPI::EndRecording() { void TransactionBuilder::Clear() { wr_resource_updates_clear(mTxn); } +Transaction* TransactionBuilder::Take() { + Transaction* txn = mTxn; + mTxn = wr_transaction_new(mUseSceneBuilderThread); + return txn; +} + void TransactionBuilder::Notify(wr::Checkpoint aWhen, UniquePtr aEvent) { wr_transaction_notify(mTxn, aWhen, diff --git a/gfx/webrender_bindings/WebRenderAPI.h b/gfx/webrender_bindings/WebRenderAPI.h index 67887b8449f7..c276b0e68763 100644 --- a/gfx/webrender_bindings/WebRenderAPI.h +++ b/gfx/webrender_bindings/WebRenderAPI.h @@ -7,6 +7,7 @@ #ifndef MOZILLA_LAYERS_WEBRENDERAPI_H #define MOZILLA_LAYERS_WEBRENDERAPI_H +#include #include #include #include @@ -15,12 +16,14 @@ #include "mozilla/AlreadyAddRefed.h" #include "mozilla/gfx/CompositorHitTestInfo.h" #include "mozilla/layers/IpcResourceUpdateQueue.h" +#include "mozilla/layers/RemoteTextureMap.h" #include "mozilla/layers/ScrollableLayerGuid.h" #include "mozilla/layers/SyncObject.h" #include "mozilla/layers/CompositionRecorder.h" #include "mozilla/MozPromise.h" #include "mozilla/Range.h" #include "mozilla/TimeStamp.h" +#include "mozilla/UniquePtr.h" #include "mozilla/VsyncDispatcher.h" #include "mozilla/webrender/webrender_ffi.h" #include "mozilla/webrender/WebRenderTypes.h" @@ -196,6 +199,8 @@ class TransactionBuilder final { void Clear(); + Transaction* Take(); + bool UseSceneBuilderThread() const { return mUseSceneBuilderThread; } layers::WebRenderBackend GetBackendType() { return mApiBackend; } Transaction* Raw() { return mTxn; } @@ -300,6 +305,11 @@ class WebRenderAPI final { RefPtr EndRecording(); + layers::RemoteTextureInfoList* GetPendingRemoteTextureInfoList(); + + void FlushPendingWrTransactionEventsWithoutWait(); + void FlushPendingWrTransactionEventsWithWait(); + protected: WebRenderAPI(wr::DocumentHandle* aHandle, wr::WindowId aId, layers::WebRenderBackend aBackend, @@ -313,6 +323,95 @@ class WebRenderAPI final { void WaitFlushed(); void UpdateDebugFlags(uint32_t aFlags); + bool CheckIsRemoteTextureReady(layers::RemoteTextureInfoList* aList); + void WaitRemoteTextureReady(layers::RemoteTextureInfoList* aList); + + enum class RemoteTextureWaitType : uint8_t { + AsyncWait = 0, + FlushWithWait = 1, + FlushWithoutWait = 2 + }; + + void HandleWrTransactionEvents(RemoteTextureWaitType aType); + + class WrTransactionEvent { + public: + enum class Tag { + Transaction, + PendingRemoteTextures, + }; + const Tag mTag; + + struct TransactionWrapper { + TransactionWrapper(wr::Transaction* aTxn, bool aUseSceneBuilderThread) + : mTxn(aTxn), mUseSceneBuilderThread(aUseSceneBuilderThread) {} + + ~TransactionWrapper() { + if (mTxn) { + wr_transaction_delete(mTxn); + } + } + + wr::Transaction* mTxn; + const bool mUseSceneBuilderThread; + }; + + private: + WrTransactionEvent(const Tag aTag, + UniquePtr&& aTransaction) + : mTag(aTag), mTransaction(std::move(aTransaction)) { + MOZ_ASSERT(mTag == Tag::Transaction); + } + WrTransactionEvent( + const Tag aTag, + UniquePtr&& aPendingRemoteTextures) + : mTag(aTag), + mPendingRemoteTextures(std::move(aPendingRemoteTextures)) { + MOZ_ASSERT(mTag == Tag::PendingRemoteTextures); + } + + UniquePtr mTransaction; + UniquePtr mPendingRemoteTextures; + + public: + static WrTransactionEvent Transaction(wr::Transaction* aTxn, + bool aUseSceneBuilderThread) { + auto transaction = + MakeUnique(aTxn, aUseSceneBuilderThread); + return WrTransactionEvent(Tag::Transaction, std::move(transaction)); + } + + static WrTransactionEvent PendingRemoteTextures( + UniquePtr&& aPendingRemoteTextures) { + return WrTransactionEvent(Tag::PendingRemoteTextures, + std::move(aPendingRemoteTextures)); + } + + wr::Transaction* Transaction() { + if (mTag == Tag::Transaction) { + return mTransaction->mTxn; + } + MOZ_ASSERT_UNREACHABLE("unexpected to be called"); + return nullptr; + } + + bool UseSceneBuilderThread() { + if (mTag == Tag::Transaction) { + return mTransaction->mUseSceneBuilderThread; + } + MOZ_ASSERT_UNREACHABLE("unexpected to be called"); + return true; + } + + layers::RemoteTextureInfoList* RemoteTextureInfoList() { + if (mTag == Tag::PendingRemoteTextures) { + MOZ_ASSERT(mPendingRemoteTextures); + return mPendingRemoteTextures.get(); + } + MOZ_ASSERT_UNREACHABLE("unexpected to be called"); + return nullptr; + } + }; wr::DocumentHandle* mDocHandle; wr::WindowId mId; @@ -327,6 +426,9 @@ class WebRenderAPI final { layers::SyncHandle mSyncHandle; bool mRendererDestroyed; + UniquePtr mPendingRemoteTextureInfoList; + std::queue mPendingWrTransactionEvents; + // We maintain alive the root api to know when to shut the render backend // down, and the root api for the document to know when to delete the // document. mRootApi is null for the api object that owns the channel (and is