Bug 1863257 - Remove sync wait in compositor thread of main thread canvas by RemoteTextureMap::WaitForRemoteTextureOwner() r=gfx-reviewers,lsalzman

Calling RemoteTextureTxnScheduler::NotifyTxn() of main thread canvas is deferred to WebRenderAPI for waiting RemoteTextureOwner at WebRenderAPI.

When RemoteTextureOwner is not registered yet, WaitingTextureOwner is used to register the callback. WaitingTextureOwner is removed in RemoteTextureMap::SuppressRemoteTextureReadyCheck() when it still exists.

Removing sync wait of off main thread canvas is going to be handled by another bug.

Differential Revision: https://phabricator.services.mozilla.com/D209647
This commit is contained in:
sotaro 2024-05-20 00:29:19 +00:00
parent 92be045106
commit 268fa0828c
8 changed files with 158 additions and 69 deletions

View File

@ -574,6 +574,13 @@ void RemoteTextureMap::RegisterTextureOwner(
owner->mRecycleBin = new RemoteTextureRecycleBin(false);
}
auto itWaiting = mWaitingTextureOwners.find(key);
if (itWaiting != mWaitingTextureOwners.end()) {
owner->mRenderingReadyCallbackHolders.swap(
itWaiting->second->mRenderingReadyCallbackHolders);
mWaitingTextureOwners.erase(itWaiting);
}
mTextureOwners.emplace(key, std::move(owner));
}
@ -1002,14 +1009,13 @@ bool RemoteTextureMap::WaitForRemoteTextureOwner(
return true;
}
bool RemoteTextureMap::GetRemoteTexture(
RemoteTextureHostWrapper* aTextureHostWrapper,
std::function<void(const RemoteTextureInfo&)>&& aReadyCallback) {
void RemoteTextureMap::GetRemoteTexture(
RemoteTextureHostWrapper* aTextureHostWrapper) {
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
MOZ_ASSERT(aTextureHostWrapper);
if (aTextureHostWrapper->IsReadyForRendering()) {
return false;
return;
}
const auto& textureId = aTextureHostWrapper->mTextureId;
@ -1023,7 +1029,7 @@ bool RemoteTextureMap::GetRemoteTexture(
auto* owner = GetTextureOwner(lock, ownerId, forPid);
if (!owner) {
return false;
return;
}
UpdateTexture(lock, owner, textureId);
@ -1031,7 +1037,7 @@ bool RemoteTextureMap::GetRemoteTexture(
if (owner->mLatestTextureHost &&
(owner->mLatestTextureHost->GetFlags() & TextureFlags::DUMMY_TEXTURE)) {
// Remote texture allocation was failed.
return false;
return;
}
if (textureId == owner->mLatestUsingTextureId) {
@ -1043,14 +1049,6 @@ bool RemoteTextureMap::GetRemoteTexture(
<< " expected: " << size;
}
textureHost = owner->mLatestTextureHost;
} else {
if (aReadyCallback) {
auto callbackHolder = MakeUnique<RenderingReadyCallbackHolder>(
textureId, std::move(aReadyCallback));
owner->mRenderingReadyCallbackHolders.push_back(
std::move(callbackHolder));
return true;
}
}
// Update mRemoteTextureHost
@ -1070,8 +1068,6 @@ bool RemoteTextureMap::GetRemoteTexture(
aTextureHostWrapper->ApplyTextureFlagsToRemoteTexture();
}
}
return false;
}
void RemoteTextureMap::NotifyTxn(const MonitorAutoLock& aProofOfLock,
@ -1201,6 +1197,28 @@ bool RemoteTextureMap::CheckRemoteTextureReady(
MonitorAutoLock lock(mMonitor);
auto* owner = GetTextureOwner(lock, aInfo.mOwnerId, aInfo.mForPid);
if (aInfo.mWaitForRemoteTextureOwner && !owner) {
// Remote texture owner is not registered yet. Waiting for remote texture
// owner
const auto key = std::pair(aInfo.mForPid, aInfo.mOwnerId);
if (!mWaitingTextureOwners[key]) {
auto waitingOwner = MakeUnique<WaitingTextureOwner>();
mWaitingTextureOwners[key] = std::move(waitingOwner);
}
MOZ_ASSERT(mWaitingTextureOwners[key]);
WaitingTextureOwner* waitingOwner = mWaitingTextureOwners[key].get();
auto callbackHolder = MakeUnique<RenderingReadyCallbackHolder>(
aInfo.mTextureId, std::move(aCallback));
waitingOwner->mRenderingReadyCallbackHolders.push_back(
std::move(callbackHolder));
return false;
}
if (!owner || owner->mIsContextLost) {
// Owner is already removed or context lost. No need to wait texture ready.
return true;
@ -1232,6 +1250,24 @@ bool RemoteTextureMap::WaitRemoteTextureReady(const RemoteTextureInfo& aInfo) {
MonitorAutoLock lock(mMonitor);
auto* owner = GetTextureOwner(lock, aInfo.mOwnerId, aInfo.mForPid);
if (aInfo.mWaitForRemoteTextureOwner &&
(!owner || (!owner->mLatestTextureHost &&
owner->mWaitingTextureDataHolders.empty()))) {
const TimeDuration timeout = TimeDuration::FromMilliseconds(10000);
while (!owner || (!owner->mLatestTextureHost &&
owner->mWaitingTextureDataHolders.empty())) {
if (owner && (owner->mIsContextLost || owner->mDeferUnregister)) {
// If the context was lost, no further updates are expected.
return false;
}
CVStatus status = mMonitor.Wait(timeout);
if (status == CVStatus::Timeout) {
return false;
}
owner = GetTextureOwner(lock, aInfo.mOwnerId, aInfo.mForPid);
}
}
if (!owner || owner->mIsContextLost) {
// Owner is already removed or context lost.
return false;
@ -1275,11 +1311,18 @@ bool RemoteTextureMap::WaitRemoteTextureReady(const RemoteTextureInfo& aInfo) {
}
void RemoteTextureMap::SuppressRemoteTextureReadyCheck(
const RemoteTextureId aTextureId, const base::ProcessId aForPid) {
const RemoteTextureInfo& aInfo) {
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
MonitorAutoLock lock(mMonitor);
const auto key = std::pair(aForPid, aTextureId);
// Clear if WaitingTextureOwner exists.
auto itWaiting =
mWaitingTextureOwners.find(std::pair(aInfo.mForPid, aInfo.mOwnerId));
if (itWaiting != mWaitingTextureOwners.end()) {
mWaitingTextureOwners.erase(itWaiting);
}
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");

View File

@ -55,11 +55,24 @@ struct RemoteTextureInfo {
RemoteTextureInfo(const RemoteTextureId aTextureId,
const RemoteTextureOwnerId aOwnerId,
const base::ProcessId aForPid)
: mTextureId(aTextureId), mOwnerId(aOwnerId), mForPid(aForPid) {}
: mTextureId(aTextureId),
mOwnerId(aOwnerId),
mForPid(aForPid),
mWaitForRemoteTextureOwner(false) {}
RemoteTextureInfo(const RemoteTextureId aTextureId,
const RemoteTextureOwnerId aOwnerId,
const base::ProcessId aForPid,
const bool aWaitForRemoteTextureOwner)
: mTextureId(aTextureId),
mOwnerId(aOwnerId),
mForPid(aForPid),
mWaitForRemoteTextureOwner(aWaitForRemoteTextureOwner) {}
const RemoteTextureId mTextureId;
const RemoteTextureOwnerId mOwnerId;
const base::ProcessId mForPid;
const bool mWaitForRemoteTextureOwner;
};
struct RemoteTextureInfoList {
@ -307,11 +320,7 @@ class RemoteTextureMap {
bool WaitForRemoteTextureOwner(RemoteTextureHostWrapper* aTextureHostWrapper);
// Get remote texture's TextureHost for RemoteTextureHostWrapper.
//
// return true when aReadyCallback will be called.
bool GetRemoteTexture(
RemoteTextureHostWrapper* aTextureHostWrapper,
std::function<void(const RemoteTextureInfo&)>&& aReadyCallback);
void GetRemoteTexture(RemoteTextureHostWrapper* aTextureHostWrapper);
bool WaitForTxn(const RemoteTextureOwnerId aOwnerId,
const base::ProcessId aForPid, RemoteTextureTxnType aTxnType,
@ -334,8 +343,7 @@ class RemoteTextureMap {
bool WaitRemoteTextureReady(const RemoteTextureInfo& aInfo);
void SuppressRemoteTextureReadyCheck(const RemoteTextureId aTextureId,
const base::ProcessId aForPid);
void SuppressRemoteTextureReadyCheck(const RemoteTextureInfo& aInfo);
UniquePtr<TextureData> GetRecycledTextureData(
const RemoteTextureOwnerId aOwnerId, const base::ProcessId aForPid,
@ -387,6 +395,11 @@ class RemoteTextureMap {
std::function<void(const RemoteTextureInfo&)> mCallback;
};
struct WaitingTextureOwner {
std::deque<UniquePtr<RenderingReadyCallbackHolder>>
mRenderingReadyCallbackHolders;
};
struct TextureOwner {
bool mIsContextLost = false;
// Whether to wait for a transaction to complete before unregistering.
@ -467,6 +480,10 @@ class RemoteTextureMap {
Monitor mMonitor MOZ_UNANNOTATED;
std::map<std::pair<base::ProcessId, RemoteTextureOwnerId>,
UniquePtr<WaitingTextureOwner>>
mWaitingTextureOwners;
std::map<std::pair<base::ProcessId, RemoteTextureOwnerId>,
UniquePtr<TextureOwner>>
mTextureOwners;

View File

@ -7,6 +7,7 @@
#ifndef MOZILLA_GFX_RemoteTextureHostWrapper_H
#define MOZILLA_GFX_RemoteTextureHostWrapper_H
#include "mozilla/layers/RemoteTextureMap.h"
#include "mozilla/layers/TextureHost.h"
#include "mozilla/Monitor.h"
@ -80,6 +81,15 @@ class RemoteTextureHostWrapper : public TextureHost {
void ApplyTextureFlagsToRemoteTexture();
void EnableWaitForRemoteTextureOwner(bool aEnable) {
mWaitForRemoteTextureOwner = true;
}
RemoteTextureInfo GetRemoteTextureInfo() const {
return RemoteTextureInfo(mTextureId, mOwnerId, mForPid,
mWaitForRemoteTextureOwner);
}
const RemoteTextureId mTextureId;
const RemoteTextureOwnerId mOwnerId;
const base::ProcessId mForPid;
@ -108,6 +118,8 @@ class RemoteTextureHostWrapper : public TextureHost {
bool mRenderTextureCreated = false;
bool mWaitForRemoteTextureOwner = false;
friend class RemoteTextureMap;
};

View File

@ -228,8 +228,7 @@ Maybe<TextureHost::ResourceUpdateOp> AsyncImagePipelineManager::UpdateImageKeys(
auto* wrapper = aTexture ? aTexture->AsRemoteTextureHostWrapper() : nullptr;
if (wrapper && !aPipeline->mImageHost->GetAsyncRef()) {
std::function<void(const RemoteTextureInfo&)> function;
RemoteTextureMap::Get()->GetRemoteTexture(wrapper, std::move(function));
RemoteTextureMap::Get()->GetRemoteTexture(wrapper);
}
if (!aTexture || aTexture->NumSubTextures() == 0) {
@ -523,8 +522,7 @@ void AsyncImagePipelineManager::ApplyAsyncImageForPipeline(
// Store pending remote texture that is used for waiting at WebRenderAPI.
if (aPendingRemoteTextures && texture &&
texture != pipeline->mCurrentTexture && wrapper) {
aPendingRemoteTextures->mList.emplace(wrapper->mTextureId,
wrapper->mOwnerId, wrapper->mForPid);
aPendingRemoteTextures->mList.emplace(wrapper->GetRemoteTextureInfo());
}
if (aPendingOps && !pipeline->mImageHost->GetAsyncRef()) {

View File

@ -1120,7 +1120,8 @@ bool WebRenderBridgeParent::SetDisplayList(
bool WebRenderBridgeParent::ProcessDisplayListData(
DisplayListData& aDisplayList, wr::Epoch aWrEpoch,
const TimeStamp& aTxnStartTime, bool aValidTransaction) {
wr::TransactionBuilder txn(mApi);
wr::TransactionBuilder txn(mApi, /* aUseSceneBuilderThread */ true,
mRemoteTextureTxnScheduler, mFwdTransactionId);
Maybe<wr::AutoTransactionSender> sender;
if (aDisplayList.mScrollData && !aDisplayList.mScrollData->Validate()) {
@ -1239,10 +1240,6 @@ mozilla::ipc::IPCResult WebRenderBridgeParent::RecvSetDisplayList(
wr::IpcResourceUpdateQueue::ReleaseShmems(this, aDisplayList.mSmallShmems);
wr::IpcResourceUpdateQueue::ReleaseShmems(this, aDisplayList.mLargeShmems);
if (mRemoteTextureTxnScheduler) {
mRemoteTextureTxnScheduler->NotifyTxn(aFwdTransactionId);
}
if (!success) {
return IPC_FAIL(this, "Failed to process DisplayListData.");
}
@ -1253,7 +1250,8 @@ mozilla::ipc::IPCResult WebRenderBridgeParent::RecvSetDisplayList(
bool WebRenderBridgeParent::ProcessEmptyTransactionUpdates(
TransactionData& aData, bool* aScheduleComposite) {
*aScheduleComposite = false;
wr::TransactionBuilder txn(mApi);
wr::TransactionBuilder txn(mApi, /* aUseSceneBuilderThread */ true,
mRemoteTextureTxnScheduler, mFwdTransactionId);
txn.SetLowPriority(!IsRootWebRenderBridgeParent());
if (!aData.mScrollUpdates.IsEmpty()) {
@ -1395,10 +1393,6 @@ mozilla::ipc::IPCResult WebRenderBridgeParent::RecvEmptyTransaction(
aTransactionData->mLargeShmems);
}
if (mRemoteTextureTxnScheduler) {
mRemoteTextureTxnScheduler->NotifyTxn(aFwdTransactionId);
}
if (!success) {
return IPC_FAIL(this, "Failed to process empty transaction update.");
}

View File

@ -199,15 +199,17 @@ void WebRenderImageHost::UseRemoteTexture() {
while (!mPendingRemoteTextureWrappers.empty()) {
auto* wrapper =
mPendingRemoteTextureWrappers.front()->AsRemoteTextureHostWrapper();
if (mWaitForRemoteTextureOwner) {
// XXX remove sync wait
RemoteTextureMap::Get()->WaitForRemoteTextureOwner(wrapper);
}
mWaitingReadyCallback =
RemoteTextureMap::Get()->GetRemoteTexture(wrapper, readyCallback);
MOZ_ASSERT_IF(mWaitingReadyCallback, !wrapper->IsReadyForRendering());
if (!wrapper->IsReadyForRendering()) {
mWaitingReadyCallback = !RemoteTextureMap::Get()->CheckRemoteTextureReady(
wrapper->GetRemoteTextureInfo(), readyCallback);
if (mWaitingReadyCallback) {
break;
}
RemoteTextureMap::Get()->GetRemoteTexture(wrapper);
texture = mPendingRemoteTextureWrappers.front();
mPendingRemoteTextureWrappers.pop_front();
}
@ -218,7 +220,7 @@ void WebRenderImageHost::UseRemoteTexture() {
MOZ_ASSERT(mPendingRemoteTextureWrappers.empty());
if (mWaitForRemoteTextureOwner) {
RemoteTextureMap::Get()->WaitForRemoteTextureOwner(wrapper);
wrapper->EnableWaitForRemoteTextureOwner(true);
}
mWaitForRemoteTextureOwner = false;
}

View File

@ -213,18 +213,26 @@ class RemoveRenderer : public RendererEvent {
layers::SynchronousTask* mTask;
};
TransactionBuilder::TransactionBuilder(WebRenderAPI* aApi,
bool aUseSceneBuilderThread)
: mUseSceneBuilderThread(aUseSceneBuilderThread),
TransactionBuilder::TransactionBuilder(
WebRenderAPI* aApi, bool aUseSceneBuilderThread,
layers::RemoteTextureTxnScheduler* aRemoteTextureTxnScheduler,
layers::RemoteTextureTxnId aRemoteTextureTxnId)
: mRemoteTextureTxnScheduler(aRemoteTextureTxnScheduler),
mRemoteTextureTxnId(aRemoteTextureTxnId),
mUseSceneBuilderThread(aUseSceneBuilderThread),
mApiBackend(aApi->GetBackendType()),
mOwnsData(true) {
mTxn = wr_transaction_new(mUseSceneBuilderThread);
}
TransactionBuilder::TransactionBuilder(WebRenderAPI* aApi, Transaction* aTxn,
bool aUseSceneBuilderThread,
bool aOwnsData)
: mTxn(aTxn),
TransactionBuilder::TransactionBuilder(
WebRenderAPI* aApi, Transaction* aTxn, bool aUseSceneBuilderThread,
bool aOwnsData,
layers::RemoteTextureTxnScheduler* aRemoteTextureTxnScheduler,
layers::RemoteTextureTxnId aRemoteTextureTxnId)
: mRemoteTextureTxnScheduler(aRemoteTextureTxnScheduler),
mRemoteTextureTxnId(aRemoteTextureTxnId),
mTxn(aTxn),
mUseSceneBuilderThread(aUseSceneBuilderThread),
mApiBackend(aApi->GetBackendType()),
mOwnsData(aOwnsData) {}
@ -473,17 +481,19 @@ void WebRenderAPI::SendTransaction(TransactionBuilder& aTxn) {
!mPendingAsyncImagePipelineOps->mList.empty()) {
mPendingWrTransactionEvents.emplace(
WrTransactionEvent::PendingAsyncImagePipelineOps(
std::move(mPendingAsyncImagePipelineOps), this, aTxn.Raw(),
aTxn.UseSceneBuilderThread()));
std::move(mPendingAsyncImagePipelineOps), this, aTxn));
}
if (!mPendingWrTransactionEvents.empty()) {
mPendingWrTransactionEvents.emplace(WrTransactionEvent::Transaction(
this, aTxn.Take(), aTxn.UseSceneBuilderThread()));
mPendingWrTransactionEvents.emplace(
WrTransactionEvent::Transaction(this, aTxn));
HandleWrTransactionEvents(RemoteTextureWaitType::AsyncWait);
} else {
wr_api_send_transaction(mDocHandle, aTxn.Raw(),
aTxn.UseSceneBuilderThread());
if (aTxn.mRemoteTextureTxnScheduler) {
aTxn.mRemoteTextureTxnScheduler->NotifyTxn(aTxn.mRemoteTextureTxnId);
}
}
}
@ -598,6 +608,10 @@ void WebRenderAPI::HandleWrTransactionEvents(RemoteTextureWaitType aType) {
case WrTransactionEvent::Tag::Transaction:
wr_api_send_transaction(mDocHandle, front.RawTransaction(),
front.UseSceneBuilderThread());
if (front.GetTransactionBuilder()->mRemoteTextureTxnScheduler) {
front.GetTransactionBuilder()->mRemoteTextureTxnScheduler->NotifyTxn(
front.GetTransactionBuilder()->mRemoteTextureTxnId);
}
break;
case WrTransactionEvent::Tag::PendingRemoteTextures: {
bool isReady = true;
@ -612,7 +626,7 @@ void WebRenderAPI::HandleWrTransactionEvents(RemoteTextureWaitType aType) {
while (!list->mList.empty()) {
auto& front = list->mList.front();
layers::RemoteTextureMap::Get()->SuppressRemoteTextureReadyCheck(
front.mTextureId, front.mForPid);
front);
list->mList.pop();
}
}

View File

@ -103,11 +103,16 @@ struct WrHitResult {
class TransactionBuilder final {
public:
explicit TransactionBuilder(WebRenderAPI* aApi,
bool aUseSceneBuilderThread = true);
explicit TransactionBuilder(
WebRenderAPI* aApi, bool aUseSceneBuilderThread = true,
layers::RemoteTextureTxnScheduler* aRemoteTextureTxnScheduler = nullptr,
layers::RemoteTextureTxnId aRemoteTextureTxnId = 0);
TransactionBuilder(WebRenderAPI* aApi, Transaction* aTxn,
bool aUseSceneBuilderThread, bool aOwnsData);
TransactionBuilder(
WebRenderAPI* aApi, Transaction* aTxn, bool aUseSceneBuilderThread,
bool aOwnsData,
layers::RemoteTextureTxnScheduler* aRemoteTextureTxnScheduler,
layers::RemoteTextureTxnId aRemoteTextureTxnId);
~TransactionBuilder();
@ -207,7 +212,10 @@ class TransactionBuilder final {
bool UseSceneBuilderThread() const { return mUseSceneBuilderThread; }
layers::WebRenderBackend GetBackendType() { return mApiBackend; }
Transaction* Raw() { return mTxn; }
Transaction* Raw() const { return mTxn; }
const RefPtr<layers::RemoteTextureTxnScheduler> mRemoteTextureTxnScheduler;
const layers::RemoteTextureTxnId mRemoteTextureTxnId;
protected:
Transaction* mTxn;
@ -391,10 +399,10 @@ class WebRenderAPI final {
public:
static WrTransactionEvent Transaction(WebRenderAPI* aApi,
wr::Transaction* aTxn,
bool aUseSceneBuilderThread) {
TransactionBuilder& aTxn) {
auto transaction = MakeUnique<TransactionBuilder>(
aApi, aTxn, aUseSceneBuilderThread, /* aOwnsData */ true);
aApi, aTxn.Take(), aTxn.UseSceneBuilderThread(), /* aOwnsData */ true,
aTxn.mRemoteTextureTxnScheduler, aTxn.mRemoteTextureTxnId);
return WrTransactionEvent(Tag::Transaction, std::move(transaction));
}
@ -407,10 +415,10 @@ class WebRenderAPI final {
static WrTransactionEvent PendingAsyncImagePipelineOps(
UniquePtr<layers::AsyncImagePipelineOps>&&
aPendingAsyncImagePipelineOps,
WebRenderAPI* aApi, wr::Transaction* aTxn,
bool aUseSceneBuilderThread) {
WebRenderAPI* aApi, const TransactionBuilder& aTxn) {
auto transaction = MakeUnique<TransactionBuilder>(
aApi, aTxn, aUseSceneBuilderThread, /* aOwnsData */ false);
aApi, aTxn.Raw(), aTxn.UseSceneBuilderThread(), /* aOwnsData */ false,
aTxn.mRemoteTextureTxnScheduler, aTxn.mRemoteTextureTxnId);
return WrTransactionEvent(Tag::PendingAsyncImagePipelineOps,
std::move(aPendingAsyncImagePipelineOps),
std::move(transaction));
@ -425,7 +433,8 @@ class WebRenderAPI final {
}
TransactionBuilder* GetTransactionBuilder() {
if (mTag == Tag::PendingAsyncImagePipelineOps) {
if (mTag == Tag::Transaction ||
mTag == Tag::PendingAsyncImagePipelineOps) {
return mTransaction.get();
}
MOZ_CRASH("Should not be called");