summaryrefslogtreecommitdiffstats
path: root/gfx/layers/RemoteTextureMap.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--gfx/layers/RemoteTextureMap.cpp1028
1 files changed, 1028 insertions, 0 deletions
diff --git a/gfx/layers/RemoteTextureMap.cpp b/gfx/layers/RemoteTextureMap.cpp
new file mode 100644
index 0000000000..cbaefe692d
--- /dev/null
+++ b/gfx/layers/RemoteTextureMap.cpp
@@ -0,0 +1,1028 @@
+/* -*- 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 <vector>
+
+#include "CompositableHost.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/WebRenderTextureHost.h"
+#include "mozilla/StaticPrefs_webgl.h"
+#include "mozilla/webrender/RenderThread.h"
+#include "SharedSurface.h"
+
+namespace mozilla::layers {
+
+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 aIsSyncMode) {
+ MOZ_ASSERT(mOwnerIds.find(aOwnerId) == mOwnerIds.end());
+ mOwnerIds.emplace(aOwnerId);
+ RemoteTextureMap::Get()->RegisterTextureOwner(aOwnerId, mForPid, aIsSyncMode);
+}
+
+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()) {
+ RemoteTextureMap::Get()->UnregisterTextureOwners(mOwnerIds, mForPid);
+ mOwnerIds.clear();
+ }
+}
+
+void RemoteTextureOwnerClient::PushTexture(
+ const RemoteTextureId aTextureId, const RemoteTextureOwnerId aOwnerId,
+ UniquePtr<TextureData>&& aTextureData,
+ const std::shared_ptr<gl::SharedSurface>& aSharedSurface) {
+ 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,
+ aSharedSurface);
+}
+
+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,
+ /* aSharedSurface */ 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::CreateOrRecycleBufferTextureData(
+ const RemoteTextureOwnerId aOwnerId, gfx::IntSize aSize,
+ gfx::SurfaceFormat aFormat) {
+ auto texture = RemoteTextureMap::Get()->GetRecycledBufferTextureData(
+ aOwnerId, mForPid, aSize, aFormat);
+ 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 RemoteTextureOwnerId aOwnerId) {
+ return RemoteTextureMap::Get()->RemoteTextureMap::GetRecycledSharedSurface(
+ aOwnerId, mForPid);
+}
+
+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("D3D11TextureMap::mMonitor") {}
+
+RemoteTextureMap::~RemoteTextureMap() = default;
+
+void RemoteTextureMap::PushTexture(
+ const RemoteTextureId aTextureId, const RemoteTextureOwnerId aOwnerId,
+ const base::ProcessId aForPid, UniquePtr<TextureData>&& aTextureData,
+ RefPtr<TextureHost>& aTextureHost,
+ const std::shared_ptr<gl::SharedSurface>& aSharedSurface) {
+ MOZ_RELEASE_ASSERT(aTextureHost);
+
+ 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;
+ }
+
+ const auto key = std::pair(aForPid, aOwnerId);
+ auto it = mRemoteTexturePushListeners.find(key);
+ // Notify a new texture if callback is requested
+ if (it != mRemoteTexturePushListeners.end()) {
+ RefPtr<CompositableHost> compositableHost = it->second;
+ RefPtr<Runnable> runnable = NS_NewRunnableFunction(
+ "RemoteTextureMap::PushTexture::Runnable",
+ [compositableHost, aTextureId, aOwnerId, aForPid]() {
+ compositableHost->NotifyPushTexture(aTextureId, aOwnerId, aForPid);
+ });
+ CompositorThread()->Dispatch(runnable.forget());
+ }
+
+ auto textureData = MakeUnique<TextureDataHolder>(
+ aTextureId, aTextureHost, std::move(aTextureData), aSharedSurface);
+
+ MOZ_ASSERT(owner->mLatestTextureId < aTextureId);
+
+ owner->mWaitingTextureDataHolders.push_back(std::move(textureData));
+
+ if (!owner->mIsSyncMode) {
+ renderingReadyCallbacks =
+ GetRenderingReadyCallbacks(lock, owner, aTextureId);
+ // Update mAsyncRemoteTextureHost for async mode.
+ // This happens when PushTexture() with RemoteTextureId is called after
+ // GetRemoteTextureForDisplayList() with the RemoteTextureId.
+ const auto key = std::pair(aForPid, aTextureId);
+ auto it = mRemoteTextureHostWrapperHolders.find(key);
+ if (it != mRemoteTextureHostWrapperHolders.end()) {
+ MOZ_ASSERT(!it->second->mAsyncRemoteTextureHost);
+ it->second->mAsyncRemoteTextureHost = aTextureHost;
+ }
+ }
+
+ mMonitor.Notify();
+
+ // Drop obsoleted remote textures.
+ while (!owner->mUsingTextureDataHolders.empty()) {
+ auto& front = owner->mUsingTextureDataHolders.front();
+ // When compositable ref of TextureHost becomes 0, the TextureHost is not
+ // used by WebRender anymore.
+ if (front->mTextureHost &&
+ front->mTextureHost->NumCompositableRefs() == 0) {
+ // Recycle gl::SharedSurface
+ if (front->mSharedSurface) {
+ owner->mRecycledSharedSurfaces.push(front->mSharedSurface);
+ front->mSharedSurface = nullptr;
+ }
+ // Recycle BufferTextureData
+ if (!(front->mTextureHost->GetFlags() & TextureFlags::DUMMY_TEXTURE) &&
+ (front->mTextureData &&
+ front->mTextureData->AsBufferTextureData())) {
+ owner->mRecycledTextures.push(std::move(front->mTextureData));
+ }
+ 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();
+ }
+ }
+ }
+
+ const auto info = RemoteTextureInfo(aTextureId, aOwnerId, aForPid);
+ for (auto& callback : renderingReadyCallbacks) {
+ callback(info);
+ }
+}
+
+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
+ {
+ 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->mLatestTextureHost) {
+ return;
+ }
+ TextureHost* textureHost =
+ !owner->mWaitingTextureDataHolders.empty()
+ ? owner->mWaitingTextureDataHolders.back()->mTextureHost
+ : owner->mLatestTextureHost;
+ if (!textureHost->AsBufferTextureHost()) {
+ // Only BufferTextureHost is supported for now.
+ MOZ_ASSERT_UNREACHABLE("unexpected to be called");
+ return;
+ }
+ 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;
+ }
+ // Increment compositable ref to prevent that TextureHost is removed during
+ // memcpy.
+ textureHostRef = textureHost;
+ }
+
+ if (!textureHostRef) {
+ return;
+ }
+
+ auto* bufferTextureHost = textureHostRef->AsBufferTextureHost();
+ if (bufferTextureHost) {
+ 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,
+ bool aIsSyncMode) {
+ 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>();
+ owner->mIsSyncMode = aIsSyncMode;
+
+ mTextureOwners.emplace(key, std::move(owner));
+}
+
+void RemoteTextureMap::KeepTextureDataAliveForTextureHostIfNecessary(
+ const MonitorAutoLock& aProofOfLock,
+ std::deque<UniquePtr<TextureDataHolder>>& aHolders) {
+ for (auto& holder : aHolders) {
+ // If remote texture of TextureHost still exist, keep
+ // gl::SharedSurface/TextureData alive while the TextureHost is alive.
+ if (holder->mTextureHost &&
+ holder->mTextureHost->NumCompositableRefs() >= 0) {
+ RefPtr<nsISerialEventTarget> eventTarget =
+ MessageLoop::current()->SerialEventTarget();
+ RefPtr<Runnable> runnable = NS_NewRunnableFunction(
+ "RemoteTextureMap::UnregisterTextureOwner::Runnable",
+ [data = std::move(holder->mTextureData),
+ surface = std::move(holder->mSharedSurface)]() {});
+
+ auto destroyedCallback = [eventTarget = std::move(eventTarget),
+ runnable = std::move(runnable)]() mutable {
+ eventTarget->Dispatch(runnable.forget());
+ };
+
+ holder->mTextureHost->SetDestroyedCallback(destroyedCallback);
+ }
+ }
+}
+
+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);
+
+ const auto key = std::pair(aForPid, aOwnerId);
+ auto it = mTextureOwners.find(key);
+ if (it == mTextureOwners.end()) {
+ MOZ_ASSERT_UNREACHABLE("unexpected to be called");
+ return;
+ }
+
+ if (it->second->mLatestTextureHost) {
+ // Release CompositableRef in mMonitor
+ releasingTextures.emplace_back(it->second->mLatestTextureHost);
+ it->second->mLatestTextureHost = nullptr;
+ }
+
+ if (it->second->mLatestRenderedTextureHost) {
+ // Release CompositableRef in mMonitor
+ releasingTextures.emplace_back(it->second->mLatestRenderedTextureHost);
+ it->second->mLatestRenderedTextureHost = nullptr;
+ }
+
+ renderingReadyCallbacks =
+ GetAllRenderingReadyCallbacks(lock, it->second.get());
+
+ KeepTextureDataAliveForTextureHostIfNecessary(
+ lock, it->second->mWaitingTextureDataHolders);
+
+ KeepTextureDataAliveForTextureHostIfNecessary(
+ lock, it->second->mUsingTextureDataHolders);
+
+ releasingOwner = std::move(it->second);
+ mTextureOwners.erase(it);
+
+ mMonitor.Notify();
+ }
+
+ const auto info =
+ RemoteTextureInfo(RemoteTextureId{0}, RemoteTextureOwnerId{0}, 0);
+ for (auto& callback : renderingReadyCallbacks) {
+ callback(info);
+ }
+}
+
+void RemoteTextureMap::UnregisterTextureOwners(
+ const std::unordered_set<RemoteTextureOwnerId,
+ RemoteTextureOwnerId::HashFn>& 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 (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;
+ }
+
+ if (it->second->mLatestTextureHost) {
+ // Release CompositableRef in mMonitor
+ releasingTextures.emplace_back(it->second->mLatestTextureHost);
+ it->second->mLatestTextureHost = nullptr;
+ }
+
+ if (it->second->mLatestRenderedTextureHost) {
+ // Release CompositableRef in mMonitor
+ releasingTextures.emplace_back(it->second->mLatestRenderedTextureHost);
+ it->second->mLatestRenderedTextureHost = nullptr;
+ }
+
+ renderingReadyCallbacks =
+ GetAllRenderingReadyCallbacks(lock, it->second.get());
+
+ KeepTextureDataAliveForTextureHostIfNecessary(
+ lock, it->second->mWaitingTextureDataHolders);
+
+ KeepTextureDataAliveForTextureHostIfNecessary(
+ lock, it->second->mUsingTextureDataHolders);
+
+ releasingOwners.push_back(std::move(it->second));
+ mTextureOwners.erase(it);
+ }
+
+ mMonitor.Notify();
+ }
+
+ const auto info =
+ RemoteTextureInfo(RemoteTextureId{0}, RemoteTextureOwnerId{0}, 0);
+ for (auto& callback : renderingReadyCallbacks) {
+ callback(info);
+ }
+}
+
+/* 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();
+ aOwner->mUsingTextureDataHolders.push_back(std::move(holder));
+ }
+}
+
+std::vector<std::function<void(const RemoteTextureInfo&)>>
+RemoteTextureMap::GetRenderingReadyCallbacks(
+ const MonitorAutoLock& aProofOfLock, RemoteTextureMap::TextureOwner* aOwner,
+ const RemoteTextureId aTextureId) {
+ MOZ_ASSERT(aOwner);
+
+ std::vector<std::function<void(const RemoteTextureInfo&)>> functions;
+
+ while (!aOwner->mRenderingReadyCallbackHolders.empty()) {
+ auto& front = aOwner->mRenderingReadyCallbackHolders.front();
+ if (aTextureId < front->mTextureId) {
+ break;
+ }
+ if (front->mCallback) {
+ functions.push_back(std::move(front->mCallback));
+ }
+ aOwner->mRenderingReadyCallbackHolders.pop_front();
+ }
+
+ return functions;
+}
+
+std::vector<std::function<void(const RemoteTextureInfo&)>>
+RemoteTextureMap::GetAllRenderingReadyCallbacks(
+ const MonitorAutoLock& aProofOfLock,
+ RemoteTextureMap::TextureOwner* aOwner) {
+ auto functions =
+ GetRenderingReadyCallbacks(aProofOfLock, aOwner, RemoteTextureId::Max());
+ MOZ_ASSERT(aOwner->mRenderingReadyCallbackHolders.empty());
+
+ return functions;
+}
+
+bool RemoteTextureMap::GetRemoteTextureForDisplayList(
+ RemoteTextureHostWrapper* aTextureHostWrapper,
+ std::function<void(const RemoteTextureInfo&)>&& aReadyCallback) {
+ 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 (!owner) {
+ return false;
+ }
+
+ UpdateTexture(lock, owner, textureId);
+
+ if (owner->mLatestTextureHost &&
+ (owner->mLatestTextureHost->GetFlags() & TextureFlags::DUMMY_TEXTURE)) {
+ // Remote texture allocation was failed.
+ return false;
+ }
+
+ bool syncMode = owner->mIsSyncMode || bool(aReadyCallback);
+
+ if (syncMode) {
+ // remote texture sync ipc
+ 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;
+ } else {
+ MOZ_ASSERT_UNREACHABLE("unexpected to be called");
+ }
+ }
+ } else {
+ // remote texture async ipc
+ if (owner->mLatestTextureHost) {
+ if (owner->mLatestTextureHost->GetSize() == size) {
+ textureHost = owner->mLatestTextureHost;
+ } else {
+ gfxCriticalNoteOnce << "unexpected remote texture size: "
+ << owner->mLatestTextureHost->GetSize()
+ << " expected: " << size;
+ MOZ_ASSERT_UNREACHABLE("unexpected to be called");
+ }
+ } else {
+ gfxCriticalNoteOnce << "remote texture does not exist";
+ MOZ_ASSERT_UNREACHABLE("unexpected to be called");
+ }
+
+ // Update mAsyncRemoteTextureHost for async mode
+ if (textureId == owner->mLatestTextureId) {
+ const auto key = std::pair(forPid, textureId);
+ auto it = mRemoteTextureHostWrapperHolders.find(key);
+ if (it != mRemoteTextureHostWrapperHolders.end() &&
+ !it->second->mAsyncRemoteTextureHost) {
+ it->second->mAsyncRemoteTextureHost = owner->mLatestTextureHost;
+ } else {
+ MOZ_ASSERT(it->second->mAsyncRemoteTextureHost ==
+ owner->mLatestTextureHost);
+ }
+ }
+ }
+
+ if (textureHost) {
+ aTextureHostWrapper->SetRemoteTextureHostForDisplayList(lock, textureHost,
+ syncMode);
+ aTextureHostWrapper->ApplyTextureFlagsToRemoteTexture();
+ }
+ }
+
+ return false;
+}
+
+wr::MaybeExternalImageId RemoteTextureMap::GetExternalImageIdOfRemoteTexture(
+ const RemoteTextureId aTextureId, const RemoteTextureOwnerId aOwnerId,
+ const base::ProcessId aForPid) {
+ MOZ_ASSERT(wr::RenderThread::IsInRenderThread());
+ 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 Nothing();
+ }
+
+ TextureHost* remoteTexture = it->second->mAsyncRemoteTextureHost;
+
+ auto* owner = GetTextureOwner(lock, aOwnerId, aForPid);
+ if (!owner) {
+ if (!remoteTexture) {
+ // This could happen with IPC abnormal shutdown
+ return Nothing();
+ }
+ return remoteTexture->GetMaybeExternalImageId();
+ }
+
+ if (remoteTexture &&
+ remoteTexture->GetFlags() & TextureFlags::DUMMY_TEXTURE) {
+ // Remote texture allocation was failed.
+ return Nothing();
+ }
+ MOZ_ASSERT(!(remoteTexture &&
+ remoteTexture->GetFlags() & TextureFlags::DUMMY_TEXTURE));
+
+ MOZ_ASSERT(owner);
+
+ if (!remoteTexture) {
+ // Use mLatestRenderedTextureHost for rendering. Remote texture of
+ // aTextureId does not exist.
+ remoteTexture = owner->mLatestRenderedTextureHost;
+ if (!it->second->mReadyCheckSuppressed) {
+ MOZ_ASSERT_UNREACHABLE("unexpected to be called");
+ gfxCriticalNoteOnce << "remote texture for rendering does not exist id:"
+ << uint64_t(aTextureId);
+ }
+ } else {
+ // Update mLatestRenderedTextureHost
+ owner->mLatestRenderedTextureHost = remoteTexture;
+ }
+
+ if (!remoteTexture) {
+ return Nothing();
+ }
+
+ return remoteTexture->GetMaybeExternalImageId();
+}
+
+void RemoteTextureMap::ReleaseRemoteTextureHostForDisplayList(
+ RemoteTextureHostWrapper* aTextureHostWrapper) {
+ MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
+ MOZ_ASSERT(aTextureHostWrapper);
+
+ RefPtr<TextureHost> releasingTexture; // Release outside the mutex
+ {
+ MonitorAutoLock lock(mMonitor);
+ releasingTexture =
+ aTextureHostWrapper->GetRemoteTextureHostForDisplayList(lock);
+ aTextureHostWrapper->ClearRemoteTextureHostForDisplayList(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->mAsyncRemoteTextureHost) {
+ releasingTextures.emplace_back(it->second->mAsyncRemoteTextureHost);
+ }
+
+ mRemoteTextureHostWrapperHolders.erase(it);
+ mMonitor.Notify();
+ }
+}
+
+void RemoteTextureMap::RegisterRemoteTexturePushListener(
+ const RemoteTextureOwnerId aOwnerId, const base::ProcessId aForPid,
+ CompositableHost* aListener) {
+ MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
+
+ RefPtr<CompositableHost>
+ releasingCompositableHost; // Release outside the monitor
+ {
+ MonitorAutoLock lock(mMonitor);
+
+ const auto key = std::pair(aForPid, aOwnerId);
+ auto it = mRemoteTexturePushListeners.find(key);
+ // Remove obsoleted CompositableHost.
+ if (it != mRemoteTexturePushListeners.end()) {
+ releasingCompositableHost = std::move(it->second);
+ mRemoteTexturePushListeners.erase(it);
+ }
+ mRemoteTexturePushListeners.emplace(key, aListener);
+
+ auto* owner = GetTextureOwner(lock, aOwnerId, aForPid);
+ if (!owner) {
+ return;
+ }
+ if (owner->mWaitingTextureDataHolders.empty() &&
+ !owner->mLatestTextureHost) {
+ return;
+ }
+
+ // Get latest RemoteTextureId.
+ auto textureId = !owner->mWaitingTextureDataHolders.empty()
+ ? owner->mWaitingTextureDataHolders.back()->mTextureId
+ : owner->mLatestTextureId;
+
+ // Notify the RemoteTextureId to callback
+ RefPtr<CompositableHost> compositableHost = aListener;
+ RefPtr<Runnable> runnable = NS_NewRunnableFunction(
+ "RemoteTextureMap::RegisterRemoteTexturePushListener::Runnable",
+ [compositableHost, textureId, aOwnerId, aForPid]() {
+ compositableHost->NotifyPushTexture(textureId, aOwnerId, aForPid);
+ });
+ CompositorThread()->Dispatch(runnable.forget());
+ }
+}
+
+void RemoteTextureMap::UnregisterRemoteTexturePushListener(
+ const RemoteTextureOwnerId aOwnerId, const base::ProcessId aForPid,
+ CompositableHost* aListener) {
+ MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
+
+ RefPtr<CompositableHost>
+ releasingCompositableHost; // Release outside the monitor
+ {
+ MonitorAutoLock lock(mMonitor);
+
+ const auto key = std::pair(aForPid, aOwnerId);
+ auto it = mRemoteTexturePushListeners.find(key);
+ if (it == mRemoteTexturePushListeners.end()) {
+ return;
+ }
+ if (aListener != it->second) {
+ // aListener was alredy obsoleted.
+ return;
+ }
+ releasingCompositableHost = std::move(it->second);
+ mRemoteTexturePushListeners.erase(it);
+ }
+}
+
+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 is already removed.
+ 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->mAsyncRemoteTextureHost) {
+ return true;
+ }
+ MOZ_ASSERT(!it->second->mAsyncRemoteTextureHost);
+
+ // 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 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;
+}
+
+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::GetRecycledBufferTextureData(
+ const RemoteTextureOwnerId aOwnerId, const base::ProcessId aForPid,
+ gfx::IntSize aSize, gfx::SurfaceFormat aFormat) {
+ std::stack<UniquePtr<TextureData>>
+ releasingTextures; // Release outside the monitor
+ UniquePtr<TextureData> texture;
+ {
+ MonitorAutoLock lock(mMonitor);
+
+ auto* owner = GetTextureOwner(lock, aOwnerId, aForPid);
+ if (!owner) {
+ return nullptr;
+ }
+
+ if (owner->mRecycledTextures.empty()) {
+ return nullptr;
+ }
+
+ if (!owner->mRecycledTextures.empty()) {
+ auto& top = owner->mRecycledTextures.top();
+ auto* bufferTexture = top->AsBufferTextureData();
+
+ if (bufferTexture && bufferTexture->GetSize() == aSize &&
+ bufferTexture->GetFormat() == aFormat) {
+ texture = std::move(top);
+ owner->mRecycledTextures.pop();
+ } else {
+ // If size or format are different, release all textures.
+ owner->mRecycledTextures.swap(releasingTextures);
+ }
+ }
+ }
+ return texture;
+}
+
+std::shared_ptr<gl::SharedSurface> RemoteTextureMap::GetRecycledSharedSurface(
+ const RemoteTextureOwnerId aOwnerId, const base::ProcessId aForPid) {
+ std::shared_ptr<gl::SharedSurface> sharedSurface;
+ {
+ MonitorAutoLock lock(mMonitor);
+
+ auto* owner = GetTextureOwner(lock, aOwnerId, aForPid);
+ if (!owner) {
+ return nullptr;
+ }
+
+ if (owner->mRecycledSharedSurfaces.empty()) {
+ return nullptr;
+ }
+
+ if (!owner->mRecycledSharedSurfaces.empty()) {
+ sharedSurface = owner->mRecycledSharedSurfaces.front();
+ owner->mRecycledSharedSurfaces.pop();
+ }
+ }
+ return sharedSurface;
+}
+
+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,
+ const std::shared_ptr<gl::SharedSurface>& aSharedSurface)
+ : mTextureId(aTextureId),
+ mTextureHost(aTextureHost),
+ mTextureData(std::move(aTextureData)),
+ mSharedSurface(aSharedSurface) {}
+
+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