Add a remote implementation of CompositorSession. (bug 1282348 part 5, r=billm)

This commit is contained in:
David Anderson 2016-07-17 21:24:28 -07:00
parent adf653992b
commit 0339421b99
15 changed files with 293 additions and 16 deletions

View File

@ -4,14 +4,17 @@
* 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/. */
#include "CompositorSession.h"
#include "base/process_util.h"
#include "GPUChild.h"
#include "mozilla/gfx/Logging.h"
#include "mozilla/gfx/GPUProcessHost.h"
#include "mozilla/layers/CompositorBridgeChild.h"
#include "mozilla/layers/CompositorBridgeParent.h"
#include "mozilla/widget/PlatformWidgetTypes.h"
#include "base/process_util.h"
namespace mozilla {
namespace layers {
using namespace gfx;
using namespace widget;

View File

@ -17,6 +17,7 @@ class CompositorWidget;
class CompositorWidgetDelegate;
} // namespace widget
namespace gfx {
class GPUProcessHost;
class GPUProcessManager;
} // namespace gfx
namespace layers {
@ -34,6 +35,7 @@ class CompositorSession
friend class gfx::GPUProcessManager;
protected:
typedef gfx::GPUProcessHost GPUProcessHost;
typedef widget::CompositorWidget CompositorWidget;
typedef widget::CompositorWidgetDelegate CompositorWidgetDelegate;

View File

@ -9,11 +9,14 @@
#include "GPUProcessHost.h"
#include "mozilla/Assertions.h"
#include "mozilla/ipc/ProcessChild.h"
#include "mozilla/layers/CompositorBridgeParent.h"
#include "mozilla/layers/CompositorThread.h"
namespace mozilla {
namespace gfx {
using namespace ipc;
using namespace layers;
GPUParent::GPUParent()
{
@ -34,7 +37,7 @@ GPUParent::Init(base::ProcessId aParentPid,
// Ensure gfxPrefs are initialized.
gfxPrefs::GetSingleton();
CompositorThreadHolder::Start();
return true;
}
@ -57,6 +60,29 @@ GPUParent::RecvUpdatePref(const GfxPrefSetting& setting)
return true;
}
static void
OpenParent(RefPtr<CompositorBridgeParent> aParent,
Endpoint<PCompositorBridgeParent>&& aEndpoint)
{
if (!aParent->Bind(Move(aEndpoint))) {
MOZ_CRASH("Failed to bind compositor");
}
}
bool
GPUParent::RecvNewWidgetCompositor(Endpoint<layers::PCompositorBridgeParent>&& aEndpoint,
const CSSToLayoutDeviceScale& aScale,
const bool& aUseExternalSurfaceSize,
const IntSize& aSurfaceSize)
{
RefPtr<CompositorBridgeParent> cbp =
new CompositorBridgeParent(aScale, aUseExternalSurfaceSize, aSurfaceSize);
MessageLoop* loop = CompositorThreadHolder::Loop();
loop->PostTask(NewRunnableFunction(OpenParent, cbp, Move(aEndpoint)));
return true;
}
void
GPUParent::ActorDestroy(ActorDestroyReason aWhy)
{
@ -70,9 +96,10 @@ GPUParent::ActorDestroy(ActorDestroyReason aWhy)
// state. Currently we quick-exit in RecvBeginShutdown so this should be
// unreachable.
ProcessChild::QuickExit();
#else
XRE_ShutdownChildProcess();
#endif
CompositorThreadHolder::Shutdown();
XRE_ShutdownChildProcess();
}
} // namespace gfx

View File

@ -23,6 +23,11 @@ public:
bool RecvInit(nsTArray<GfxPrefSetting>&& prefs) override;
bool RecvUpdatePref(const GfxPrefSetting& pref) override;
bool RecvNewWidgetCompositor(
Endpoint<PCompositorBridgeParent>&& aEndpoint,
const CSSToLayoutDeviceScale& aScale,
const bool& aUseExternalSurface,
const IntSize& aSurfaceSize) override;
void ActorDestroy(ActorDestroyReason aWhy) override;
};

View File

@ -5,8 +5,13 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "GPUProcessManager.h"
#include "GPUProcessHost.h"
#include "mozilla/layers/InProcessCompositorSession.h"
#include "mozilla/StaticPtr.h"
#include "mozilla/layers/InProcessCompositorSession.h"
#include "mozilla/layers/RemoteCompositorSession.h"
#include "mozilla/widget/PlatformWidgetTypes.h"
#ifdef MOZ_WIDGET_SUPPORTS_OOP_COMPOSITING
# include "mozilla/widget/CompositorWidgetChild.h"
#endif
#include "nsContentUtils.h"
namespace mozilla {
@ -159,7 +164,6 @@ GPUProcessManager::NotifyRemoteActorDestroyed(const uint64_t& aProcessToken)
// prematurely terminated, and we're receiving a notification. This
// can happen if the ActorDestroy for a bridged protocol fires
// before the ActorDestroy for PGPUChild.
MOZ_ASSERT(mProcess);
DestroyProcess();
}
@ -186,6 +190,23 @@ GPUProcessManager::CreateTopLevelCompositor(nsIWidget* aWidget,
{
uint64_t layerTreeId = AllocateLayerTreeId();
if (mGPUChild) {
RefPtr<CompositorSession> session = CreateRemoteSession(
aWidget,
aLayerManager,
layerTreeId,
aScale,
aUseAPZ,
aUseExternalSurfaceSize,
aSurfaceSize);
if (session) {
return session;
}
// We couldn't create a remote compositor, so abort the process.
DisableGPUProcess("Failed to create remote compositor");
}
return InProcessCompositorSession::Create(
aWidget,
aLayerManager,
@ -196,6 +217,64 @@ GPUProcessManager::CreateTopLevelCompositor(nsIWidget* aWidget,
aSurfaceSize);
}
RefPtr<CompositorSession>
GPUProcessManager::CreateRemoteSession(nsIWidget* aWidget,
ClientLayerManager* aLayerManager,
const uint64_t& aRootLayerTreeId,
CSSToLayoutDeviceScale aScale,
bool aUseAPZ,
bool aUseExternalSurfaceSize,
const gfx::IntSize& aSurfaceSize)
{
#ifdef MOZ_WIDGET_SUPPORTS_OOP_COMPOSITING
ipc::Endpoint<PCompositorBridgeParent> parentPipe;
ipc::Endpoint<PCompositorBridgeChild> childPipe;
nsresult rv = PCompositorBridge::CreateEndpoints(
mGPUChild->OtherPid(),
base::GetCurrentProcId(),
&parentPipe,
&childPipe);
if (NS_FAILED(rv)) {
gfxCriticalNote << "Failed to create PCompositorBridge endpoints: " << hexa(int(rv));
return nullptr;
}
RefPtr<CompositorBridgeChild> child = CompositorBridgeChild::CreateRemote(
mProcessToken,
aLayerManager,
Move(childPipe));
if (!child) {
gfxCriticalNote << "Failed to create CompositorBridgeChild";
return nullptr;
}
CompositorWidgetInitData initData;
aWidget->GetCompositorWidgetInitData(&initData);
bool ok = mGPUChild->SendNewWidgetCompositor(
Move(parentPipe),
aScale,
aUseExternalSurfaceSize,
aSurfaceSize);
if (!ok)
return nullptr;
CompositorWidgetChild* widget = new CompositorWidgetChild(aWidget);
if (!child->SendPCompositorWidgetConstructor(widget, initData))
return nullptr;
if (!child->SendInitialize(aRootLayerTreeId))
return nullptr;
RefPtr<RemoteCompositorSession> session =
new RemoteCompositorSession(child, widget, aRootLayerTreeId);
return session.forget();
#else
gfxCriticalNote << "Platform does not support out-of-process compositing";
return nullptr;
#endif
}
PCompositorBridgeParent*
GPUProcessManager::CreateTabCompositorBridge(ipc::Transport* aTransport,
base::ProcessId aOtherProcess)

View File

@ -44,6 +44,8 @@ class GPUChild;
class GPUProcessManager final : public GPUProcessHost::Listener
{
typedef layers::APZCTreeManager APZCTreeManager;
typedef layers::ClientLayerManager ClientLayerManager;
typedef layers::CompositorSession CompositorSession;
typedef layers::CompositorUpdateObserver CompositorUpdateObserver;
public:
@ -61,9 +63,9 @@ public:
// Otherwise it blocks until the GPU process has finished launching.
void EnsureGPUReady();
RefPtr<layers::CompositorSession> CreateTopLevelCompositor(
RefPtr<CompositorSession> CreateTopLevelCompositor(
nsIWidget* aWidget,
layers::ClientLayerManager* aLayerManager,
ClientLayerManager* aLayerManager,
CSSToLayoutDeviceScale aScale,
bool aUseAPZ,
bool aUseExternalSurfaceSize,
@ -129,6 +131,15 @@ private:
// Shutdown the GPU process.
void DestroyProcess();
RefPtr<CompositorSession> CreateRemoteSession(
nsIWidget* aWidget,
ClientLayerManager* aLayerManager,
const uint64_t& aRootLayerTreeId,
CSSToLayoutDeviceScale aScale,
bool aUseAPZ,
bool aUseExternalSurfaceSize,
const gfx::IntSize& aSurfaceSize);
DISALLOW_COPY_AND_ASSIGN(GPUProcessManager);
class Observer final : public nsIObserver {

View File

@ -3,7 +3,10 @@
* 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/. */
include protocol PContent;
include protocol PCompositorBridge;
using mozilla::CSSToLayoutDeviceScale from "Units.h";
using mozilla::gfx::IntSize from "mozilla/gfx/2D.h";
namespace mozilla {
namespace gfx {
@ -28,6 +31,12 @@ parent:
// Called to update a gfx preference.
async UpdatePref(GfxPrefSetting pref);
// Create a new top-level compositor.
async NewWidgetCompositor(Endpoint<PCompositorBridgeParent> endpoint,
CSSToLayoutDeviceScale scale,
bool useExternalSurface,
IntSize surfaceSize);
};
} // namespace gfx

View File

@ -0,0 +1,48 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=99: */
/* 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/. */
#include "RemoteCompositorSession.h"
namespace mozilla {
namespace layers {
using namespace gfx;
using namespace widget;
RemoteCompositorSession::RemoteCompositorSession(CompositorBridgeChild* aChild,
CompositorWidgetDelegate* aWidgetDelegate,
const uint64_t& aRootLayerTreeId)
: CompositorSession(aWidgetDelegate, aChild, aRootLayerTreeId)
{
}
CompositorBridgeParent*
RemoteCompositorSession::GetInProcessBridge() const
{
return nullptr;
}
void
RemoteCompositorSession::SetContentController(GeckoContentController* aController)
{
MOZ_CRASH("NYI");
}
already_AddRefed<APZCTreeManager>
RemoteCompositorSession::GetAPZCTreeManager() const
{
return nullptr;
}
void
RemoteCompositorSession::Shutdown()
{
mCompositorBridgeChild->Destroy();
mCompositorBridgeChild = nullptr;
mCompositorWidgetDelegate = nullptr;
}
} // namespace layers
} // namespace mozilla

View File

@ -0,0 +1,33 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=99: */
/* 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 include_mozilla_gfx_ipc_RemoteCompositorSession_h
#define include_mozilla_gfx_ipc_RemoteCompositorSession_h
#include "CompositorSession.h"
#include "mozilla/gfx/Point.h"
#include "Units.h"
namespace mozilla {
namespace layers {
class RemoteCompositorSession final : public CompositorSession
{
public:
RemoteCompositorSession(CompositorBridgeChild* aChild,
CompositorWidgetDelegate* aWidgetDelegate,
const uint64_t& aRootLayerTreeId);
CompositorBridgeParent* GetInProcessBridge() const override;
void SetContentController(GeckoContentController* aController) override;
already_AddRefed<APZCTreeManager> GetAPZCTreeManager() const override;
void Shutdown() override;
};
} // namespace layers
} // namespace mozilla
#endif // include_mozilla_gfx_ipc_RemoteCompositorSession_h

View File

@ -21,6 +21,7 @@ EXPORTS.mozilla.gfx += [
EXPORTS.mozilla.layers += [
'CompositorSession.h',
'InProcessCompositorSession.h',
'RemoteCompositorSession.h',
]
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
@ -42,6 +43,7 @@ UNIFIED_SOURCES += [
'GPUProcessImpl.cpp',
'GPUProcessManager.cpp',
'InProcessCompositorSession.cpp',
'RemoteCompositorSession.cpp',
'SharedDIB.cpp',
]

View File

@ -15,6 +15,7 @@
#include "mozilla/layers/PLayerTransactionChild.h"
#include "mozilla/layers/TextureClient.h"// for TextureClient
#include "mozilla/layers/TextureClientPool.h"// for TextureClientPool
#include "mozilla/gfx/GPUProcessManager.h"
#include "mozilla/mozalloc.h" // for operator new, etc
#include "nsAutoPtr.h"
#include "nsDebug.h" // for NS_RUNTIMEABORT
@ -126,6 +127,8 @@ CompositorBridgeChild::Destroy()
SendWillClose();
mCanSend = false;
// We no longer care about unexpected shutdowns, in the remote process case.
mProcessToken = 0;
// The call just made to SendWillClose can result in IPC from the
// CompositorBridgeParent to the CompositorBridgeChild (e.g. caused by the destruction
@ -209,6 +212,21 @@ CompositorBridgeChild::InitSameProcess(widget::CompositorWidget* aWidget,
return mCompositorBridgeParent;
}
/* static */ RefPtr<CompositorBridgeChild>
CompositorBridgeChild::CreateRemote(const uint64_t& aProcessToken,
ClientLayerManager* aLayerManager,
Endpoint<PCompositorBridgeChild>&& aEndpoint)
{
RefPtr<CompositorBridgeChild> child = new CompositorBridgeChild(aLayerManager);
if (!aEndpoint.Bind(child, nullptr)) {
return nullptr;
}
child->mCanSend = true;
child->mProcessToken = aProcessToken;
return child;
}
/*static*/ CompositorBridgeChild*
CompositorBridgeChild::Get()
{
@ -493,6 +511,10 @@ CompositorBridgeChild::ActorDestroy(ActorDestroyReason aWhy)
mCanSend = false;
gfxCriticalNote << "Receive IPC close with reason=AbnormalShutdown";
}
if (mProcessToken && XRE_IsParentProcess()) {
GPUProcessManager::Get()->NotifyRemoteActorDestroyed(mProcessToken);
}
}
bool
@ -983,7 +1005,7 @@ CompositorBridgeChild::DeallocPCompositorWidgetChild(PCompositorWidgetChild* aAc
void
CompositorBridgeChild::ProcessingError(Result aCode, const char* aReason)
{
MOZ_CRASH("Processing error in CompositorBridgeChild");
MOZ_RELEASE_ASSERT(aCode == MsgDropped, "Processing error in CompositorBridgeChild");
}
} // namespace layers

View File

@ -66,6 +66,11 @@ public:
static PCompositorBridgeChild*
Create(Transport* aTransport, ProcessId aOtherProcess);
static RefPtr<CompositorBridgeChild> CreateRemote(
const uint64_t& aProcessToken,
ClientLayerManager* aLayerManager,
Endpoint<PCompositorBridgeChild>&& aEndpoint);
/**
* Initialize the CompositorBridgeChild, create CompositorBridgeParent, and
* open a same-process connection.
@ -297,6 +302,8 @@ private:
MessageLoop* mMessageLoop;
AutoTArray<RefPtr<TextureClientPool>,2> mTexturePools;
uint64_t mProcessToken;
};
} // namespace layers

View File

@ -612,6 +612,9 @@ CompositorBridgeParent::CompositorBridgeParent(CSSToLayoutDeviceScale aScale,
, mPluginWindowsHidden(false)
#endif
{
// Always run destructor on the main thread
MOZ_ASSERT(NS_IsMainThread());
SetMessageLoopToPostDestructionTo(MessageLoop::current());
}
void
@ -624,6 +627,7 @@ CompositorBridgeParent::InitSameProcess(widget::CompositorWidget* aWidget,
if (aUseAPZ) {
mApzcTreeManager = new APZCTreeManager();
}
mCompositorScheduler = new CompositorVsyncScheduler(this, mWidget);
// IPDL initialization. mSelfRef is cleared in DeferredDestroy.
SetOtherProcessId(base::GetCurrentProcId());
@ -632,16 +636,31 @@ CompositorBridgeParent::InitSameProcess(widget::CompositorWidget* aWidget,
Initialize();
}
bool
CompositorBridgeParent::Bind(Endpoint<PCompositorBridgeParent>&& aEndpoint)
{
if (!aEndpoint.Bind(this, nullptr)) {
return false;
}
mSelfRef = this;
return true;
}
bool
CompositorBridgeParent::RecvInitialize(const uint64_t& aRootLayerTreeId)
{
mRootLayerTreeID = aRootLayerTreeId;
Initialize();
return true;
}
void
CompositorBridgeParent::Initialize()
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(CompositorThread(),
"The compositor thread must be Initialized before instanciating a CompositorBridgeParent.");
// Always run destructor on the main thread
SetMessageLoopToPostDestructionTo(MessageLoop::current());
mCompositorID = 0;
// FIXME: This holds on the the fact that right now the only thing that
// can destroy this instance is initialized on the compositor thread after
@ -658,7 +677,6 @@ CompositorBridgeParent::Initialize()
sIndirectLayerTrees[mRootLayerTreeID].mParent = this;
}
mCompositorScheduler = new CompositorVsyncScheduler(this, mWidget);
LayerScope::SetPixelScale(mScale.scale);
}
@ -1895,6 +1913,7 @@ public:
virtual void ActorDestroy(ActorDestroyReason aWhy) override;
// FIXME/bug 774388: work out what shutdown protocol we need.
virtual bool RecvInitialize(const uint64_t& aRootLayerTreeId) override { return false; }
virtual bool RecvRequestOverfill() override { return true; }
virtual bool RecvWillClose() override { return true; }
virtual bool RecvPause() override { return true; }

View File

@ -223,6 +223,12 @@ public:
const uint64_t& aLayerTreeId,
bool aUseAPZ);
// 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<PCompositorBridgeParent>&& aEndpoint);
virtual bool RecvInitialize(const uint64_t& aRootLayerTreeId) override;
virtual bool RecvGetFrameUniformity(FrameUniformityData* aOutData) override;
virtual bool RecvRequestOverfill() override;
virtual bool RecvWillClose() override;

View File

@ -106,8 +106,12 @@ child:
async ParentAsyncMessages(AsyncParentMessageData[] aMessages);
parent:
// Must be called before Initialize().
async PCompositorWidget(CompositorWidgetInitData aInitData);
// When out-of-process, this must be called to finish initialization.
sync Initialize(uint64_t rootLayerTreeId);
/**
* Confirmation callback for UpdatePluginConfigurations and HideAllPlugins.
*/