/* -*- 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 #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&& aTextureData, const std::shared_ptr& aSharedSurface) { MOZ_ASSERT(IsRegistered(aOwnerId)); RefPtr 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(rawData); RefPtr 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 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(data); } std::shared_ptr RemoteTextureOwnerClient::GetRecycledSharedSurface( const RemoteTextureOwnerId aOwnerId) { return RemoteTextureMap::Get()->RemoteTextureMap::GetRecycledSharedSurface( aOwnerId, mForPid); } StaticAutoPtr 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&& aTextureData, RefPtr& aTextureHost, const std::shared_ptr& aSharedSurface) { MOZ_RELEASE_ASSERT(aTextureHost); std::vector> 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 = it->second; RefPtr runnable = NS_NewRunnableFunction( "RemoteTextureMap::PushTexture::Runnable", [compositableHost, aTextureId, aOwnerId, aForPid]() { compositableHost->NotifyPushTexture(aTextureId, aOwnerId, aForPid); }); CompositorThread()->Dispatch(runnable.forget()); } auto textureData = MakeUnique( 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 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* src = bufferTextureHost->GetBuffer(); MOZ_ASSERT(bufferSize <= aDestShmem.Size()); 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(); owner->mIsSyncMode = aIsSyncMode; mTextureOwners.emplace(key, std::move(owner)); } void RemoteTextureMap::KeepTextureDataAliveForTextureHostIfNecessary( const MonitorAutoLock& aProofOfLock, std::deque>& 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 eventTarget = MessageLoop::current()->SerialEventTarget(); RefPtr 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 releasingOwner; // Release outside the monitor std::vector> releasingTextures; // Release outside the monitor std::vector> 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& aOwnerIds, const base::ProcessId aForPid) { std::vector> releasingOwners; // Release outside the monitor std::vector> releasingTextures; // Release outside the monitor std::vector> 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 RemoteTextureMap::CreateRemoteTexture( TextureData* aTextureData, TextureFlags aTextureFlags) { SurfaceDescriptor desc; DebugOnly ret = aTextureData->Serialize(desc); MOZ_ASSERT(ret); TextureFlags flags = aTextureFlags | TextureFlags::REMOTE_TEXTURE | TextureFlags::DEALLOCATE_CLIENT; Maybe externalImageId = Nothing(); RefPtr 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 holder = std::move(front); aOwner->mWaitingTextureDataHolders.pop_front(); aOwner->mUsingTextureDataHolders.push_back(std::move(holder)); } } std::vector> RemoteTextureMap::GetRenderingReadyCallbacks( const MonitorAutoLock& aProofOfLock, RemoteTextureMap::TextureOwner* aOwner, const RemoteTextureId aTextureId) { MOZ_ASSERT(aOwner); std::vector> 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> 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&& 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; { 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( 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 releasingTexture; // Release outside the mutex { MonitorAutoLock lock(mMonitor); releasingTexture = aTextureHostWrapper->GetRemoteTextureHostForDisplayList(lock); aTextureHostWrapper->ClearRemoteTextureHostForDisplayList(lock); } } RefPtr 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(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> 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 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 = aListener; RefPtr 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 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&& 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( 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 RemoteTextureMap::GetRecycledBufferTextureData( const RemoteTextureOwnerId aOwnerId, const base::ProcessId aForPid, gfx::IntSize aSize, gfx::SurfaceFormat aFormat) { std::stack> releasingTextures; // Release outside the monitor UniquePtr 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 RemoteTextureMap::GetRecycledSharedSurface( const RemoteTextureOwnerId aOwnerId, const base::ProcessId aForPid) { std::shared_ptr 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 aTextureHost, UniquePtr&& aTextureData, const std::shared_ptr& aSharedSurface) : mTextureId(aTextureId), mTextureHost(aTextureHost), mTextureData(std::move(aTextureData)), mSharedSurface(aSharedSurface) {} RemoteTextureMap::RenderingReadyCallbackHolder::RenderingReadyCallbackHolder( const RemoteTextureId aTextureId, std::function&& aCallback) : mTextureId(aTextureId), mCallback(aCallback) {} RemoteTextureMap::RemoteTextureHostWrapperHolder:: RemoteTextureHostWrapperHolder( RefPtr aRemoteTextureHostWrapper) : mRemoteTextureHostWrapper(aRemoteTextureHostWrapper) {} } // namespace mozilla::layers