Add a top-level protocol for sending vsync messages to the GPU process. (bug 1285625 part 1, r=billm)

This commit is contained in:
David Anderson 2016-07-19 11:56:06 -07:00
parent eedafe7234
commit ad5abd7a72
14 changed files with 450 additions and 2 deletions

View File

@ -6,8 +6,9 @@
#ifndef _include_mozilla_gfx_ipc_GPUChild_h_
#define _include_mozilla_gfx_ipc_GPUChild_h_
#include "mozilla/gfx/PGPUChild.h"
#include "mozilla/RefPtr.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/gfx/PGPUChild.h"
namespace mozilla {
namespace gfx {

View File

@ -7,6 +7,7 @@
#include "gfxConfig.h"
#include "gfxPrefs.h"
#include "GPUProcessHost.h"
#include "VsyncBridgeParent.h"
#include "mozilla/Assertions.h"
#include "mozilla/ipc/ProcessChild.h"
#include "mozilla/layers/CompositorBridgeParent.h"
@ -48,7 +49,13 @@ GPUParent::RecvInit(nsTArray<GfxPrefSetting>&& prefs)
gfxPrefs::Pref* pref = gfxPrefs::all()[setting.index()];
pref->SetCachedValue(setting.value());
}
return true;
}
bool
GPUParent::RecvInitVsyncBridge(Endpoint<PVsyncBridgeParent>&& aVsyncEndpoint)
{
VsyncBridgeParent::Start(Move(aVsyncEndpoint));
return true;
}
@ -104,6 +111,9 @@ GPUParent::ActorDestroy(ActorDestroyReason aWhy)
ProcessChild::QuickExit();
#endif
if (mVsyncBridge) {
mVsyncBridge->Shutdown();
}
CompositorThreadHolder::Shutdown();
XRE_ShutdownChildProcess();
}

View File

@ -6,11 +6,14 @@
#ifndef _include_gfx_ipc_GPUParent_h__
#define _include_gfx_ipc_GPUParent_h__
#include "mozilla/RefPtr.h"
#include "mozilla/gfx/PGPUParent.h"
namespace mozilla {
namespace gfx {
class VsyncBridgeParent;
class GPUParent final : public PGPUParent
{
public:
@ -22,6 +25,7 @@ public:
IPC::Channel* aChannel);
bool RecvInit(nsTArray<GfxPrefSetting>&& prefs) override;
bool RecvInitVsyncBridge(Endpoint<PVsyncBridgeParent>&& aVsyncEndpoint) override;
bool RecvUpdatePref(const GfxPrefSetting& pref) override;
bool RecvNewWidgetCompositor(
Endpoint<PCompositorBridgeParent>&& aEndpoint,
@ -31,6 +35,9 @@ public:
bool RecvNewContentCompositorBridge(Endpoint<PCompositorBridgeParent>&& aEndpoint) override;
void ActorDestroy(ActorDestroyReason aWhy) override;
private:
RefPtr<VsyncBridgeParent> mVsyncBridge;
};
} // namespace gfx

View File

@ -14,6 +14,8 @@
# include "mozilla/widget/CompositorWidgetChild.h"
#endif
#include "nsContentUtils.h"
#include "VsyncBridgeChild.h"
#include "VsyncIOThreadHolder.h"
namespace mozilla {
namespace gfx {
@ -84,7 +86,7 @@ GPUProcessManager::OnXPCOMShutdown()
mObserver = nullptr;
}
DestroyProcess();
CleanShutdown();
}
void
@ -94,6 +96,9 @@ GPUProcessManager::EnableGPUProcess()
return;
}
// Start the Vsync I/O thread so can use it as soon as the process launches.
EnsureVsyncIOThread();
// The subprocess is launched asynchronously, so we wait for a callback to
// acquire the IPDL actor.
mProcess = new GPUProcessHost(this);
@ -109,6 +114,7 @@ GPUProcessManager::DisableGPUProcess(const char* aMessage)
gfxCriticalNote << aMessage;
DestroyProcess();
ShutdownVsyncIOThread();
}
void
@ -136,6 +142,21 @@ GPUProcessManager::OnProcessLaunchComplete(GPUProcessHost* aHost)
mGPUChild = mProcess->GetActor();
mProcessToken = mProcess->GetProcessToken();
Endpoint<PVsyncBridgeParent> vsyncParent;
Endpoint<PVsyncBridgeChild> vsyncChild;
nsresult rv = PVsyncBridge::CreateEndpoints(
mGPUChild->OtherPid(),
base::GetCurrentProcId(),
&vsyncParent,
&vsyncChild);
if (NS_FAILED(rv)) {
DisableGPUProcess("Failed to create PVsyncBridge endpoints");
return;
}
mVsyncBridge = VsyncBridgeChild::Create(mVsyncIOThread, mProcessToken, Move(vsyncChild));
mGPUChild->SendInitVsyncBridge(Move(vsyncParent));
}
void
@ -168,6 +189,19 @@ GPUProcessManager::NotifyRemoteActorDestroyed(const uint64_t& aProcessToken)
DestroyProcess();
}
void
GPUProcessManager::CleanShutdown()
{
if (!mProcess) {
return;
}
#ifdef NS_FREE_PERMANENT_DATA
mVsyncBridge->Close();
#endif
DestroyProcess();
}
void
GPUProcessManager::DestroyProcess()
{
@ -179,6 +213,7 @@ GPUProcessManager::DestroyProcess()
mProcessToken = 0;
mProcess = nullptr;
mGPUChild = nullptr;
mVsyncBridge = nullptr;
}
RefPtr<CompositorSession>
@ -358,5 +393,22 @@ GPUProcessManager::UpdateRemoteContentController(uint64_t aLayersId,
aBrowserParent);
}
void
GPUProcessManager::EnsureVsyncIOThread()
{
if (mVsyncIOThread) {
return;
}
mVsyncIOThread = new VsyncIOThreadHolder();
MOZ_RELEASE_ASSERT(mVsyncIOThread->Start());
}
void
GPUProcessManager::ShutdownVsyncIOThread()
{
mVsyncIOThread = nullptr;
}
} // namespace gfx
} // namespace mozilla

View File

@ -9,6 +9,7 @@
#include "base/basictypes.h"
#include "base/process.h"
#include "Units.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/dom/ipc/IdType.h"
#include "mozilla/gfx/GPUProcessHost.h"
#include "mozilla/gfx/Point.h"
@ -40,6 +41,8 @@ class GeckoChildProcessHost;
namespace gfx {
class GPUChild;
class VsyncBridgeChild;
class VsyncIOThreadHolder;
// The GPUProcessManager is a singleton responsible for creating GPU-bound
// objects that may live in another process. Currently, it provides access
@ -132,8 +135,12 @@ private:
void DisableGPUProcess(const char* aMessage);
// Shutdown the GPU process.
void CleanShutdown();
void DestroyProcess();
void EnsureVsyncIOThread();
void ShutdownVsyncIOThread();
RefPtr<CompositorSession> CreateRemoteSession(
nsIWidget* aWidget,
ClientLayerManager* aLayerManager,
@ -161,11 +168,14 @@ private:
private:
RefPtr<Observer> mObserver;
ipc::TaskFactory<GPUProcessManager> mTaskFactory;
RefPtr<VsyncIOThreadHolder> mVsyncIOThread;
uint64_t mNextLayerTreeId;
// Fields that are associated with the current GPU process.
GPUProcessHost* mProcess;
uint64_t mProcessToken;
GPUChild* mGPUChild;
RefPtr<VsyncBridgeChild> mVsyncBridge;
};
} // namespace gfx

View File

@ -4,6 +4,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
include protocol PCompositorBridge;
include protocol PVsyncBridge;
using mozilla::CSSToLayoutDeviceScale from "Units.h";
using mozilla::gfx::IntSize from "mozilla/gfx/2D.h";
@ -29,6 +30,8 @@ parent:
// Sent by the UI process to initiate core settings.
async Init(GfxPrefSetting[] prefs);
async InitVsyncBridge(Endpoint<PVsyncBridgeParent> vsyncEndpoint);
// Called to update a gfx preference.
async UpdatePref(GfxPrefSetting pref);

22
gfx/ipc/PVsyncBridge.ipdl Normal file
View File

@ -0,0 +1,22 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
using class mozilla::TimeStamp from "mozilla/TimeStamp.h";
namespace mozilla {
namespace gfx {
// This protocol only serves one purpose: deliver vsync notifications from a
// dedicated thread in the UI process to the compositor thread in the
// compositor process. The child side exists in the UI process, and the
// parent side in the GPU process.
sync protocol PVsyncBridge
{
parent:
async NotifyVsync(TimeStamp vsyncTimeStamp);
};
} // namespace gfx
} // namespace mozilla

View File

@ -0,0 +1,92 @@
/* -*- 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 "VsyncBridgeChild.h"
#include "VsyncIOThreadHolder.h"
namespace mozilla {
namespace gfx {
VsyncBridgeChild::VsyncBridgeChild(RefPtr<VsyncIOThreadHolder> aThread, const uint64_t& aProcessToken)
: mThread(aThread),
mLoop(nullptr),
mProcessToken(aProcessToken)
{
}
VsyncBridgeChild::~VsyncBridgeChild()
{
}
/* static */ RefPtr<VsyncBridgeChild>
VsyncBridgeChild::Create(RefPtr<VsyncIOThreadHolder> aThread,
const uint64_t& aProcessToken,
Endpoint<PVsyncBridgeChild>&& aEndpoint)
{
RefPtr<VsyncBridgeChild> child = new VsyncBridgeChild(aThread, aProcessToken);
RefPtr<nsIRunnable> task = NewRunnableMethod<Endpoint<PVsyncBridgeChild>&&>(
child, &VsyncBridgeChild::Open, Move(aEndpoint));
aThread->GetThread()->Dispatch(task.forget(), nsIThread::DISPATCH_NORMAL);
return child;
}
void
VsyncBridgeChild::Open(Endpoint<PVsyncBridgeChild>&& aEndpoint)
{
if (!aEndpoint.Bind(this, nullptr)) {
// The GPU Process Manager might be gone if we receive ActorDestroy very
// late in shutdown.
if (GPUProcessManager* gpm = GPUProcessManager::Get())
gpm->NotifyRemoteActorDestroyed(mProcessToken);
return;
}
mLoop = MessageLoop::current();
// Last reference is freed in DeallocPVsyncBridgeChild.
AddRef();
}
void
VsyncBridgeChild::Close()
{
if (MessageLoop::current() != mLoop) {
mLoop->PostTask(NewRunnableMethod(this, &VsyncBridgeChild::Close));
return;
}
// We clear mProcessToken when the channel is closed.
if (!mProcessToken) {
return;
}
PVsyncBridgeChild::Close();
mProcessToken = 0;
}
void
VsyncBridgeChild::ActorDestroy(ActorDestroyReason aWhy)
{
if (mProcessToken) {
GPUProcessManager::Get()->NotifyRemoteActorDestroyed(mProcessToken);
mProcessToken = 0;
}
}
void
VsyncBridgeChild::DeallocPVsyncBridgeChild()
{
Release();
}
void
VsyncBridgeChild::ProcessingError(Result aCode, const char* aReason)
{
MOZ_RELEASE_ASSERT(aCode != MsgDropped, "Processing error in VsyncBridgeChild");
}
} // namespace gfx
} // namespace mozilla

View File

@ -0,0 +1,47 @@
/* -*- 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_gfx_ipc_VsyncBridgeChild_h
#define include_gfx_ipc_VsyncBridgeChild_h
#include "mozilla/RefPtr.h"
#include "mozilla/gfx/PVsyncBridgeChild.h"
namespace mozilla {
namespace gfx {
class VsyncIOThreadHolder;
class VsyncBridgeChild final : public PVsyncBridgeChild
{
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VsyncBridgeChild)
static RefPtr<VsyncBridgeChild> Create(RefPtr<VsyncIOThreadHolder> aThread,
const uint64_t& aProcessToken,
Endpoint<PVsyncBridgeChild>&& aEndpoint);
void Close();
void ActorDestroy(ActorDestroyReason aWhy) override;
void DeallocPVsyncBridgeChild() override;
void ProcessingError(Result aCode, const char* aReason) override;
private:
VsyncBridgeChild(RefPtr<VsyncIOThreadHolder>, const uint64_t& aProcessToken);
~VsyncBridgeChild();
void Open(Endpoint<PVsyncBridgeChild>&& aEndpoint);
private:
RefPtr<VsyncIOThreadHolder> mThread;
MessageLoop* mLoop;
uint64_t mProcessToken;
};
} // namespace gfx
} // namespace mozilla
#endif // include_gfx_ipc_VsyncBridgeChild_h

View File

@ -0,0 +1,80 @@
/* -*- 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 "VsyncBridgeParent.h"
#include "mozilla/layers/CompositorThread.h"
namespace mozilla {
namespace gfx {
RefPtr<VsyncBridgeParent>
VsyncBridgeParent::Start(Endpoint<PVsyncBridgeParent>&& aEndpoint)
{
RefPtr<VsyncBridgeParent> parent = new VsyncBridgeParent();
RefPtr<Runnable> task = NewRunnableMethod<Endpoint<PVsyncBridgeParent>&&>(
parent, &VsyncBridgeParent::Open, Move(aEndpoint));
CompositorThreadHolder::Loop()->PostTask(task.forget());
return parent;
}
VsyncBridgeParent::VsyncBridgeParent()
: mOpen(false)
{
MOZ_COUNT_CTOR(VsyncBridgeParent);
}
VsyncBridgeParent::~VsyncBridgeParent()
{
MOZ_COUNT_DTOR(VsyncBridgeParent);
}
void
VsyncBridgeParent::Open(Endpoint<PVsyncBridgeParent>&& aEndpoint)
{
if (!aEndpoint.Bind(this, nullptr)) {
// We can't recover from this.
MOZ_CRASH("Failed to bind VsyncBridgeParent to endpoint");
}
AddRef();
mOpen = true;
}
bool
VsyncBridgeParent::RecvNotifyVsync(const TimeStamp& vsyncTimeStamp)
{
return true;
}
void
VsyncBridgeParent::Shutdown()
{
MessageLoop* ccloop = CompositorThreadHolder::Loop();
if (MessageLoop::current() != ccloop) {
ccloop->PostTask(NewRunnableMethod(this, &VsyncBridgeParent::Shutdown));
return;
}
if (mOpen) {
Close();
mOpen = false;
}
}
void
VsyncBridgeParent::ActorDestroy(ActorDestroyReason aWhy)
{
mOpen = false;
}
void
VsyncBridgeParent::DeallocPVsyncBridgeParent()
{
Release();
}
} // namespace gfx
} // namespace mozilla

View File

@ -0,0 +1,41 @@
/* -*- 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_gfx_ipc_VsyncBridgeParent_h
#define include_gfx_ipc_VsyncBridgeParent_h
#include "mozilla/RefPtr.h"
#include "mozilla/gfx/PVsyncBridgeParent.h"
namespace mozilla {
namespace gfx {
class VsyncBridgeParent final : public PVsyncBridgeParent
{
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VsyncBridgeParent)
static RefPtr<VsyncBridgeParent> Start(Endpoint<PVsyncBridgeParent>&& aEndpoint);
bool RecvNotifyVsync(const TimeStamp& vsyncTimeStamp) override;
void ActorDestroy(ActorDestroyReason aWhy) override;
void DeallocPVsyncBridgeParent() override;
void Shutdown();
private:
VsyncBridgeParent();
~VsyncBridgeParent();
void Open(Endpoint<PVsyncBridgeParent>&& aEndpoint);
private:
bool mOpen;
};
} // namespace gfx
} // namespace mozilla
#endif // include_gfx_ipc_VsyncBridgeParent_h

View File

@ -0,0 +1,39 @@
/* -*- 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 "VsyncIOThreadHolder.h"
namespace mozilla {
namespace gfx {
VsyncIOThreadHolder::VsyncIOThreadHolder()
{
}
VsyncIOThreadHolder::~VsyncIOThreadHolder()
{
if (!mThread) {
return;
}
NS_DispatchToMainThread(NewRunnableMethod(mThread, &nsIThread::AsyncShutdown));
}
bool
VsyncIOThreadHolder::Start()
{
nsresult rv = NS_NewNamedThread("VsyncIOThread", getter_AddRefs(mThread));
return NS_SUCCEEDED(rv);
}
RefPtr<nsIThread>
VsyncIOThreadHolder::GetThread() const
{
return mThread;
}
} // namespace gfx
} // namespace mozilla

View File

@ -0,0 +1,37 @@
/* -*- 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 mozilla_gfx_ipc_VsyncIOThreadHolder_h
#define mozilla_gfx_ipc_VsyncIOThreadHolder_h
#include "mozilla/RefPtr.h"
#include "nsThreadUtils.h"
namespace mozilla {
namespace gfx {
class VsyncIOThreadHolder final
{
public:
VsyncIOThreadHolder();
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VsyncIOThreadHolder)
bool Start();
RefPtr<nsIThread> GetThread() const;
private:
~VsyncIOThreadHolder();
private:
RefPtr<nsIThread> mThread;
};
} // namespace gfx
} // namespace mozilla
#endif // mozilla_gfx_ipc_VsyncIOThreadHolder_h

View File

@ -16,6 +16,9 @@ EXPORTS.mozilla.gfx += [
'GPUProcessImpl.h',
'GPUProcessManager.h',
'SharedDIB.h',
'VsyncBridgeChild.h',
'VsyncBridgeParent.h',
'VsyncIOThreadHolder.h',
]
EXPORTS.mozilla.layers += [
@ -45,11 +48,15 @@ UNIFIED_SOURCES += [
'InProcessCompositorSession.cpp',
'RemoteCompositorSession.cpp',
'SharedDIB.cpp',
'VsyncBridgeChild.cpp',
'VsyncBridgeParent.cpp',
'VsyncIOThreadHolder.cpp',
]
IPDL_SOURCES = [
'GraphicsMessages.ipdlh',
'PGPU.ipdl',
'PVsyncBridge.ipdl',
]
include('/ipc/chromium/chromium-config.mozbuild')