/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
RefPtr<TextureHost> textureHost = RemoteTextureMap::CreateRemoteTexture(
aTextureData.get(), TextureFlags::DEFAULT); if (!textureHost) {
MOZ_ASSERT_UNREACHABLE("unexpected to be called"); return;
}
auto flags = TextureFlags::DEALLOCATE_CLIENT | TextureFlags::REMOTE_TEXTURE |
TextureFlags::DUMMY_TEXTURE; auto* rawData = BufferTextureData::Create(
gfx::IntSize(1, 1), gfx::SurfaceFormat::B8G8R8A8, gfx::BackendType::SKIA,
LayersBackend::LAYERS_WR, flags, ALLOC_DEFAULT, nullptr); if (!rawData) {
MOZ_ASSERT_UNREACHABLE("unexpected to be called"); return;
}
auto textureData = UniquePtr<TextureData>(rawData);
RefPtr<TextureHost> textureHost = RemoteTextureMap::CreateRemoteTexture(
textureData.get(), TextureFlags::DUMMY_TEXTURE); if (!textureHost) {
MOZ_ASSERT_UNREACHABLE("unexpected to be called"); return;
}
// Expire old textures so they don't sit in the list forever if unused.
constexpr size_t kSharedTextureLimit = 21;
constexpr size_t kTextureLimit = 7; while (aRecycleBin->mRecycledTextures.size() >=
(aRecycleBin->mIsShared ? kSharedTextureLimit : kTextureLimit)) { if (!aExpireOldTextures) { // There are too many textures, and we can't expire any to make room. returnfalse;
}
aRecycleBin->mRecycledTextures.pop_front();
}
TextureData::Info info;
aHolder.mTextureData->FillInfo(info);
RemoteTextureRecycleBin::RecycledTextureHolder recycled{info.size,
info.format}; if (aHolder.mResourceWrapper) { // Don't attempt to recycle non-recyclable shared surfaces if (aHolder.mResourceWrapper->mSharedSurface &&
!aHolder.mResourceWrapper->mSharedSurface->mDesc.canRecycle) { returnfalse;
}
std::vector<RefPtr<TextureHost>>
releasingTextures; // Release outside the monitor
std::vector<std::function<void(const RemoteTextureInfo&)>>
renderingReadyCallbacks; // Call outside the monitor
{
MonitorAutoLock lock(mMonitor);
auto* owner = GetTextureOwner(lock, aOwnerId, aForPid); if (!owner) {
MOZ_ASSERT_UNREACHABLE("unexpected to be called"); return;
}
if (owner->mIsContextLost &&
!(aTextureHost->GetFlags() & TextureFlags::DUMMY_TEXTURE)) {
MOZ_ASSERT_UNREACHABLE("unexpected to be called");
gfxCriticalNoteOnce << "Texture pushed during context lost";
}
auto textureData = MakeUnique<TextureDataHolder>(
aTextureId, aTextureHost, std::move(aTextureData),
std::move(aResourceWrapper));
{
GetRenderingReadyCallbacks(lock, owner, aTextureId,
renderingReadyCallbacks); // Update mRemoteTextureHost. // This happens when PushTexture() with RemoteTextureId is called after // GetRemoteTexture() with the RemoteTextureId. constauto key = std::pair(aForPid, aTextureId); auto it = mRemoteTextureHostWrapperHolders.find(key); if (it != mRemoteTextureHostWrapperHolders.end()) {
MOZ_ASSERT(!it->second->mRemoteTextureHost);
it->second->mRemoteTextureHost = aTextureHost;
}
}
// Drop obsoleted remote textures. while (!owner->mUsingTextureDataHolders.empty()) { auto& front = owner->mUsingTextureDataHolders.front(); // If mLatestRenderedTextureHost is last compositable ref of remote // texture's TextureHost, its RemoteTextureHostWrapper is already // unregistered. It happens when pushed remote textures that follow are // not rendered since last mLatestRenderedTextureHost update. In this // case, remove the TextureHost from mUsingTextureDataHolders. It is for // unblocking remote texture recyclieng. if (front->mTextureHost &&
front->mTextureHost->NumCompositableRefs() == 1 &&
front->mTextureHost == owner->mLatestRenderedTextureHost) {
owner->mUsingTextureDataHolders.pop_front(); continue;
} // When compositable ref of TextureHost becomes 0, the TextureHost is not // used by WebRender anymore. if (front->mTextureHost &&
front->mTextureHost->NumCompositableRefs() == 0) {
owner->mReleasingTextureDataHolders.push_back(std::move(front));
owner->mUsingTextureDataHolders.pop_front();
} elseif (front->mTextureHost &&
front->mTextureHost->NumCompositableRefs() >= 0) { // Remote texture is still in use by WebRender. break;
} else {
MOZ_ASSERT_UNREACHABLE("unexpected to be called");
owner->mUsingTextureDataHolders.pop_front();
}
} while (!owner->mReleasingTextureDataHolders.empty()) {
RecycleTexture(owner->mRecycleBin,
*owner->mReleasingTextureDataHolders.front(), true);
owner->mReleasingTextureDataHolders.pop_front();
}
}
constauto info = RemoteTextureInfo(aTextureId, aOwnerId, aForPid); for (auto& callback : renderingReadyCallbacks) {
callback(info);
}
}
for (auto it = owner->mWaitingTextureDataHolders.begin();
it != owner->mWaitingTextureDataHolders.end(); it++) { auto& data = *it; if (data->mTextureId == aTextureId) { if (mRemoteTextureHostWrapperHolders.find(std::pair(
aForPid, aTextureId)) != mRemoteTextureHostWrapperHolders.end()) { returnfalse;
} if (!RecycleTexture(owner->mRecycleBin, *data, false)) {
owner->mReleasingTextureDataHolders.push_back(std::move(data));
}
owner->mWaitingTextureDataHolders.erase(it); returntrue;
}
}
returnfalse;
}
void RemoteTextureMap::GetLatestBufferSnapshot( const RemoteTextureOwnerId aOwnerId, const base::ProcessId aForPid, 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
std::shared_ptr<webgpu::ExternalTexture> externalTexture;
{
MonitorAutoLock lock(mMonitor);
auto* owner = GetTextureOwner(lock, aOwnerId, aForPid); if (!owner) {
MOZ_ASSERT_UNREACHABLE("unexpected to be called"); return;
}
// Get latest TextureHost of remote Texture. if (owner->mWaitingTextureDataHolders.empty() &&
owner->mUsingTextureDataHolders.empty()) { return;
} constauto* holder = !owner->mWaitingTextureDataHolders.empty()
? owner->mWaitingTextureDataHolders.back().get()
: owner->mUsingTextureDataHolders.back().get();
TextureHost* textureHost = holder->mTextureHost;
if (textureHost->GetSize() != aSize) {
MOZ_ASSERT_UNREACHABLE("unexpected to be called"); return;
} if (textureHost->GetFormat() != gfx::SurfaceFormat::R8G8B8A8 &&
textureHost->GetFormat() != gfx::SurfaceFormat::B8G8R8A8) {
MOZ_ASSERT_UNREACHABLE("unexpected to be called"); return;
} if (holder->mResourceWrapper &&
holder->mResourceWrapper->mExternalTexture) { // Increment compositable ref to prevent that TextureDataHolder is removed // during memcpy.
textureHostRef = textureHost;
externalTexture = holder->mResourceWrapper->mExternalTexture;
} elseif (textureHost->AsBufferTextureHost()) { // Increment compositable ref to prevent that TextureDataHolder is removed // during memcpy.
textureHostRef = textureHost;
} else {
MOZ_ASSERT_UNREACHABLE("unexpected to be called"); return;
}
}
constauto key = std::pair(aForPid, aOwnerId); auto it = mTextureOwners.find(key); if (it != mTextureOwners.end()) {
MOZ_ASSERT_UNREACHABLE("unexpected to be called"); return;
} auto owner = MakeUnique<TextureOwner>(); if (aRecycleBin) {
owner->mRecycleBin = aRecycleBin;
} else {
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));
}
void RemoteTextureMap::KeepTextureDataAliveForTextureHostIfNecessary( const MonitorAutoLock& aProofOfLock, RemoteTextureMap::TextureOwner* aOwner,
std::deque<UniquePtr<TextureDataHolder>>& aHolders) { for (auto& holder : aHolders) { // If remote texture of TextureHost still exist, keep // SharedResourceWrapper/TextureData alive while the TextureHost is alive. if (holder->mTextureHost &&
holder->mTextureHost->NumCompositableRefs() > 0) {
RefPtr<nsISerialEventTarget> eventTarget = GetCurrentSerialEventTarget();
RefPtr<Runnable> runnable = NS_NewRunnableFunction( "RemoteTextureMap::UnregisterTextureOwner::Runnable",
[data = std::move(holder->mTextureData),
wrapper = std::move(holder->mResourceWrapper)]() {});
UniquePtr<RemoteTextureMap::TextureOwner>
RemoteTextureMap::UnregisterTextureOwner(
MonitorAutoLock& aProofOfLock, const RemoteTextureOwnerId aOwnerId, const base::ProcessId aForPid,
std::vector<RefPtr<TextureHost>>& aReleasingTextures,
std::vector<std::function<void(const RemoteTextureInfo&)>>&
aRenderingReadyCallbacks) { constauto key = std::pair(aForPid, aOwnerId); auto it = mTextureOwners.find(key); if (it == mTextureOwners.end()) {
MOZ_ASSERT_UNREACHABLE("unexpected to be called"); return nullptr;
}
auto* owner = it->second.get(); // If waiting for a last use, and it hasn't arrived yet, then defer // unregistering. if (owner->mWaitForTxn) {
owner->mDeferUnregister = GetCurrentSerialEventTarget(); // If another thread is waiting on this owner to produce textures, // it must be notified that owner is going away. if (!owner->mLatestTextureHost &&
owner->mWaitingTextureDataHolders.empty()) {
aProofOfLock.Notify();
} return nullptr;
}
if (owner->mLatestTextureHost) { // Release CompositableRef in mMonitor
aReleasingTextures.emplace_back(owner->mLatestTextureHost);
owner->mLatestTextureHost = nullptr;
}
// mReleasingRenderedTextureHosts and mLatestRenderedTextureHost could // simply be cleared. Since NumCompositableRefs() > 0 keeps TextureHosts in // mUsingTextureDataHolders alive. They need to be cleared before // KeepTextureDataAliveForTextureHostIfNecessary() call. The function uses // NumCompositableRefs(). if (!owner->mReleasingRenderedTextureHosts.empty()) {
std::transform(owner->mReleasingRenderedTextureHosts.begin(),
owner->mReleasingRenderedTextureHosts.end(),
std::back_inserter(aReleasingTextures),
[](CompositableTextureHostRef& aRef) { return aRef.get(); });
owner->mReleasingRenderedTextureHosts.clear();
} if (owner->mLatestRenderedTextureHost) {
owner->mLatestRenderedTextureHost = nullptr;
}
constauto key = std::pair(aForPid, aType); auto it = mTxnSchedulers.find(key); if (it == mTxnSchedulers.end()) {
MOZ_ASSERT_UNREACHABLE("Remote texture txn scheduler does not exist."); return;
}
mTxnSchedulers.erase(it);
}
already_AddRefed<RemoteTextureTxnScheduler> RemoteTextureTxnScheduler::Create(
mozilla::ipc::IProtocol* aProtocol) { if (auto* instance = RemoteTextureMap::Get()) { if (auto* toplevel = aProtocol->ToplevelProtocol()) { auto pid = toplevel->OtherPidMaybeInvalid(); if (pid != base::kInvalidProcessId) { return instance->RegisterTxnScheduler(pid, toplevel->GetProtocolId());
}
}
} return nullptr;
}
if (aRecycleBin) {
releasingTextures.splice(releasingTextures.end(),
aRecycleBin->mRecycledTextures);
}
for (constauto& id : aOwnerIds) { constauto key = std::pair(aForPid, id); auto it = mTextureOwners.find(key); if (it == mTextureOwners.end()) {
MOZ_ASSERT_UNREACHABLE("unexpected to be called"); continue;
} auto& owner = it->second;
if (aTextureId == aOwner->mLatestUsingTextureId) { // No need to update texture. return;
}
// Move remote textures to mUsingTextureDataHolders. while (!aOwner->mWaitingTextureDataHolders.empty()) { auto& front = aOwner->mWaitingTextureDataHolders.front(); if (aTextureId < front->mTextureId) { break;
}
MOZ_RELEASE_ASSERT(front->mTextureHost);
aOwner->mLatestTextureHost = front->mTextureHost;
aOwner->mLatestUsingTextureId = front->mTextureId;
UniquePtr<TextureDataHolder> holder = std::move(front);
aOwner->mWaitingTextureDataHolders.pop_front(); // If there are textures not being used by the compositor that will be // obsoleted by this new texture, then queue them for removal later on // the creating thread. while (!aOwner->mUsingTextureDataHolders.empty()) { auto& back = aOwner->mUsingTextureDataHolders.back(); if (back->mTextureHost &&
back->mTextureHost->NumCompositableRefs() == 0) { if (!RecycleTexture(aOwner->mRecycleBin, *back, false)) {
aOwner->mReleasingTextureDataHolders.push_back(std::move(back));
}
aOwner->mUsingTextureDataHolders.pop_back(); continue;
} break;
}
aOwner->mUsingTextureDataHolders.push_back(std::move(holder));
}
}
auto* owner = GetTextureOwner(lock, ownerId, forPid); // If there is no texture owner yet, then we might need to wait for one to // be created, if allowed. If so, we must also wait for an initial texture // host to be created so we can use it. if (!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. returnfalse;
}
CVStatus status = mMonitor.Wait(timeout); if (status == CVStatus::Timeout) { returnfalse;
}
owner = GetTextureOwner(lock, ownerId, forPid);
}
} returntrue;
}
// Update mRemoteTextureHost if (textureId == owner->mLatestUsingTextureId) { constauto key = std::pair(forPid, textureId); auto it = mRemoteTextureHostWrapperHolders.find(key); if (it != mRemoteTextureHostWrapperHolders.end() &&
!it->second->mRemoteTextureHost) {
it->second->mRemoteTextureHost = owner->mLatestTextureHost;
} else {
MOZ_ASSERT(it->second->mRemoteTextureHost == owner->mLatestTextureHost);
}
}
if (textureHost) {
aTextureHostWrapper->SetRemoteTextureHost(lock, textureHost);
aTextureHostWrapper->ApplyTextureFlagsToRemoteTexture();
}
}
}
void RemoteTextureMap::NotifyTxn(const MonitorAutoLock& aProofOfLock, const RemoteTextureOwnerId aOwnerId, const base::ProcessId aForPid) { if (auto* owner = GetTextureOwner(aProofOfLock, aOwnerId, aForPid)) { if (!owner->mWaitForTxn) {
MOZ_ASSERT_UNREACHABLE("Expected texture owner to wait for txn."); return;
}
owner->mWaitForTxn = false; if (!owner->mDeferUnregister) { // If unregistering was not deferred, then don't try to force // unregistering yet. return;
}
owner->mDeferUnregister->Dispatch(NS_NewRunnableFunction( "RemoteTextureMap::SetLastRemoteTextureUse::Runnable",
[aOwnerId, aForPid]() {
RemoteTextureMap::Get()->UnregisterTextureOwner(aOwnerId, aForPid);
}));
}
}
bool RemoteTextureMap::WaitForTxn(const RemoteTextureOwnerId aOwnerId, const base::ProcessId aForPid,
RemoteTextureTxnType aTxnType,
RemoteTextureTxnId aTxnId) {
MonitorAutoLock lock(mMonitor); if (auto* owner = GetTextureOwner(lock, aOwnerId, aForPid)) { if (owner->mDeferUnregister) {
MOZ_ASSERT_UNREACHABLE( "Texture owner must wait for txn before unregistering."); returnfalse;
} if (owner->mWaitForTxn) {
MOZ_ASSERT_UNREACHABLE("Texture owner already waiting for txn."); returnfalse;
} constauto key = std::pair(aForPid, aTxnType); auto it = mTxnSchedulers.find(key); if (it == mTxnSchedulers.end()) { // During shutdown, different toplevel protocols may go away in // disadvantageous orders, causing us to sometimes be processing // waits even though the source of transactions upon which the // wait depends shut down. This is generally harmless to ignore, // as it means no further transactions will be generated of that // type and all such transactions have been processed before it // unregistered.
NS_WARNING("Could not find scheduler for txn type."); returnfalse;
} if (it->second->WaitForTxn(lock, aOwnerId, aTxnId)) {
owner->mWaitForTxn = true;
} returntrue;
} returnfalse;
}
std::vector<RefPtr<TextureHost>>
releasingTextures; // Release outside the monitor
{
MonitorAutoLock lock(mMonitor);
constauto key = std::pair(aForPid, aTextureId); auto it = mRemoteTextureHostWrapperHolders.find(key); if (it == mRemoteTextureHostWrapperHolders.end()) {
MOZ_ASSERT_UNREACHABLE("unexpected to be called"); return;
}
releasingTextures.emplace_back(it->second->mRemoteTextureHostWrapper); if (it->second->mRemoteTextureHost) {
releasingTextures.emplace_back(it->second->mRemoteTextureHost);
}
auto callbackHolder = MakeUnique<RenderingReadyCallbackHolder>(
aInfo.mTextureId, std::move(aCallback));
waitingOwner->mRenderingReadyCallbackHolders.push_back(
std::move(callbackHolder));
returnfalse;
}
if (!owner || owner->mIsContextLost) { // Owner is already removed or context lost. No need to wait texture ready. returntrue;
}
constauto 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); returntrue;
}
if (owner->mLatestPushedTextureId >= aInfo.mTextureId) { returntrue;
}
auto callbackHolder = MakeUnique<RenderingReadyCallbackHolder>(
aInfo.mTextureId, std::move(aCallback));
owner->mRenderingReadyCallbackHolders.push_back(std::move(callbackHolder));
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. returnfalse;
}
CVStatus status = mMonitor.Wait(timeout); if (status == CVStatus::Timeout) { returnfalse;
}
owner = GetTextureOwner(lock, aInfo.mOwnerId, aInfo.mForPid);
}
}
if (!owner || owner->mIsContextLost) { // Owner is already removed or context lost. returnfalse;
}
constauto 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); returnfalse;
}
while (owner->mLatestPushedTextureId < aInfo.mTextureId) {
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); returnfalse;
}
auto it = mRemoteTextureHostWrapperHolders.find(key); if (it == mRemoteTextureHostWrapperHolders.end()) {
MOZ_ASSERT_UNREACHABLE("unexpected to be called"); returnfalse;
}
auto* owner = GetTextureOwner(lock, aInfo.mOwnerId, aInfo.mForPid); // When owner is alreay unregistered, remote texture will not be pushed. if (!owner || owner->mIsContextLost) { // This could happen with IPC abnormal shutdown returnfalse;
}
}
// Clear if WaitingTextureOwner exists. auto itWaiting =
mWaitingTextureOwners.find(std::pair(aInfo.mForPid, aInfo.mOwnerId)); if (itWaiting != mWaitingTextureOwners.end()) {
mWaitingTextureOwners.erase(itWaiting);
}
constauto key = std::pair(aInfo.mForPid, aInfo.mTextureId); auto it = mRemoteTextureHostWrapperHolders.find(key); if (it == mRemoteTextureHostWrapperHolders.end()) {
MOZ_ASSERT_UNREACHABLE("unexpected to be called"); return;
}
it->second->mReadyCheckSuppressed = true;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.