/* -*- 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/. */ #ifndef MOZILLA_GFX_RemoteTextureMap_H #define MOZILLA_GFX_RemoteTextureMap_H #include #include #include #include #include #include #include #include #include "mozilla/gfx/Point.h" // for IntSize #include "mozilla/gfx/Types.h" // for SurfaceFormat #include "mozilla/ipc/Shmem.h" #include "mozilla/layers/CompositorTypes.h" // for TextureFlags, etc #include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor #include "mozilla/layers/TextureHost.h" #include "mozilla/Monitor.h" #include "mozilla/StaticPtr.h" #include "mozilla/ThreadSafeWeakPtr.h" #include "mozilla/UniquePtr.h" #include "mozilla/webrender/WebRenderTypes.h" class nsISerialEventTarget; namespace mozilla { namespace ipc { class IProtocol; } namespace gl { class SharedSurface; } namespace webgpu { class ExternalTexture; } namespace layers { class CompositableHost; class RemoteTextureHostWrapper; class TextureData; class TextureHost; struct RemoteTextureInfo { RemoteTextureInfo(const RemoteTextureId aTextureId, const RemoteTextureOwnerId aOwnerId, const base::ProcessId aForPid) : mTextureId(aTextureId), mOwnerId(aOwnerId), mForPid(aForPid) {} const RemoteTextureId mTextureId; const RemoteTextureOwnerId mOwnerId; const base::ProcessId mForPid; }; struct RemoteTextureInfoList { std::queue mList; }; class SharedResourceWrapper { public: enum class Tag { SharedSurface, ExternalTexture }; const Tag mTag; static UniquePtr SharedSurface( const std::shared_ptr& aSharedSurface) { return MakeUnique(Tag::SharedSurface, aSharedSurface); } static UniquePtr ExternalTexture( const std::shared_ptr& aExternalTexture) { return MakeUnique(Tag::ExternalTexture, aExternalTexture); } SharedResourceWrapper( const Tag aTag, const std::shared_ptr& aSharedSurface) : mTag(aTag), mSharedSurface(aSharedSurface) { MOZ_ASSERT(mTag == Tag::SharedSurface); } SharedResourceWrapper( const Tag aTag, const std::shared_ptr& aExternalTexture) : mTag(aTag), mExternalTexture(aExternalTexture) { MOZ_ASSERT(mTag == Tag::ExternalTexture); } const std::shared_ptr mSharedSurface; const std::shared_ptr mExternalTexture; std::shared_ptr SharedSurface() { if (mTag == Tag::SharedSurface) { return mSharedSurface; } MOZ_ASSERT_UNREACHABLE("unexpected to be called"); return nullptr; } std::shared_ptr ExternalTexture() { if (mTag == Tag::ExternalTexture) { return mExternalTexture; } MOZ_ASSERT_UNREACHABLE("unexpected to be called"); return nullptr; } }; class RemoteTextureRecycleBin final { public: NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RemoteTextureRecycleBin) explicit RemoteTextureRecycleBin(bool aIsShared); private: friend class RemoteTextureMap; ~RemoteTextureRecycleBin(); struct RecycledTextureHolder { gfx::IntSize mSize; gfx::SurfaceFormat mFormat = gfx::SurfaceFormat::UNKNOWN; SurfaceDescriptor::Type mType = SurfaceDescriptor::Tnull_t; UniquePtr mTextureData; UniquePtr mResourceWrapper; }; bool mIsShared = false; std::list mRecycledTextures; }; /** * RemoteTextureTxnScheduler manages dependencies on transaction numbers for a * given top-level protocol ("type"). It expects that transaction numbers are * all sequenced and comparable for this top-level protocol. Dependencies may * then be issued on a given future transaction number. Clients must notify the * scheduler when transactions are completed, so that any dependencies can be * cleared as the transaction number advances. Generally, transaction numbers * will be generated by a FwdTransactionCounter on a top-level protocol child, * and there should be a RemoteTextureTxnScheduler instantiated on the top-level * protocol parent that corresponds to the same protocol lifetime as the child. * To ease sharing in sub-protocols, RemoteTextureTxnScheduler is ref-counted * and may be multiply-registered by the various sub-protocols that derive from * a given top-level protocol, without having to directly refer to the original * top-level protocol. */ class RemoteTextureTxnScheduler final { public: NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RemoteTextureTxnScheduler) static already_AddRefed Create( mozilla::ipc::IProtocol* aProtocol); void NotifyTxn(RemoteTextureTxnId aTxnId); private: friend class RemoteTextureMap; RemoteTextureTxnScheduler(base::ProcessId aForPid, RemoteTextureTxnType aType) : mForPid(aForPid), mType(aType) {} ~RemoteTextureTxnScheduler(); bool WaitForTxn(const MonitorAutoLock& aProofOfLock, RemoteTextureOwnerId aOwnerId, RemoteTextureTxnId aTxnId); struct Wait { RemoteTextureOwnerId mOwnerId; RemoteTextureTxnId mTxnId; friend bool operator<(RemoteTextureTxnId aTxnId, const Wait& aWait) { return aTxnId < aWait.mTxnId; } }; base::ProcessId mForPid = base::kInvalidProcessId; RemoteTextureTxnType mType = 0; RemoteTextureTxnId mLastTxnId = 0; std::deque mWaits; }; typedef std::unordered_set RemoteTextureOwnerIdSet; /** * A class provides API for remote texture owners. */ class RemoteTextureOwnerClient final { public: NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RemoteTextureOwnerClient) explicit RemoteTextureOwnerClient(const base::ProcessId aForPid); bool IsRegistered(const RemoteTextureOwnerId aOwnerId); void RegisterTextureOwner(const RemoteTextureOwnerId aOwnerId, bool aSharedRecycling = false); void UnregisterTextureOwner(const RemoteTextureOwnerId aOwnerId); void UnregisterAllTextureOwners(); bool WaitForTxn(const RemoteTextureOwnerId aOwnerId, RemoteTextureTxnType aTxnType, RemoteTextureTxnId aTxnId); void ClearRecycledTextures(); void NotifyContextLost(const RemoteTextureOwnerIdSet* aOwnerIds = nullptr); void NotifyContextRestored( const RemoteTextureOwnerIdSet* aOwnerIds = nullptr); void PushTexture(const RemoteTextureId aTextureId, const RemoteTextureOwnerId aOwnerId, UniquePtr&& aTextureData); void PushTexture(const RemoteTextureId aTextureId, const RemoteTextureOwnerId aOwnerId, const std::shared_ptr& aSharedSurface, const gfx::IntSize& aSize, gfx::SurfaceFormat aFormat, const SurfaceDescriptor& aDesc); void PushTexture( const RemoteTextureId aTextureId, const RemoteTextureOwnerId aOwnerId, const std::shared_ptr& aExternalTexture, const gfx::IntSize& aSize, gfx::SurfaceFormat aFormat, const SurfaceDescriptor& aDesc); void PushDummyTexture(const RemoteTextureId aTextureId, const RemoteTextureOwnerId aOwnerId); void GetLatestBufferSnapshot(const RemoteTextureOwnerId aOwnerId, const mozilla::ipc::Shmem& aDestShmem, const gfx::IntSize& aSize); UniquePtr GetRecycledTextureData( const gfx::IntSize& aSize, gfx::SurfaceFormat aFormat, TextureType aTextureType, RemoteTextureOwnerId aOwnerId = RemoteTextureOwnerId()); UniquePtr CreateOrRecycleBufferTextureData( const gfx::IntSize& aSize, gfx::SurfaceFormat aFormat, RemoteTextureOwnerId aOwnerId = RemoteTextureOwnerId()); std::shared_ptr GetRecycledSharedSurface( const gfx::IntSize& aSize, gfx::SurfaceFormat aFormat, SurfaceDescriptor::Type aType, RemoteTextureOwnerId aOwnerId = RemoteTextureOwnerId()); std::shared_ptr GetRecycledExternalTexture( const gfx::IntSize& aSize, gfx::SurfaceFormat aFormat, SurfaceDescriptor::Type aType, RemoteTextureOwnerId aOwnerId = RemoteTextureOwnerId()); const base::ProcessId mForPid; protected: ~RemoteTextureOwnerClient(); RemoteTextureOwnerIdSet mOwnerIds; RefPtr mSharedRecycleBin; }; /** * A class to map RemoteTextureId to remote texture(TextureHost). * Remote textures are provided by texture owner. */ class RemoteTextureMap { public: static void Init(); static void Shutdown(); static RemoteTextureMap* Get() { return sInstance; } RemoteTextureMap(); ~RemoteTextureMap(); // Push remote texture data and gl::SharedSurface from texture owner. // The texture data is used for creating TextureHost. // gl::SharedSurface is pushed only when the surface needs to be kept alive // during TextureHost usage. The texture data and the surface might be // recycled when TextureHost is destroyed. void PushTexture(const RemoteTextureId aTextureId, const RemoteTextureOwnerId aOwnerId, const base::ProcessId aForPid, UniquePtr&& aTextureData, RefPtr& aTextureHost, UniquePtr&& aResourceWrapper); // Remove waiting texture that will not be used. bool RemoveTexture(const RemoteTextureId aTextureId, const RemoteTextureOwnerId aOwnerId, const base::ProcessId aForPid); void GetLatestBufferSnapshot(const RemoteTextureOwnerId aOwnerId, const base::ProcessId aForPid, const mozilla::ipc::Shmem& aDestShmem, const gfx::IntSize& aSize); void RegisterTextureOwner( const RemoteTextureOwnerId aOwnerId, const base::ProcessId aForPid, const RefPtr& aRecycleBin = nullptr); void UnregisterTextureOwner(const RemoteTextureOwnerId aOwnerId, const base::ProcessId aForPid); void UnregisterTextureOwners(const RemoteTextureOwnerIdSet& aOwnerIds, const base::ProcessId aForPid); void ClearRecycledTextures( const RemoteTextureOwnerIdSet& aOwnerIds, const base::ProcessId aForPid, const RefPtr& aRecycleBin = nullptr); void NotifyContextLost(const RemoteTextureOwnerIdSet& aOwnerIds, const base::ProcessId aForPid); void NotifyContextRestored(const RemoteTextureOwnerIdSet& aOwnerIds, const base::ProcessId aForPid); bool WaitForRemoteTextureOwner(RemoteTextureHostWrapper* aTextureHostWrapper); // Get remote texture's TextureHost for RemoteTextureHostWrapper. // // return true when aReadyCallback will be called. bool GetRemoteTexture( RemoteTextureHostWrapper* aTextureHostWrapper, std::function&& aReadyCallback); bool WaitForTxn(const RemoteTextureOwnerId aOwnerId, const base::ProcessId aForPid, RemoteTextureTxnType aTxnType, RemoteTextureTxnId aTxnId); void ReleaseRemoteTextureHost(RemoteTextureHostWrapper* aTextureHostWrapper); RefPtr GetOrCreateRemoteTextureHostWrapper( const RemoteTextureId aTextureId, const RemoteTextureOwnerId aOwnerId, const base::ProcessId aForPid, const gfx::IntSize& aSize, const TextureFlags aFlags); void UnregisterRemoteTextureHostWrapper(const RemoteTextureId aTextureId, const RemoteTextureOwnerId aOwnerId, const base::ProcessId aForPid); bool CheckRemoteTextureReady( const RemoteTextureInfo& aInfo, std::function&& aCallback); bool WaitRemoteTextureReady(const RemoteTextureInfo& aInfo); void SuppressRemoteTextureReadyCheck(const RemoteTextureId aTextureId, const base::ProcessId aForPid); UniquePtr GetRecycledTextureData( const RemoteTextureOwnerId aOwnerId, const base::ProcessId aForPid, const RefPtr& aRecycleBin, const gfx::IntSize& aSize, gfx::SurfaceFormat aFormat, TextureType aTextureType); UniquePtr GetRecycledSharedTexture( const RemoteTextureOwnerId aOwnerId, const base::ProcessId aForPid, const RefPtr& aRecycleBin, const gfx::IntSize& aSize, gfx::SurfaceFormat aFormat, SurfaceDescriptor::Type aType); static RefPtr CreateRemoteTexture(TextureData* aTextureData, TextureFlags aTextureFlags); already_AddRefed RegisterTxnScheduler( base::ProcessId aForPid, RemoteTextureTxnType aType); protected: friend class RemoteTextureTxnScheduler; // Holds data related to remote texture struct TextureDataHolder { TextureDataHolder(const RemoteTextureId aTextureId, RefPtr aTextureHost, UniquePtr&& aTextureData, UniquePtr&& aResourceWrapper); const RemoteTextureId mTextureId; // TextureHost of remote texture // Compositable ref of the mTextureHost should be updated within mMonitor. // The compositable ref is used to check if TextureHost(remote texture) is // still in use by WebRender. RefPtr mTextureHost; // Holds BufferTextureData of TextureHost UniquePtr mTextureData; // Holds gl::SharedSurface of TextureHost UniquePtr mResourceWrapper; }; struct RenderingReadyCallbackHolder { RenderingReadyCallbackHolder( const RemoteTextureId aTextureId, std::function&& aCallback); const RemoteTextureId mTextureId; // callback of RemoteTexture ready std::function mCallback; }; struct TextureOwner { bool mIsContextLost = false; // Whether to wait for a transaction to complete before unregistering. bool mWaitForTxn = false; // The thread on which to finally unregister when ready. RefPtr mDeferUnregister; // Holds TextureDataHolders that wait to be used for building wr display // list. std::deque> mWaitingTextureDataHolders; // Holds TextureDataHolders that are used for building wr display list. std::deque> mUsingTextureDataHolders; std::deque> mReleasingTextureDataHolders; // Holds RemoteTexture ready callbacks. std::deque> mRenderingReadyCallbackHolders; RemoteTextureId mLatestPushedTextureId = {0}; RemoteTextureId mLatestUsingTextureId = {0}; CompositableTextureHostRef mLatestTextureHost; CompositableTextureHostRef mLatestRenderedTextureHost; // Holds compositable refs to TextureHosts of RenderTextureHosts that are // waiting to be released in non-RenderThread. std::deque mReleasingRenderedTextureHosts; RefPtr mRecycleBin; }; // Holds data related to remote texture wrapper struct RemoteTextureHostWrapperHolder { explicit RemoteTextureHostWrapperHolder( RefPtr aRemoteTextureHostWrapper); const RefPtr mRemoteTextureHostWrapper; // Hold compositable ref of remote texture of the RemoteTextureId. CompositableTextureHostRef mRemoteTextureHost; bool mReadyCheckSuppressed = false; }; void UpdateTexture(const MonitorAutoLock& aProofOfLock, RemoteTextureMap::TextureOwner* aOwner, const RemoteTextureId aTextureId); UniquePtr UnregisterTextureOwner( MonitorAutoLock& aProofOfLock, const RemoteTextureOwnerId aOwnerId, const base::ProcessId aForPid, std::vector>& aReleasingTextures, std::vector>& aRenderingReadyCallbacks); void GetRenderingReadyCallbacks( const MonitorAutoLock& aProofOfLock, RemoteTextureMap::TextureOwner* aOwner, const RemoteTextureId aTextureId, std::vector>& aFunctions); void GetAllRenderingReadyCallbacks( const MonitorAutoLock& aProofOfLock, RemoteTextureMap::TextureOwner* aOwner, std::vector>& aFunctions); void KeepTextureDataAliveForTextureHostIfNecessary( const MonitorAutoLock& aProofOfLock, RemoteTextureMap::TextureOwner* aOwner, std::deque>& aHolders); bool RecycleTexture(const RefPtr& aRecycleBin, TextureDataHolder& aHolder, bool aExpireOldTextures); RemoteTextureMap::TextureOwner* GetTextureOwner( const MonitorAutoLock& aProofOfLock, const RemoteTextureOwnerId aOwnerId, const base::ProcessId aForPid); void NotifyTxn(const MonitorAutoLock& aProofOfLock, const RemoteTextureOwnerId aOwnerId, const base::ProcessId aForPid); void UnregisterTxnScheduler(base::ProcessId aForPid, RemoteTextureTxnType aType); Monitor mMonitor MOZ_UNANNOTATED; std::map, UniquePtr> mTextureOwners; std::map, UniquePtr> mRemoteTextureHostWrapperHolders; std::map, RemoteTextureTxnScheduler*> mTxnSchedulers; static StaticAutoPtr sInstance; }; } // namespace layers } // namespace mozilla #endif // MOZILLA_GFX_RemoteTextureMap_H