fune/gfx/layers/wr/WebRenderBridgeChild.h
Lee Salzman 6accc1036c 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
2024-01-09 11:53:14 +00:00

264 lines
9.3 KiB
C++

/* -*- 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_layers_WebRenderBridgeChild_h
#define mozilla_layers_WebRenderBridgeChild_h
#include "mozilla/layers/CompositableForwarder.h"
#include "mozilla/layers/PWebRenderBridgeChild.h"
namespace mozilla {
namespace widget {
class CompositorWidget;
}
namespace wr {
class DisplayListBuilder;
class ResourceUpdateQueue;
class IpcResourceUpdateQueue;
} // namespace wr
namespace layers {
class CompositableClient;
class CompositorBridgeChild;
class StackingContextHelper;
class TextureForwarder;
class WebRenderLayerManager;
template <class T>
class ThreadSafeWeakPtrHashKey : public PLDHashEntryHdr {
public:
typedef RefPtr<T> KeyType;
typedef const T* KeyTypePointer;
explicit ThreadSafeWeakPtrHashKey(KeyTypePointer aKey)
: mKey(do_AddRef(const_cast<T*>(aKey))) {}
KeyType GetKey() const { return do_AddRef(mKey); }
bool KeyEquals(KeyTypePointer aKey) const { return mKey == aKey; }
static KeyTypePointer KeyToPointer(const KeyType& aKey) { return aKey.get(); }
static PLDHashNumber HashKey(KeyTypePointer aKey) {
return NS_PTR_TO_UINT32(aKey) >> 2;
}
enum { ALLOW_MEMMOVE = true };
private:
ThreadSafeWeakPtr<T> mKey;
};
typedef ThreadSafeWeakPtrHashKey<gfx::UnscaledFont> UnscaledFontHashKey;
typedef ThreadSafeWeakPtrHashKey<gfx::ScaledFont> ScaledFontHashKey;
class WebRenderBridgeChild final : public PWebRenderBridgeChild,
public CompositableForwarder {
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WebRenderBridgeChild, override)
friend class PWebRenderBridgeChild;
public:
explicit WebRenderBridgeChild(const wr::PipelineId& aPipelineId);
void AddWebRenderParentCommand(const WebRenderParentCommand& aCmd);
bool HasWebRenderParentCommands() { return !mParentCommands.IsEmpty(); }
void UpdateResources(wr::IpcResourceUpdateQueue& aResources);
void BeginTransaction();
bool EndTransaction(DisplayListData&& aDisplayListData,
TransactionId aTransactionId, bool aContainsSVGroup,
const mozilla::VsyncId& aVsyncId,
const mozilla::TimeStamp& aVsyncStartTime,
const mozilla::TimeStamp& aRefreshStartTime,
const mozilla::TimeStamp& aTxnStartTime,
const nsCString& aTxtURL);
void EndEmptyTransaction(const FocusTarget& aFocusTarget,
Maybe<TransactionData>&& aTransactionData,
TransactionId aTransactionId,
const mozilla::VsyncId& aVsyncId,
const mozilla::TimeStamp& aVsyncStartTime,
const mozilla::TimeStamp& aRefreshStartTime,
const mozilla::TimeStamp& aTxnStartTime,
const nsCString& aTxtURL);
void ProcessWebRenderParentCommands();
CompositorBridgeChild* GetCompositorBridgeChild();
wr::PipelineId GetPipeline() { return mPipelineId; }
// KnowsCompositor
TextureForwarder* GetTextureForwarder() override;
LayersIPCActor* GetLayersIPCActor() override;
void SyncWithCompositor() override;
void AddPipelineIdForCompositable(const wr::PipelineId& aPipelineId,
const CompositableHandle& aHandle,
CompositableHandleOwner aOwner);
void RemovePipelineIdForCompositable(const wr::PipelineId& aPipelineId);
/// Release TextureClient that is bounded to ImageKey.
/// It is used for recycling TextureClient.
void ReleaseTextureOfImage(const wr::ImageKey& aKey);
/**
* Clean this up, finishing with SendShutDown() which will cause __delete__
* to be sent from the parent side.
*/
void Destroy(bool aIsSync);
bool IPCOpen() const { return mIPCOpen && !mDestroyed; }
bool GetSentDisplayList() const { return mSentDisplayList; }
bool IsDestroyed() const { return mDestroyed; }
uint32_t GetNextResourceId() { return ++mResourceId; }
wr::IdNamespace GetNamespace() { return mIdNamespace; }
void SetNamespace(wr::IdNamespace aIdNamespace) {
mIdNamespace = aIdNamespace;
}
bool MatchesNamespace(const wr::ImageKey& aImageKey) const {
return aImageKey.mNamespace == mIdNamespace;
}
bool MatchesNamespace(const wr::BlobImageKey& aBlobKey) const {
return MatchesNamespace(aBlobKey._0);
}
wr::FontKey GetNextFontKey() {
return wr::FontKey{GetNamespace(), GetNextResourceId()};
}
wr::FontInstanceKey GetNextFontInstanceKey() {
return wr::FontInstanceKey{GetNamespace(), GetNextResourceId()};
}
wr::WrImageKey GetNextImageKey() {
return wr::WrImageKey{GetNamespace(), GetNextResourceId()};
}
void PushGlyphs(wr::DisplayListBuilder& aBuilder,
wr::IpcResourceUpdateQueue& aResources,
Range<const wr::GlyphInstance> aGlyphs,
gfx::ScaledFont* aFont, const wr::ColorF& aColor,
const StackingContextHelper& aSc,
const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip,
bool aBackfaceVisible,
const wr::GlyphOptions* aGlyphOptions = nullptr);
Maybe<wr::FontInstanceKey> GetFontKeyForScaledFont(
gfx::ScaledFont* aScaledFont, wr::IpcResourceUpdateQueue& aResources);
Maybe<wr::FontKey> GetFontKeyForUnscaledFont(
gfx::UnscaledFont* aUnscaledFont, wr::IpcResourceUpdateQueue& aResources);
void RemoveExpiredFontKeys(wr::IpcResourceUpdateQueue& aResources);
void BeginClearCachedResources();
void EndClearCachedResources();
void SetWebRenderLayerManager(WebRenderLayerManager* aManager);
mozilla::ipc::IShmemAllocator* GetShmemAllocator();
bool IsThreadSafe() const override { return false; }
RefPtr<KnowsCompositor> GetForMedia() override;
/// Alloc a specific type of shmem that is intended for use in
/// IpcResourceUpdateQueue only, and cache at most one of them,
/// when called multiple times.
///
/// Do not use this for anything else.
bool AllocResourceShmem(size_t aSize, RefCountedShmem& aShm);
/// Dealloc shared memory that was allocated with AllocResourceShmem.
///
/// Do not use this for anything else.
void DeallocResourceShmem(RefCountedShmem& aShm);
void Capture();
void StartCaptureSequence(const nsCString& path, uint32_t aFlags);
void StopCaptureSequence();
private:
friend class CompositorBridgeChild;
~WebRenderBridgeChild();
wr::ExternalImageId GetNextExternalImageId();
// CompositableForwarder
void Connect(CompositableClient* aCompositable,
ImageContainer* aImageContainer = nullptr) override;
void ReleaseCompositable(const CompositableHandle& aHandle) override;
bool DestroyInTransaction(PTextureChild* aTexture) override;
bool DestroyInTransaction(const CompositableHandle& aHandle);
void RemoveTextureFromCompositable(CompositableClient* aCompositable,
TextureClient* aTexture) override;
void UseTextures(CompositableClient* aCompositable,
const nsTArray<TimedTextureClient>& aTextures) override;
void UseRemoteTexture(CompositableClient* aCompositable,
const RemoteTextureId aTextureId,
const RemoteTextureOwnerId aOwnerId,
const gfx::IntSize aSize,
const TextureFlags aFlags) override;
void EnableRemoteTexturePushCallback(CompositableClient* aCompositable,
const RemoteTextureOwnerId aOwnerId,
const gfx::IntSize aSize,
const TextureFlags aFlags) override;
FwdTransactionCounter& GetFwdTransactionCounter() override;
bool InForwarderThread() override;
void ActorDestroy(ActorDestroyReason why) override;
void DoDestroy();
mozilla::ipc::IPCResult RecvWrUpdated(
const wr::IdNamespace& aNewIdNamespace,
const TextureFactoryIdentifier& textureFactoryIdentifier);
mozilla::ipc::IPCResult RecvWrReleasedImages(
nsTArray<wr::ExternalImageKeyPair>&& aPairs);
void AddIPDLReference() {
MOZ_ASSERT(mIPCOpen == false);
mIPCOpen = true;
AddRef();
}
void ReleaseIPDLReference() {
MOZ_ASSERT(mIPCOpen == true);
mIPCOpen = false;
Release();
}
bool AddOpDestroy(const OpDestroy& aOp);
nsTArray<OpDestroy> mDestroyedActors;
nsTArray<WebRenderParentCommand> mParentCommands;
nsTHashMap<nsUint64HashKey, CompositableClient*> mCompositables;
bool mIsInTransaction;
bool mIsInClearCachedResources;
wr::IdNamespace mIdNamespace;
uint32_t mResourceId;
wr::PipelineId mPipelineId;
WebRenderLayerManager* mManager;
bool mIPCOpen;
bool mDestroyed;
// True iff we have called SendSetDisplayList and haven't called
// SendClearCachedResources since that call.
bool mSentDisplayList;
uint32_t mFontKeysDeleted;
nsTHashMap<UnscaledFontHashKey, wr::FontKey> mFontKeys;
uint32_t mFontInstanceKeysDeleted;
nsTHashMap<ScaledFontHashKey, wr::FontInstanceKey> mFontInstanceKeys;
RefCountedShmem mResourceShm;
};
} // namespace layers
} // namespace mozilla
#endif // mozilla_layers_WebRenderBridgeChild_h