Bug 1873075 - Delay UnregisterTextureOwner until all potential UseRemoteTextures are received. r=aosmond

UnregisterTextureOwner, if called before any use of UseRemoteTexture, can cause UseRemoteTexture to wait
for the texture owner to be created, since the texture owner does not exist, and there is no evidence it
was previously unregistered.

This patch attempts to address the issue by delaying the actual UnregisterTextureOwner until all such
UseRemoteTexture instances are processed. This is accomplished by noting that UseRemoteTexture ops come
in via transactions from a CompositableForwarder and so all are associated with a forwarder transaction
with a FwdTransactionId. RecordedTextureData on destruction reports the last FwdTransactionId associated
with its final UseRemoteTexture before it attempts to call UnregisterTextureOwner. If RemoteTextureMap
has not been notified of a given FwdTransactionId yet, then the UnregisterTextureOwner call will be
deferred until it has seen this FwdTransactionId.

This adds a RemoteTextureTxnScheduler to track the issuing of dependencies and waiting for FwdTransactionIds.

This patch also cleans up the issuing of FwdTransactionIds themselves to be associated with a given
top-level protocol so that all sub-protocols have transaction numbers that can be safely compared amongst
each other. This makes dependency expiration more robust since any advancement of the transaction number
from any source can help retire expired dependencies.

Differential Revision: https://phabricator.services.mozilla.com/D197895
This commit is contained in:
Lee Salzman 2024-01-09 11:53:14 +00:00
parent 9a8f92d48a
commit 6accc1036c
27 changed files with 472 additions and 157 deletions

View file

@ -390,6 +390,9 @@ struct RemoteTextureOwnerId {
}; };
}; };
typedef uint32_t RemoteTextureTxnType;
typedef uint64_t RemoteTextureTxnId;
// TextureId allocated in GPU process // TextureId allocated in GPU process
struct GpuProcessTextureId { struct GpuProcessTextureId {
uint64_t mId = 0; uint64_t mId = 0;

View file

@ -255,6 +255,11 @@ bool PersistentBufferProviderAccelerated::RequiresRefresh() const {
return mTexture->GetInternalData()->RequiresRefresh(); return mTexture->GetInternalData()->RequiresRefresh();
} }
void PersistentBufferProviderAccelerated::UseCompositableForwarder(
CompositableForwarder* aForwarder) {
mTexture->GetInternalData()->UseCompositableForwarder(aForwarder);
}
// static // static
already_AddRefed<PersistentBufferProviderShared> already_AddRefed<PersistentBufferProviderShared>
PersistentBufferProviderShared::Create(gfx::IntSize aSize, PersistentBufferProviderShared::Create(gfx::IntSize aSize,

View file

@ -28,6 +28,7 @@ class DrawTarget;
namespace layers { namespace layers {
class CompositableForwarder;
class KnowsCompositor; class KnowsCompositor;
struct RemoteTextureOwnerId; struct RemoteTextureOwnerId;
class TextureClient; class TextureClient;
@ -106,6 +107,8 @@ class PersistentBufferProvider : public RefCounted<PersistentBufferProvider>,
virtual bool RequiresRefresh() const { return false; } virtual bool RequiresRefresh() const { return false; }
virtual Maybe<SurfaceDescriptor> GetFrontBuffer() { return Nothing(); } virtual Maybe<SurfaceDescriptor> GetFrontBuffer() { return Nothing(); }
virtual void UseCompositableForwarder(CompositableForwarder* aForwarder) {}
}; };
class PersistentBufferProviderBasic : public PersistentBufferProvider { class PersistentBufferProviderBasic : public PersistentBufferProvider {
@ -171,6 +174,8 @@ class PersistentBufferProviderAccelerated : public PersistentBufferProvider {
bool RequiresRefresh() const override; bool RequiresRefresh() const override;
void UseCompositableForwarder(CompositableForwarder* aForwarder) override;
protected: protected:
explicit PersistentBufferProviderAccelerated( explicit PersistentBufferProviderAccelerated(
const RefPtr<TextureClient>& aTexture); const RefPtr<TextureClient>& aTexture);

View file

@ -531,8 +531,12 @@ RecordedNextTextureId::RecordedNextTextureId(S& aStream)
class RecordedTextureDestruction final class RecordedTextureDestruction final
: public RecordedEventDerived<RecordedTextureDestruction> { : public RecordedEventDerived<RecordedTextureDestruction> {
public: public:
explicit RecordedTextureDestruction(int64_t aTextureId) RecordedTextureDestruction(int64_t aTextureId, RemoteTextureTxnType aTxnType,
: RecordedEventDerived(TEXTURE_DESTRUCTION), mTextureId(aTextureId) {} RemoteTextureTxnId aTxnId)
: RecordedEventDerived(TEXTURE_DESTRUCTION),
mTextureId(aTextureId),
mTxnType(aTxnType),
mTxnId(aTxnId) {}
template <class S> template <class S>
MOZ_IMPLICIT RecordedTextureDestruction(S& aStream); MOZ_IMPLICIT RecordedTextureDestruction(S& aStream);
@ -546,23 +550,29 @@ class RecordedTextureDestruction final
private: private:
int64_t mTextureId = 0; int64_t mTextureId = 0;
RemoteTextureTxnType mTxnType = 0;
RemoteTextureTxnId mTxnId = 0;
}; };
inline bool RecordedTextureDestruction::PlayCanvasEvent( inline bool RecordedTextureDestruction::PlayCanvasEvent(
CanvasTranslator* aTranslator) const { CanvasTranslator* aTranslator) const {
aTranslator->RemoveTexture(mTextureId); aTranslator->RemoveTexture(mTextureId, mTxnType, mTxnId);
return true; return true;
} }
template <class S> template <class S>
void RecordedTextureDestruction::Record(S& aStream) const { void RecordedTextureDestruction::Record(S& aStream) const {
WriteElement(aStream, mTextureId); WriteElement(aStream, mTextureId);
WriteElement(aStream, mTxnType);
WriteElement(aStream, mTxnId);
} }
template <class S> template <class S>
RecordedTextureDestruction::RecordedTextureDestruction(S& aStream) RecordedTextureDestruction::RecordedTextureDestruction(S& aStream)
: RecordedEventDerived(TEXTURE_DESTRUCTION) { : RecordedEventDerived(TEXTURE_DESTRUCTION) {
ReadElement(aStream, mTextureId); ReadElement(aStream, mTextureId);
ReadElement(aStream, mTxnType);
ReadElement(aStream, mTxnId);
} }
class RecordedCheckpoint final class RecordedCheckpoint final

View file

@ -6,6 +6,7 @@
#include "mozilla/layers/RemoteTextureMap.h" #include "mozilla/layers/RemoteTextureMap.h"
#include <algorithm>
#include <vector> #include <vector>
#include "CompositableHost.h" #include "CompositableHost.h"
@ -352,8 +353,8 @@ void RemoteTextureMap::PushTexture(
owner->mWaitingTextureDataHolders.push_back(std::move(textureData)); owner->mWaitingTextureDataHolders.push_back(std::move(textureData));
{ {
renderingReadyCallbacks = GetRenderingReadyCallbacks(lock, owner, aTextureId,
GetRenderingReadyCallbacks(lock, owner, aTextureId); renderingReadyCallbacks);
// Update mRemoteTextureHost. // Update mRemoteTextureHost.
// This happens when PushTexture() with RemoteTextureId is called after // This happens when PushTexture() with RemoteTextureId is called after
// GetRemoteTexture() with the RemoteTextureId. // GetRemoteTexture() with the RemoteTextureId.
@ -574,6 +575,66 @@ void RemoteTextureMap::KeepTextureDataAliveForTextureHostIfNecessary(
} }
} }
UniquePtr<RemoteTextureMap::TextureOwner>
RemoteTextureMap::UnregisterTextureOwner(
const MonitorAutoLock& aProofOfLock, const RemoteTextureOwnerId aOwnerId,
const base::ProcessId aForPid,
std::vector<RefPtr<TextureHost>>& aReleasingTextures,
std::vector<std::function<void(const RemoteTextureInfo&)>>&
aRenderingReadyCallbacks) {
const auto key = std::pair(aForPid, aOwnerId);
auto it = mTextureOwners.find(key);
if (it == mTextureOwners.end()) {
MOZ_ASSERT_UNREACHABLE("unexpected to be called");
return nullptr;
}
auto* owner = it->second.get();
// If waiting for a last use, and it hasn't arrived yet, then defer
// unregistering.
if (owner->mWaitForTxn) {
owner->mDeferUnregister = GetCurrentSerialEventTarget();
return nullptr;
}
if (owner->mLatestTextureHost) {
// Release CompositableRef in mMonitor
aReleasingTextures.emplace_back(owner->mLatestTextureHost);
owner->mLatestTextureHost = nullptr;
}
// mReleasingRenderedTextureHosts and mLatestRenderedTextureHost could
// simply be cleared. Since NumCompositableRefs() > 0 keeps TextureHosts in
// mUsingTextureDataHolders alive. They need to be cleared before
// KeepTextureDataAliveForTextureHostIfNecessary() call. The function uses
// NumCompositableRefs().
if (!owner->mReleasingRenderedTextureHosts.empty()) {
std::transform(owner->mReleasingRenderedTextureHosts.begin(),
owner->mReleasingRenderedTextureHosts.end(),
std::back_inserter(aReleasingTextures),
[](CompositableTextureHostRef& aRef) { return aRef.get(); });
owner->mReleasingRenderedTextureHosts.clear();
}
if (owner->mLatestRenderedTextureHost) {
owner->mLatestRenderedTextureHost = nullptr;
}
GetAllRenderingReadyCallbacks(aProofOfLock, owner, aRenderingReadyCallbacks);
KeepTextureDataAliveForTextureHostIfNecessary(
aProofOfLock, owner, owner->mWaitingTextureDataHolders);
KeepTextureDataAliveForTextureHostIfNecessary(
aProofOfLock, owner, owner->mUsingTextureDataHolders);
KeepTextureDataAliveForTextureHostIfNecessary(
aProofOfLock, owner, owner->mReleasingTextureDataHolders);
UniquePtr<TextureOwner> releasingOwner = std::move(it->second);
mTextureOwners.erase(it);
return releasingOwner;
}
void RemoteTextureMap::UnregisterTextureOwner( void RemoteTextureMap::UnregisterTextureOwner(
const RemoteTextureOwnerId aOwnerId, const base::ProcessId aForPid) { const RemoteTextureOwnerId aOwnerId, const base::ProcessId aForPid) {
UniquePtr<TextureOwner> releasingOwner; // Release outside the monitor UniquePtr<TextureOwner> releasingOwner; // Release outside the monitor
@ -584,51 +645,12 @@ void RemoteTextureMap::UnregisterTextureOwner(
{ {
MonitorAutoLock lock(mMonitor); MonitorAutoLock lock(mMonitor);
const auto key = std::pair(aForPid, aOwnerId); releasingOwner = UnregisterTextureOwner(
auto it = mTextureOwners.find(key); lock, aOwnerId, aForPid, releasingTextures, renderingReadyCallbacks);
if (it == mTextureOwners.end()) { if (!releasingOwner) {
MOZ_ASSERT_UNREACHABLE("unexpected to be called");
return; return;
} }
auto* owner = it->second.get();
if (owner->mLatestTextureHost) {
// Release CompositableRef in mMonitor
releasingTextures.emplace_back(owner->mLatestTextureHost);
owner->mLatestTextureHost = nullptr;
}
// mReleasingRenderedTextureHosts and mLatestRenderedTextureHost could
// simply be cleared. Since NumCompositableRefs() > 0 keeps TextureHosts in
// mUsingTextureDataHolders alive. They need to be cleared before
// KeepTextureDataAliveForTextureHostIfNecessary() call. The function uses
// NumCompositableRefs().
if (!owner->mReleasingRenderedTextureHosts.empty()) {
std::transform(
owner->mReleasingRenderedTextureHosts.begin(),
owner->mReleasingRenderedTextureHosts.end(),
std::back_inserter(releasingTextures),
[](CompositableTextureHostRef& aRef) { return aRef.get(); });
owner->mReleasingRenderedTextureHosts.clear();
}
if (owner->mLatestRenderedTextureHost) {
owner->mLatestRenderedTextureHost = nullptr;
}
renderingReadyCallbacks = GetAllRenderingReadyCallbacks(lock, owner);
KeepTextureDataAliveForTextureHostIfNecessary(
lock, owner, owner->mWaitingTextureDataHolders);
KeepTextureDataAliveForTextureHostIfNecessary(
lock, owner, owner->mUsingTextureDataHolders);
KeepTextureDataAliveForTextureHostIfNecessary(
lock, owner, owner->mReleasingTextureDataHolders);
releasingOwner = std::move(it->second);
mTextureOwners.erase(it);
mMonitor.Notify(); mMonitor.Notify();
} }
@ -653,50 +675,14 @@ void RemoteTextureMap::UnregisterTextureOwners(
MonitorAutoLock lock(mMonitor); MonitorAutoLock lock(mMonitor);
for (const auto& id : aOwnerIds) { for (const auto& id : aOwnerIds) {
const auto key = std::pair(aForPid, id); if (auto releasingOwner = UnregisterTextureOwner(
auto it = mTextureOwners.find(key); lock, id, aForPid, releasingTextures, renderingReadyCallbacks)) {
if (it == mTextureOwners.end()) { releasingOwners.push_back(std::move(releasingOwner));
MOZ_ASSERT_UNREACHABLE("unexpected to be called");
continue;
} }
}
auto* owner = it->second.get(); if (releasingOwners.empty()) {
if (owner->mLatestTextureHost) { return;
// Release CompositableRef in mMonitor
releasingTextures.emplace_back(owner->mLatestTextureHost);
owner->mLatestTextureHost = nullptr;
}
// mReleasingRenderedTextureHosts and mLatestRenderedTextureHost could
// simply be cleared. Since NumCompositableRefs() > 0 keeps TextureHosts
// in mUsingTextureDataHolders alive. They need to be cleared before
// KeepTextureDataAliveForTextureHostIfNecessary() call. The function uses
// NumCompositableRefs().
if (!owner->mReleasingRenderedTextureHosts.empty()) {
std::transform(
owner->mReleasingRenderedTextureHosts.begin(),
owner->mReleasingRenderedTextureHosts.end(),
std::back_inserter(releasingTextures),
[](CompositableTextureHostRef& aRef) { return aRef.get(); });
owner->mReleasingRenderedTextureHosts.clear();
}
if (owner->mLatestRenderedTextureHost) {
owner->mLatestRenderedTextureHost = nullptr;
}
renderingReadyCallbacks = GetAllRenderingReadyCallbacks(lock, owner);
KeepTextureDataAliveForTextureHostIfNecessary(
lock, owner, owner->mWaitingTextureDataHolders);
KeepTextureDataAliveForTextureHostIfNecessary(
lock, owner, owner->mUsingTextureDataHolders);
KeepTextureDataAliveForTextureHostIfNecessary(
lock, owner, owner->mReleasingTextureDataHolders);
releasingOwners.push_back(std::move(it->second));
mTextureOwners.erase(it);
} }
mMonitor.Notify(); mMonitor.Notify();
@ -709,6 +695,66 @@ void RemoteTextureMap::UnregisterTextureOwners(
} }
} }
already_AddRefed<RemoteTextureTxnScheduler>
RemoteTextureMap::RegisterTxnScheduler(base::ProcessId aForPid,
RemoteTextureTxnType aType) {
MonitorAutoLock lock(mMonitor);
const auto key = std::pair(aForPid, aType);
auto it = mTxnSchedulers.find(key);
if (it != mTxnSchedulers.end()) {
return do_AddRef(it->second);
}
RefPtr<RemoteTextureTxnScheduler> scheduler(
new RemoteTextureTxnScheduler(aForPid, aType));
mTxnSchedulers.emplace(key, scheduler.get());
return scheduler.forget();
}
void RemoteTextureMap::UnregisterTxnScheduler(base::ProcessId aForPid,
RemoteTextureTxnType aType) {
MonitorAutoLock lock(mMonitor);
const auto key = std::pair(aForPid, aType);
auto it = mTxnSchedulers.find(key);
if (it == mTxnSchedulers.end()) {
MOZ_ASSERT_UNREACHABLE("Remote texture txn scheduler does not exist.");
return;
}
mTxnSchedulers.erase(it);
}
RemoteTextureTxnScheduler::~RemoteTextureTxnScheduler() {
NotifyTxn(std::numeric_limits<RemoteTextureTxnId>::max());
RemoteTextureMap::Get()->UnregisterTxnScheduler(mForPid, mType);
}
void RemoteTextureTxnScheduler::NotifyTxn(RemoteTextureTxnId aTxnId) {
MonitorAutoLock lock(RemoteTextureMap::Get()->mMonitor);
mLastTxnId = aTxnId;
for (; !mWaits.empty(); mWaits.pop_front()) {
auto& wait = mWaits.front();
if (wait.mTxnId > aTxnId) {
break;
}
RemoteTextureMap::Get()->NotifyTxn(lock, wait.mOwnerId, mForPid);
}
}
bool RemoteTextureTxnScheduler::WaitForTxn(const MonitorAutoLock& aProofOfLock,
RemoteTextureOwnerId aOwnerId,
RemoteTextureTxnId aTxnId) {
if (aTxnId <= mLastTxnId) {
return false;
}
mWaits.insert(std::upper_bound(mWaits.begin(), mWaits.end(), aTxnId),
Wait{aOwnerId, aTxnId});
return true;
}
void RemoteTextureMap::ClearRecycledTextures( void RemoteTextureMap::ClearRecycledTextures(
const std::unordered_set<RemoteTextureOwnerId, const std::unordered_set<RemoteTextureOwnerId,
RemoteTextureOwnerId::HashFn>& aOwnerIds, RemoteTextureOwnerId::HashFn>& aOwnerIds,
@ -846,37 +892,30 @@ void RemoteTextureMap::UpdateTexture(const MonitorAutoLock& aProofOfLock,
} }
} }
std::vector<std::function<void(const RemoteTextureInfo&)>> void RemoteTextureMap::GetRenderingReadyCallbacks(
RemoteTextureMap::GetRenderingReadyCallbacks(
const MonitorAutoLock& aProofOfLock, RemoteTextureMap::TextureOwner* aOwner, const MonitorAutoLock& aProofOfLock, RemoteTextureMap::TextureOwner* aOwner,
const RemoteTextureId aTextureId) { const RemoteTextureId aTextureId,
std::vector<std::function<void(const RemoteTextureInfo&)>>& aFunctions) {
MOZ_ASSERT(aOwner); MOZ_ASSERT(aOwner);
std::vector<std::function<void(const RemoteTextureInfo&)>> functions;
while (!aOwner->mRenderingReadyCallbackHolders.empty()) { while (!aOwner->mRenderingReadyCallbackHolders.empty()) {
auto& front = aOwner->mRenderingReadyCallbackHolders.front(); auto& front = aOwner->mRenderingReadyCallbackHolders.front();
if (aTextureId < front->mTextureId) { if (aTextureId < front->mTextureId) {
break; break;
} }
if (front->mCallback) { if (front->mCallback) {
functions.push_back(std::move(front->mCallback)); aFunctions.push_back(std::move(front->mCallback));
} }
aOwner->mRenderingReadyCallbackHolders.pop_front(); aOwner->mRenderingReadyCallbackHolders.pop_front();
} }
return functions;
} }
std::vector<std::function<void(const RemoteTextureInfo&)>> void RemoteTextureMap::GetAllRenderingReadyCallbacks(
RemoteTextureMap::GetAllRenderingReadyCallbacks( const MonitorAutoLock& aProofOfLock, RemoteTextureMap::TextureOwner* aOwner,
const MonitorAutoLock& aProofOfLock, std::vector<std::function<void(const RemoteTextureInfo&)>>& aFunctions) {
RemoteTextureMap::TextureOwner* aOwner) { GetRenderingReadyCallbacks(aProofOfLock, aOwner, RemoteTextureId::Max(),
auto functions = aFunctions);
GetRenderingReadyCallbacks(aProofOfLock, aOwner, RemoteTextureId::Max());
MOZ_ASSERT(aOwner->mRenderingReadyCallbackHolders.empty()); MOZ_ASSERT(aOwner->mRenderingReadyCallbackHolders.empty());
return functions;
} }
bool RemoteTextureMap::GetRemoteTexture( bool RemoteTextureMap::GetRemoteTexture(
@ -967,6 +1006,64 @@ bool RemoteTextureMap::GetRemoteTexture(
return false; return false;
} }
void RemoteTextureMap::NotifyTxn(const MonitorAutoLock& aProofOfLock,
const RemoteTextureOwnerId aOwnerId,
const base::ProcessId aForPid) {
if (auto* owner = GetTextureOwner(aProofOfLock, aOwnerId, aForPid)) {
if (!owner->mWaitForTxn) {
MOZ_ASSERT_UNREACHABLE("Expected texture owner to wait for txn.");
return;
}
owner->mWaitForTxn = false;
if (!owner->mDeferUnregister) {
// If unregistering was not deferred, then don't try to force
// unregistering yet.
return;
}
owner->mDeferUnregister->Dispatch(NS_NewRunnableFunction(
"RemoteTextureMap::SetLastRemoteTextureUse::Runnable",
[aOwnerId, aForPid]() {
RemoteTextureMap::Get()->UnregisterTextureOwner(aOwnerId, aForPid);
}));
}
}
bool RemoteTextureMap::WaitForTxn(const RemoteTextureOwnerId aOwnerId,
const base::ProcessId aForPid,
RemoteTextureTxnType aTxnType,
RemoteTextureTxnId aTxnId) {
MonitorAutoLock lock(mMonitor);
if (auto* owner = GetTextureOwner(lock, aOwnerId, aForPid)) {
if (owner->mDeferUnregister) {
MOZ_ASSERT_UNREACHABLE(
"Texture owner must wait for txn before unregistering.");
return false;
}
if (owner->mWaitForTxn) {
MOZ_ASSERT_UNREACHABLE("Texture owner already waiting for txn.");
return false;
}
const auto key = std::pair(aForPid, aTxnType);
auto it = mTxnSchedulers.find(key);
if (it == mTxnSchedulers.end()) {
// During shutdown, different toplevel protocols may go away in
// disadvantageous orders, causing us to sometimes be processing
// waits even though the source of transactions upon which the
// wait depends shut down. This is generally harmless to ignore,
// as it means no further transactions will be generated of that
// type and all such transactions have been processed before it
// unregistered.
NS_WARNING("Could not find scheduler for txn type.");
return false;
}
if (it->second->WaitForTxn(lock, aOwnerId, aTxnId)) {
owner->mWaitForTxn = true;
}
return true;
}
return false;
}
void RemoteTextureMap::ReleaseRemoteTextureHost( void RemoteTextureMap::ReleaseRemoteTextureHost(
RemoteTextureHostWrapper* aTextureHostWrapper) { RemoteTextureHostWrapper* aTextureHostWrapper) {
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());

View file

@ -134,6 +134,52 @@ class RemoteTextureRecycleBin final {
std::list<RecycledTextureHolder> mRecycledTextures; 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)
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;
};
/** /**
* A class provides API for remote texture owners. * A class provides API for remote texture owners.
*/ */
@ -233,7 +279,7 @@ class RemoteTextureMap {
void RegisterTextureOwner( void RegisterTextureOwner(
const RemoteTextureOwnerId aOwnerId, const base::ProcessId aForPid, const RemoteTextureOwnerId aOwnerId, const base::ProcessId aForPid,
const RefPtr<RemoteTextureRecycleBin>& aRecycleBin = nullptr); const RefPtr<RemoteTextureRecycleBin>& aRecycleBin = nullptr);
void UnregisterTextureOwner(const RemoteTextureOwnerId aOwnerIds, void UnregisterTextureOwner(const RemoteTextureOwnerId aOwnerId,
const base::ProcessId aForPid); const base::ProcessId aForPid);
void UnregisterTextureOwners( void UnregisterTextureOwners(
const std::unordered_set<RemoteTextureOwnerId, const std::unordered_set<RemoteTextureOwnerId,
@ -262,6 +308,10 @@ class RemoteTextureMap {
std::function<void(const RemoteTextureInfo&)>&& aReadyCallback, std::function<void(const RemoteTextureInfo&)>&& aReadyCallback,
bool aWaitForRemoteTextureOwner = false); bool aWaitForRemoteTextureOwner = false);
bool WaitForTxn(const RemoteTextureOwnerId aOwnerId,
const base::ProcessId aForPid, RemoteTextureTxnType aTxnType,
RemoteTextureTxnId aTxnId);
void ReleaseRemoteTextureHost(RemoteTextureHostWrapper* aTextureHostWrapper); void ReleaseRemoteTextureHost(RemoteTextureHostWrapper* aTextureHostWrapper);
RefPtr<TextureHost> GetOrCreateRemoteTextureHostWrapper( RefPtr<TextureHost> GetOrCreateRemoteTextureHostWrapper(
@ -305,7 +355,19 @@ class RemoteTextureMap {
static RefPtr<TextureHost> CreateRemoteTexture(TextureData* aTextureData, static RefPtr<TextureHost> CreateRemoteTexture(TextureData* aTextureData,
TextureFlags aTextureFlags); TextureFlags aTextureFlags);
already_AddRefed<RemoteTextureTxnScheduler> RegisterTxnScheduler(
base::ProcessId aForPid, RemoteTextureTxnType aType);
template <typename P>
already_AddRefed<RemoteTextureTxnScheduler> RegisterTxnScheduler(
P* aProtocol) {
return RegisterTxnScheduler(aProtocol->OtherPid(),
aProtocol->ToplevelProtocol()->GetProtocolId());
}
protected: protected:
friend class RemoteTextureTxnScheduler;
// Holds data related to remote texture // Holds data related to remote texture
struct TextureDataHolder { struct TextureDataHolder {
TextureDataHolder(const RemoteTextureId aTextureId, TextureDataHolder(const RemoteTextureId aTextureId,
@ -337,6 +399,11 @@ class RemoteTextureMap {
struct TextureOwner { struct TextureOwner {
bool mIsContextLost = false; 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 // Holds TextureDataHolders that wait to be used for building wr display
// list. // list.
std::deque<UniquePtr<TextureDataHolder>> mWaitingTextureDataHolders; std::deque<UniquePtr<TextureDataHolder>> mWaitingTextureDataHolders;
@ -371,14 +438,22 @@ class RemoteTextureMap {
RemoteTextureMap::TextureOwner* aOwner, RemoteTextureMap::TextureOwner* aOwner,
const RemoteTextureId aTextureId); const RemoteTextureId aTextureId);
std::vector<std::function<void(const RemoteTextureInfo&)>> UniquePtr<TextureOwner> UnregisterTextureOwner(
GetRenderingReadyCallbacks(const MonitorAutoLock& aProofOfLock, const MonitorAutoLock& aProofOfLock, const RemoteTextureOwnerId aOwnerId,
RemoteTextureMap::TextureOwner* aOwner, const base::ProcessId aForPid,
const RemoteTextureId aTextureId); std::vector<RefPtr<TextureHost>>& aReleasingTextures,
std::vector<std::function<void(const RemoteTextureInfo&)>>&
aRenderingReadyCallbacks);
std::vector<std::function<void(const RemoteTextureInfo&)>> void GetRenderingReadyCallbacks(
GetAllRenderingReadyCallbacks(const MonitorAutoLock& aProofOfLock, const MonitorAutoLock& aProofOfLock,
RemoteTextureMap::TextureOwner* aOwner); 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( void KeepTextureDataAliveForTextureHostIfNecessary(
const MonitorAutoLock& aProofOfLock, const MonitorAutoLock& aProofOfLock,
@ -392,6 +467,13 @@ class RemoteTextureMap {
const MonitorAutoLock& aProofOfLock, const RemoteTextureOwnerId aOwnerId, const MonitorAutoLock& aProofOfLock, const RemoteTextureOwnerId aOwnerId,
const base::ProcessId aForPid); 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; Monitor mMonitor MOZ_UNANNOTATED;
std::map<std::pair<base::ProcessId, RemoteTextureOwnerId>, std::map<std::pair<base::ProcessId, RemoteTextureOwnerId>,
@ -406,6 +488,10 @@ class RemoteTextureMap {
RefPtr<CompositableHost>> RefPtr<CompositableHost>>
mRemoteTexturePushListeners; mRemoteTexturePushListeners;
std::map<std::pair<base::ProcessId, RemoteTextureTxnType>,
RemoteTextureTxnScheduler*>
mTxnSchedulers;
static StaticAutoPtr<RemoteTextureMap> sInstance; static StaticAutoPtr<RemoteTextureMap> sInstance;
}; };

View file

@ -196,7 +196,9 @@ void ShareableCanvasRenderer::UpdateCompositableClient() {
EnsurePipeline(); EnsurePipeline();
forwarder->UseRemoteTexture(mCanvasClient, textureDesc.textureId(), forwarder->UseRemoteTexture(mCanvasClient, textureDesc.textureId(),
textureDesc.ownerId(), mData.mSize, flags); textureDesc.ownerId(), mData.mSize, flags);
if (provider) {
provider->UseCompositableForwarder(forwarder);
}
FireDidTransactionCallback(); FireDidTransactionCallback();
return; return;
} }

View file

@ -332,6 +332,8 @@ class TextureData {
virtual bool RequiresRefresh() const { return false; } virtual bool RequiresRefresh() const { return false; }
virtual void UseCompositableForwarder(CompositableForwarder* aForwarder) {}
protected: protected:
MOZ_COUNTED_DEFAULT_CTOR(TextureData) MOZ_COUNTED_DEFAULT_CTOR(TextureData)
}; };

View file

@ -5,6 +5,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "TextureRecorded.h" #include "TextureRecorded.h"
#include "mozilla/layers/CompositableForwarder.h"
#include "RecordedCanvasEventImpl.h" #include "RecordedCanvasEventImpl.h"
@ -31,7 +32,8 @@ RecordedTextureData::~RecordedTextureData() {
// because the TextureData might need to destroy its DrawTarget within a lock. // because the TextureData might need to destroy its DrawTarget within a lock.
mDT = nullptr; mDT = nullptr;
mCanvasChild->CleanupTexture(mTextureId); mCanvasChild->CleanupTexture(mTextureId);
mCanvasChild->RecordEvent(RecordedTextureDestruction(mTextureId)); mCanvasChild->RecordEvent(
RecordedTextureDestruction(mTextureId, mLastTxnType, mLastTxnId));
} }
void RecordedTextureData::FillInfo(TextureData::Info& aInfo) const { void RecordedTextureData::FillInfo(TextureData::Info& aInfo) const {
@ -165,6 +167,12 @@ bool RecordedTextureData::Serialize(SurfaceDescriptor& aDescriptor) {
return true; return true;
} }
void RecordedTextureData::UseCompositableForwarder(
CompositableForwarder* aForwarder) {
mLastTxnType = (RemoteTextureTxnType)aForwarder->GetFwdTransactionType();
mLastTxnId = (RemoteTextureTxnId)aForwarder->GetFwdTransactionId();
}
void RecordedTextureData::OnForwardedToHost() { void RecordedTextureData::OnForwardedToHost() {
// Compositing with RecordedTextureData requires RemoteTextureMap. // Compositing with RecordedTextureData requires RemoteTextureMap.
MOZ_CRASH("OnForwardedToHost not supported!"); MOZ_CRASH("OnForwardedToHost not supported!");

View file

@ -49,6 +49,8 @@ class RecordedTextureData final : public TextureData {
bool RequiresRefresh() const final; bool RequiresRefresh() const final;
void UseCompositableForwarder(CompositableForwarder* aForwarder) final;
private: private:
DISALLOW_COPY_AND_ASSIGN(RecordedTextureData); DISALLOW_COPY_AND_ASSIGN(RecordedTextureData);
@ -62,8 +64,10 @@ class RecordedTextureData final : public TextureData {
RefPtr<gfx::SourceSurface> mSnapshot; RefPtr<gfx::SourceSurface> mSnapshot;
ThreadSafeWeakPtr<gfx::SourceSurface> mSnapshotWrapper; ThreadSafeWeakPtr<gfx::SourceSurface> mSnapshotWrapper;
OpenMode mLockedMode; OpenMode mLockedMode;
layers::RemoteTextureId mLastRemoteTextureId; RemoteTextureId mLastRemoteTextureId;
layers::RemoteTextureOwnerId mRemoteTextureOwnerId; RemoteTextureOwnerId mRemoteTextureOwnerId;
RemoteTextureTxnType mLastTxnType = 0;
RemoteTextureTxnId mLastTxnId = 0;
bool mUsedRemoteTexture = false; bool mUsedRemoteTexture = false;
bool mInvalidContents = true; bool mInvalidContents = true;
}; };

View file

@ -796,19 +796,29 @@ already_AddRefed<gfx::DrawTarget> CanvasTranslator::CreateDrawTarget(
return dt.forget(); return dt.forget();
} }
void CanvasTranslator::RemoveTexture(int64_t aTextureId) { void CanvasTranslator::RemoveTexture(int64_t aTextureId,
RemoteTextureTxnType aTxnType,
RemoteTextureTxnId aTxnId) {
// Don't erase the texture if still in use // Don't erase the texture if still in use
auto result = mTextureInfo.find(aTextureId); auto result = mTextureInfo.find(aTextureId);
if (result == mTextureInfo.end() || --result->second.mLocked > 0) { if (result == mTextureInfo.end()) {
return; return;
} }
if (result->second.mTextureData) { auto& info = result->second;
result->second.mTextureData->Unlock(); if (aTxnType && aTxnId) {
RemoteTextureMap::Get()->WaitForTxn(info.mRemoteTextureOwnerId, mOtherPid,
aTxnType, aTxnId);
}
if (--info.mLocked > 0) {
return;
}
if (info.mTextureData) {
info.mTextureData->Unlock();
} }
if (mRemoteTextureOwner) { if (mRemoteTextureOwner) {
// If this texture id was manually registered as a remote texture owner, // If this texture id was manually registered as a remote texture owner,
// unregister it so it does not stick around after the texture id goes away. // unregister it so it does not stick around after the texture id goes away.
RemoteTextureOwnerId owner = result->second.mRemoteTextureOwnerId; RemoteTextureOwnerId owner = info.mRemoteTextureOwnerId;
if (owner.IsValid()) { if (owner.IsValid()) {
mRemoteTextureOwner->UnregisterTextureOwner(owner); mRemoteTextureOwner->UnregisterTextureOwner(owner);
} }

View file

@ -171,7 +171,8 @@ class CanvasTranslator final : public gfx::InlineTranslator,
* *
* @param aTextureId the texture ID to remove * @param aTextureId the texture ID to remove
*/ */
void RemoveTexture(int64_t aTextureId); void RemoveTexture(int64_t aTextureId, RemoteTextureTxnType aTxnType = 0,
RemoteTextureTxnId aTxnId = 0);
bool LockTexture(int64_t aTextureId, OpenMode aMode, bool LockTexture(int64_t aTextureId, OpenMode aMode,
bool aInvalidContents = false); bool aInvalidContents = false);

View file

@ -9,8 +9,9 @@
#include <stdint.h> // for int32_t, uint32_t, uint64_t #include <stdint.h> // for int32_t, uint32_t, uint64_t
#include "mozilla/Assertions.h" // for AssertionConditionType, MOZ_ASSERT, MOZ_ASSERT_HELPER1 #include "mozilla/Assertions.h" // for AssertionConditionType, MOZ_ASSERT, MOZ_ASSERT_HELPER1
#include "mozilla/RefPtr.h" // for RefPtr #include "mozilla/RefPtr.h" // for RefPtr
#include "mozilla/TimeStamp.h" // for TimeStamp #include "mozilla/TimeStamp.h" // for TimeStamp
#include "mozilla/ipc/ProtocolUtils.h" // for IToplevelProtocol, ProtocolID
#include "mozilla/layers/KnowsCompositor.h" // for KnowsCompositor #include "mozilla/layers/KnowsCompositor.h" // for KnowsCompositor
#include "nsRect.h" // for nsIntRect #include "nsRect.h" // for nsIntRect
#include "nsRegion.h" // for nsIntRegion #include "nsRegion.h" // for nsIntRegion
@ -25,6 +26,34 @@ class PTextureChild;
class SurfaceDescriptorTiles; class SurfaceDescriptorTiles;
class TextureClient; class TextureClient;
/**
* FwdTransactionCounter issues forwarder transaction numbers that represent a
* sequential stream of transactions to be transported over IPDL. Since every
* top-level protocol represents its own independently-sequenced IPDL queue,
* transaction numbers most naturally align with top-level protocols, rather
* than have different sub-protocols with their own independent transaction
* numbers that can't be usefully sequenced. FwdTransactionCounter expects
* users of it to provide themselves as proof they are a top-level protocol
* to avoid issues.
*/
struct FwdTransactionCounter {
explicit FwdTransactionCounter(mozilla::ipc::IToplevelProtocol* aToplevel)
: mFwdTransactionType(aToplevel->GetProtocolId()) {}
/**
* The ID of the top-level protocol. This is useful to tag the source of
* the transaction numbers in case different sources must be disambiguated.
*/
mozilla::ipc::ProtocolId mFwdTransactionType;
/**
* Transaction id of ShadowLayerForwarder.
* It is incremented by UpdateFwdTransactionId() in each BeginTransaction()
* call.
*/
uint64_t mFwdTransactionId = 0;
};
/** /**
* A transaction is a set of changes that happenned on the content side, that * A transaction is a set of changes that happenned on the content side, that
* should be sent to the compositor side. * should be sent to the compositor side.
@ -92,14 +121,23 @@ class CompositableForwarder : public KnowsCompositor {
CompositableClient* aCompositable, const RemoteTextureOwnerId aOwnerId, CompositableClient* aCompositable, const RemoteTextureOwnerId aOwnerId,
const gfx::IntSize aSize, const TextureFlags aFlags) = 0; const gfx::IntSize aSize, const TextureFlags aFlags) = 0;
virtual void UpdateFwdTransactionId() = 0; void UpdateFwdTransactionId() {
virtual uint64_t GetFwdTransactionId() = 0; ++GetFwdTransactionCounter().mFwdTransactionId;
}
uint64_t GetFwdTransactionId() {
return GetFwdTransactionCounter().mFwdTransactionId;
}
mozilla::ipc::ProtocolId GetFwdTransactionType() {
return GetFwdTransactionCounter().mFwdTransactionType;
}
virtual bool InForwarderThread() = 0; virtual bool InForwarderThread() = 0;
void AssertInForwarderThread() { MOZ_ASSERT(InForwarderThread()); } void AssertInForwarderThread() { MOZ_ASSERT(InForwarderThread()); }
protected: protected:
virtual FwdTransactionCounter& GetFwdTransactionCounter() = 0;
nsTArray<RefPtr<TextureClient>> mTexturesToRemove; nsTArray<RefPtr<TextureClient>> mTexturesToRemove;
nsTArray<RefPtr<CompositableClient>> mCompositableClientsToRemove; nsTArray<RefPtr<CompositableClient>> mCompositableClientsToRemove;
}; };

View file

@ -80,7 +80,6 @@ CompositorBridgeChild::CompositorBridgeChild(CompositorManagerChild* aManager)
mCanSend(false), mCanSend(false),
mActorDestroyed(false), mActorDestroyed(false),
mPaused(false), mPaused(false),
mFwdTransactionId(0),
mThread(NS_GetCurrentThread()), mThread(NS_GetCurrentThread()),
mProcessToken(0), mProcessToken(0),
mSectionAllocator(nullptr) { mSectionAllocator(nullptr) {
@ -470,7 +469,8 @@ void CompositorBridgeChild::HoldUntilCompositableRefReleasedIfNecessary(
return; return;
} }
aClient->SetLastFwdTransactionId(GetFwdTransactionId()); aClient->SetLastFwdTransactionId(
GetFwdTransactionCounter().mFwdTransactionId);
mTexturesWaitingNotifyNotUsed.emplace(aClient->GetSerial(), aClient); mTexturesWaitingNotifyNotUsed.emplace(aClient->GetSerial(), aClient);
} }
@ -632,5 +632,9 @@ wr::PipelineId CompositorBridgeChild::GetNextPipelineId() {
return wr::AsPipelineId(GetNextResourceId()); return wr::AsPipelineId(GetNextResourceId());
} }
FwdTransactionCounter& CompositorBridgeChild::GetFwdTransactionCounter() {
return mCompositorManager->GetFwdTransactionCounter();
}
} // namespace layers } // namespace layers
} // namespace mozilla } // namespace mozilla

View file

@ -47,6 +47,7 @@ class WebRenderLayerManager;
class TextureClient; class TextureClient;
class TextureClientPool; class TextureClientPool;
struct FrameMetrics; struct FrameMetrics;
struct FwdTransactionCounter;
class CompositorBridgeChild final : public PCompositorBridgeChild, class CompositorBridgeChild final : public PCompositorBridgeChild,
public TextureForwarder { public TextureForwarder {
@ -134,8 +135,7 @@ class CompositorBridgeChild final : public PCompositorBridgeChild,
static void ShutDown(); static void ShutDown();
void UpdateFwdTransactionId() { ++mFwdTransactionId; } FwdTransactionCounter& GetFwdTransactionCounter();
uint64_t GetFwdTransactionId() { return mFwdTransactionId; }
/** /**
* Hold TextureClient ref until end of usage on host side if * Hold TextureClient ref until end of usage on host side if
@ -224,13 +224,6 @@ class CompositorBridgeChild final : public PCompositorBridgeChild,
bool mPaused; bool mPaused;
/**
* Transaction id of ShadowLayerForwarder.
* It is incremented by UpdateFwdTransactionId() in each BeginTransaction()
* call.
*/
uint64_t mFwdTransactionId;
/** /**
* Hold TextureClients refs until end of their usages on host side. * Hold TextureClients refs until end of their usages on host side.
* It defer calling of TextureClient recycle callback. * It defer calling of TextureClient recycle callback.

View file

@ -176,7 +176,8 @@ CompositorManagerChild::CompositorManagerChild(CompositorManagerParent* aParent,
mNamespace(aNamespace), mNamespace(aNamespace),
mResourceId(0), mResourceId(0),
mCanSend(false), mCanSend(false),
mSameProcess(true) { mSameProcess(true),
mFwdTransactionCounter(this) {
MOZ_ASSERT(aParent); MOZ_ASSERT(aParent);
SetOtherProcessId(base::GetCurrentProcId()); SetOtherProcessId(base::GetCurrentProcId());
@ -195,7 +196,8 @@ CompositorManagerChild::CompositorManagerChild(
mNamespace(aNamespace), mNamespace(aNamespace),
mResourceId(0), mResourceId(0),
mCanSend(false), mCanSend(false),
mSameProcess(false) { mSameProcess(false),
mFwdTransactionCounter(this) {
if (NS_WARN_IF(!aEndpoint.Bind(this))) { if (NS_WARN_IF(!aEndpoint.Bind(this))) {
return; return;
} }

View file

@ -10,9 +10,10 @@
#include <stddef.h> // for size_t #include <stddef.h> // for size_t
#include <stdint.h> // for uint32_t, uint64_t #include <stdint.h> // for uint32_t, uint64_t
#include "mozilla/Atomics.h" #include "mozilla/Atomics.h"
#include "mozilla/Attributes.h" // for override #include "mozilla/Attributes.h" // for override
#include "mozilla/RefPtr.h" // for already_AddRefed #include "mozilla/RefPtr.h" // for already_AddRefed
#include "mozilla/StaticPtr.h" // for StaticRefPtr #include "mozilla/StaticPtr.h" // for StaticRefPtr
#include "mozilla/layers/CompositableForwarder.h" // for FwdTransactionCounter
#include "mozilla/layers/PCompositorManagerChild.h" #include "mozilla/layers/PCompositorManagerChild.h"
namespace mozilla { namespace mozilla {
@ -92,6 +93,10 @@ class CompositorManagerChild : public PCompositorManagerChild {
mozilla::ipc::IPCResult RecvNotifyWebRenderError( mozilla::ipc::IPCResult RecvNotifyWebRenderError(
const WebRenderError&& aError); const WebRenderError&& aError);
FwdTransactionCounter& GetFwdTransactionCounter() {
return mFwdTransactionCounter;
}
private: private:
static StaticRefPtr<CompositorManagerChild> sInstance; static StaticRefPtr<CompositorManagerChild> sInstance;
static Atomic<base::ProcessId> sOtherPid; static Atomic<base::ProcessId> sOtherPid;
@ -111,6 +116,7 @@ class CompositorManagerChild : public PCompositorManagerChild {
uint32_t mResourceId; uint32_t mResourceId;
bool mCanSend; bool mCanSend;
bool mSameProcess; bool mSameProcess;
FwdTransactionCounter mFwdTransactionCounter;
}; };
} // namespace layers } // namespace layers

View file

@ -12,6 +12,7 @@
#include "mozilla/layers/CompositorBridgeParent.h" #include "mozilla/layers/CompositorBridgeParent.h"
#include "mozilla/layers/ContentCompositorBridgeParent.h" #include "mozilla/layers/ContentCompositorBridgeParent.h"
#include "mozilla/layers/CompositorThread.h" #include "mozilla/layers/CompositorThread.h"
#include "mozilla/layers/RemoteTextureMap.h"
#include "mozilla/layers/SharedSurfacesParent.h" #include "mozilla/layers/SharedSurfacesParent.h"
#include "mozilla/UniquePtr.h" #include "mozilla/UniquePtr.h"
#include "mozilla/Unused.h" #include "mozilla/Unused.h"
@ -151,6 +152,10 @@ void CompositorManagerParent::ActorDestroy(ActorDestroyReason aReason) {
NewRunnableMethod("layers::CompositorManagerParent::DeferredDestroy", NewRunnableMethod("layers::CompositorManagerParent::DeferredDestroy",
this, &CompositorManagerParent::DeferredDestroy)); this, &CompositorManagerParent::DeferredDestroy));
if (mRemoteTextureTxnScheduler) {
mRemoteTextureTxnScheduler = nullptr;
}
StaticMonitorAutoLock lock(sMonitor); StaticMonitorAutoLock lock(sMonitor);
if (sInstance == this) { if (sInstance == this) {
sInstance = nullptr; sInstance = nullptr;
@ -372,6 +377,8 @@ mozilla::ipc::IPCResult CompositorManagerParent::RecvInitCanvasManager(
Endpoint<PCanvasManagerParent>&& aEndpoint) { Endpoint<PCanvasManagerParent>&& aEndpoint) {
gfx::CanvasManagerParent::Init(std::move(aEndpoint), mSharedSurfacesHolder, gfx::CanvasManagerParent::Init(std::move(aEndpoint), mSharedSurfacesHolder,
mContentId); mContentId);
mRemoteTextureTxnScheduler =
RemoteTextureMap::Get()->RegisterTxnScheduler(this);
return IPC_OK(); return IPC_OK();
} }

View file

@ -27,6 +27,7 @@ namespace layers {
class CompositorBridgeParent; class CompositorBridgeParent;
class CompositorThreadHolder; class CompositorThreadHolder;
class RemoteTextureTxnScheduler;
class SharedSurfacesHolder; class SharedSurfacesHolder;
class CompositorManagerParent final : public PCompositorManagerParent { class CompositorManagerParent final : public PCompositorManagerParent {
@ -104,6 +105,7 @@ class CompositorManagerParent final : public PCompositorManagerParent {
const dom::ContentParentId mContentId; const dom::ContentParentId mContentId;
const uint32_t mNamespace; const uint32_t mNamespace;
uint32_t mLastSharedSurfaceResourceId MOZ_GUARDED_BY(sMonitor) = 0; uint32_t mLastSharedSurfaceResourceId MOZ_GUARDED_BY(sMonitor) = 0;
RefPtr<RemoteTextureTxnScheduler> mRemoteTextureTxnScheduler;
}; };
} // namespace layers } // namespace layers

View file

@ -246,7 +246,7 @@ ImageBridgeChild::ImageBridgeChild(uint32_t aNamespace)
: mNamespace(aNamespace), : mNamespace(aNamespace),
mCanSend(false), mCanSend(false),
mDestroyed(false), mDestroyed(false),
mFwdTransactionId(0), mFwdTransactionCounter(this),
mContainerMapLock("ImageBridgeChild.mContainerMapLock") { mContainerMapLock("ImageBridgeChild.mContainerMapLock") {
MOZ_ASSERT(mNamespace); MOZ_ASSERT(mNamespace);
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());

View file

@ -308,8 +308,9 @@ class ImageBridgeChild final : public PImageBridgeChild,
bool IsSameProcess() const override; bool IsSameProcess() const override;
void UpdateFwdTransactionId() override { ++mFwdTransactionId; } FwdTransactionCounter& GetFwdTransactionCounter() override {
uint64_t GetFwdTransactionId() override { return mFwdTransactionId; } return mFwdTransactionCounter;
}
bool InForwarderThread() override { return InImageBridgeChildThread(); } bool InForwarderThread() override { return InImageBridgeChildThread(); }
@ -351,7 +352,7 @@ class ImageBridgeChild final : public PImageBridgeChild,
* It is incrementaed by UpdateFwdTransactionId() in each BeginTransaction() * It is incrementaed by UpdateFwdTransactionId() in each BeginTransaction()
* call. * call.
*/ */
uint64_t mFwdTransactionId; FwdTransactionCounter mFwdTransactionCounter;
/** /**
* Hold TextureClients refs until end of their usages on host side. * Hold TextureClients refs until end of their usages on host side.

View file

@ -22,6 +22,7 @@
#include "mozilla/layers/PImageBridgeParent.h" #include "mozilla/layers/PImageBridgeParent.h"
#include "mozilla/layers/TextureHostOGL.h" // for TextureHostOGL #include "mozilla/layers/TextureHostOGL.h" // for TextureHostOGL
#include "mozilla/layers/Compositor.h" #include "mozilla/layers/Compositor.h"
#include "mozilla/layers/RemoteTextureMap.h"
#include "mozilla/Monitor.h" #include "mozilla/Monitor.h"
#include "mozilla/mozalloc.h" // for operator new, etc #include "mozilla/mozalloc.h" // for operator new, etc
#include "mozilla/ProfilerLabels.h" #include "mozilla/ProfilerLabels.h"
@ -70,6 +71,8 @@ ImageBridgeParent::ImageBridgeParent(nsISerialEventTarget* aThread,
mCompositorThreadHolder(CompositorThreadHolder::GetSingleton()) { mCompositorThreadHolder(CompositorThreadHolder::GetSingleton()) {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
SetOtherProcessId(aChildProcessId); SetOtherProcessId(aChildProcessId);
mRemoteTextureTxnScheduler =
RemoteTextureMap::Get()->RegisterTxnScheduler(this);
} }
ImageBridgeParent::~ImageBridgeParent() = default; ImageBridgeParent::~ImageBridgeParent() = default;
@ -142,6 +145,9 @@ void ImageBridgeParent::ActorDestroy(ActorDestroyReason aWhy) {
// Can't alloc/dealloc shmems from now on. // Can't alloc/dealloc shmems from now on.
mClosed = true; mClosed = true;
if (mRemoteTextureTxnScheduler) {
mRemoteTextureTxnScheduler = nullptr;
}
for (const auto& entry : mCompositables) { for (const auto& entry : mCompositables) {
entry.second->OnReleased(); entry.second->OnReleased();
} }
@ -198,13 +204,16 @@ mozilla::ipc::IPCResult ImageBridgeParent::RecvUpdate(
&aToDestroy); &aToDestroy);
UpdateFwdTransactionId(aFwdTransactionId); UpdateFwdTransactionId(aFwdTransactionId);
auto result = IPC_OK();
for (const auto& edit : aEdits) { for (const auto& edit : aEdits) {
RefPtr<CompositableHost> compositable = RefPtr<CompositableHost> compositable =
FindCompositable(edit.compositable()); FindCompositable(edit.compositable());
if (!compositable || if (!compositable ||
!ReceiveCompositableUpdate(edit.detail(), WrapNotNull(compositable), !ReceiveCompositableUpdate(edit.detail(), WrapNotNull(compositable),
edit.compositable())) { edit.compositable())) {
return IPC_FAIL_NO_REASON(this); result = IPC_FAIL_NO_REASON(this);
break;
} }
uint32_t dropped = compositable->GetDroppedFrames(); uint32_t dropped = compositable->GetDroppedFrames();
if (dropped) { if (dropped) {
@ -212,7 +221,11 @@ mozilla::ipc::IPCResult ImageBridgeParent::RecvUpdate(
} }
} }
return IPC_OK(); if (mRemoteTextureTxnScheduler) {
mRemoteTextureTxnScheduler->NotifyTxn(aFwdTransactionId);
}
return result;
} }
/* static */ /* static */

View file

@ -28,6 +28,7 @@ class Shmem;
namespace layers { namespace layers {
struct ImageCompositeNotificationInfo; struct ImageCompositeNotificationInfo;
class RemoteTextureTxnScheduler;
/** /**
* ImageBridgeParent is the manager Protocol of async Compositables. * ImageBridgeParent is the manager Protocol of async Compositables.
@ -143,6 +144,8 @@ class ImageBridgeParent final : public PImageBridgeParent,
static ImageBridgeMap sImageBridges; static ImageBridgeMap sImageBridges;
RefPtr<CompositorThreadHolder> mCompositorThreadHolder; RefPtr<CompositorThreadHolder> mCompositorThreadHolder;
RefPtr<RemoteTextureTxnScheduler> mRemoteTextureTxnScheduler;
}; };
} // namespace layers } // namespace layers

View file

@ -460,12 +460,8 @@ void WebRenderBridgeChild::EnableRemoteTexturePushCallback(
OpEnableRemoteTexturePushCallback(aOwnerId, aSize, aFlags))); OpEnableRemoteTexturePushCallback(aOwnerId, aSize, aFlags)));
} }
void WebRenderBridgeChild::UpdateFwdTransactionId() { FwdTransactionCounter& WebRenderBridgeChild::GetFwdTransactionCounter() {
GetCompositorBridgeChild()->UpdateFwdTransactionId(); return GetCompositorBridgeChild()->GetFwdTransactionCounter();
}
uint64_t WebRenderBridgeChild::GetFwdTransactionId() {
return GetCompositorBridgeChild()->GetFwdTransactionId();
} }
bool WebRenderBridgeChild::InForwarderThread() { return NS_IsMainThread(); } bool WebRenderBridgeChild::InForwarderThread() { return NS_IsMainThread(); }

View file

@ -206,8 +206,8 @@ class WebRenderBridgeChild final : public PWebRenderBridgeChild,
const RemoteTextureOwnerId aOwnerId, const RemoteTextureOwnerId aOwnerId,
const gfx::IntSize aSize, const gfx::IntSize aSize,
const TextureFlags aFlags) override; const TextureFlags aFlags) override;
void UpdateFwdTransactionId() override; FwdTransactionCounter& GetFwdTransactionCounter() override;
uint64_t GetFwdTransactionId() override;
bool InForwarderThread() override; bool InForwarderThread() override;
void ActorDestroy(ActorDestroyReason why) override; void ActorDestroy(ActorDestroyReason why) override;

View file

@ -34,6 +34,7 @@
#include "mozilla/layers/ImageDataSerializer.h" #include "mozilla/layers/ImageDataSerializer.h"
#include "mozilla/layers/IpcResourceUpdateQueue.h" #include "mozilla/layers/IpcResourceUpdateQueue.h"
#include "mozilla/layers/OMTASampler.h" #include "mozilla/layers/OMTASampler.h"
#include "mozilla/layers/RemoteTextureMap.h"
#include "mozilla/layers/SharedSurfacesParent.h" #include "mozilla/layers/SharedSurfacesParent.h"
#include "mozilla/layers/TextureHost.h" #include "mozilla/layers/TextureHost.h"
#include "mozilla/layers/AsyncImagePipelineManager.h" #include "mozilla/layers/AsyncImagePipelineManager.h"
@ -314,6 +315,8 @@ WebRenderBridgeParent::WebRenderBridgeParent(
mBoolParameterBits = ~gfxVars::WebRenderBoolParameters(); mBoolParameterBits = ~gfxVars::WebRenderBoolParameters();
UpdateBoolParameters(); UpdateBoolParameters();
} }
mRemoteTextureTxnScheduler =
RemoteTextureMap::Get()->RegisterTxnScheduler(aCompositorBridge);
} }
WebRenderBridgeParent::WebRenderBridgeParent(const wr::PipelineId& aPipelineId, WebRenderBridgeParent::WebRenderBridgeParent(const wr::PipelineId& aPipelineId,
@ -391,6 +394,9 @@ void WebRenderBridgeParent::Destroy() {
IsRootWebRenderBridgeParent()); IsRootWebRenderBridgeParent());
mDestroyed = true; mDestroyed = true;
if (mRemoteTextureTxnScheduler) {
mRemoteTextureTxnScheduler = nullptr;
}
if (mWebRenderBridgeRef) { if (mWebRenderBridgeRef) {
// Break mutual reference // Break mutual reference
mWebRenderBridgeRef->Clear(); mWebRenderBridgeRef->Clear();
@ -1232,6 +1238,10 @@ mozilla::ipc::IPCResult WebRenderBridgeParent::RecvSetDisplayList(
wr::IpcResourceUpdateQueue::ReleaseShmems(this, aDisplayList.mSmallShmems); wr::IpcResourceUpdateQueue::ReleaseShmems(this, aDisplayList.mSmallShmems);
wr::IpcResourceUpdateQueue::ReleaseShmems(this, aDisplayList.mLargeShmems); wr::IpcResourceUpdateQueue::ReleaseShmems(this, aDisplayList.mLargeShmems);
if (mRemoteTextureTxnScheduler) {
mRemoteTextureTxnScheduler->NotifyTxn(aFwdTransactionId);
}
if (!success) { if (!success) {
return IPC_FAIL(this, "Failed to process DisplayListData."); return IPC_FAIL(this, "Failed to process DisplayListData.");
} }
@ -1383,6 +1393,10 @@ mozilla::ipc::IPCResult WebRenderBridgeParent::RecvEmptyTransaction(
aTransactionData->mLargeShmems); aTransactionData->mLargeShmems);
} }
if (mRemoteTextureTxnScheduler) {
mRemoteTextureTxnScheduler->NotifyTxn(aFwdTransactionId);
}
if (!success) { if (!success) {
return IPC_FAIL(this, "Failed to process empty transaction update."); return IPC_FAIL(this, "Failed to process empty transaction update.");
} }

View file

@ -47,6 +47,7 @@ class Compositor;
class CompositorBridgeParentBase; class CompositorBridgeParentBase;
class CompositorVsyncScheduler; class CompositorVsyncScheduler;
class OMTASampler; class OMTASampler;
class RemoteTextureTxnScheduler;
class UiCompositorControllerParent; class UiCompositorControllerParent;
class WebRenderBridgeParentRef; class WebRenderBridgeParentRef;
class WebRenderImageHost; class WebRenderImageHost;
@ -496,6 +497,8 @@ class WebRenderBridgeParent final : public PWebRenderBridgeParent,
// These payloads are being used for SCROLL_PRESENT_LATENCY telemetry // These payloads are being used for SCROLL_PRESENT_LATENCY telemetry
DataMutex<nsClassHashtable<nsUint64HashKey, nsTArray<CompositionPayload>>> DataMutex<nsClassHashtable<nsUint64HashKey, nsTArray<CompositionPayload>>>
mPendingScrollPayloads; mPendingScrollPayloads;
RefPtr<RemoteTextureTxnScheduler> mRemoteTextureTxnScheduler;
}; };
// Use this class, since WebRenderBridgeParent could not supports // Use this class, since WebRenderBridgeParent could not supports