diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
commit | 26a029d407be480d791972afb5975cf62c9360a6 (patch) | |
tree | f435a8308119effd964b339f76abb83a57c29483 /gfx/layers/RemoteTextureMap.cpp | |
parent | Initial commit. (diff) | |
download | firefox-upstream/124.0.1.tar.xz firefox-upstream/124.0.1.zip |
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'gfx/layers/RemoteTextureMap.cpp')
-rw-r--r-- | gfx/layers/RemoteTextureMap.cpp | 1380 |
1 files changed, 1380 insertions, 0 deletions
diff --git a/gfx/layers/RemoteTextureMap.cpp b/gfx/layers/RemoteTextureMap.cpp new file mode 100644 index 0000000000..fa0cfd33f5 --- /dev/null +++ b/gfx/layers/RemoteTextureMap.cpp @@ -0,0 +1,1380 @@ +/* -*- 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/. */ + +#include "mozilla/layers/RemoteTextureMap.h" + +#include <algorithm> +#include <vector> + +#include "CompositableHost.h" +#include "mozilla/ipc/ProtocolUtils.h" +#include "mozilla/gfx/gfxVars.h" +#include "mozilla/layers/AsyncImagePipelineManager.h" +#include "mozilla/layers/BufferTexture.h" +#include "mozilla/layers/CompositorThread.h" +#include "mozilla/layers/ImageDataSerializer.h" +#include "mozilla/layers/RemoteTextureHostWrapper.h" +#include "mozilla/layers/TextureClientSharedSurface.h" +#include "mozilla/layers/WebRenderTextureHost.h" +#include "mozilla/StaticPrefs_webgl.h" +#include "mozilla/webgpu/ExternalTexture.h" +#include "mozilla/webrender/RenderThread.h" +#include "SharedSurface.h" + +namespace mozilla::layers { + +RemoteTextureRecycleBin::RemoteTextureRecycleBin(bool aIsShared) + : mIsShared(aIsShared) {} + +RemoteTextureRecycleBin::~RemoteTextureRecycleBin() = default; + +RemoteTextureOwnerClient::RemoteTextureOwnerClient( + const base::ProcessId aForPid) + : mForPid(aForPid) {} + +RemoteTextureOwnerClient::~RemoteTextureOwnerClient() = default; + +bool RemoteTextureOwnerClient::IsRegistered( + const RemoteTextureOwnerId aOwnerId) { + auto it = mOwnerIds.find(aOwnerId); + if (it == mOwnerIds.end()) { + return false; + } + return true; +} + +void RemoteTextureOwnerClient::RegisterTextureOwner( + const RemoteTextureOwnerId aOwnerId, bool aSharedRecycling) { + MOZ_ASSERT(mOwnerIds.find(aOwnerId) == mOwnerIds.end()); + mOwnerIds.emplace(aOwnerId); + RefPtr<RemoteTextureRecycleBin> recycleBin; + if (aSharedRecycling) { + if (!mSharedRecycleBin) { + mSharedRecycleBin = new RemoteTextureRecycleBin(true); + } + recycleBin = mSharedRecycleBin; + } + RemoteTextureMap::Get()->RegisterTextureOwner(aOwnerId, mForPid, recycleBin); +} + +void RemoteTextureOwnerClient::UnregisterTextureOwner( + const RemoteTextureOwnerId aOwnerId) { + auto it = mOwnerIds.find(aOwnerId); + if (it == mOwnerIds.end()) { + return; + } + mOwnerIds.erase(it); + RemoteTextureMap::Get()->UnregisterTextureOwner(aOwnerId, mForPid); +} + +void RemoteTextureOwnerClient::UnregisterAllTextureOwners() { + if (mOwnerIds.empty()) { + return; + } + RemoteTextureMap::Get()->UnregisterTextureOwners(mOwnerIds, mForPid); + mOwnerIds.clear(); + mSharedRecycleBin = nullptr; +} + +bool RemoteTextureOwnerClient::WaitForTxn(const RemoteTextureOwnerId aOwnerId, + RemoteTextureTxnType aTxnType, + RemoteTextureTxnId aTxnId) { + auto it = mOwnerIds.find(aOwnerId); + if (it == mOwnerIds.end() || !aTxnType || !aTxnId) { + return false; + } + return RemoteTextureMap::Get()->WaitForTxn(aOwnerId, mForPid, aTxnType, + aTxnId); +} + +void RemoteTextureOwnerClient::ClearRecycledTextures() { + RemoteTextureMap::Get()->ClearRecycledTextures(mOwnerIds, mForPid, + mSharedRecycleBin); +} + +void RemoteTextureOwnerClient::NotifyContextLost( + const RemoteTextureOwnerIdSet* aOwnerIds) { + if (aOwnerIds) { + for (const auto& id : *aOwnerIds) { + if (mOwnerIds.find(id) == mOwnerIds.end()) { + MOZ_ASSERT_UNREACHABLE("owner id not registered by client"); + return; + } + } + } else { + aOwnerIds = &mOwnerIds; + } + if (aOwnerIds->empty()) { + return; + } + RemoteTextureMap::Get()->NotifyContextLost(*aOwnerIds, mForPid); +} + +void RemoteTextureOwnerClient::NotifyContextRestored( + const RemoteTextureOwnerIdSet* aOwnerIds) { + if (aOwnerIds) { + for (const auto& id : *aOwnerIds) { + if (mOwnerIds.find(id) == mOwnerIds.end()) { + MOZ_ASSERT_UNREACHABLE("owner id not registered by client"); + return; + } + } + } else { + aOwnerIds = &mOwnerIds; + } + if (aOwnerIds->empty()) { + return; + } + RemoteTextureMap::Get()->NotifyContextRestored(*aOwnerIds, mForPid); +} + +void RemoteTextureOwnerClient::PushTexture( + const RemoteTextureId aTextureId, const RemoteTextureOwnerId aOwnerId, + UniquePtr<TextureData>&& aTextureData) { + MOZ_ASSERT(IsRegistered(aOwnerId)); + + RefPtr<TextureHost> textureHost = RemoteTextureMap::CreateRemoteTexture( + aTextureData.get(), TextureFlags::DEFAULT); + if (!textureHost) { + MOZ_ASSERT_UNREACHABLE("unexpected to be called"); + return; + } + + RemoteTextureMap::Get()->PushTexture(aTextureId, aOwnerId, mForPid, + std::move(aTextureData), textureHost, + /* aResourceWrapper */ nullptr); +} + +void RemoteTextureOwnerClient::PushTexture( + const RemoteTextureId aTextureId, const RemoteTextureOwnerId aOwnerId, + const std::shared_ptr<gl::SharedSurface>& aSharedSurface, + const gfx::IntSize& aSize, gfx::SurfaceFormat aFormat, + const SurfaceDescriptor& aDesc) { + MOZ_ASSERT(IsRegistered(aOwnerId)); + + UniquePtr<TextureData> textureData = + MakeUnique<SharedSurfaceTextureData>(aDesc, aFormat, aSize); + RefPtr<TextureHost> textureHost = RemoteTextureMap::CreateRemoteTexture( + textureData.get(), TextureFlags::DEFAULT); + if (!textureHost) { + MOZ_ASSERT_UNREACHABLE("unexpected to be called"); + return; + } + + RemoteTextureMap::Get()->PushTexture( + aTextureId, aOwnerId, mForPid, std::move(textureData), textureHost, + SharedResourceWrapper::SharedSurface(aSharedSurface)); +} + +void RemoteTextureOwnerClient::PushTexture( + const RemoteTextureId aTextureId, const RemoteTextureOwnerId aOwnerId, + const std::shared_ptr<webgpu::ExternalTexture>& aExternalTexture, + const gfx::IntSize& aSize, gfx::SurfaceFormat aFormat, + const SurfaceDescriptor& aDesc) { + MOZ_ASSERT(IsRegistered(aOwnerId)); + + UniquePtr<TextureData> textureData = + MakeUnique<SharedSurfaceTextureData>(aDesc, aFormat, aSize); + RefPtr<TextureHost> textureHost = RemoteTextureMap::CreateRemoteTexture( + textureData.get(), TextureFlags::DEFAULT); + if (!textureHost) { + MOZ_ASSERT_UNREACHABLE("unexpected to be called"); + return; + } + + RemoteTextureMap::Get()->PushTexture( + aTextureId, aOwnerId, mForPid, std::move(textureData), textureHost, + SharedResourceWrapper::ExternalTexture(aExternalTexture)); +} + +void RemoteTextureOwnerClient::PushDummyTexture( + const RemoteTextureId aTextureId, const RemoteTextureOwnerId aOwnerId) { + MOZ_ASSERT(IsRegistered(aOwnerId)); + + 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; + } + + RemoteTextureMap::Get()->PushTexture(aTextureId, aOwnerId, mForPid, + std::move(textureData), textureHost, + /* aResourceWrapper */ nullptr); +} + +void RemoteTextureOwnerClient::GetLatestBufferSnapshot( + const RemoteTextureOwnerId aOwnerId, const mozilla::ipc::Shmem& aDestShmem, + const gfx::IntSize& aSize) { + MOZ_ASSERT(IsRegistered(aOwnerId)); + RemoteTextureMap::Get()->GetLatestBufferSnapshot(aOwnerId, mForPid, + aDestShmem, aSize); +} + +UniquePtr<TextureData> RemoteTextureOwnerClient::GetRecycledTextureData( + const gfx::IntSize& aSize, gfx::SurfaceFormat aFormat, + TextureType aTextureType, RemoteTextureOwnerId aOwnerId) { + return RemoteTextureMap::Get()->GetRecycledTextureData( + aOwnerId, mForPid, mSharedRecycleBin, aSize, aFormat, aTextureType); +} + +UniquePtr<TextureData> +RemoteTextureOwnerClient::CreateOrRecycleBufferTextureData( + const gfx::IntSize& aSize, gfx::SurfaceFormat aFormat, + RemoteTextureOwnerId aOwnerId) { + auto texture = + GetRecycledTextureData(aSize, aFormat, TextureType::Unknown, aOwnerId); + if (texture) { + return texture; + } + + auto flags = TextureFlags::DEALLOCATE_CLIENT | TextureFlags::REMOTE_TEXTURE; + auto* data = BufferTextureData::Create(aSize, aFormat, gfx::BackendType::SKIA, + LayersBackend::LAYERS_WR, flags, + ALLOC_DEFAULT, nullptr); + return UniquePtr<TextureData>(data); +} + +std::shared_ptr<gl::SharedSurface> +RemoteTextureOwnerClient::GetRecycledSharedSurface( + const gfx::IntSize& aSize, gfx::SurfaceFormat aFormat, + SurfaceDescriptor::Type aType, RemoteTextureOwnerId aOwnerId) { + UniquePtr<SharedResourceWrapper> wrapper = + RemoteTextureMap::Get()->RemoteTextureMap::GetRecycledSharedTexture( + aOwnerId, mForPid, mSharedRecycleBin, aSize, aFormat, aType); + if (!wrapper) { + return nullptr; + } + MOZ_ASSERT(wrapper->mSharedSurface); + return wrapper->mSharedSurface; +} + +std::shared_ptr<webgpu::ExternalTexture> +RemoteTextureOwnerClient::GetRecycledExternalTexture( + const gfx::IntSize& aSize, gfx::SurfaceFormat aFormat, + SurfaceDescriptor::Type aType, RemoteTextureOwnerId aOwnerId) { + UniquePtr<SharedResourceWrapper> wrapper = + RemoteTextureMap::Get()->RemoteTextureMap::GetRecycledSharedTexture( + aOwnerId, mForPid, mSharedRecycleBin, aSize, aFormat, aType); + if (!wrapper) { + return nullptr; + } + MOZ_ASSERT(wrapper->mExternalTexture); + return wrapper->mExternalTexture; +} + +StaticAutoPtr<RemoteTextureMap> RemoteTextureMap::sInstance; + +/* static */ +void RemoteTextureMap::Init() { + MOZ_ASSERT(!sInstance); + sInstance = new RemoteTextureMap(); +} + +/* static */ +void RemoteTextureMap::Shutdown() { + if (sInstance) { + sInstance = nullptr; + } +} + +RemoteTextureMap::RemoteTextureMap() : mMonitor("RemoteTextureMap::mMonitor") {} + +RemoteTextureMap::~RemoteTextureMap() = default; + +bool RemoteTextureMap::RecycleTexture( + const RefPtr<RemoteTextureRecycleBin>& aRecycleBin, + TextureDataHolder& aHolder, bool aExpireOldTextures) { + if (!aHolder.mTextureData || + (aHolder.mTextureHost && + aHolder.mTextureHost->GetFlags() & TextureFlags::DUMMY_TEXTURE)) { + return false; + } + + // 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. + return false; + } + aRecycleBin->mRecycledTextures.pop_front(); + } + + TextureData::Info info; + aHolder.mTextureData->FillInfo(info); + RemoteTextureRecycleBin::RecycledTextureHolder recycled{info.size, + info.format}; + if (aHolder.mResourceWrapper) { + // Recycle shared texture + SurfaceDescriptor desc; + if (!aHolder.mTextureData->Serialize(desc)) { + return false; + } + recycled.mType = desc.type(); + recycled.mResourceWrapper = std::move(aHolder.mResourceWrapper); + } else { + // Recycle texture data + recycled.mTextureData = std::move(aHolder.mTextureData); + } + aRecycleBin->mRecycledTextures.push_back(std::move(recycled)); + + return true; +} + +void RemoteTextureMap::PushTexture( + const RemoteTextureId aTextureId, const RemoteTextureOwnerId aOwnerId, + const base::ProcessId aForPid, UniquePtr<TextureData>&& aTextureData, + RefPtr<TextureHost>& aTextureHost, + UniquePtr<SharedResourceWrapper>&& aResourceWrapper) { + MOZ_RELEASE_ASSERT(aTextureHost); + + 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)); + + MOZ_ASSERT(owner->mLatestTextureId < aTextureId); + + owner->mWaitingTextureDataHolders.push_back(std::move(textureData)); + + { + GetRenderingReadyCallbacks(lock, owner, aTextureId, + renderingReadyCallbacks); + // Update mRemoteTextureHost. + // This happens when PushTexture() with RemoteTextureId is called after + // GetRemoteTexture() with the RemoteTextureId. + const auto key = std::pair(aForPid, aTextureId); + auto it = mRemoteTextureHostWrapperHolders.find(key); + if (it != mRemoteTextureHostWrapperHolders.end()) { + MOZ_ASSERT(!it->second->mRemoteTextureHost); + it->second->mRemoteTextureHost = aTextureHost; + } + } + + mMonitor.Notify(); + + // Release owner->mReleasingRenderedTextureHosts before checking + // NumCompositableRefs() + if (!owner->mReleasingRenderedTextureHosts.empty()) { + std::transform( + owner->mReleasingRenderedTextureHosts.begin(), + owner->mReleasingRenderedTextureHosts.end(), + std::back_inserter(releasingTextures), + [](CompositableTextureHostRef& aRef) { return aRef.get(); }); + owner->mReleasingRenderedTextureHosts.clear(); + } + + // 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(); + } else if (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(); + } + } + + const auto info = RemoteTextureInfo(aTextureId, aOwnerId, aForPid); + for (auto& callback : renderingReadyCallbacks) { + callback(info); + } +} + +bool RemoteTextureMap::RemoveTexture(const RemoteTextureId aTextureId, + const RemoteTextureOwnerId aOwnerId, + const base::ProcessId aForPid) { + MonitorAutoLock lock(mMonitor); + + auto* owner = GetTextureOwner(lock, aOwnerId, aForPid); + if (!owner) { + return false; + } + + 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()) { + return false; + } + if (!RecycleTexture(owner->mRecycleBin, *data, false)) { + owner->mReleasingTextureDataHolders.push_back(std::move(data)); + } + owner->mWaitingTextureDataHolders.erase(it); + return true; + } + } + + return false; +} + +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; + } + const auto* 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; + } else if (textureHost->AsBufferTextureHost()) { + // Increment compositable ref to prevent that TextureDataHolder is removed + // during memcpy. + textureHostRef = textureHost; + } else { + MOZ_ASSERT_UNREACHABLE("unexpected to be called"); + return; + } + } + + if (!textureHostRef) { + return; + } + + if (externalTexture) { + externalTexture->GetSnapshot(aDestShmem, aSize); + } else if (auto* bufferTextureHost = textureHostRef->AsBufferTextureHost()) { + uint32_t stride = ImageDataSerializer::ComputeRGBStride( + bufferTextureHost->GetFormat(), aSize.width); + uint32_t bufferSize = stride * aSize.height; + uint8_t* dst = aDestShmem.get<uint8_t>(); + uint8_t* src = bufferTextureHost->GetBuffer(); + + MOZ_ASSERT(bufferSize <= aDestShmem.Size<uint8_t>()); + memcpy(dst, src, bufferSize); + } + + { + MonitorAutoLock lock(mMonitor); + // Release compositable ref in mMonitor lock, but release RefPtr outside the + // monitor + releasingTexture = textureHostRef; + textureHostRef = nullptr; + } +} + +void RemoteTextureMap::RegisterTextureOwner( + const RemoteTextureOwnerId aOwnerId, const base::ProcessId aForPid, + const RefPtr<RemoteTextureRecycleBin>& aRecycleBin) { + MonitorAutoLock lock(mMonitor); + + const auto 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); + } + + 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)]() {}); + + auto destroyedCallback = [eventTarget = std::move(eventTarget), + runnable = std::move(runnable)]() mutable { + eventTarget->Dispatch(runnable.forget()); + }; + + holder->mTextureHost->SetDestroyedCallback(destroyedCallback); + } else { + RecycleTexture(aOwner->mRecycleBin, *holder, true); + } + } +} + +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) { + const auto 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; + } + + GetAllRenderingReadyCallbacks(aProofOfLock, owner, aRenderingReadyCallbacks); + + KeepTextureDataAliveForTextureHostIfNecessary( + aProofOfLock, owner, owner->mWaitingTextureDataHolders); + + KeepTextureDataAliveForTextureHostIfNecessary( + aProofOfLock, owner, owner->mUsingTextureDataHolders); + + KeepTextureDataAliveForTextureHostIfNecessary( + aProofOfLock, owner, owner->mReleasingTextureDataHolders); + + UniquePtr<TextureOwner> releasingOwner = std::move(it->second); + mTextureOwners.erase(it); + return releasingOwner; +} + +void RemoteTextureMap::UnregisterTextureOwner( + const RemoteTextureOwnerId aOwnerId, const base::ProcessId aForPid) { + UniquePtr<TextureOwner> releasingOwner; // Release outside the monitor + std::vector<RefPtr<TextureHost>> + releasingTextures; // Release outside the monitor + std::vector<std::function<void(const RemoteTextureInfo&)>> + renderingReadyCallbacks; // Call outside the monitor + { + MonitorAutoLock lock(mMonitor); + + releasingOwner = UnregisterTextureOwner( + lock, aOwnerId, aForPid, releasingTextures, renderingReadyCallbacks); + if (!releasingOwner) { + return; + } + + mMonitor.Notify(); + } + + const auto info = + RemoteTextureInfo(RemoteTextureId{0}, RemoteTextureOwnerId{0}, 0); + for (auto& callback : renderingReadyCallbacks) { + callback(info); + } +} + +void RemoteTextureMap::UnregisterTextureOwners( + const RemoteTextureOwnerIdSet& aOwnerIds, const base::ProcessId aForPid) { + std::vector<UniquePtr<TextureOwner>> + releasingOwners; // Release outside the monitor + std::vector<RefPtr<TextureHost>> + releasingTextures; // Release outside the monitor + std::vector<std::function<void(const RemoteTextureInfo&)>> + renderingReadyCallbacks; // Call outside the monitor + { + MonitorAutoLock lock(mMonitor); + + for (const auto& id : aOwnerIds) { + if (auto releasingOwner = UnregisterTextureOwner( + lock, id, aForPid, releasingTextures, renderingReadyCallbacks)) { + releasingOwners.push_back(std::move(releasingOwner)); + } + } + + if (releasingOwners.empty()) { + return; + } + + mMonitor.Notify(); + } + + const auto info = + RemoteTextureInfo(RemoteTextureId{0}, RemoteTextureOwnerId{0}, 0); + for (auto& callback : renderingReadyCallbacks) { + callback(info); + } +} + +already_AddRefed<RemoteTextureTxnScheduler> +RemoteTextureMap::RegisterTxnScheduler(base::ProcessId aForPid, + RemoteTextureTxnType aType) { + MonitorAutoLock lock(mMonitor); + + const auto key = std::pair(aForPid, aType); + auto it = mTxnSchedulers.find(key); + if (it != mTxnSchedulers.end()) { + return do_AddRef(it->second); + } + + RefPtr<RemoteTextureTxnScheduler> scheduler( + new RemoteTextureTxnScheduler(aForPid, aType)); + mTxnSchedulers.emplace(key, scheduler.get()); + return scheduler.forget(); +} + +void RemoteTextureMap::UnregisterTxnScheduler(base::ProcessId aForPid, + RemoteTextureTxnType aType) { + MonitorAutoLock lock(mMonitor); + + const auto 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; +} + +RemoteTextureTxnScheduler::~RemoteTextureTxnScheduler() { + NotifyTxn(std::numeric_limits<RemoteTextureTxnId>::max()); + RemoteTextureMap::Get()->UnregisterTxnScheduler(mForPid, mType); +} + +void RemoteTextureTxnScheduler::NotifyTxn(RemoteTextureTxnId aTxnId) { + MonitorAutoLock lock(RemoteTextureMap::Get()->mMonitor); + + mLastTxnId = aTxnId; + + for (; !mWaits.empty(); mWaits.pop_front()) { + auto& wait = mWaits.front(); + if (wait.mTxnId > aTxnId) { + break; + } + RemoteTextureMap::Get()->NotifyTxn(lock, wait.mOwnerId, mForPid); + } +} + +bool RemoteTextureTxnScheduler::WaitForTxn(const MonitorAutoLock& aProofOfLock, + RemoteTextureOwnerId aOwnerId, + RemoteTextureTxnId aTxnId) { + if (aTxnId <= mLastTxnId) { + return false; + } + mWaits.insert(std::upper_bound(mWaits.begin(), mWaits.end(), aTxnId), + Wait{aOwnerId, aTxnId}); + return true; +} + +void RemoteTextureMap::ClearRecycledTextures( + const RemoteTextureOwnerIdSet& aOwnerIds, const base::ProcessId aForPid, + const RefPtr<RemoteTextureRecycleBin>& aRecycleBin) { + std::list<RemoteTextureRecycleBin::RecycledTextureHolder> + releasingTextures; // Release outside the monitor + { + MonitorAutoLock lock(mMonitor); + + if (aRecycleBin) { + releasingTextures.splice(releasingTextures.end(), + aRecycleBin->mRecycledTextures); + } + + for (const auto& id : aOwnerIds) { + const auto 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; + + releasingTextures.splice(releasingTextures.end(), + owner->mRecycleBin->mRecycledTextures); + } + } +} + +void RemoteTextureMap::NotifyContextLost( + const RemoteTextureOwnerIdSet& aOwnerIds, const base::ProcessId aForPid) { + MonitorAutoLock lock(mMonitor); + + bool changed = false; + for (const auto& id : aOwnerIds) { + const auto 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 (!owner->mIsContextLost) { + owner->mIsContextLost = true; + changed = true; + } + } + + if (changed) { + mMonitor.Notify(); + } +} + +void RemoteTextureMap::NotifyContextRestored( + const RemoteTextureOwnerIdSet& aOwnerIds, const base::ProcessId aForPid) { + MonitorAutoLock lock(mMonitor); + + bool changed = false; + for (const auto& id : aOwnerIds) { + const auto 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 (owner->mIsContextLost) { + owner->mIsContextLost = false; + changed = true; + } + } + + if (changed) { + mMonitor.Notify(); + } +} + +/* static */ +RefPtr<TextureHost> RemoteTextureMap::CreateRemoteTexture( + TextureData* aTextureData, TextureFlags aTextureFlags) { + SurfaceDescriptor desc; + DebugOnly<bool> ret = aTextureData->Serialize(desc); + MOZ_ASSERT(ret); + TextureFlags flags = aTextureFlags | TextureFlags::REMOTE_TEXTURE | + TextureFlags::DEALLOCATE_CLIENT; + + Maybe<wr::ExternalImageId> externalImageId = Nothing(); + RefPtr<TextureHost> textureHost = + TextureHost::Create(desc, null_t(), nullptr, LayersBackend::LAYERS_WR, + flags, externalImageId); + MOZ_ASSERT(textureHost); + if (!textureHost) { + gfxCriticalNoteOnce << "Failed to create remote texture"; + return nullptr; + } + + textureHost->EnsureRenderTexture(Nothing()); + + return textureHost; +} + +void RemoteTextureMap::UpdateTexture(const MonitorAutoLock& aProofOfLock, + RemoteTextureMap::TextureOwner* aOwner, + const RemoteTextureId aTextureId) { + MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); + MOZ_ASSERT(aOwner); + MOZ_ASSERT(aTextureId >= aOwner->mLatestTextureId); + + if (aTextureId == aOwner->mLatestTextureId) { + // 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->mLatestTextureId = 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)); + } +} + +void RemoteTextureMap::GetRenderingReadyCallbacks( + const MonitorAutoLock& aProofOfLock, RemoteTextureMap::TextureOwner* aOwner, + const RemoteTextureId aTextureId, + std::vector<std::function<void(const RemoteTextureInfo&)>>& aFunctions) { + MOZ_ASSERT(aOwner); + + while (!aOwner->mRenderingReadyCallbackHolders.empty()) { + auto& front = aOwner->mRenderingReadyCallbackHolders.front(); + if (aTextureId < front->mTextureId) { + break; + } + if (front->mCallback) { + aFunctions.push_back(std::move(front->mCallback)); + } + aOwner->mRenderingReadyCallbackHolders.pop_front(); + } +} + +void RemoteTextureMap::GetAllRenderingReadyCallbacks( + const MonitorAutoLock& aProofOfLock, RemoteTextureMap::TextureOwner* aOwner, + std::vector<std::function<void(const RemoteTextureInfo&)>>& aFunctions) { + GetRenderingReadyCallbacks(aProofOfLock, aOwner, RemoteTextureId::Max(), + aFunctions); + MOZ_ASSERT(aOwner->mRenderingReadyCallbackHolders.empty()); +} + +bool RemoteTextureMap::GetRemoteTexture( + RemoteTextureHostWrapper* aTextureHostWrapper, + std::function<void(const RemoteTextureInfo&)>&& aReadyCallback, + bool aWaitForRemoteTextureOwner) { + MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); + MOZ_ASSERT(aTextureHostWrapper); + + if (aTextureHostWrapper->IsReadyForRendering()) { + return false; + } + + const auto& textureId = aTextureHostWrapper->mTextureId; + const auto& ownerId = aTextureHostWrapper->mOwnerId; + const auto& forPid = aTextureHostWrapper->mForPid; + const auto& size = aTextureHostWrapper->mSize; + + RefPtr<TextureHost> textureHost; + { + MonitorAutoLock lock(mMonitor); + + 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 || (aWaitForRemoteTextureOwner && !owner->mLatestTextureHost && + owner->mWaitingTextureDataHolders.empty())) { + if (!aWaitForRemoteTextureOwner) { + return false; + } + 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, ownerId, forPid); + } + } + + UpdateTexture(lock, owner, textureId); + + if (owner->mLatestTextureHost && + (owner->mLatestTextureHost->GetFlags() & TextureFlags::DUMMY_TEXTURE)) { + // Remote texture allocation was failed. + return false; + } + + if (textureId == owner->mLatestTextureId) { + MOZ_ASSERT(owner->mLatestTextureHost); + MOZ_ASSERT(owner->mLatestTextureHost->GetSize() == size); + if (owner->mLatestTextureHost->GetSize() != size) { + gfxCriticalNoteOnce << "unexpected remote texture size: " + << owner->mLatestTextureHost->GetSize() + << " 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 + if (textureId == owner->mLatestTextureId) { + const auto 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(); + } + } + + return false; +} + +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."); + return false; + } + if (owner->mWaitForTxn) { + MOZ_ASSERT_UNREACHABLE("Texture owner already waiting for txn."); + return false; + } + const auto 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."); + return false; + } + if (it->second->WaitForTxn(lock, aOwnerId, aTxnId)) { + owner->mWaitForTxn = true; + } + return true; + } + return false; +} + +void RemoteTextureMap::ReleaseRemoteTextureHost( + RemoteTextureHostWrapper* aTextureHostWrapper) { + MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); + MOZ_ASSERT(aTextureHostWrapper); + + RefPtr<TextureHost> releasingTexture; // Release outside the mutex + { + MonitorAutoLock lock(mMonitor); + releasingTexture = aTextureHostWrapper->GetRemoteTextureHost(lock); + aTextureHostWrapper->ClearRemoteTextureHost(lock); + } +} + +RefPtr<TextureHost> RemoteTextureMap::GetOrCreateRemoteTextureHostWrapper( + const RemoteTextureId aTextureId, const RemoteTextureOwnerId aOwnerId, + const base::ProcessId aForPid, const gfx::IntSize& aSize, + const TextureFlags aFlags) { + MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); + MonitorAutoLock lock(mMonitor); + + const auto key = std::pair(aForPid, aTextureId); + auto it = mRemoteTextureHostWrapperHolders.find(key); + if (it != mRemoteTextureHostWrapperHolders.end()) { + return it->second->mRemoteTextureHostWrapper; + } + + auto wrapper = RemoteTextureHostWrapper::Create(aTextureId, aOwnerId, aForPid, + aSize, aFlags); + auto wrapperHolder = MakeUnique<RemoteTextureHostWrapperHolder>(wrapper); + + mRemoteTextureHostWrapperHolders.emplace(key, std::move(wrapperHolder)); + + return wrapper; +} + +void RemoteTextureMap::UnregisterRemoteTextureHostWrapper( + const RemoteTextureId aTextureId, const RemoteTextureOwnerId aOwnerId, + const base::ProcessId aForPid) { + MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); + + std::vector<RefPtr<TextureHost>> + releasingTextures; // Release outside the monitor + { + MonitorAutoLock lock(mMonitor); + + const auto 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); + } + + mRemoteTextureHostWrapperHolders.erase(it); + mMonitor.Notify(); + } +} + +bool RemoteTextureMap::CheckRemoteTextureReady( + const RemoteTextureInfo& aInfo, + std::function<void(const RemoteTextureInfo&)>&& aCallback) { + MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); + + MonitorAutoLock lock(mMonitor); + + auto* owner = GetTextureOwner(lock, aInfo.mOwnerId, aInfo.mForPid); + if (!owner || owner->mIsContextLost) { + // Owner is already removed or context lost. No need to wait texture ready. + return true; + } + + 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 true; + } + + if (it->second->mRemoteTextureHost) { + return true; + } + MOZ_ASSERT(!it->second->mRemoteTextureHost); + + // Check if RemoteTextureId is as expected. + if (!owner->mRenderingReadyCallbackHolders.empty()) { + auto& front = owner->mRenderingReadyCallbackHolders.front(); + MOZ_RELEASE_ASSERT(aInfo.mTextureId >= front->mTextureId); + } + + auto callbackHolder = MakeUnique<RenderingReadyCallbackHolder>( + aInfo.mTextureId, std::move(aCallback)); + owner->mRenderingReadyCallbackHolders.push_back(std::move(callbackHolder)); + + 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->mIsContextLost) { + // Owner is already removed or context lost. + 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->mRemoteTextureHost; + + 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->mRemoteTextureHost; + if (!remoteTexture) { + 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 + return false; + } + } + } + + return true; +} + +void RemoteTextureMap::SuppressRemoteTextureReadyCheck( + const RemoteTextureId aTextureId, const base::ProcessId aForPid) { + MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); + MonitorAutoLock lock(mMonitor); + + const auto key = std::pair(aForPid, aTextureId); + auto it = mRemoteTextureHostWrapperHolders.find(key); + if (it == mRemoteTextureHostWrapperHolders.end()) { + MOZ_ASSERT_UNREACHABLE("unexpected to be called"); + return; + } + it->second->mReadyCheckSuppressed = true; +} + +UniquePtr<TextureData> RemoteTextureMap::GetRecycledTextureData( + const RemoteTextureOwnerId aOwnerId, const base::ProcessId aForPid, + const RefPtr<RemoteTextureRecycleBin>& aRecycleBin, + const gfx::IntSize& aSize, gfx::SurfaceFormat aFormat, + TextureType aTextureType) { + MonitorAutoLock lock(mMonitor); + + RefPtr<RemoteTextureRecycleBin> bin; + if (aOwnerId.IsValid()) { + if (auto* owner = GetTextureOwner(lock, aOwnerId, aForPid)) { + bin = owner->mRecycleBin; + } + } else { + bin = aRecycleBin; + } + if (!bin) { + return nullptr; + } + + for (auto it = bin->mRecycledTextures.begin(); + it != bin->mRecycledTextures.end(); it++) { + auto& holder = *it; + if (holder.mTextureData && + holder.mTextureData->GetTextureType() == aTextureType && + holder.mSize == aSize && holder.mFormat == aFormat) { + UniquePtr<TextureData> texture = std::move(holder.mTextureData); + bin->mRecycledTextures.erase(it); + return texture; + } + } + + return nullptr; +} + +UniquePtr<SharedResourceWrapper> RemoteTextureMap::GetRecycledSharedTexture( + const RemoteTextureOwnerId aOwnerId, const base::ProcessId aForPid, + const RefPtr<RemoteTextureRecycleBin>& aRecycleBin, + const gfx::IntSize& aSize, const gfx::SurfaceFormat aFormat, + SurfaceDescriptor::Type aType) { + MonitorAutoLock lock(mMonitor); + + RefPtr<RemoteTextureRecycleBin> bin; + if (aOwnerId.IsValid()) { + if (auto* owner = GetTextureOwner(lock, aOwnerId, aForPid)) { + bin = owner->mRecycleBin; + } + } else { + bin = aRecycleBin; + } + if (!bin) { + return nullptr; + } + + for (auto it = bin->mRecycledTextures.begin(); + it != bin->mRecycledTextures.end(); it++) { + auto& holder = *it; + if (holder.mType == aType && holder.mSize == aSize && + holder.mFormat == aFormat) { + UniquePtr<SharedResourceWrapper> wrapper = + std::move(holder.mResourceWrapper); + bin->mRecycledTextures.erase(it); + return wrapper; + } + } + + return nullptr; +} + +RemoteTextureMap::TextureOwner* RemoteTextureMap::GetTextureOwner( + const MonitorAutoLock& aProofOfLock, const RemoteTextureOwnerId aOwnerId, + const base::ProcessId aForPid) { + const auto key = std::pair(aForPid, aOwnerId); + auto it = mTextureOwners.find(key); + if (it == mTextureOwners.end()) { + return nullptr; + } + return it->second.get(); +} + +RemoteTextureMap::TextureDataHolder::TextureDataHolder( + const RemoteTextureId aTextureId, RefPtr<TextureHost> aTextureHost, + UniquePtr<TextureData>&& aTextureData, + UniquePtr<SharedResourceWrapper>&& aResourceWrapper) + : mTextureId(aTextureId), + mTextureHost(aTextureHost), + mTextureData(std::move(aTextureData)), + mResourceWrapper(std::move(aResourceWrapper)) {} + +RemoteTextureMap::RenderingReadyCallbackHolder::RenderingReadyCallbackHolder( + const RemoteTextureId aTextureId, + std::function<void(const RemoteTextureInfo&)>&& aCallback) + : mTextureId(aTextureId), mCallback(aCallback) {} + +RemoteTextureMap::RemoteTextureHostWrapperHolder:: + RemoteTextureHostWrapperHolder( + RefPtr<TextureHost> aRemoteTextureHostWrapper) + : mRemoteTextureHostWrapper(aRemoteTextureHostWrapper) {} + +} // namespace mozilla::layers |