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
This commit is contained in:
sotaro 2023-04-18 20:38:20 +00:00
parent 6a18af4167
commit 62a86ac73d
13 changed files with 370 additions and 193 deletions

View File

@ -474,7 +474,8 @@ Maybe<layers::SurfaceDescriptor> 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.

View File

@ -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<TextureHost> releasingTexture; // Release outside the monitor
@ -835,7 +835,7 @@ void RemoteTextureMap::UnregisterRemoteTexturePushListener(
bool RemoteTextureMap::CheckRemoteTextureReady(
const RemoteTextureInfo& aInfo,
std::function<void(const RemoteTextureInfo&)>&& 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<TextureData> RemoteTextureMap::GetRecycledBufferTextureData(
const RemoteTextureOwnerId aOwnerId, const base::ProcessId aForPid,
gfx::IntSize aSize, gfx::SurfaceFormat aFormat) {

View File

@ -16,8 +16,9 @@
#include <unordered_set>
#include <utility>
#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<TextureData> 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<void(const RemoteTextureInfo&)>&& aCallback);
bool WaitRemoteTextureReady(const RemoteTextureInfo& aInfo);
UniquePtr<TextureData> GetRecycledBufferTextureData(
const RemoteTextureOwnerId aOwnerId, const base::ProcessId aForPid,
gfx::IntSize aSize, gfx::SurfaceFormat aFormat);

View File

@ -1901,6 +1901,26 @@ mozilla::ipc::IPCResult CompositorBridgeParent::RecvEndRecording(
return IPC_OK();
}
void CompositorBridgeParent::FlushPendingWrTransactionEventsWithWait() {
if (!mWrBridge) {
return;
}
std::vector<RefPtr<WebRenderBridgeParent>> 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<CompositionPayload>& aPayloads) {

View File

@ -506,6 +506,8 @@ class CompositorBridgeParent final : public CompositorBridgeParentBase,
WebRenderBridgeParent* GetWrBridge() { return mWrBridge; }
void FlushPendingWrTransactionEventsWithWait();
private:
void Initialize();

View File

@ -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<TextureHost::ResourceUpdateOp> AsyncImagePipelineManager::UpdateImageKeys(
const wr::Epoch& aEpoch, const wr::PipelineId& aPipelineId,
AsyncImagePipeline* aPipeline, nsTArray<wr::ImageKey>& aKeys,
wr::TransactionBuilder& aSceneBuilderTxn,
wr::TransactionBuilder& aMaybeFastTxn) {
wr::TransactionBuilder& aMaybeFastTxn, RemoteTextureInfoList* aList) {
MOZ_ASSERT(aKeys.IsEmpty());
MOZ_ASSERT(aPipeline);
@ -233,6 +232,13 @@ Maybe<TextureHost::ResourceUpdateOp> 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<wr::ImageKey> 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<RemoteTextureInfoList>
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<RemoteTextureInfoList>();
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<const wr::WebRenderPipelineInfo>&& aInfo,
ipc::FileDescriptor&& aFenceFd)

View File

@ -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<RemoteTextureInfoList> 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<TextureHost::ResourceUpdateOp> UpdateImageKeys(
const wr::Epoch& aEpoch, const wr::PipelineId& aPipelineId,
AsyncImagePipeline* aPipeline, nsTArray<wr::ImageKey>& aKeys,
wr::TransactionBuilder& aSceneBuilderTxn,
wr::TransactionBuilder& aMaybeFastTxn);
wr::TransactionBuilder& aMaybeFastTxn, RemoteTextureInfoList* aList);
Maybe<TextureHost::ResourceUpdateOp> UpdateWithoutExternalImage(
TextureHost* aTexture, wr::ImageKey aKey, TextureHost::ResourceUpdateOp,
wr::TransactionBuilder& aTxn);

View File

@ -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<RemoteTextureInfoList>&& 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<RemoteTextureInfoList> 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<SchedulePendingRemoteTextures>(
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<WebRenderBridgeParentRef>
WebRenderBridgeParent::GetWebRenderBridgeParentRef() {
if (mDestroyed) {

View File

@ -311,6 +311,8 @@ class WebRenderBridgeParent final : public PWebRenderBridgeParent,
RefPtr<WebRenderBridgeParentRef> GetWebRenderBridgeParentRef();
void FlushPendingWrTransactionEventsWithWait();
private:
class ScheduleSharedSurfaceRelease;

View File

@ -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<layers::RemoteTextureInfoList>&& 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<nsIRunnable> runnable = NewRunnableMethod<WrWindowId>(
"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<nsIRunnable> runnable = NewRunnableMethod<WrWindowId>(
"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();
}

View File

@ -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<layers::RemoteTextureInfoList>&& 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<layers::RemoteTextureInfoList>&& aPendingRemoteTextures)
: mTag(aTag),
mPendingRemoteTextures(std::move(aPendingRemoteTextures)) {
MOZ_ASSERT(mTag == Tag::PendingRemoteTextures);
}
const bool mCompositeNeeded = false;
const FramePublishId mPublishId = FramePublishId::INVALID;
UniquePtr<RendererEvent> mRendererEvent;
UniquePtr<layers::RemoteTextureInfoList> 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<layers::RemoteTextureInfoList>&& 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<nsIThread> aThread);
@ -442,8 +413,6 @@ class RenderThread final {
FramePublishId aPublishId);
void WrNotifierEvent_HandleExternalEvent(
wr::WindowId aWindowId, UniquePtr<RendererEvent> aRendererEvent);
bool CheckIsRemoteTextureReady(WrWindowId aWindowId,
layers::RemoteTextureInfoList* aList);
~RenderThread();
@ -478,7 +447,6 @@ class RenderThread final {
bool mIsDestroyed = false;
RefPtr<nsIRunnable> mWrNotifierEventsRunnable;
std::queue<WrNotifierEvent> mPendingWrNotifierEvents;
bool mIsWaitingRemoteTextureReady = false;
};
DataMutex<std::unordered_map<uint64_t, UniquePtr<WindowInfo>>> mWindowInfos;

View File

@ -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<layers::RemoteTextureInfoList>();
}
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<WebRenderAPI> self = this;
auto callback = [self](const layers::RemoteTextureInfo&) {
RefPtr<nsIRunnable> runnable = NewRunnableMethod<RemoteTextureWaitType>(
"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<WrHitResult> WebRenderAPI::HitTest(const wr::WorldPoint& aPoint) {
@ -733,6 +854,12 @@ RefPtr<WebRenderAPI::EndRecordingPromise> 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<NotificationHandler> aEvent) {
wr_transaction_notify(mTxn, aWhen,

View File

@ -7,6 +7,7 @@
#ifndef MOZILLA_LAYERS_WEBRENDERAPI_H
#define MOZILLA_LAYERS_WEBRENDERAPI_H
#include <queue>
#include <stdint.h>
#include <vector>
#include <unordered_map>
@ -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<EndRecordingPromise> 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<TransactionWrapper>&& aTransaction)
: mTag(aTag), mTransaction(std::move(aTransaction)) {
MOZ_ASSERT(mTag == Tag::Transaction);
}
WrTransactionEvent(
const Tag aTag,
UniquePtr<layers::RemoteTextureInfoList>&& aPendingRemoteTextures)
: mTag(aTag),
mPendingRemoteTextures(std::move(aPendingRemoteTextures)) {
MOZ_ASSERT(mTag == Tag::PendingRemoteTextures);
}
UniquePtr<TransactionWrapper> mTransaction;
UniquePtr<layers::RemoteTextureInfoList> mPendingRemoteTextures;
public:
static WrTransactionEvent Transaction(wr::Transaction* aTxn,
bool aUseSceneBuilderThread) {
auto transaction =
MakeUnique<TransactionWrapper>(aTxn, aUseSceneBuilderThread);
return WrTransactionEvent(Tag::Transaction, std::move(transaction));
}
static WrTransactionEvent PendingRemoteTextures(
UniquePtr<layers::RemoteTextureInfoList>&& 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<layers::RemoteTextureInfoList> mPendingRemoteTextureInfoList;
std::queue<WrTransactionEvent> 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