Source code

Revision control

Copy as Markdown

Other Tools

/* -*- 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 <deque>
#include <functional>
#include <list>
#include <map>
#include <memory>
#include <queue>
#include <unordered_set>
#include <utility>
#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),
mWaitForRemoteTextureOwner(false) {}
RemoteTextureInfo(const RemoteTextureId aTextureId,
const RemoteTextureOwnerId aOwnerId,
const base::ProcessId aForPid,
const bool aWaitForRemoteTextureOwner)
: mTextureId(aTextureId),
mOwnerId(aOwnerId),
mForPid(aForPid),
mWaitForRemoteTextureOwner(aWaitForRemoteTextureOwner) {}
const RemoteTextureId mTextureId;
const RemoteTextureOwnerId mOwnerId;
const base::ProcessId mForPid;
const bool mWaitForRemoteTextureOwner;
};
struct RemoteTextureInfoList {
std::queue<RemoteTextureInfo> mList;
};
class SharedResourceWrapper {
public:
enum class Tag { SharedSurface, ExternalTexture };
const Tag mTag;
static UniquePtr<SharedResourceWrapper> SharedSurface(
const std::shared_ptr<gl::SharedSurface>& aSharedSurface) {
return MakeUnique<SharedResourceWrapper>(Tag::SharedSurface,
aSharedSurface);
}
static UniquePtr<SharedResourceWrapper> ExternalTexture(
const std::shared_ptr<webgpu::ExternalTexture>& aExternalTexture) {
return MakeUnique<SharedResourceWrapper>(Tag::ExternalTexture,
aExternalTexture);
}
SharedResourceWrapper(
const Tag aTag, const std::shared_ptr<gl::SharedSurface>& aSharedSurface)
: mTag(aTag), mSharedSurface(aSharedSurface) {
MOZ_ASSERT(mTag == Tag::SharedSurface);
}
SharedResourceWrapper(
const Tag aTag,
const std::shared_ptr<webgpu::ExternalTexture>& aExternalTexture)
: mTag(aTag), mExternalTexture(aExternalTexture) {
MOZ_ASSERT(mTag == Tag::ExternalTexture);
}
const std::shared_ptr<gl::SharedSurface> mSharedSurface;
const std::shared_ptr<webgpu::ExternalTexture> mExternalTexture;
std::shared_ptr<gl::SharedSurface> SharedSurface() {
if (mTag == Tag::SharedSurface) {
return mSharedSurface;
}
MOZ_ASSERT_UNREACHABLE("unexpected to be called");
return nullptr;
}
std::shared_ptr<webgpu::ExternalTexture> 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<TextureData> mTextureData;
UniquePtr<SharedResourceWrapper> mResourceWrapper;
};
bool mIsShared = false;
std::list<RecycledTextureHolder> 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<RemoteTextureTxnScheduler> 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<Wait> mWaits;
};
typedef std::unordered_set<RemoteTextureOwnerId, RemoteTextureOwnerId::HashFn>
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<TextureData>&& aTextureData);
void PushTexture(const RemoteTextureId aTextureId,
const RemoteTextureOwnerId aOwnerId,
const std::shared_ptr<gl::SharedSurface>& aSharedSurface,
const gfx::IntSize& aSize, gfx::SurfaceFormat aFormat,
const SurfaceDescriptor& aDesc);
void PushTexture(
const RemoteTextureId aTextureId, const RemoteTextureOwnerId aOwnerId,
const std::shared_ptr<webgpu::ExternalTexture>& 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<TextureData> GetRecycledTextureData(
const gfx::IntSize& aSize, gfx::SurfaceFormat aFormat,
TextureType aTextureType,
RemoteTextureOwnerId aOwnerId = RemoteTextureOwnerId());
UniquePtr<TextureData> CreateOrRecycleBufferTextureData(
const gfx::IntSize& aSize, gfx::SurfaceFormat aFormat,
RemoteTextureOwnerId aOwnerId = RemoteTextureOwnerId());
std::shared_ptr<gl::SharedSurface> GetRecycledSharedSurface(
const gfx::IntSize& aSize, gfx::SurfaceFormat aFormat,
SurfaceDescriptor::Type aType,
RemoteTextureOwnerId aOwnerId = RemoteTextureOwnerId());
std::shared_ptr<webgpu::ExternalTexture> GetRecycledExternalTexture(
const gfx::IntSize& aSize, gfx::SurfaceFormat aFormat,
SurfaceDescriptor::Type aType,
RemoteTextureOwnerId aOwnerId = RemoteTextureOwnerId());
const base::ProcessId mForPid;
protected:
~RemoteTextureOwnerClient();
RemoteTextureOwnerIdSet mOwnerIds;
RefPtr<RemoteTextureRecycleBin> 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<TextureData>&& aTextureData,
RefPtr<TextureHost>& aTextureHost,
UniquePtr<SharedResourceWrapper>&& 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<RemoteTextureRecycleBin>& 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<RemoteTextureRecycleBin>& 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.
void GetRemoteTexture(RemoteTextureHostWrapper* aTextureHostWrapper);
bool WaitForTxn(const RemoteTextureOwnerId aOwnerId,
const base::ProcessId aForPid, RemoteTextureTxnType aTxnType,
RemoteTextureTxnId aTxnId);
void ReleaseRemoteTextureHost(RemoteTextureHostWrapper* aTextureHostWrapper);
RefPtr<TextureHost> 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<void(const RemoteTextureInfo&)>&& aCallback);
bool WaitRemoteTextureReady(const RemoteTextureInfo& aInfo);
void SuppressRemoteTextureReadyCheck(const RemoteTextureInfo& aInfo);
UniquePtr<TextureData> GetRecycledTextureData(
const RemoteTextureOwnerId aOwnerId, const base::ProcessId aForPid,
const RefPtr<RemoteTextureRecycleBin>& aRecycleBin,
const gfx::IntSize& aSize, gfx::SurfaceFormat aFormat,
TextureType aTextureType);
UniquePtr<SharedResourceWrapper> GetRecycledSharedTexture(
const RemoteTextureOwnerId aOwnerId, const base::ProcessId aForPid,
const RefPtr<RemoteTextureRecycleBin>& aRecycleBin,
const gfx::IntSize& aSize, gfx::SurfaceFormat aFormat,
SurfaceDescriptor::Type aType);
static RefPtr<TextureHost> CreateRemoteTexture(TextureData* aTextureData,
TextureFlags aTextureFlags);
already_AddRefed<RemoteTextureTxnScheduler> RegisterTxnScheduler(
base::ProcessId aForPid, RemoteTextureTxnType aType);
protected:
friend class RemoteTextureTxnScheduler;
// Holds data related to remote texture
struct TextureDataHolder {
TextureDataHolder(const RemoteTextureId aTextureId,
RefPtr<TextureHost> aTextureHost,
UniquePtr<TextureData>&& aTextureData,
UniquePtr<SharedResourceWrapper>&& 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<TextureHost> mTextureHost;
// Holds BufferTextureData of TextureHost
UniquePtr<TextureData> mTextureData;
// Holds gl::SharedSurface of TextureHost
UniquePtr<SharedResourceWrapper> mResourceWrapper;
};
struct RenderingReadyCallbackHolder {
RenderingReadyCallbackHolder(
const RemoteTextureId aTextureId,
std::function<void(const RemoteTextureInfo&)>&& aCallback);
const RemoteTextureId mTextureId;
// callback of RemoteTexture ready
std::function<void(const RemoteTextureInfo&)> mCallback;
};
struct WaitingTextureOwner {
std::deque<UniquePtr<RenderingReadyCallbackHolder>>
mRenderingReadyCallbackHolders;
};
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<nsISerialEventTarget> mDeferUnregister;
// Holds TextureDataHolders that wait to be used for building wr display
// list.
std::deque<UniquePtr<TextureDataHolder>> mWaitingTextureDataHolders;
// Holds TextureDataHolders that are used for building wr display list.
std::deque<UniquePtr<TextureDataHolder>> mUsingTextureDataHolders;
std::deque<UniquePtr<TextureDataHolder>> mReleasingTextureDataHolders;
// Holds RemoteTexture ready callbacks.
std::deque<UniquePtr<RenderingReadyCallbackHolder>>
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<CompositableTextureHostRef> mReleasingRenderedTextureHosts;
RefPtr<RemoteTextureRecycleBin> mRecycleBin;
};
// Holds data related to remote texture wrapper
struct RemoteTextureHostWrapperHolder {
explicit RemoteTextureHostWrapperHolder(
RefPtr<TextureHost> aRemoteTextureHostWrapper);
const RefPtr<TextureHost> 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<TextureOwner> UnregisterTextureOwner(
MonitorAutoLock& aProofOfLock, const RemoteTextureOwnerId aOwnerId,
const base::ProcessId aForPid,
std::vector<RefPtr<TextureHost>>& aReleasingTextures,
std::vector<std::function<void(const RemoteTextureInfo&)>>&
aRenderingReadyCallbacks);
void GetRenderingReadyCallbacks(
const MonitorAutoLock& aProofOfLock,
RemoteTextureMap::TextureOwner* aOwner, const RemoteTextureId aTextureId,
std::vector<std::function<void(const RemoteTextureInfo&)>>& aFunctions);
void GetAllRenderingReadyCallbacks(
const MonitorAutoLock& aProofOfLock,
RemoteTextureMap::TextureOwner* aOwner,
std::vector<std::function<void(const RemoteTextureInfo&)>>& aFunctions);
void KeepTextureDataAliveForTextureHostIfNecessary(
const MonitorAutoLock& aProofOfLock,
RemoteTextureMap::TextureOwner* aOwner,
std::deque<UniquePtr<TextureDataHolder>>& aHolders);
bool RecycleTexture(const RefPtr<RemoteTextureRecycleBin>& 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<std::pair<base::ProcessId, RemoteTextureOwnerId>,
UniquePtr<WaitingTextureOwner>>
mWaitingTextureOwners;
std::map<std::pair<base::ProcessId, RemoteTextureOwnerId>,
UniquePtr<TextureOwner>>
mTextureOwners;
std::map<std::pair<base::ProcessId, RemoteTextureId>,
UniquePtr<RemoteTextureHostWrapperHolder>>
mRemoteTextureHostWrapperHolders;
std::map<std::pair<base::ProcessId, RemoteTextureTxnType>,
RemoteTextureTxnScheduler*>
mTxnSchedulers;
static StaticAutoPtr<RemoteTextureMap> sInstance;
};
} // namespace layers
} // namespace mozilla
#endif // MOZILLA_GFX_RemoteTextureMap_H