diff --git a/gfx/layers/ipc/CompositorBridgeChild.cpp b/gfx/layers/ipc/CompositorBridgeChild.cpp index d5465ec7d31f..1f1dd9b72775 100644 --- a/gfx/layers/ipc/CompositorBridgeChild.cpp +++ b/gfx/layers/ipc/CompositorBridgeChild.cpp @@ -13,6 +13,7 @@ #include "base/task.h" // for NewRunnableMethod, etc #include "gfxPrefs.h" #include "mozilla/dom/TabGroup.h" +#include "mozilla/layers/CompositorManagerChild.h" #include "mozilla/layers/ImageBridgeChild.h" #include "mozilla/layers/APZChild.h" #include "mozilla/layers/IAPZCTreeManager.h" @@ -77,17 +78,18 @@ static StaticRefPtr sCompositorBridge; Atomic KnowsCompositor::sSerialCounter(0); -CompositorBridgeChild::CompositorBridgeChild(LayerManager *aLayerManager, uint32_t aNamespace) - : mLayerManager(aLayerManager) - , mIdNamespace(aNamespace) +CompositorBridgeChild::CompositorBridgeChild(CompositorManagerChild *aManager) + : mCompositorManager(aManager) + , mIdNamespace(0) , mResourceId(0) , mCanSend(false) + , mActorDestroyed(false) , mFwdTransactionId(0) , mDeviceResetSequenceNumber(0) , mMessageLoop(MessageLoop::current()) + , mProcessToken(0) , mSectionAllocator(nullptr) { - MOZ_ASSERT(mIdNamespace); MOZ_ASSERT(NS_IsMainThread()); } @@ -104,12 +106,18 @@ CompositorBridgeChild::IsSameProcess() const return OtherPid() == base::GetCurrentProcId(); } -static void DeferredDestroyCompositor(RefPtr aCompositorBridgeParent, - RefPtr aCompositorBridgeChild) +void +CompositorBridgeChild::AfterDestroy() { - aCompositorBridgeChild->Close(); + // Note that we cannot rely upon mCanSend here because we already set that to + // false to prevent normal IPDL calls from being made after SendWillClose. + // The only time we should not issue Send__delete__ is if the actor is already + // destroyed, e.g. the compositor process crashed. + if (!mActorDestroyed) { + Send__delete__(this); + } - if (sCompositorBridge == aCompositorBridgeChild) { + if (sCompositorBridge == this) { sCompositorBridge = nullptr; } } @@ -183,8 +191,9 @@ CompositorBridgeChild::Destroy() // handle compositor desctruction. // From now on we can't send any message message. - MessageLoop::current()->PostTask( - NewRunnableFunction(DeferredDestroyCompositor, mCompositorBridgeParent, selfRef)); + MessageLoop::current()->PostTask(NewRunnableMethod( + "CompositorBridgeChild::AfterDestroy", + selfRef, &CompositorBridgeChild::AfterDestroy)); } // static @@ -209,28 +218,11 @@ CompositorBridgeChild::LookupCompositorFrameMetrics(const FrameMetrics::ViewID a return false; } -/* static */ bool -CompositorBridgeChild::InitForContent(Endpoint&& aEndpoint, uint32_t aNamespace) -{ - // There's only one compositor per child process. - MOZ_ASSERT(!sCompositorBridge); - - RefPtr child(new CompositorBridgeChild(nullptr, aNamespace)); - if (!aEndpoint.Bind(child)) { - NS_RUNTIMEABORT("Couldn't Open() Compositor channel."); - return false; - } - child->InitIPDL(); - - // We release this ref in DeferredDestroyCompositor. - sCompositorBridge = child; - return true; -} - -/* static */ bool -CompositorBridgeChild::ReinitForContent(Endpoint&& aEndpoint, uint32_t aNamespace) +void +CompositorBridgeChild::InitForContent(uint32_t aNamespace) { MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(aNamespace); if (RefPtr old = sCompositorBridge.forget()) { // Note that at this point, ActorDestroy may not have been called yet, @@ -240,59 +232,25 @@ CompositorBridgeChild::ReinitForContent(Endpoint&& aEndp old->Destroy(); } - return InitForContent(Move(aEndpoint), aNamespace); -} - -CompositorBridgeParent* -CompositorBridgeChild::InitSameProcess(widget::CompositorWidget* aWidget, - const uint64_t& aLayerTreeId, - CSSToLayoutDeviceScale aScale, - const CompositorOptions& aOptions, - bool aUseExternalSurface, - const gfx::IntSize& aSurfaceSize) -{ - TimeDuration vsyncRate = - gfxPlatform::GetPlatform()->GetHardwareVsync()->GetGlobalDisplay().GetVsyncRate(); - - mCompositorBridgeParent = - new CompositorBridgeParent(aScale, vsyncRate, aOptions, aUseExternalSurface, aSurfaceSize); - - bool ok = Open(mCompositorBridgeParent->GetIPCChannel(), - CompositorThreadHolder::Loop(), - ipc::ChildSide); - MOZ_RELEASE_ASSERT(ok); - - InitIPDL(); - mCompositorBridgeParent->InitSameProcess(aWidget, aLayerTreeId); - return mCompositorBridgeParent; -} - -/* static */ RefPtr -CompositorBridgeChild::CreateRemote(const uint64_t& aProcessToken, - LayerManager* aLayerManager, - Endpoint&& aEndpoint, - uint32_t aNamespace) -{ - RefPtr child = new CompositorBridgeChild(aLayerManager, aNamespace); - if (!aEndpoint.Bind(child)) { - return nullptr; - } - child->InitIPDL(); - child->mProcessToken = aProcessToken; - return child; -} - -void -CompositorBridgeChild::InitIPDL() -{ mCanSend = true; - AddRef(); + mIdNamespace = aNamespace; + sCompositorBridge = this; } void -CompositorBridgeChild::DeallocPCompositorBridgeChild() +CompositorBridgeChild::InitForWidget(uint64_t aProcessToken, + LayerManager* aLayerManager, + uint32_t aNamespace) { - Release(); + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(aProcessToken); + MOZ_ASSERT(aLayerManager); + MOZ_ASSERT(aNamespace); + + mCanSend = true; + mProcessToken = aProcessToken; + mLayerManager = aLayerManager; + mIdNamespace = aNamespace; } /*static*/ CompositorBridgeChild* @@ -584,6 +542,7 @@ CompositorBridgeChild::ActorDestroy(ActorDestroyReason aWhy) } mCanSend = false; + mActorDestroyed = true; if (mProcessToken && XRE_IsParentProcess()) { GPUProcessManager::Get()->NotifyRemoteActorDestroyed(mProcessToken); diff --git a/gfx/layers/ipc/CompositorBridgeChild.h b/gfx/layers/ipc/CompositorBridgeChild.h index 7986e90bdb9d..d488dc5c7772 100644 --- a/gfx/layers/ipc/CompositorBridgeChild.h +++ b/gfx/layers/ipc/CompositorBridgeChild.h @@ -39,6 +39,7 @@ class IAPZCTreeManager; class APZCTreeManagerChild; class ClientLayerManager; class CompositorBridgeParent; +class CompositorManagerChild; class CompositorOptions; class TextureClient; class TextureClientPool; @@ -52,7 +53,16 @@ class CompositorBridgeChild final : public PCompositorBridgeChild, public: NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CompositorBridgeChild, override); - explicit CompositorBridgeChild(LayerManager *aLayerManager, uint32_t aNamespace); + explicit CompositorBridgeChild(CompositorManagerChild* aManager); + + /** + * Initialize the singleton compositor bridge for a content process. + */ + void InitForContent(uint32_t aNamespace); + + void InitForWidget(uint64_t aProcessToken, + LayerManager* aLayerManager, + uint32_t aNamespace); void Destroy(); @@ -63,30 +73,6 @@ public: */ bool LookupCompositorFrameMetrics(const FrameMetrics::ViewID aId, FrameMetrics&); - /** - * Initialize the singleton compositor bridge for a content process. - */ - static bool InitForContent(Endpoint&& aEndpoint, uint32_t aNamespace); - static bool ReinitForContent(Endpoint&& aEndpoint, uint32_t aNamespace); - - static RefPtr CreateRemote( - const uint64_t& aProcessToken, - LayerManager* aLayerManager, - Endpoint&& aEndpoint, - uint32_t aNamespace); - - /** - * Initialize the CompositorBridgeChild, create CompositorBridgeParent, and - * open a same-process connection. - */ - CompositorBridgeParent* InitSameProcess( - widget::CompositorWidget* aWidget, - const uint64_t& aLayerTreeId, - CSSToLayoutDeviceScale aScale, - const CompositorOptions& aOptions, - bool aUseExternalSurface, - const gfx::IntSize& aSurfaceSize); - static CompositorBridgeChild* Get(); static bool ChildProcessHasCompositorBridge(); @@ -237,8 +223,7 @@ private: // Private destructor, to discourage deletion outside of Release(): virtual ~CompositorBridgeChild(); - void InitIPDL(); - void DeallocPCompositorBridgeChild() override; + void AfterDestroy(); virtual PLayerTransactionChild* AllocPLayerTransactionChild(const nsTArray& aBackendHints, @@ -291,6 +276,8 @@ private: uint32_t mAPZCId; }; + RefPtr mCompositorManager; + RefPtr mLayerManager; uint32_t mIdNamespace; @@ -313,6 +300,9 @@ private: // True until the beginning of the two-step shutdown sequence of this actor. bool mCanSend; + // False until the actor is destroyed. + bool mActorDestroyed; + /** * Transaction id of ShadowLayerForwarder. * It is incrementaed by UpdateFwdTransactionId() in each BeginTransaction() call. diff --git a/gfx/layers/ipc/CompositorBridgeParent.cpp b/gfx/layers/ipc/CompositorBridgeParent.cpp index 9ceaf19669c7..689870520d91 100644 --- a/gfx/layers/ipc/CompositorBridgeParent.cpp +++ b/gfx/layers/ipc/CompositorBridgeParent.cpp @@ -42,6 +42,7 @@ #include "mozilla/layers/AsyncCompositionManager.h" #include "mozilla/layers/BasicCompositor.h" // for BasicCompositor #include "mozilla/layers/Compositor.h" // for Compositor +#include "mozilla/layers/CompositorManagerParent.h" // for CompositorManagerParent #include "mozilla/layers/CompositorOGL.h" // for CompositorOGL #include "mozilla/layers/CompositorThread.h" #include "mozilla/layers/CompositorTypes.h" @@ -106,6 +107,16 @@ using namespace std; using base::ProcessId; using base::Thread; +CompositorBridgeParentBase::CompositorBridgeParentBase(CompositorManagerParent* aManager) + : mCanSend(true) + , mCompositorManager(aManager) +{ +} + +CompositorBridgeParentBase::~CompositorBridgeParentBase() +{ +} + ProcessId CompositorBridgeParentBase::GetChildProcessId() { @@ -169,6 +180,9 @@ CompositorBridgeParentBase::StartSharingMetrics(ipc::SharedMemoryBasic::Handle a uint64_t aLayersId, uint32_t aApzcId) { + if (!mCanSend) { + return false; + } return PCompositorBridgeParent::SendSharedCompositorFrameMetrics( aHandle, aMutexHandle, aLayersId, aApzcId); } @@ -177,6 +191,9 @@ bool CompositorBridgeParentBase::StopSharingMetrics(FrameMetrics::ViewID aScrollId, uint32_t aApzcId) { + if (!mCanSend) { + return false; + } return PCompositorBridgeParent::SendReleaseSharedCompositorFrameMetrics( aScrollId, aApzcId); } @@ -298,12 +315,14 @@ CompositorLoop() return CompositorThreadHolder::Loop(); } -CompositorBridgeParent::CompositorBridgeParent(CSSToLayoutDeviceScale aScale, +CompositorBridgeParent::CompositorBridgeParent(CompositorManagerParent* aManager, + CSSToLayoutDeviceScale aScale, const TimeDuration& aVsyncRate, const CompositorOptions& aOptions, bool aUseExternalSurfaceSize, const gfx::IntSize& aSurfaceSize) - : mWidget(nullptr) + : CompositorBridgeParentBase(aManager) + , mWidget(nullptr) , mScale(aScale) , mVsyncRate(aVsyncRate) , mIsTesting(false) @@ -327,37 +346,24 @@ CompositorBridgeParent::CompositorBridgeParent(CSSToLayoutDeviceScale aScale, , mPluginWindowsHidden(false) #endif { - // Always run destructor on the main thread - MOZ_ASSERT(NS_IsMainThread()); } void CompositorBridgeParent::InitSameProcess(widget::CompositorWidget* aWidget, const uint64_t& aLayerTreeId) { + MOZ_ASSERT(XRE_IsParentProcess()); + MOZ_ASSERT(NS_IsMainThread()); + mWidget = aWidget; mRootLayerTreeID = aLayerTreeId; if (mOptions.UseAPZ()) { mApzcTreeManager = new APZCTreeManager(); } - // IPDL initialization. mSelfRef is cleared in DeferredDestroy. - SetOtherProcessId(base::GetCurrentProcId()); - mSelfRef = this; - Initialize(); } -bool -CompositorBridgeParent::Bind(Endpoint&& aEndpoint) -{ - if (!aEndpoint.Bind(this)) { - return false; - } - mSelfRef = this; - return true; -} - mozilla::ipc::IPCResult CompositorBridgeParent::RecvInitialize(const uint64_t& aRootLayerTreeId) { @@ -640,6 +646,8 @@ CompositorBridgeParent::RecvNotifyApproximatelyVisibleRegion(const ScrollableLay void CompositorBridgeParent::ActorDestroy(ActorDestroyReason why) { + mCanSend = false; + StopAndClearResources(); RemoveCompositor(mCompositorID); @@ -1936,25 +1944,6 @@ CompositorBridgeParent::InvalidateRemoteLayers() }); } -static void -OpenCompositor(RefPtr aCompositor, - Endpoint&& aEndpoint) -{ - aCompositor->Bind(Move(aEndpoint)); -} - -/* static */ bool -CompositorBridgeParent::CreateForContent(Endpoint&& aEndpoint) -{ - gfxPlatform::InitLayersIPC(); - - RefPtr cpcp = - new CrossProcessCompositorBridgeParent(); - - CompositorLoop()->PostTask(NewRunnableFunction(OpenCompositor, cpcp, Move(aEndpoint))); - return true; -} - void UpdateIndirectTree(uint64_t aId, Layer* aRoot, const TargetConfig& aTargetConfig) { diff --git a/gfx/layers/ipc/CompositorBridgeParent.h b/gfx/layers/ipc/CompositorBridgeParent.h index 08f415193399..0d0f6fed3d2b 100644 --- a/gfx/layers/ipc/CompositorBridgeParent.h +++ b/gfx/layers/ipc/CompositorBridgeParent.h @@ -67,6 +67,7 @@ class AsyncCompositionManager; class Compositor; class CompositorAnimationStorage; class CompositorBridgeParent; +class CompositorManagerParent; class CompositorVsyncScheduler; class HostLayerManager; class LayerTransactionParent; @@ -94,6 +95,8 @@ class CompositorBridgeParentBase : public PCompositorBridgeParent, public MetricsSharingController { public: + explicit CompositorBridgeParentBase(CompositorManagerParent* aManager); + virtual void ShadowLayersUpdated(LayerTransactionParent* aLayerTree, const TransactionInfo& aInfo, bool aHitTestUpdate) = 0; @@ -122,6 +125,8 @@ public: virtual mozilla::ipc::IPCResult RecvSyncWithCompositor() override { return IPC_OK(); } + mozilla::ipc::IPCResult Recv__delete__() override { return IPC_OK(); } + virtual void ObserveLayerUpdate(uint64_t aLayersId, uint64_t aEpoch, bool aActive) = 0; virtual void NotifyDidCompositeToPipeline(const wr::PipelineId& aPipelineId, const wr::Epoch& aEpoch, TimeStamp& aCompositeStart, TimeStamp& aCompositeEnd) {} @@ -154,6 +159,14 @@ public: virtual bool IsRemote() const { return false; } + +protected: + ~CompositorBridgeParentBase() override; + + bool mCanSend; + +private: + RefPtr mCompositorManager; }; class CompositorBridgeParent final : public CompositorBridgeParentBase @@ -169,22 +182,14 @@ public: NS_IMETHOD_(MozExternalRefCountType) AddRef() override { return CompositorBridgeParentBase::AddRef(); } NS_IMETHOD_(MozExternalRefCountType) Release() override { return CompositorBridgeParentBase::Release(); } - explicit CompositorBridgeParent(CSSToLayoutDeviceScale aScale, + explicit CompositorBridgeParent(CompositorManagerParent* aManager, + CSSToLayoutDeviceScale aScale, const TimeDuration& aVsyncRate, const CompositorOptions& aOptions, bool aUseExternalSurfaceSize, const gfx::IntSize& aSurfaceSize); - // Must only be called by CompositorBridgeChild. After invoking this, the - // IPC channel is active and RecvWillStop/ActorDestroy must be called to - // free the compositor. - void InitSameProcess(widget::CompositorWidget* aWidget, - const uint64_t& aLayerTreeId); - - // Must only be called by GPUParent. After invoking this, the IPC channel - // is active and RecvWillStop/ActorDestroy must be called to free the - // compositor. - bool Bind(Endpoint&& aEndpoint); + void InitSameProcess(widget::CompositorWidget* aWidget, const uint64_t& aLayerTreeId); virtual mozilla::ipc::IPCResult RecvInitialize(const uint64_t& aRootLayerTreeId) override; virtual mozilla::ipc::IPCResult RecvGetFrameUniformity(FrameUniformityData* aOutData) override; @@ -344,13 +349,6 @@ public: static void SetControllerForLayerTree(uint64_t aLayersId, GeckoContentController* aController); - /** - * A new child process has been configured to push transactions - * directly to us. Transport is to its thread context. - */ - static bool - CreateForContent(Endpoint&& aEndpoint); - struct LayerTreeState { LayerTreeState(); ~LayerTreeState(); diff --git a/gfx/layers/ipc/CompositorManagerChild.cpp b/gfx/layers/ipc/CompositorManagerChild.cpp index 98977e0b917b..b5b10f7c1933 100644 --- a/gfx/layers/ipc/CompositorManagerChild.cpp +++ b/gfx/layers/ipc/CompositorManagerChild.cpp @@ -10,6 +10,7 @@ #include "mozilla/dom/ContentChild.h" // for ContentChild #include "mozilla/dom/TabChild.h" // for TabChild #include "mozilla/dom/TabGroup.h" // for TabGroup +#include "VsyncSource.h" namespace mozilla { namespace layers { @@ -69,7 +70,21 @@ CompositorManagerChild::Shutdown() /* static */ bool CompositorManagerChild::CreateContentCompositorBridge(uint32_t aNamespace) { - return false; + MOZ_ASSERT(NS_IsMainThread()); + if (NS_WARN_IF(!sInstance)) { + return false; + } + + CompositorBridgeOptions options = ContentCompositorOptions(); + PCompositorBridgeChild* pbridge = + sInstance->SendPCompositorBridgeConstructor(options); + if (NS_WARN_IF(!pbridge)) { + return true; + } + + auto bridge = static_cast(pbridge); + bridge->InitForContent(aNamespace); + return true; } /* static */ already_AddRefed @@ -81,14 +96,51 @@ CompositorManagerChild::CreateWidgetCompositorBridge(uint64_t aProcessToken, bool aUseExternalSurfaceSize, const gfx::IntSize& aSurfaceSize) { - return nullptr; + MOZ_ASSERT(XRE_IsParentProcess()); + MOZ_ASSERT(NS_IsMainThread()); + if (NS_WARN_IF(!sInstance)) { + return nullptr; + } + + TimeDuration vsyncRate = + gfxPlatform::GetPlatform()->GetHardwareVsync()->GetGlobalDisplay().GetVsyncRate(); + + CompositorBridgeOptions options = + WidgetCompositorOptions(aScale, vsyncRate, aOptions, + aUseExternalSurfaceSize, aSurfaceSize); + PCompositorBridgeChild* pbridge = + sInstance->SendPCompositorBridgeConstructor(options); + if (NS_WARN_IF(!pbridge)) { + return nullptr; + } + + RefPtr bridge = + static_cast(pbridge); + bridge->InitForWidget(aProcessToken, aLayerManager, aNamespace); + return bridge.forget(); } /* static */ already_AddRefed CompositorManagerChild::CreateSameProcessWidgetCompositorBridge(LayerManager* aLayerManager, uint32_t aNamespace) { - return nullptr; + MOZ_ASSERT(XRE_IsParentProcess()); + MOZ_ASSERT(NS_IsMainThread()); + if (NS_WARN_IF(!sInstance)) { + return nullptr; + } + + CompositorBridgeOptions options = SameProcessWidgetCompositorOptions(); + PCompositorBridgeChild* pbridge = + sInstance->SendPCompositorBridgeConstructor(options); + if (NS_WARN_IF(!pbridge)) { + return nullptr; + } + + RefPtr bridge = + static_cast(pbridge); + bridge->InitForWidget(1, aLayerManager, aNamespace); + return bridge.forget(); } CompositorManagerChild::CompositorManagerChild(CompositorManagerParent* aParent, @@ -137,6 +189,21 @@ CompositorManagerChild::ActorDestroy(ActorDestroyReason aReason) mCanSend = false; } +PCompositorBridgeChild* +CompositorManagerChild::AllocPCompositorBridgeChild(const CompositorBridgeOptions& aOptions) +{ + CompositorBridgeChild* child = new CompositorBridgeChild(this); + child->AddRef(); + return child; +} + +bool +CompositorManagerChild::DeallocPCompositorBridgeChild(PCompositorBridgeChild* aActor) +{ + static_cast(aActor)->Release(); + return true; +} + void CompositorManagerChild::HandleFatalError(const char* aName, const char* aMsg) const { diff --git a/gfx/layers/ipc/CompositorManagerChild.h b/gfx/layers/ipc/CompositorManagerChild.h index 13f30128eaff..37abdf2f7301 100644 --- a/gfx/layers/ipc/CompositorManagerChild.h +++ b/gfx/layers/ipc/CompositorManagerChild.h @@ -62,6 +62,10 @@ public: void ProcessingError(Result aCode, const char* aReason) override; + PCompositorBridgeChild* AllocPCompositorBridgeChild(const CompositorBridgeOptions& aOptions) override; + + bool DeallocPCompositorBridgeChild(PCompositorBridgeChild* aActor) override; + private: static StaticRefPtr sInstance; diff --git a/gfx/layers/ipc/CompositorManagerParent.cpp b/gfx/layers/ipc/CompositorManagerParent.cpp index 9cead12c0c7b..17cfeecc7b94 100644 --- a/gfx/layers/ipc/CompositorManagerParent.cpp +++ b/gfx/layers/ipc/CompositorManagerParent.cpp @@ -5,8 +5,11 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "mozilla/layers/CompositorManagerParent.h" +#include "mozilla/gfx/GPUParent.h" #include "mozilla/layers/CompositorBridgeParent.h" +#include "mozilla/layers/CrossProcessCompositorBridgeParent.h" #include "mozilla/layers/CompositorThread.h" +#include "VsyncSource.h" namespace mozilla { namespace layers { @@ -66,7 +69,38 @@ CompositorManagerParent::CreateSameProcessWidgetCompositorBridge(CSSToLayoutDevi bool aUseExternalSurfaceSize, const gfx::IntSize& aSurfaceSize) { - return nullptr; + MOZ_ASSERT(XRE_IsParentProcess()); + MOZ_ASSERT(NS_IsMainThread()); + + // When we are in a combined UI / GPU process, InProcessCompositorSession + // requires both the parent and child PCompositorBridge actors for its own + // construction, which is done on the main thread. Normally + // CompositorBridgeParent is created on the compositor thread via the IPDL + // plumbing (CompositorManagerParent::AllocPCompositorBridgeParent). Thus to + // actually get a reference to the parent, we would need to block on the + // compositor thread until it handles our constructor message. Because only + // one one IPDL constructor is permitted per parent and child protocol, we + // cannot make the normal case async and this case sync. Instead what we do + // is leave the constructor async (a boon to the content process setup) and + // create the parent ahead of time. It will pull the preinitialized parent + // from the queue when it receives the message and give that to IPDL. + + // Note that the static mutex not only is used to protect sInstance, but also + // mPendingCompositorBridges. + StaticMutexAutoLock lock(sMutex); + if (NS_WARN_IF(!sInstance)) { + return nullptr; + } + + TimeDuration vsyncRate = + gfxPlatform::GetPlatform()->GetHardwareVsync()->GetGlobalDisplay().GetVsyncRate(); + + RefPtr bridge = + new CompositorBridgeParent(sInstance, aScale, vsyncRate, aOptions, + aUseExternalSurfaceSize, aSurfaceSize); + + sInstance->mPendingCompositorBridges.AppendElement(bridge); + return bridge.forget(); } CompositorManagerParent::CompositorManagerParent() @@ -106,5 +140,66 @@ CompositorManagerParent::DeallocPCompositorManagerParent() Release(); } +PCompositorBridgeParent* +CompositorManagerParent::AllocPCompositorBridgeParent(const CompositorBridgeOptions& aOpt) +{ + switch (aOpt.type()) { + case CompositorBridgeOptions::TContentCompositorOptions: { + CrossProcessCompositorBridgeParent* bridge = + new CrossProcessCompositorBridgeParent(this); + bridge->AddRef(); + return bridge; + } + case CompositorBridgeOptions::TWidgetCompositorOptions: { + // Only the UI process is allowed to create widget compositors in the + // compositor process. + gfx::GPUParent* gpu = gfx::GPUParent::GetSingleton(); + if (NS_WARN_IF(!gpu || OtherPid() != gpu->OtherPid())) { + MOZ_ASSERT_UNREACHABLE("Child cannot create widget compositor!"); + break; + } + + const WidgetCompositorOptions& opt = aOpt.get_WidgetCompositorOptions(); + CompositorBridgeParent* bridge = + new CompositorBridgeParent(this, opt.scale(), opt.vsyncRate(), + opt.options(), opt.useExternalSurfaceSize(), + opt.surfaceSize()); + bridge->AddRef(); + return bridge; + } + case CompositorBridgeOptions::TSameProcessWidgetCompositorOptions: { + // If the GPU and UI process are combined, we actually already created the + // CompositorBridgeParent, so we need to reuse that to inject it into the + // IPDL framework. + if (NS_WARN_IF(OtherPid() != base::GetCurrentProcId())) { + MOZ_ASSERT_UNREACHABLE("Child cannot create same process compositor!"); + break; + } + + // Note that the static mutex not only is used to protect sInstance, but + // also mPendingCompositorBridges. + StaticMutexAutoLock lock(sMutex); + MOZ_ASSERT(sInstance == this); + MOZ_ASSERT(!mPendingCompositorBridges.IsEmpty()); + + CompositorBridgeParent* bridge = mPendingCompositorBridges[0]; + bridge->AddRef(); + mPendingCompositorBridges.RemoveElementAt(0); + return bridge; + } + default: + break; + } + + return nullptr; +} + +bool +CompositorManagerParent::DeallocPCompositorBridgeParent(PCompositorBridgeParent* aActor) +{ + static_cast(aActor)->Release(); + return true; +} + } // namespace layers } // namespace mozilla diff --git a/gfx/layers/ipc/CompositorManagerParent.h b/gfx/layers/ipc/CompositorManagerParent.h index 43215537afd7..0c1094cfbaef 100644 --- a/gfx/layers/ipc/CompositorManagerParent.h +++ b/gfx/layers/ipc/CompositorManagerParent.h @@ -36,7 +36,8 @@ public: void ActorDestroy(ActorDestroyReason aReason) override; - ipc::IPCResult RecvIgnoreTemporarySkeletonMessage() override { return IPC_OK(); } + bool DeallocPCompositorBridgeParent(PCompositorBridgeParent* aActor) override; + PCompositorBridgeParent* AllocPCompositorBridgeParent(const CompositorBridgeOptions& aOpt) override; private: static StaticRefPtr sInstance; @@ -50,6 +51,8 @@ private: void DeallocPCompositorManagerParent() override; RefPtr mCompositorThreadHolder; + + AutoTArray, 1> mPendingCompositorBridges; }; } // namespace layers diff --git a/gfx/layers/ipc/CrossProcessCompositorBridgeParent.cpp b/gfx/layers/ipc/CrossProcessCompositorBridgeParent.cpp index bde87e7dcb7a..d3996a18e938 100644 --- a/gfx/layers/ipc/CrossProcessCompositorBridgeParent.cpp +++ b/gfx/layers/ipc/CrossProcessCompositorBridgeParent.cpp @@ -54,6 +54,8 @@ CrossProcessCompositorBridgeParent::RecvRequestNotifyAfterRemotePaint() void CrossProcessCompositorBridgeParent::ActorDestroy(ActorDestroyReason aWhy) { + mCanSend = false; + // We must keep this object alive untill the code handling message // reception is finished on this thread. MessageLoop::current()->PostTask(NewRunnableMethod(this, &CrossProcessCompositorBridgeParent::DeferredDestroy)); @@ -485,7 +487,6 @@ CrossProcessCompositorBridgeParent::DeferredDestroy() CrossProcessCompositorBridgeParent::~CrossProcessCompositorBridgeParent() { MOZ_ASSERT(XRE_GetIOMessageLoop()); - MOZ_ASSERT(IToplevelProtocol::GetTransport()); } PTextureParent* diff --git a/gfx/layers/ipc/CrossProcessCompositorBridgeParent.h b/gfx/layers/ipc/CrossProcessCompositorBridgeParent.h index 2e388ae2e86e..2706f4e6d7bc 100644 --- a/gfx/layers/ipc/CrossProcessCompositorBridgeParent.h +++ b/gfx/layers/ipc/CrossProcessCompositorBridgeParent.h @@ -28,18 +28,11 @@ class CrossProcessCompositorBridgeParent final : public CompositorBridgeParentBa friend class CompositorBridgeParent; public: - explicit CrossProcessCompositorBridgeParent() - : mNotifyAfterRemotePaint(false) + explicit CrossProcessCompositorBridgeParent(CompositorManagerParent* aManager) + : CompositorBridgeParentBase(aManager) + , mNotifyAfterRemotePaint(false) , mDestroyCalled(false) { - MOZ_ASSERT(NS_IsMainThread()); - } - - void Bind(Endpoint&& aEndpoint) { - if (!aEndpoint.Bind(this)) { - return; - } - mSelfRef = this; } virtual void ActorDestroy(ActorDestroyReason aWhy) override; @@ -158,10 +151,6 @@ public: return true; } -protected: - void OnChannelConnected(int32_t pid) override { - mCompositorThreadHolder = CompositorThreadHolder::GetSingleton(); - } private: // Private destructor, to discourage deletion outside of Release(): virtual ~CrossProcessCompositorBridgeParent(); diff --git a/gfx/layers/ipc/PCompositorBridge.ipdl b/gfx/layers/ipc/PCompositorBridge.ipdl index 5fdbb2c0fa66..b97feb23caae 100644 --- a/gfx/layers/ipc/PCompositorBridge.ipdl +++ b/gfx/layers/ipc/PCompositorBridge.ipdl @@ -11,6 +11,7 @@ include PlatformWidgetTypes; include protocol PAPZ; include protocol PAPZCTreeManager; include protocol PBrowser; +include protocol PCompositorManager; include protocol PCompositorWidget; include protocol PLayerTransaction; include protocol PTexture; @@ -72,6 +73,8 @@ namespace layers { */ sync protocol PCompositorBridge { + manager PCompositorManager; + manages PAPZ; manages PAPZCTreeManager; // A Compositor manages a single Layer Manager (PLayerTransaction) @@ -130,6 +133,8 @@ child: async ObserveLayerUpdate(uint64_t aLayersId, uint64_t aEpoch, bool aActive); parent: + async __delete__(); + // Must be called before Initialize(). async PCompositorWidget(CompositorWidgetInitData aInitData); diff --git a/gfx/layers/ipc/PCompositorManager.ipdl b/gfx/layers/ipc/PCompositorManager.ipdl index ad4cd005ba35..2035573ee2e4 100644 --- a/gfx/layers/ipc/PCompositorManager.ipdl +++ b/gfx/layers/ipc/PCompositorManager.ipdl @@ -52,8 +52,21 @@ union CompositorBridgeOptions { */ sync protocol PCompositorManager { + manages PCompositorBridge; + parent: - async IgnoreTemporarySkeletonMessage(); + /** + * There are three variants of a PCompositorBridge protocol, each of which can + * only be created by certain processes and configurations: + * - A "content" PCompositorBridge is requested by each content process, + * representing the drawable area for Web content. + * - A "widget" PCompositorBridge is requested by the UI process for each + * "top level browser window" for chrome and such. + * - A "same process widget" PCompositorBridge is requested by the combined + * GPU/UI process for each "top level browser window" as above. + * See gfx/layers/ipc/PCompositorBridge.ipdl for more details. + */ + async PCompositorBridge(CompositorBridgeOptions options); }; } // layers