summaryrefslogtreecommitdiff
path: root/gfx/ipc
diff options
context:
space:
mode:
authorMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
committerMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
commit5f8de423f190bbb79a62f804151bc24824fa32d8 (patch)
tree10027f336435511475e392454359edea8e25895d /gfx/ipc
parent49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff)
downloaduxp-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz
Add m-esr52 at 52.6.0
Diffstat (limited to 'gfx/ipc')
-rw-r--r--gfx/ipc/CompositorSession.cpp41
-rw-r--r--gfx/ipc/CompositorSession.h92
-rw-r--r--gfx/ipc/CompositorWidgetVsyncObserver.cpp35
-rw-r--r--gfx/ipc/CompositorWidgetVsyncObserver.h37
-rw-r--r--gfx/ipc/D3DMessageUtils.cpp81
-rw-r--r--gfx/ipc/D3DMessageUtils.h48
-rw-r--r--gfx/ipc/GPUChild.cpp203
-rw-r--r--gfx/ipc/GPUChild.h59
-rw-r--r--gfx/ipc/GPUParent.cpp390
-rw-r--r--gfx/ipc/GPUParent.h62
-rw-r--r--gfx/ipc/GPUProcessHost.cpp247
-rw-r--r--gfx/ipc/GPUProcessHost.h146
-rw-r--r--gfx/ipc/GPUProcessImpl.cpp39
-rw-r--r--gfx/ipc/GPUProcessImpl.h44
-rw-r--r--gfx/ipc/GPUProcessListener.h27
-rw-r--r--gfx/ipc/GPUProcessManager.cpp852
-rw-r--r--gfx/ipc/GPUProcessManager.h234
-rw-r--r--gfx/ipc/GfxMessageUtils.h1273
-rw-r--r--gfx/ipc/GraphicsMessages.ipdlh87
-rw-r--r--gfx/ipc/InProcessCompositorSession.cpp83
-rw-r--r--gfx/ipc/InProcessCompositorSession.h49
-rw-r--r--gfx/ipc/PGPU.ipdl106
-rw-r--r--gfx/ipc/PVsyncBridge.ipdl22
-rw-r--r--gfx/ipc/RemoteCompositorSession.cpp112
-rw-r--r--gfx/ipc/RemoteCompositorSession.h46
-rw-r--r--gfx/ipc/SharedDIB.cpp77
-rw-r--r--gfx/ipc/SharedDIB.h50
-rw-r--r--gfx/ipc/SharedDIBSurface.cpp63
-rw-r--r--gfx/ipc/SharedDIBSurface.h62
-rw-r--r--gfx/ipc/SharedDIBWin.cpp139
-rw-r--r--gfx/ipc/SharedDIBWin.h56
-rw-r--r--gfx/ipc/VsyncBridgeChild.cpp155
-rw-r--r--gfx/ipc/VsyncBridgeChild.h57
-rw-r--r--gfx/ipc/VsyncBridgeParent.cpp87
-rw-r--r--gfx/ipc/VsyncBridgeParent.h42
-rw-r--r--gfx/ipc/VsyncIOThreadHolder.cpp46
-rw-r--r--gfx/ipc/VsyncIOThreadHolder.h37
-rw-r--r--gfx/ipc/moz.build82
38 files changed, 5368 insertions, 0 deletions
diff --git a/gfx/ipc/CompositorSession.cpp b/gfx/ipc/CompositorSession.cpp
new file mode 100644
index 0000000000..b200b341c8
--- /dev/null
+++ b/gfx/ipc/CompositorSession.cpp
@@ -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/. */
+#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"
+
+namespace mozilla {
+namespace layers {
+
+using namespace gfx;
+using namespace widget;
+
+
+CompositorSession::CompositorSession(CompositorWidgetDelegate* aDelegate,
+ CompositorBridgeChild* aChild,
+ const uint64_t& aRootLayerTreeId)
+ : mCompositorWidgetDelegate(aDelegate),
+ mCompositorBridgeChild(aChild),
+ mRootLayerTreeId(aRootLayerTreeId)
+{
+}
+
+CompositorSession::~CompositorSession()
+{
+}
+
+CompositorBridgeChild*
+CompositorSession::GetCompositorBridgeChild()
+{
+ return mCompositorBridgeChild;
+}
+
+} // namespace layers
+} // namespace mozilla
diff --git a/gfx/ipc/CompositorSession.h b/gfx/ipc/CompositorSession.h
new file mode 100644
index 0000000000..6205725c5e
--- /dev/null
+++ b/gfx/ipc/CompositorSession.h
@@ -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/. */
+#ifndef _include_mozilla_gfx_ipc_CompositorSession_h_
+#define _include_mozilla_gfx_ipc_CompositorSession_h_
+
+#include "base/basictypes.h"
+#include "mozilla/layers/LayersTypes.h"
+#include "mozilla/layers/CompositorTypes.h"
+#include "nsISupportsImpl.h"
+
+class nsIWidget;
+
+namespace mozilla {
+namespace widget {
+class CompositorWidget;
+class CompositorWidgetDelegate;
+} // namespace widget
+namespace gfx {
+class GPUProcessHost;
+class GPUProcessManager;
+} // namespace gfx
+namespace layers {
+
+class GeckoContentController;
+class IAPZCTreeManager;
+class CompositorBridgeParent;
+class CompositorBridgeChild;
+class ClientLayerManager;
+
+// A CompositorSession provides access to a compositor without exposing whether
+// or not it's in-process or out-of-process.
+class CompositorSession
+{
+ friend class gfx::GPUProcessManager;
+
+protected:
+ typedef gfx::GPUProcessHost GPUProcessHost;
+ typedef widget::CompositorWidget CompositorWidget;
+ typedef widget::CompositorWidgetDelegate CompositorWidgetDelegate;
+
+public:
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CompositorSession)
+
+ virtual bool Reset(const nsTArray<LayersBackend>& aBackendHints,
+ TextureFactoryIdentifier* aOutIdentifier) = 0;
+
+ virtual void Shutdown() = 0;
+
+ // This returns a CompositorBridgeParent if the compositor resides in the same process.
+ virtual CompositorBridgeParent* GetInProcessBridge() const = 0;
+
+ // Set the GeckoContentController for the root of the layer tree.
+ virtual void SetContentController(GeckoContentController* aController) = 0;
+
+ // Return the Async Pan/Zoom Tree Manager for this compositor.
+ virtual RefPtr<IAPZCTreeManager> GetAPZCTreeManager() const = 0;
+
+ // Return the child end of the compositor IPC bridge.
+ CompositorBridgeChild* GetCompositorBridgeChild();
+
+ // Return the proxy for accessing the compositor's widget.
+ CompositorWidgetDelegate* GetCompositorWidgetDelegate() {
+ return mCompositorWidgetDelegate;
+ }
+
+ // Return the id of the root layer tree.
+ uint64_t RootLayerTreeId() const {
+ return mRootLayerTreeId;
+ }
+
+protected:
+ CompositorSession(CompositorWidgetDelegate* aDelegate,
+ CompositorBridgeChild* aChild,
+ const uint64_t& aRootLayerTreeId);
+ virtual ~CompositorSession();
+
+protected:
+ CompositorWidgetDelegate* mCompositorWidgetDelegate;
+ RefPtr<CompositorBridgeChild> mCompositorBridgeChild;
+ uint64_t mRootLayerTreeId;
+
+private:
+ DISALLOW_COPY_AND_ASSIGN(CompositorSession);
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif // _include_mozilla_gfx_ipc_CompositorSession_h_
diff --git a/gfx/ipc/CompositorWidgetVsyncObserver.cpp b/gfx/ipc/CompositorWidgetVsyncObserver.cpp
new file mode 100644
index 0000000000..767dc9da47
--- /dev/null
+++ b/gfx/ipc/CompositorWidgetVsyncObserver.cpp
@@ -0,0 +1,35 @@
+/* -*- 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 "CompositorWidgetVsyncObserver.h"
+#include "mozilla/gfx/VsyncBridgeChild.h"
+
+namespace mozilla {
+namespace widget {
+
+CompositorWidgetVsyncObserver::CompositorWidgetVsyncObserver(
+ RefPtr<VsyncBridgeChild> aVsyncBridge,
+ const uint64_t& aRootLayerTreeId)
+ : mVsyncBridge(aVsyncBridge),
+ mRootLayerTreeId(aRootLayerTreeId)
+{
+ MOZ_ASSERT(XRE_IsParentProcess());
+ MOZ_ASSERT(NS_IsMainThread());
+}
+
+bool
+CompositorWidgetVsyncObserver::NotifyVsync(TimeStamp aTimeStamp)
+{
+ // Vsync notifications should only arrive on the vsync thread.
+ MOZ_ASSERT(XRE_IsParentProcess());
+ MOZ_ASSERT(!NS_IsMainThread());
+
+ mVsyncBridge->NotifyVsync(aTimeStamp, mRootLayerTreeId);
+ return true;
+}
+
+} // namespace widget
+} // namespace mozilla
diff --git a/gfx/ipc/CompositorWidgetVsyncObserver.h b/gfx/ipc/CompositorWidgetVsyncObserver.h
new file mode 100644
index 0000000000..c136624743
--- /dev/null
+++ b/gfx/ipc/CompositorWidgetVsyncObserver.h
@@ -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_CompositorWidgetVsyncObserver_h
+#define mozilla_gfx_ipc_CompositorWidgetVsyncObserver_h
+
+#include "mozilla/VsyncDispatcher.h"
+
+namespace mozilla {
+namespace gfx {
+class VsyncBridgeChild;
+} // namespace gfx
+
+namespace widget {
+
+class CompositorWidgetVsyncObserver : public VsyncObserver
+{
+ typedef gfx::VsyncBridgeChild VsyncBridgeChild;
+
+ public:
+ CompositorWidgetVsyncObserver(RefPtr<VsyncBridgeChild> aVsyncBridge,
+ const uint64_t& aRootLayerTreeId);
+
+ bool NotifyVsync(TimeStamp aVsyncTimestamp) override;
+
+ private:
+ RefPtr<VsyncBridgeChild> mVsyncBridge;
+ uint64_t mRootLayerTreeId;
+};
+
+} // namespace widget
+} // namespace mozilla
+
+#endif // mozilla_gfx_ipc_CompositorWidgetVsyncObserver_h
diff --git a/gfx/ipc/D3DMessageUtils.cpp b/gfx/ipc/D3DMessageUtils.cpp
new file mode 100644
index 0000000000..f3895fdae9
--- /dev/null
+++ b/gfx/ipc/D3DMessageUtils.cpp
@@ -0,0 +1,81 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim: set ts=8 sts=4 et sw=4 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/. */
+#include "D3DMessageUtils.h"
+#if defined(XP_WIN)
+# include "gfxWindowsPlatform.h"
+#endif
+
+bool
+DxgiAdapterDesc::operator ==(const DxgiAdapterDesc& aOther) const
+{
+ return memcmp(&aOther, this, sizeof(*this)) == 0;
+}
+
+#if defined(XP_WIN)
+static_assert(sizeof(DxgiAdapterDesc) == sizeof(DXGI_ADAPTER_DESC),
+ "DXGI_ADAPTER_DESC doe snot match DxgiAdapterDesc");
+
+const DxgiAdapterDesc&
+DxgiAdapterDesc::From(const DXGI_ADAPTER_DESC& aDesc)
+{
+ return reinterpret_cast<const DxgiAdapterDesc&>(aDesc);
+}
+
+const DXGI_ADAPTER_DESC&
+DxgiAdapterDesc::ToDesc() const
+{
+ return reinterpret_cast<const DXGI_ADAPTER_DESC&>(*this);
+}
+#endif
+
+namespace IPC {
+
+void
+ParamTraits<DxgiAdapterDesc>::Write(Message* aMsg, const paramType& aParam)
+{
+#if defined(XP_WIN)
+ aMsg->WriteBytes(aParam.Description, sizeof(aParam.Description));
+ WriteParam(aMsg, aParam.VendorId);
+ WriteParam(aMsg, aParam.DeviceId);
+ WriteParam(aMsg, aParam.SubSysId);
+ WriteParam(aMsg, aParam.Revision);
+ WriteParam(aMsg, aParam.DedicatedVideoMemory);
+ WriteParam(aMsg, aParam.DedicatedSystemMemory);
+ WriteParam(aMsg, aParam.SharedSystemMemory);
+ WriteParam(aMsg, aParam.AdapterLuid.LowPart);
+ WriteParam(aMsg, aParam.AdapterLuid.HighPart);
+#else
+ MOZ_ASSERT_UNREACHABLE("DxgiAdapterDesc is Windows-only");
+#endif
+}
+
+bool
+ParamTraits<DxgiAdapterDesc>::Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
+{
+#if defined(XP_WIN)
+ if (!aMsg->ReadBytesInto(aIter, aResult->Description, sizeof(aResult->Description))) {
+ return false;
+ }
+
+ if (ReadParam(aMsg, aIter, &aResult->VendorId) &&
+ ReadParam(aMsg, aIter, &aResult->DeviceId) &&
+ ReadParam(aMsg, aIter, &aResult->SubSysId) &&
+ ReadParam(aMsg, aIter, &aResult->Revision) &&
+ ReadParam(aMsg, aIter, &aResult->DedicatedVideoMemory) &&
+ ReadParam(aMsg, aIter, &aResult->DedicatedSystemMemory) &&
+ ReadParam(aMsg, aIter, &aResult->SharedSystemMemory) &&
+ ReadParam(aMsg, aIter, &aResult->AdapterLuid.LowPart) &&
+ ReadParam(aMsg, aIter, &aResult->AdapterLuid.HighPart))
+ {
+ return true;
+ }
+#else
+ MOZ_ASSERT_UNREACHABLE("DxgiAdapterDesc is Windows-only");
+#endif
+ return false;
+}
+
+} // namespace IPC
diff --git a/gfx/ipc/D3DMessageUtils.h b/gfx/ipc/D3DMessageUtils.h
new file mode 100644
index 0000000000..0dc9b48434
--- /dev/null
+++ b/gfx/ipc/D3DMessageUtils.h
@@ -0,0 +1,48 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim: set ts=8 sts=4 et sw=4 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 _include_gfx_ipc_D3DMessageUtils_h__
+#define _include_gfx_ipc_D3DMessageUtils_h__
+
+#include "chrome/common/ipc_message_utils.h"
+#include "ipc/IPCMessageUtils.h"
+
+// Can't include dxgi.h, since it leaks random identifiers and #defines, and
+// IPDL causes this file to be #included all over.
+typedef struct DXGI_ADAPTER_DESC DXGI_ADAPTER_DESC;
+
+struct DxgiAdapterDesc
+{
+#if defined(XP_WIN)
+ WCHAR Description[128];
+ UINT VendorId;
+ UINT DeviceId;
+ UINT SubSysId;
+ UINT Revision;
+ SIZE_T DedicatedVideoMemory;
+ SIZE_T DedicatedSystemMemory;
+ SIZE_T SharedSystemMemory;
+ LUID AdapterLuid;
+
+ static const DxgiAdapterDesc& From(const DXGI_ADAPTER_DESC& aDesc);
+ const DXGI_ADAPTER_DESC& ToDesc() const;
+#endif
+
+ bool operator ==(const DxgiAdapterDesc& aOther) const;
+};
+
+namespace IPC {
+
+template <>
+struct ParamTraits<DxgiAdapterDesc>
+{
+ typedef DxgiAdapterDesc paramType;
+ static void Write(Message* aMsg, const paramType& aParam);
+ static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult);
+};
+
+} // namespace IPC
+
+#endif // _include_gfx_ipc_D3DMessageUtils_h__
diff --git a/gfx/ipc/GPUChild.cpp b/gfx/ipc/GPUChild.cpp
new file mode 100644
index 0000000000..72328ac0b6
--- /dev/null
+++ b/gfx/ipc/GPUChild.cpp
@@ -0,0 +1,203 @@
+/* -*- 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 "GPUChild.h"
+#include "gfxConfig.h"
+#include "gfxPrefs.h"
+#include "GPUProcessHost.h"
+#include "GPUProcessManager.h"
+#include "mozilla/Telemetry.h"
+#include "mozilla/dom/CheckerboardReportService.h"
+#include "mozilla/gfx/gfxVars.h"
+#if defined(XP_WIN)
+# include "mozilla/gfx/DeviceManagerDx.h"
+#endif
+#include "mozilla/ipc/CrashReporterHost.h"
+
+namespace mozilla {
+namespace gfx {
+
+GPUChild::GPUChild(GPUProcessHost* aHost)
+ : mHost(aHost),
+ mGPUReady(false)
+{
+ MOZ_COUNT_CTOR(GPUChild);
+}
+
+GPUChild::~GPUChild()
+{
+ MOZ_COUNT_DTOR(GPUChild);
+}
+
+void
+GPUChild::Init()
+{
+ // Build a list of prefs the GPU process will need. Note that because we
+ // limit the GPU process to prefs contained in gfxPrefs, we can simplify
+ // the message in two ways: one, we only need to send its index in gfxPrefs
+ // rather than its name, and two, we only need to send prefs that don't
+ // have their default value.
+ nsTArray<GfxPrefSetting> prefs;
+ for (auto pref : gfxPrefs::all()) {
+ if (pref->HasDefaultValue()) {
+ continue;
+ }
+
+ GfxPrefValue value;
+ pref->GetCachedValue(&value);
+ prefs.AppendElement(GfxPrefSetting(pref->Index(), value));
+ }
+
+ nsTArray<GfxVarUpdate> updates = gfxVars::FetchNonDefaultVars();
+
+ DevicePrefs devicePrefs;
+ devicePrefs.hwCompositing() = gfxConfig::GetValue(Feature::HW_COMPOSITING);
+ devicePrefs.d3d11Compositing() = gfxConfig::GetValue(Feature::D3D11_COMPOSITING);
+ devicePrefs.d3d9Compositing() = gfxConfig::GetValue(Feature::D3D9_COMPOSITING);
+ devicePrefs.oglCompositing() = gfxConfig::GetValue(Feature::OPENGL_COMPOSITING);
+ devicePrefs.useD2D1() = gfxConfig::GetValue(Feature::DIRECT2D);
+
+ SendInit(prefs, updates, devicePrefs);
+
+ gfxVars::AddReceiver(this);
+}
+
+void
+GPUChild::OnVarChanged(const GfxVarUpdate& aVar)
+{
+ SendUpdateVar(aVar);
+}
+
+void
+GPUChild::EnsureGPUReady()
+{
+ if (mGPUReady) {
+ return;
+ }
+
+ GPUDeviceData data;
+ SendGetDeviceStatus(&data);
+
+ gfxPlatform::GetPlatform()->ImportGPUDeviceData(data);
+ Telemetry::AccumulateTimeDelta(Telemetry::GPU_PROCESS_LAUNCH_TIME_MS, mHost->GetLaunchTime());
+ mGPUReady = true;
+}
+
+bool
+GPUChild::RecvInitComplete(const GPUDeviceData& aData)
+{
+ // We synchronously requested GPU parameters before this arrived.
+ if (mGPUReady) {
+ return true;
+ }
+
+ gfxPlatform::GetPlatform()->ImportGPUDeviceData(aData);
+ Telemetry::AccumulateTimeDelta(Telemetry::GPU_PROCESS_LAUNCH_TIME_MS, mHost->GetLaunchTime());
+ mGPUReady = true;
+ return true;
+}
+
+bool
+GPUChild::RecvReportCheckerboard(const uint32_t& aSeverity, const nsCString& aLog)
+{
+ layers::CheckerboardEventStorage::Report(aSeverity, std::string(aLog.get()));
+ return true;
+}
+
+bool
+GPUChild::RecvGraphicsError(const nsCString& aError)
+{
+ gfx::LogForwarder* lf = gfx::Factory::GetLogForwarder();
+ if (lf) {
+ std::stringstream message;
+ message << "GP+" << aError.get();
+ lf->UpdateStringsVector(message.str());
+ }
+ return true;
+}
+
+bool
+GPUChild::RecvInitCrashReporter(Shmem&& aShmem)
+{
+#ifdef MOZ_CRASHREPORTER
+ mCrashReporter = MakeUnique<ipc::CrashReporterHost>(GeckoProcessType_GPU, aShmem);
+#endif
+ return true;
+}
+
+bool
+GPUChild::RecvNotifyUiObservers(const nsCString& aTopic)
+{
+ nsCOMPtr<nsIObserverService> obsSvc = mozilla::services::GetObserverService();
+ MOZ_ASSERT(obsSvc);
+ if (obsSvc) {
+ obsSvc->NotifyObservers(nullptr, aTopic.get(), nullptr);
+ }
+ return true;
+}
+
+bool
+GPUChild::RecvAccumulateChildHistogram(InfallibleTArray<Accumulation>&& aAccumulations)
+{
+ Telemetry::AccumulateChild(GeckoProcessType_GPU, aAccumulations);
+ return true;
+}
+
+bool
+GPUChild::RecvAccumulateChildKeyedHistogram(InfallibleTArray<KeyedAccumulation>&& aAccumulations)
+{
+ Telemetry::AccumulateChildKeyed(GeckoProcessType_GPU, aAccumulations);
+ return true;
+}
+
+bool
+GPUChild::RecvNotifyDeviceReset()
+{
+ mHost->mListener->OnProcessDeviceReset(mHost);
+ return true;
+}
+
+void
+GPUChild::ActorDestroy(ActorDestroyReason aWhy)
+{
+ if (aWhy == AbnormalShutdown) {
+#ifdef MOZ_CRASHREPORTER
+ if (mCrashReporter) {
+ mCrashReporter->GenerateCrashReport(OtherPid());
+ mCrashReporter = nullptr;
+ }
+#endif
+ Telemetry::Accumulate(Telemetry::SUBPROCESS_ABNORMAL_ABORT,
+ nsDependentCString(XRE_ChildProcessTypeToString(GeckoProcessType_GPU), 1));
+ }
+
+ gfxVars::RemoveReceiver(this);
+ mHost->OnChannelClosed();
+}
+
+class DeferredDeleteGPUChild : public Runnable
+{
+public:
+ explicit DeferredDeleteGPUChild(UniquePtr<GPUChild>&& aChild)
+ : mChild(Move(aChild))
+ {
+ }
+
+ NS_IMETHODIMP Run() override {
+ return NS_OK;
+ }
+
+private:
+ UniquePtr<GPUChild> mChild;
+};
+
+/* static */ void
+GPUChild::Destroy(UniquePtr<GPUChild>&& aChild)
+{
+ NS_DispatchToMainThread(new DeferredDeleteGPUChild(Move(aChild)));
+}
+
+} // namespace gfx
+} // namespace mozilla
diff --git a/gfx/ipc/GPUChild.h b/gfx/ipc/GPUChild.h
new file mode 100644
index 0000000000..c0f7d076fb
--- /dev/null
+++ b/gfx/ipc/GPUChild.h
@@ -0,0 +1,59 @@
+/* -*- 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_GPUChild_h_
+#define _include_mozilla_gfx_ipc_GPUChild_h_
+
+#include "mozilla/RefPtr.h"
+#include "mozilla/UniquePtr.h"
+#include "mozilla/gfx/PGPUChild.h"
+#include "mozilla/gfx/gfxVarReceiver.h"
+
+namespace mozilla {
+namespace ipc {
+class CrashReporterHost;
+} // namespace
+namespace gfx {
+
+class GPUProcessHost;
+
+class GPUChild final
+ : public PGPUChild,
+ public gfxVarReceiver
+{
+public:
+ explicit GPUChild(GPUProcessHost* aHost);
+ ~GPUChild();
+
+ void Init();
+
+ void EnsureGPUReady();
+
+ // gfxVarReceiver overrides.
+ void OnVarChanged(const GfxVarUpdate& aVar) override;
+
+ // PGPUChild overrides.
+ bool RecvInitComplete(const GPUDeviceData& aData) override;
+ bool RecvReportCheckerboard(const uint32_t& aSeverity, const nsCString& aLog) override;
+ bool RecvInitCrashReporter(Shmem&& shmem) override;
+ bool RecvAccumulateChildHistogram(InfallibleTArray<Accumulation>&& aAccumulations) override;
+ bool RecvAccumulateChildKeyedHistogram(InfallibleTArray<KeyedAccumulation>&& aAccumulations) override;
+ void ActorDestroy(ActorDestroyReason aWhy) override;
+ bool RecvGraphicsError(const nsCString& aError) override;
+ bool RecvNotifyUiObservers(const nsCString& aTopic) override;
+ bool RecvNotifyDeviceReset() override;
+
+ static void Destroy(UniquePtr<GPUChild>&& aChild);
+
+private:
+ GPUProcessHost* mHost;
+ UniquePtr<ipc::CrashReporterHost> mCrashReporter;
+ bool mGPUReady;
+};
+
+} // namespace gfx
+} // namespace mozilla
+
+#endif // _include_mozilla_gfx_ipc_GPUChild_h_
diff --git a/gfx/ipc/GPUParent.cpp b/gfx/ipc/GPUParent.cpp
new file mode 100644
index 0000000000..d63e17e2f4
--- /dev/null
+++ b/gfx/ipc/GPUParent.cpp
@@ -0,0 +1,390 @@
+/* -*- 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/. */
+#ifdef XP_WIN
+#include "WMF.h"
+#endif
+#include "GPUParent.h"
+#include "gfxConfig.h"
+#include "gfxPlatform.h"
+#include "gfxPrefs.h"
+#include "GPUProcessHost.h"
+#include "mozilla/Assertions.h"
+#include "mozilla/gfx/2D.h"
+#include "mozilla/gfx/gfxVars.h"
+#include "mozilla/ipc/CrashReporterClient.h"
+#include "mozilla/ipc/ProcessChild.h"
+#include "mozilla/layers/APZThreadUtils.h"
+#include "mozilla/layers/APZCTreeManager.h"
+#include "mozilla/layers/CompositorBridgeParent.h"
+#include "mozilla/dom/VideoDecoderManagerParent.h"
+#include "mozilla/layers/CompositorThread.h"
+#include "mozilla/layers/ImageBridgeParent.h"
+#include "mozilla/dom/VideoDecoderManagerChild.h"
+#include "mozilla/layers/LayerTreeOwnerTracker.h"
+#include "nsDebugImpl.h"
+#include "nsExceptionHandler.h"
+#include "nsThreadManager.h"
+#include "prenv.h"
+#include "ProcessUtils.h"
+#include "VRManager.h"
+#include "VRManagerParent.h"
+#include "VsyncBridgeParent.h"
+#if defined(XP_WIN)
+# include "DeviceManagerD3D9.h"
+# include "mozilla/gfx/DeviceManagerDx.h"
+#endif
+#ifdef MOZ_WIDGET_GTK
+# include <gtk/gtk.h>
+#endif
+
+namespace mozilla {
+namespace gfx {
+
+using namespace ipc;
+using namespace layers;
+
+static GPUParent* sGPUParent;
+
+GPUParent::GPUParent()
+{
+ sGPUParent = this;
+}
+
+GPUParent::~GPUParent()
+{
+ sGPUParent = nullptr;
+}
+
+/* static */ GPUParent*
+GPUParent::GetSingleton()
+{
+ return sGPUParent;
+}
+
+bool
+GPUParent::Init(base::ProcessId aParentPid,
+ MessageLoop* aIOLoop,
+ IPC::Channel* aChannel)
+{
+ // Initialize the thread manager before starting IPC. Otherwise, messages
+ // may be posted to the main thread and we won't be able to process them.
+ if (NS_WARN_IF(NS_FAILED(nsThreadManager::get().Init()))) {
+ return false;
+ }
+
+ // Now it's safe to start IPC.
+ if (NS_WARN_IF(!Open(aChannel, aParentPid, aIOLoop))) {
+ return false;
+ }
+
+ nsDebugImpl::SetMultiprocessMode("GPU");
+
+#ifdef MOZ_CRASHREPORTER
+ // Init crash reporter support.
+ CrashReporterClient::InitSingleton(this);
+#endif
+
+ // Ensure gfxPrefs are initialized.
+ gfxPrefs::GetSingleton();
+ gfxConfig::Init();
+ gfxVars::Initialize();
+ gfxPlatform::InitNullMetadata();
+ // Ensure our Factory is initialised, mainly for gfx logging to work.
+ gfxPlatform::InitMoz2DLogging();
+#if defined(XP_WIN)
+ DeviceManagerDx::Init();
+ DeviceManagerD3D9::Init();
+#endif
+
+ if (NS_FAILED(NS_InitMinimalXPCOM())) {
+ return false;
+ }
+
+ CompositorThreadHolder::Start();
+ APZThreadUtils::SetControllerThread(CompositorThreadHolder::Loop());
+ APZCTreeManager::InitializeGlobalState();
+ VRManager::ManagerInit();
+ LayerTreeOwnerTracker::Initialize();
+ mozilla::ipc::SetThisProcessName("GPU Process");
+#ifdef XP_WIN
+ wmf::MFStartup();
+#endif
+ return true;
+}
+
+void
+GPUParent::NotifyDeviceReset()
+{
+ if (!NS_IsMainThread()) {
+ NS_DispatchToMainThread(NS_NewRunnableFunction([] () -> void {
+ GPUParent::GetSingleton()->NotifyDeviceReset();
+ }));
+ return;
+ }
+
+ // Reset and reinitialize the compositor devices
+#ifdef XP_WIN
+ if (!DeviceManagerDx::Get()->MaybeResetAndReacquireDevices()) {
+ // If the device doesn't need to be reset then the device
+ // has already been reset by a previous NotifyDeviceReset message.
+ return;
+ }
+#endif
+
+ // Notify the main process that there's been a device reset
+ // and that they should reset their compositors and repaint
+ Unused << SendNotifyDeviceReset();
+}
+
+bool
+GPUParent::RecvInit(nsTArray<GfxPrefSetting>&& prefs,
+ nsTArray<GfxVarUpdate>&& vars,
+ const DevicePrefs& devicePrefs)
+{
+ const nsTArray<gfxPrefs::Pref*>& globalPrefs = gfxPrefs::all();
+ for (auto& setting : prefs) {
+ gfxPrefs::Pref* pref = globalPrefs[setting.index()];
+ pref->SetCachedValue(setting.value());
+ }
+ for (const auto& var : vars) {
+ gfxVars::ApplyUpdate(var);
+ }
+
+ // Inherit device preferences.
+ gfxConfig::Inherit(Feature::HW_COMPOSITING, devicePrefs.hwCompositing());
+ gfxConfig::Inherit(Feature::D3D11_COMPOSITING, devicePrefs.d3d11Compositing());
+ gfxConfig::Inherit(Feature::D3D9_COMPOSITING, devicePrefs.d3d9Compositing());
+ gfxConfig::Inherit(Feature::OPENGL_COMPOSITING, devicePrefs.oglCompositing());
+ gfxConfig::Inherit(Feature::DIRECT2D, devicePrefs.useD2D1());
+
+#if defined(XP_WIN)
+ if (gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) {
+ DeviceManagerDx::Get()->CreateCompositorDevices();
+ }
+#endif
+
+#if defined(MOZ_WIDGET_GTK)
+ char* display_name = PR_GetEnv("DISPLAY");
+ if (display_name) {
+ int argc = 3;
+ char option_name[] = "--display";
+ char* argv[] = {
+ // argv0 is unused because g_set_prgname() was called in
+ // XRE_InitChildProcess().
+ nullptr,
+ option_name,
+ display_name,
+ nullptr
+ };
+ char** argvp = argv;
+ gtk_init(&argc, &argvp);
+ } else {
+ gtk_init(nullptr, nullptr);
+ }
+#endif
+
+ // Send a message to the UI process that we're done.
+ GPUDeviceData data;
+ RecvGetDeviceStatus(&data);
+ Unused << SendInitComplete(data);
+
+ return true;
+}
+
+bool
+GPUParent::RecvInitVsyncBridge(Endpoint<PVsyncBridgeParent>&& aVsyncEndpoint)
+{
+ mVsyncBridge = VsyncBridgeParent::Start(Move(aVsyncEndpoint));
+ return true;
+}
+
+bool
+GPUParent::RecvInitImageBridge(Endpoint<PImageBridgeParent>&& aEndpoint)
+{
+ ImageBridgeParent::CreateForGPUProcess(Move(aEndpoint));
+ return true;
+}
+
+bool
+GPUParent::RecvInitVRManager(Endpoint<PVRManagerParent>&& aEndpoint)
+{
+ VRManagerParent::CreateForGPUProcess(Move(aEndpoint));
+ return true;
+}
+
+bool
+GPUParent::RecvUpdatePref(const GfxPrefSetting& setting)
+{
+ gfxPrefs::Pref* pref = gfxPrefs::all()[setting.index()];
+ pref->SetCachedValue(setting.value());
+ return true;
+}
+
+bool
+GPUParent::RecvUpdateVar(const GfxVarUpdate& aUpdate)
+{
+ gfxVars::ApplyUpdate(aUpdate);
+ return true;
+}
+
+static void
+CopyFeatureChange(Feature aFeature, FeatureChange* aOut)
+{
+ FeatureState& feature = gfxConfig::GetFeature(aFeature);
+ if (feature.DisabledByDefault() || feature.IsEnabled()) {
+ // No change:
+ // - Disabled-by-default means the parent process told us not to use this feature.
+ // - Enabled means we were told to use this feature, and we didn't discover anything
+ // that would prevent us from doing so.
+ *aOut = null_t();
+ return;
+ }
+
+ MOZ_ASSERT(!feature.IsEnabled());
+
+ nsCString message;
+ message.AssignASCII(feature.GetFailureMessage());
+
+ *aOut = FeatureFailure(feature.GetValue(), message, feature.GetFailureId());
+}
+
+bool
+GPUParent::RecvGetDeviceStatus(GPUDeviceData* aOut)
+{
+ CopyFeatureChange(Feature::D3D11_COMPOSITING, &aOut->d3d11Compositing());
+ CopyFeatureChange(Feature::D3D9_COMPOSITING, &aOut->d3d9Compositing());
+ CopyFeatureChange(Feature::OPENGL_COMPOSITING, &aOut->oglCompositing());
+
+#if defined(XP_WIN)
+ if (DeviceManagerDx* dm = DeviceManagerDx::Get()) {
+ D3D11DeviceStatus deviceStatus;
+ dm->ExportDeviceInfo(&deviceStatus);
+ aOut->gpuDevice() = deviceStatus;
+ }
+#else
+ aOut->gpuDevice() = null_t();
+#endif
+
+ 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 TimeDuration& aVsyncRate,
+ const bool& aUseExternalSurfaceSize,
+ const IntSize& aSurfaceSize)
+{
+ RefPtr<CompositorBridgeParent> cbp =
+ new CompositorBridgeParent(aScale, aVsyncRate, aUseExternalSurfaceSize, aSurfaceSize);
+
+ MessageLoop* loop = CompositorThreadHolder::Loop();
+ loop->PostTask(NewRunnableFunction(OpenParent, cbp, Move(aEndpoint)));
+ return true;
+}
+
+bool
+GPUParent::RecvNewContentCompositorBridge(Endpoint<PCompositorBridgeParent>&& aEndpoint)
+{
+ return CompositorBridgeParent::CreateForContent(Move(aEndpoint));
+}
+
+bool
+GPUParent::RecvNewContentImageBridge(Endpoint<PImageBridgeParent>&& aEndpoint)
+{
+ return ImageBridgeParent::CreateForContent(Move(aEndpoint));
+}
+
+bool
+GPUParent::RecvNewContentVRManager(Endpoint<PVRManagerParent>&& aEndpoint)
+{
+ return VRManagerParent::CreateForContent(Move(aEndpoint));
+}
+
+bool
+GPUParent::RecvNewContentVideoDecoderManager(Endpoint<PVideoDecoderManagerParent>&& aEndpoint)
+{
+ return dom::VideoDecoderManagerParent::CreateForContent(Move(aEndpoint));
+}
+
+bool
+GPUParent::RecvAddLayerTreeIdMapping(nsTArray<LayerTreeIdMapping>&& aMappings)
+{
+ for (const LayerTreeIdMapping& map : aMappings) {
+ LayerTreeOwnerTracker::Get()->Map(map.layersId(), map.ownerId());
+ }
+ return true;
+}
+
+bool
+GPUParent::RecvRemoveLayerTreeIdMapping(const LayerTreeIdMapping& aMapping)
+{
+ LayerTreeOwnerTracker::Get()->Unmap(aMapping.layersId(), aMapping.ownerId());
+ CompositorBridgeParent::DeallocateLayerTreeId(aMapping.layersId());
+ return true;
+}
+
+bool
+GPUParent::RecvNotifyGpuObservers(const nsCString& aTopic)
+{
+ nsCOMPtr<nsIObserverService> obsSvc = mozilla::services::GetObserverService();
+ MOZ_ASSERT(obsSvc);
+ if (obsSvc) {
+ obsSvc->NotifyObservers(nullptr, aTopic.get(), nullptr);
+ }
+ return true;
+}
+
+void
+GPUParent::ActorDestroy(ActorDestroyReason aWhy)
+{
+ if (AbnormalShutdown == aWhy) {
+ NS_WARNING("Shutting down GPU process early due to a crash!");
+ ProcessChild::QuickExit();
+ }
+
+#ifdef XP_WIN
+ wmf::MFShutdown();
+#endif
+
+#ifndef NS_FREE_PERMANENT_DATA
+ // No point in going through XPCOM shutdown because we don't keep persistent
+ // state.
+ ProcessChild::QuickExit();
+#endif
+
+ if (mVsyncBridge) {
+ mVsyncBridge->Shutdown();
+ mVsyncBridge = nullptr;
+ }
+ dom::VideoDecoderManagerParent::ShutdownVideoBridge();
+ CompositorThreadHolder::Shutdown();
+ Factory::ShutDown();
+#if defined(XP_WIN)
+ DeviceManagerDx::Shutdown();
+ DeviceManagerD3D9::Shutdown();
+#endif
+ LayerTreeOwnerTracker::Shutdown();
+ gfxVars::Shutdown();
+ gfxConfig::Shutdown();
+ gfxPrefs::DestroySingleton();
+#ifdef MOZ_CRASHREPORTER
+ CrashReporterClient::DestroySingleton();
+#endif
+ XRE_ShutdownChildProcess();
+}
+
+} // namespace gfx
+} // namespace mozilla
diff --git a/gfx/ipc/GPUParent.h b/gfx/ipc/GPUParent.h
new file mode 100644
index 0000000000..126efce500
--- /dev/null
+++ b/gfx/ipc/GPUParent.h
@@ -0,0 +1,62 @@
+/* -*- 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_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:
+ GPUParent();
+ ~GPUParent();
+
+ static GPUParent* GetSingleton();
+
+ bool Init(base::ProcessId aParentPid,
+ MessageLoop* aIOLoop,
+ IPC::Channel* aChannel);
+ void NotifyDeviceReset();
+
+ bool RecvInit(nsTArray<GfxPrefSetting>&& prefs,
+ nsTArray<GfxVarUpdate>&& vars,
+ const DevicePrefs& devicePrefs) override;
+ bool RecvInitVsyncBridge(Endpoint<PVsyncBridgeParent>&& aVsyncEndpoint) override;
+ bool RecvInitImageBridge(Endpoint<PImageBridgeParent>&& aEndpoint) override;
+ bool RecvInitVRManager(Endpoint<PVRManagerParent>&& aEndpoint) override;
+ bool RecvUpdatePref(const GfxPrefSetting& pref) override;
+ bool RecvUpdateVar(const GfxVarUpdate& pref) override;
+ bool RecvNewWidgetCompositor(
+ Endpoint<PCompositorBridgeParent>&& aEndpoint,
+ const CSSToLayoutDeviceScale& aScale,
+ const TimeDuration& aVsyncRate,
+ const bool& aUseExternalSurface,
+ const IntSize& aSurfaceSize) override;
+ bool RecvNewContentCompositorBridge(Endpoint<PCompositorBridgeParent>&& aEndpoint) override;
+ bool RecvNewContentImageBridge(Endpoint<PImageBridgeParent>&& aEndpoint) override;
+ bool RecvNewContentVRManager(Endpoint<PVRManagerParent>&& aEndpoint) override;
+ bool RecvNewContentVideoDecoderManager(Endpoint<PVideoDecoderManagerParent>&& aEndpoint) override;
+ bool RecvGetDeviceStatus(GPUDeviceData* aOutStatus) override;
+ bool RecvAddLayerTreeIdMapping(nsTArray<LayerTreeIdMapping>&& aMappings) override;
+ bool RecvRemoveLayerTreeIdMapping(const LayerTreeIdMapping& aMapping) override;
+ bool RecvNotifyGpuObservers(const nsCString& aTopic) override;
+
+ void ActorDestroy(ActorDestroyReason aWhy) override;
+
+private:
+ RefPtr<VsyncBridgeParent> mVsyncBridge;
+};
+
+} // namespace gfx
+} // namespace mozilla
+
+#endif // _include_gfx_ipc_GPUParent_h__
diff --git a/gfx/ipc/GPUProcessHost.cpp b/gfx/ipc/GPUProcessHost.cpp
new file mode 100644
index 0000000000..613f353a4b
--- /dev/null
+++ b/gfx/ipc/GPUProcessHost.cpp
@@ -0,0 +1,247 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: sts=8 sw=2 ts=2 tw=99 et :
+ * 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 "GPUProcessHost.h"
+#include "chrome/common/process_watcher.h"
+#include "gfxPrefs.h"
+#include "mozilla/gfx/Logging.h"
+#include "nsITimer.h"
+
+namespace mozilla {
+namespace gfx {
+
+using namespace ipc;
+
+GPUProcessHost::GPUProcessHost(Listener* aListener)
+ : GeckoChildProcessHost(GeckoProcessType_GPU),
+ mListener(aListener),
+ mTaskFactory(this),
+ mLaunchPhase(LaunchPhase::Unlaunched),
+ mProcessToken(0),
+ mShutdownRequested(false),
+ mChannelClosed(false)
+{
+ MOZ_COUNT_CTOR(GPUProcessHost);
+}
+
+GPUProcessHost::~GPUProcessHost()
+{
+ MOZ_COUNT_DTOR(GPUProcessHost);
+}
+
+bool
+GPUProcessHost::Launch()
+{
+ MOZ_ASSERT(mLaunchPhase == LaunchPhase::Unlaunched);
+ MOZ_ASSERT(!mGPUChild);
+
+ mLaunchPhase = LaunchPhase::Waiting;
+ mLaunchTime = TimeStamp::Now();
+
+ if (!GeckoChildProcessHost::AsyncLaunch()) {
+ mLaunchPhase = LaunchPhase::Complete;
+ return false;
+ }
+ return true;
+}
+
+bool
+GPUProcessHost::WaitForLaunch()
+{
+ if (mLaunchPhase == LaunchPhase::Complete) {
+ return !!mGPUChild;
+ }
+
+ int32_t timeoutMs = gfxPrefs::GPUProcessDevTimeoutMs();
+
+ // Our caller expects the connection to be finished after we return, so we
+ // immediately set up the IPDL actor and fire callbacks. The IO thread will
+ // still dispatch a notification to the main thread - we'll just ignore it.
+ bool result = GeckoChildProcessHost::WaitUntilConnected(timeoutMs);
+ InitAfterConnect(result);
+ return result;
+}
+
+void
+GPUProcessHost::OnChannelConnected(int32_t peer_pid)
+{
+ MOZ_ASSERT(!NS_IsMainThread());
+
+ GeckoChildProcessHost::OnChannelConnected(peer_pid);
+
+ // Post a task to the main thread. Take the lock because mTaskFactory is not
+ // thread-safe.
+ RefPtr<Runnable> runnable;
+ {
+ MonitorAutoLock lock(mMonitor);
+ runnable = mTaskFactory.NewRunnableMethod(&GPUProcessHost::OnChannelConnectedTask);
+ }
+ NS_DispatchToMainThread(runnable);
+}
+
+void
+GPUProcessHost::OnChannelError()
+{
+ MOZ_ASSERT(!NS_IsMainThread());
+
+ GeckoChildProcessHost::OnChannelError();
+
+ // Post a task to the main thread. Take the lock because mTaskFactory is not
+ // thread-safe.
+ RefPtr<Runnable> runnable;
+ {
+ MonitorAutoLock lock(mMonitor);
+ runnable = mTaskFactory.NewRunnableMethod(&GPUProcessHost::OnChannelErrorTask);
+ }
+ NS_DispatchToMainThread(runnable);
+}
+
+void
+GPUProcessHost::OnChannelConnectedTask()
+{
+ if (mLaunchPhase == LaunchPhase::Waiting) {
+ InitAfterConnect(true);
+ }
+}
+
+void
+GPUProcessHost::OnChannelErrorTask()
+{
+ if (mLaunchPhase == LaunchPhase::Waiting) {
+ InitAfterConnect(false);
+ }
+}
+
+static uint64_t sProcessTokenCounter = 0;
+
+void
+GPUProcessHost::InitAfterConnect(bool aSucceeded)
+{
+ MOZ_ASSERT(mLaunchPhase == LaunchPhase::Waiting);
+ MOZ_ASSERT(!mGPUChild);
+
+ mLaunchPhase = LaunchPhase::Complete;
+
+ if (aSucceeded) {
+ mProcessToken = ++sProcessTokenCounter;
+ mGPUChild = MakeUnique<GPUChild>(this);
+ DebugOnly<bool> rv =
+ mGPUChild->Open(GetChannel(), base::GetProcId(GetChildProcessHandle()));
+ MOZ_ASSERT(rv);
+
+ mGPUChild->Init();
+ }
+
+ if (mListener) {
+ mListener->OnProcessLaunchComplete(this);
+ }
+}
+
+void
+GPUProcessHost::Shutdown()
+{
+ MOZ_ASSERT(!mShutdownRequested);
+
+ mListener = nullptr;
+
+ if (mGPUChild) {
+ // OnChannelClosed uses this to check if the shutdown was expected or
+ // unexpected.
+ mShutdownRequested = true;
+
+#ifdef NS_FREE_PERMANENT_DATA
+ // The channel might already be closed if we got here unexpectedly.
+ if (!mChannelClosed) {
+ mGPUChild->Close();
+ }
+#else
+ // No need to communicate shutdown, the GPU process doesn't need to
+ // communicate anything back.
+ KillHard("NormalShutdown");
+#endif
+
+ // If we're shutting down unexpectedly, we're in the middle of handling an
+ // ActorDestroy for PGPUChild, which is still on the stack. We'll return
+ // back to OnChannelClosed.
+ //
+ // Otherwise, we'll wait for OnChannelClose to be called whenever PGPUChild
+ // acknowledges shutdown.
+ return;
+ }
+
+ DestroyProcess();
+}
+
+void
+GPUProcessHost::OnChannelClosed()
+{
+ if (!mShutdownRequested) {
+ // This is an unclean shutdown. Notify our listener that we're going away.
+ mChannelClosed = true;
+ if (mListener) {
+ mListener->OnProcessUnexpectedShutdown(this);
+ }
+ }
+
+ // Release the actor.
+ GPUChild::Destroy(Move(mGPUChild));
+ MOZ_ASSERT(!mGPUChild);
+
+ // If the owner of GPUProcessHost already requested shutdown, we can now
+ // schedule destruction. Otherwise we must wait for someone to call
+ // Shutdown. Note that GPUProcessManager calls Shutdown within
+ // OnProcessUnexpectedShutdown.
+ if (mShutdownRequested) {
+ DestroyProcess();
+ }
+}
+
+void
+GPUProcessHost::KillHard(const char* aReason)
+{
+ ProcessHandle handle = GetChildProcessHandle();
+ if (!base::KillProcess(handle, base::PROCESS_END_KILLED_BY_USER, false)) {
+ NS_WARNING("failed to kill subprocess!");
+ }
+
+ SetAlreadyDead();
+}
+
+uint64_t
+GPUProcessHost::GetProcessToken() const
+{
+ return mProcessToken;
+}
+
+static void
+DelayedDeleteSubprocess(GeckoChildProcessHost* aSubprocess)
+{
+ XRE_GetIOMessageLoop()->
+ PostTask(mozilla::MakeAndAddRef<DeleteTask<GeckoChildProcessHost>>(aSubprocess));
+}
+
+void
+GPUProcessHost::KillProcess()
+{
+ KillHard("DiagnosticKill");
+}
+
+void
+GPUProcessHost::DestroyProcess()
+{
+ // Cancel all tasks. We don't want anything triggering after our caller
+ // expects this to go away.
+ {
+ MonitorAutoLock lock(mMonitor);
+ mTaskFactory.RevokeAll();
+ }
+
+ MessageLoop::current()->
+ PostTask(NewRunnableFunction(DelayedDeleteSubprocess, this));
+}
+
+} // namespace gfx
+} // namespace mozilla
diff --git a/gfx/ipc/GPUProcessHost.h b/gfx/ipc/GPUProcessHost.h
new file mode 100644
index 0000000000..d5c19f35d9
--- /dev/null
+++ b/gfx/ipc/GPUProcessHost.h
@@ -0,0 +1,146 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: sts=8 sw=2 ts=2 tw=99 et :
+ * 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_GPUProcessHost_h_
+#define _include_mozilla_gfx_ipc_GPUProcessHost_h_
+
+#include "mozilla/Function.h"
+#include "mozilla/Maybe.h"
+#include "mozilla/UniquePtr.h"
+#include "mozilla/ipc/GeckoChildProcessHost.h"
+#include "mozilla/ipc/ProtocolUtils.h"
+#include "mozilla/ipc/TaskFactory.h"
+
+class nsITimer;
+
+namespace mozilla {
+namespace gfx {
+
+class GPUChild;
+
+// GPUProcessHost is the "parent process" container for a subprocess handle and
+// IPC connection. It owns the parent process IPDL actor, which in this case,
+// is a GPUChild.
+//
+// GPUProcessHosts are allocated and managed by GPUProcessManager. For all
+// intents and purposes it is a singleton, though more than one may be allocated
+// at a time due to its shutdown being asynchronous.
+class GPUProcessHost final : public ipc::GeckoChildProcessHost
+{
+ friend class GPUChild;
+
+public:
+ class Listener {
+ public:
+ virtual void OnProcessLaunchComplete(GPUProcessHost* aHost)
+ {}
+
+ // The GPUProcessHost has unexpectedly shutdown or had its connection
+ // severed. This is not called if an error occurs after calling
+ // Shutdown().
+ virtual void OnProcessUnexpectedShutdown(GPUProcessHost* aHost)
+ {}
+
+ virtual void OnProcessDeviceReset(GPUProcessHost* aHost)
+ {}
+ };
+
+public:
+ explicit GPUProcessHost(Listener* listener);
+ ~GPUProcessHost();
+
+ // Launch the subprocess asynchronously. On failure, false is returned.
+ // Otherwise, true is returned, and the OnLaunchComplete listener callback
+ // will be invoked either when a connection has been established, or if a
+ // connection could not be established due to an asynchronous error.
+ bool Launch();
+
+ // If the process is being launched, block until it has launched and
+ // connected. If a launch task is pending, it will fire immediately.
+ //
+ // Returns true if the process is successfully connected; false otherwise.
+ bool WaitForLaunch();
+
+ // Inform the process that it should clean up its resources and shut down.
+ // This initiates an asynchronous shutdown sequence. After this method returns,
+ // it is safe for the caller to forget its pointer to the GPUProcessHost.
+ //
+ // After this returns, the attached Listener is no longer used.
+ void Shutdown();
+
+ // Return the actor for the top-level actor of the process. If the process
+ // has not connected yet, this returns null.
+ GPUChild* GetActor() const {
+ return mGPUChild.get();
+ }
+
+ // Return a unique id for this process, guaranteed not to be shared with any
+ // past or future instance of GPUProcessHost.
+ uint64_t GetProcessToken() const;
+
+ bool IsConnected() const {
+ return !!mGPUChild;
+ }
+
+ // Return the time stamp for when we tried to launch the GPU process. This is
+ // currently used for Telemetry so that we can determine how long GPU processes
+ // take to spin up. Note this doesn't denote a successful launch, just when we
+ // attempted launch.
+ TimeStamp GetLaunchTime() const {
+ return mLaunchTime;
+ }
+
+ // Called on the IO thread.
+ void OnChannelConnected(int32_t peer_pid) override;
+ void OnChannelError() override;
+
+ void SetListener(Listener* aListener);
+
+ // Used for tests and diagnostics
+ void KillProcess();
+
+private:
+ // Called on the main thread.
+ void OnChannelConnectedTask();
+ void OnChannelErrorTask();
+
+ // Called on the main thread after a connection has been established.
+ void InitAfterConnect(bool aSucceeded);
+
+ // Called on the main thread when the mGPUChild actor is shutting down.
+ void OnChannelClosed();
+
+ // Kill the remote process, triggering IPC shutdown.
+ void KillHard(const char* aReason);
+
+ void DestroyProcess();
+
+private:
+ DISALLOW_COPY_AND_ASSIGN(GPUProcessHost);
+
+ Listener* mListener;
+ ipc::TaskFactory<GPUProcessHost> mTaskFactory;
+
+ enum class LaunchPhase {
+ Unlaunched,
+ Waiting,
+ Complete
+ };
+ LaunchPhase mLaunchPhase;
+
+ UniquePtr<GPUChild> mGPUChild;
+ uint64_t mProcessToken;
+
+ bool mShutdownRequested;
+ bool mChannelClosed;
+
+ TimeStamp mLaunchTime;
+};
+
+} // namespace gfx
+} // namespace mozilla
+
+#endif // _include_mozilla_gfx_ipc_GPUProcessHost_h_
diff --git a/gfx/ipc/GPUProcessImpl.cpp b/gfx/ipc/GPUProcessImpl.cpp
new file mode 100644
index 0000000000..38d13484b3
--- /dev/null
+++ b/gfx/ipc/GPUProcessImpl.cpp
@@ -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 "GPUProcessImpl.h"
+#include "mozilla/ipc/IOThreadChild.h"
+#include "nsXPCOM.h"
+
+namespace mozilla {
+namespace gfx {
+
+using namespace ipc;
+
+GPUProcessImpl::GPUProcessImpl(ProcessId aParentPid)
+ : ProcessChild(aParentPid)
+{
+}
+
+GPUProcessImpl::~GPUProcessImpl()
+{
+}
+
+bool
+GPUProcessImpl::Init()
+{
+ return mGPU.Init(ParentPid(),
+ IOThreadChild::message_loop(),
+ IOThreadChild::channel());
+}
+
+void
+GPUProcessImpl::CleanUp()
+{
+ NS_ShutdownXPCOM(nullptr);
+}
+
+} // namespace gfx
+} // namespace mozilla
diff --git a/gfx/ipc/GPUProcessImpl.h b/gfx/ipc/GPUProcessImpl.h
new file mode 100644
index 0000000000..5e8b6694a6
--- /dev/null
+++ b/gfx/ipc/GPUProcessImpl.h
@@ -0,0 +1,44 @@
+/* -*- 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_GPUProcessImpl_h__
+#define _include_gfx_ipc_GPUProcessImpl_h__
+
+#include "mozilla/ipc/ProcessChild.h"
+#include "GPUParent.h"
+
+#if defined(XP_WIN)
+# include "mozilla/mscom/MainThreadRuntime.h"
+#endif
+
+namespace mozilla {
+namespace gfx {
+
+// This class owns the subprocess instance of a PGPU - which in this case,
+// is a GPUParent. It is instantiated as a singleton in XRE_InitChildProcess.
+class GPUProcessImpl final : public ipc::ProcessChild
+{
+public:
+ explicit GPUProcessImpl(ProcessId aParentPid);
+ ~GPUProcessImpl();
+
+ bool Init() override;
+ void CleanUp() override;
+
+private:
+ DISALLOW_COPY_AND_ASSIGN(GPUProcessImpl);
+
+ GPUParent mGPU;
+
+#if defined(XP_WIN)
+ // This object initializes and configures COM.
+ mozilla::mscom::MainThreadRuntime mCOMRuntime;
+#endif
+};
+
+} // namespace gfx
+} // namespace mozilla
+
+#endif // _include_gfx_ipc_GPUProcessImpl_h__
diff --git a/gfx/ipc/GPUProcessListener.h b/gfx/ipc/GPUProcessListener.h
new file mode 100644
index 0000000000..d69e912dea
--- /dev/null
+++ b/gfx/ipc/GPUProcessListener.h
@@ -0,0 +1,27 @@
+/* -*- 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_GPUProcessListener_h_
+#define _include_mozilla_gfx_ipc_GPUProcessListener_h_
+
+namespace mozilla {
+namespace gfx {
+
+class GPUProcessListener
+{
+ public:
+ virtual ~GPUProcessListener()
+ {}
+
+ // Called when the compositor has died and the rendering stack must be
+ // recreated.
+ virtual void OnCompositorUnexpectedShutdown()
+ {}
+};
+
+} // namespace gfx
+} // namespace mozilla
+
+#endif // _include_mozilla_gfx_ipc_GPUProcessListener_h_
diff --git a/gfx/ipc/GPUProcessManager.cpp b/gfx/ipc/GPUProcessManager.cpp
new file mode 100644
index 0000000000..0b55cd9b7d
--- /dev/null
+++ b/gfx/ipc/GPUProcessManager.cpp
@@ -0,0 +1,852 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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 "GPUProcessManager.h"
+#include "GPUProcessHost.h"
+#include "GPUProcessListener.h"
+#include "mozilla/StaticPtr.h"
+#include "mozilla/dom/ContentParent.h"
+#include "mozilla/layers/APZCTreeManager.h"
+#include "mozilla/layers/APZCTreeManagerChild.h"
+#include "mozilla/layers/CompositorBridgeParent.h"
+#include "mozilla/layers/ImageBridgeChild.h"
+#include "mozilla/layers/ImageBridgeParent.h"
+#include "mozilla/layers/InProcessCompositorSession.h"
+#include "mozilla/layers/LayerTreeOwnerTracker.h"
+#include "mozilla/layers/RemoteCompositorSession.h"
+#include "mozilla/widget/PlatformWidgetTypes.h"
+#ifdef MOZ_WIDGET_SUPPORTS_OOP_COMPOSITING
+# include "mozilla/widget/CompositorWidgetChild.h"
+#endif
+#include "nsBaseWidget.h"
+#include "nsContentUtils.h"
+#include "VRManagerChild.h"
+#include "VRManagerParent.h"
+#include "VsyncBridgeChild.h"
+#include "VsyncIOThreadHolder.h"
+#include "VsyncSource.h"
+#include "mozilla/dom/VideoDecoderManagerChild.h"
+#include "mozilla/dom/VideoDecoderManagerParent.h"
+#include "MediaPrefs.h"
+
+namespace mozilla {
+namespace gfx {
+
+using namespace mozilla::layers;
+
+static StaticAutoPtr<GPUProcessManager> sSingleton;
+
+GPUProcessManager*
+GPUProcessManager::Get()
+{
+ return sSingleton;
+}
+
+void
+GPUProcessManager::Initialize()
+{
+ MOZ_ASSERT(XRE_IsParentProcess());
+ sSingleton = new GPUProcessManager();
+}
+
+void
+GPUProcessManager::Shutdown()
+{
+ sSingleton = nullptr;
+}
+
+GPUProcessManager::GPUProcessManager()
+ : mTaskFactory(this),
+ mNextLayerTreeId(0),
+ mNumProcessAttempts(0),
+ mDeviceResetCount(0),
+ mProcess(nullptr),
+ mGPUChild(nullptr)
+{
+ MOZ_COUNT_CTOR(GPUProcessManager);
+
+ mObserver = new Observer(this);
+ nsContentUtils::RegisterShutdownObserver(mObserver);
+
+ mDeviceResetLastTime = TimeStamp::Now();
+
+ LayerTreeOwnerTracker::Initialize();
+}
+
+GPUProcessManager::~GPUProcessManager()
+{
+ MOZ_COUNT_DTOR(GPUProcessManager);
+
+ LayerTreeOwnerTracker::Shutdown();
+
+ // The GPU process should have already been shut down.
+ MOZ_ASSERT(!mProcess && !mGPUChild);
+
+ // We should have already removed observers.
+ MOZ_ASSERT(!mObserver);
+}
+
+NS_IMPL_ISUPPORTS(GPUProcessManager::Observer, nsIObserver);
+
+GPUProcessManager::Observer::Observer(GPUProcessManager* aManager)
+ : mManager(aManager)
+{
+}
+
+NS_IMETHODIMP
+GPUProcessManager::Observer::Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aData)
+{
+ if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
+ mManager->OnXPCOMShutdown();
+ }
+ return NS_OK;
+}
+
+void
+GPUProcessManager::OnXPCOMShutdown()
+{
+ if (mObserver) {
+ nsContentUtils::UnregisterShutdownObserver(mObserver);
+ mObserver = nullptr;
+ }
+
+ CleanShutdown();
+}
+
+void
+GPUProcessManager::LaunchGPUProcess()
+{
+ if (mProcess) {
+ return;
+ }
+
+ // Start the Vsync I/O thread so can use it as soon as the process launches.
+ EnsureVsyncIOThread();
+
+ mNumProcessAttempts++;
+
+ // The subprocess is launched asynchronously, so we wait for a callback to
+ // acquire the IPDL actor.
+ mProcess = new GPUProcessHost(this);
+ if (!mProcess->Launch()) {
+ DisableGPUProcess("Failed to launch GPU process");
+ }
+}
+
+void
+GPUProcessManager::DisableGPUProcess(const char* aMessage)
+{
+ if (!gfxConfig::IsEnabled(Feature::GPU_PROCESS)) {
+ return;
+ }
+
+ gfxConfig::SetFailed(Feature::GPU_PROCESS, FeatureStatus::Failed, aMessage);
+ gfxCriticalNote << aMessage;
+
+ DestroyProcess();
+ ShutdownVsyncIOThread();
+}
+
+void
+GPUProcessManager::EnsureGPUReady()
+{
+ if (mProcess && !mProcess->IsConnected()) {
+ if (!mProcess->WaitForLaunch()) {
+ // If this fails, we should have fired OnProcessLaunchComplete and
+ // removed the process.
+ MOZ_ASSERT(!mProcess && !mGPUChild);
+ return;
+ }
+ }
+
+ if (mGPUChild) {
+ mGPUChild->EnsureGPUReady();
+ }
+}
+
+void
+GPUProcessManager::EnsureImageBridgeChild()
+{
+ if (ImageBridgeChild::GetSingleton()) {
+ return;
+ }
+
+ EnsureGPUReady();
+
+ if (!mGPUChild) {
+ ImageBridgeChild::InitSameProcess();
+ return;
+ }
+
+ ipc::Endpoint<PImageBridgeParent> parentPipe;
+ ipc::Endpoint<PImageBridgeChild> childPipe;
+ nsresult rv = PImageBridge::CreateEndpoints(
+ mGPUChild->OtherPid(),
+ base::GetCurrentProcId(),
+ &parentPipe,
+ &childPipe);
+ if (NS_FAILED(rv)) {
+ DisableGPUProcess("Failed to create PImageBridge endpoints");
+ return;
+ }
+
+ mGPUChild->SendInitImageBridge(Move(parentPipe));
+ ImageBridgeChild::InitWithGPUProcess(Move(childPipe));
+}
+
+void
+GPUProcessManager::EnsureVRManager()
+{
+ if (VRManagerChild::IsCreated()) {
+ return;
+ }
+
+ EnsureGPUReady();
+
+ if (!mGPUChild) {
+ VRManagerChild::InitSameProcess();
+ return;
+ }
+
+ ipc::Endpoint<PVRManagerParent> parentPipe;
+ ipc::Endpoint<PVRManagerChild> childPipe;
+ nsresult rv = PVRManager::CreateEndpoints(
+ mGPUChild->OtherPid(),
+ base::GetCurrentProcId(),
+ &parentPipe,
+ &childPipe);
+ if (NS_FAILED(rv)) {
+ DisableGPUProcess("Failed to create PVRManager endpoints");
+ return;
+ }
+
+ mGPUChild->SendInitVRManager(Move(parentPipe));
+ VRManagerChild::InitWithGPUProcess(Move(childPipe));
+}
+
+void
+GPUProcessManager::OnProcessLaunchComplete(GPUProcessHost* aHost)
+{
+ MOZ_ASSERT(mProcess && mProcess == aHost);
+
+ if (!mProcess->IsConnected()) {
+ DisableGPUProcess("Failed to launch GPU process");
+ return;
+ }
+
+ 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));
+
+ nsTArray<LayerTreeIdMapping> mappings;
+ LayerTreeOwnerTracker::Get()->Iterate([&](uint64_t aLayersId, base::ProcessId aProcessId) {
+ mappings.AppendElement(LayerTreeIdMapping(aLayersId, aProcessId));
+ });
+ mGPUChild->SendAddLayerTreeIdMapping(mappings);
+}
+
+static bool
+ShouldLimitDeviceResets(uint32_t count, int32_t deltaMilliseconds)
+{
+ // We decide to limit by comparing the amount of resets that have happened
+ // and time since the last reset to two prefs.
+ int32_t timeLimit = gfxPrefs::DeviceResetThresholdMilliseconds();
+ int32_t countLimit = gfxPrefs::DeviceResetLimitCount();
+
+ bool hasTimeLimit = timeLimit != -1;
+ bool hasCountLimit = countLimit != -1;
+
+ bool triggeredTime = deltaMilliseconds < timeLimit;
+ bool triggeredCount = count > (uint32_t)countLimit;
+
+ // If we have both prefs set then it needs to trigger both limits,
+ // otherwise we only test the pref that is set or none
+ if (hasTimeLimit && hasCountLimit) {
+ return triggeredTime && triggeredCount;
+ } else if (hasTimeLimit) {
+ return triggeredTime;
+ } else if (hasCountLimit) {
+ return triggeredCount;
+ }
+
+ return false;
+}
+
+void
+GPUProcessManager::OnProcessDeviceReset(GPUProcessHost* aHost)
+{
+ // Detect whether the device is resetting too quickly or too much
+ // indicating that we should give up and use software
+ mDeviceResetCount++;
+
+ auto newTime = TimeStamp::Now();
+ auto delta = (int32_t)(newTime - mDeviceResetLastTime).ToMilliseconds();
+ mDeviceResetLastTime = newTime;
+
+ if (ShouldLimitDeviceResets(mDeviceResetCount, delta)) {
+ DestroyProcess();
+ DisableGPUProcess("GPU processed experienced too many device resets");
+
+ HandleProcessLost();
+ return;
+ }
+
+ // We're good, do a reset like normal
+ for (auto& session : mRemoteSessions) {
+ session->NotifyDeviceReset();
+ }
+}
+
+void
+GPUProcessManager::OnProcessUnexpectedShutdown(GPUProcessHost* aHost)
+{
+ MOZ_ASSERT(mProcess && mProcess == aHost);
+
+ DestroyProcess();
+
+ if (mNumProcessAttempts > uint32_t(gfxPrefs::GPUProcessDevMaxRestarts())) {
+ DisableGPUProcess("GPU processed crashed too many times");
+ }
+
+ HandleProcessLost();
+}
+
+void
+GPUProcessManager::HandleProcessLost()
+{
+ if (gfxConfig::IsEnabled(Feature::GPU_PROCESS)) {
+ LaunchGPUProcess();
+ }
+
+ // The shutdown and restart sequence for the GPU process is as follows:
+ //
+ // (1) The GPU process dies. IPDL will enqueue an ActorDestroy message on
+ // each channel owning a bridge to the GPU process, on the thread
+ // owning that channel.
+ //
+ // (2) The first channel to process its ActorDestroy message will post a
+ // message to the main thread to call NotifyRemoteActorDestroyed on
+ // the GPUProcessManager, which calls OnProcessUnexpectedShutdown if
+ // it has not handled shutdown for this process yet.
+ //
+ // (3) We then notify each widget that its session with the compositor is
+ // now invalid. The widget is responsible for destroying its layer
+ // manager and CompositorBridgeChild. Note that at this stage, not
+ // all actors may have received ActorDestroy yet. CompositorBridgeChild
+ // may attempt to send messages, and if this happens, it will probably
+ // report a MsgDropped error. This is okay.
+ //
+ // (4) At this point, the UI process has a clean slate: no layers should
+ // exist for the old compositor. We may make a decision on whether or
+ // not to re-launch the GPU process. Currently, we do not relaunch it,
+ // and any new compositors will be created in-process and will default
+ // to software.
+ //
+ // (5) Next we notify each ContentParent of the lost connection. It will
+ // request new endpoints from the GPUProcessManager and forward them
+ // to its ContentChild. The parent-side of these endpoints may come
+ // from the compositor thread of the UI process, or the compositor
+ // thread of the GPU process. However, no actual compositors should
+ // exist yet.
+ //
+ // (6) Each ContentChild will receive new endpoints. It will destroy its
+ // Compositor/ImageBridgeChild singletons and recreate them, as well
+ // as invalidate all retained layers.
+ //
+ // (7) In addition, each ContentChild will ask each of its TabChildren
+ // to re-request association with the compositor for the window
+ // owning the tab. The sequence of calls looks like:
+ // (a) [CONTENT] ContentChild::RecvReinitRendering
+ // (b) [CONTENT] TabChild::ReinitRendering
+ // (c) [CONTENT] TabChild::SendEnsureLayersConnected
+ // (d) [UI] TabParent::RecvEnsureLayersConnected
+ // (e) [UI] RenderFrameParent::EnsureLayersConnected
+ // (f) [UI] CompositorBridgeChild::SendNotifyChildRecreated
+ //
+ // Note that at step (e), RenderFrameParent will call GetLayerManager
+ // on the nsIWidget owning the tab. This step ensures that a compositor
+ // exists for the window. If we decided to launch a new GPU Process,
+ // at this point we block until the process has launched and we're
+ // able to create a new window compositor. Otherwise, if compositing
+ // is now in-process, this will simply create a new
+ // CompositorBridgeParent in the UI process. If there are multiple tabs
+ // in the same window, additional tabs will simply return the already-
+ // established compositor.
+ //
+ // Finally, this step serves one other crucial function: tabs must be
+ // associated with a window compositor or else they can't forward
+ // layer transactions. So this step both ensures that a compositor
+ // exists, and that the tab can forward layers.
+ //
+ // (8) Last, if the window had no remote tabs, step (7) will not have
+ // applied, and the window will not have a new compositor just yet.
+ // The next refresh tick and paint will ensure that one exists, again
+ // via nsIWidget::GetLayerManager.
+
+ // Build a list of sessions to notify, since notification might delete
+ // entries from the list.
+ nsTArray<RefPtr<RemoteCompositorSession>> sessions;
+ for (auto& session : mRemoteSessions) {
+ sessions.AppendElement(session);
+ }
+
+ // Notify each widget that we have lost the GPU process. This will ensure
+ // that each widget destroys its layer manager and CompositorBridgeChild.
+ for (const auto& session : sessions) {
+ session->NotifySessionLost();
+ }
+
+ // Notify content. This will ensure that each content process re-establishes
+ // a connection to the compositor thread (whether it's in-process or in a
+ // newly launched GPU process).
+ for (const auto& listener : mListeners) {
+ listener->OnCompositorUnexpectedShutdown();
+ }
+}
+
+void
+GPUProcessManager::NotifyRemoteActorDestroyed(const uint64_t& aProcessToken)
+{
+ if (!NS_IsMainThread()) {
+ RefPtr<Runnable> task = mTaskFactory.NewRunnableMethod(
+ &GPUProcessManager::NotifyRemoteActorDestroyed, aProcessToken);
+ NS_DispatchToMainThread(task.forget());
+ return;
+ }
+
+ if (mProcessToken != aProcessToken) {
+ // This token is for an older process; we can safely ignore it.
+ return;
+ }
+
+ // One of the bridged top-level actors for the GPU process has been
+ // prematurely terminated, and we're receiving a notification. This
+ // can happen if the ActorDestroy for a bridged protocol fires
+ // before the ActorDestroy for PGPUChild.
+ OnProcessUnexpectedShutdown(mProcess);
+}
+
+void
+GPUProcessManager::CleanShutdown()
+{
+ DestroyProcess();
+ mVsyncIOThread = nullptr;
+}
+
+void
+GPUProcessManager::KillProcess()
+{
+ if (!mProcess) {
+ return;
+ }
+
+ mProcess->KillProcess();
+}
+
+void
+GPUProcessManager::DestroyProcess()
+{
+ if (!mProcess) {
+ return;
+ }
+
+ mProcess->Shutdown();
+ mProcessToken = 0;
+ mProcess = nullptr;
+ mGPUChild = nullptr;
+ if (mVsyncBridge) {
+ mVsyncBridge->Close();
+ mVsyncBridge = nullptr;
+ }
+}
+
+RefPtr<CompositorSession>
+GPUProcessManager::CreateTopLevelCompositor(nsBaseWidget* aWidget,
+ LayerManager* aLayerManager,
+ CSSToLayoutDeviceScale aScale,
+ bool aUseAPZ,
+ bool aUseExternalSurfaceSize,
+ const gfx::IntSize& aSurfaceSize)
+{
+ uint64_t layerTreeId = AllocateLayerTreeId();
+
+ EnsureGPUReady();
+ EnsureImageBridgeChild();
+ EnsureVRManager();
+
+ 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,
+ layerTreeId,
+ aScale,
+ aUseAPZ,
+ aUseExternalSurfaceSize,
+ aSurfaceSize);
+}
+
+RefPtr<CompositorSession>
+GPUProcessManager::CreateRemoteSession(nsBaseWidget* aWidget,
+ LayerManager* 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);
+
+ TimeDuration vsyncRate =
+ gfxPlatform::GetPlatform()->GetHardwareVsync()->GetGlobalDisplay().GetVsyncRate();
+
+ bool ok = mGPUChild->SendNewWidgetCompositor(
+ Move(parentPipe),
+ aScale,
+ vsyncRate,
+ aUseExternalSurfaceSize,
+ aSurfaceSize);
+ if (!ok) {
+ return nullptr;
+ }
+
+ RefPtr<CompositorVsyncDispatcher> dispatcher = aWidget->GetCompositorVsyncDispatcher();
+ RefPtr<CompositorWidgetVsyncObserver> observer =
+ new CompositorWidgetVsyncObserver(mVsyncBridge, aRootLayerTreeId);
+
+ CompositorWidgetChild* widget = new CompositorWidgetChild(dispatcher, observer);
+ if (!child->SendPCompositorWidgetConstructor(widget, initData)) {
+ return nullptr;
+ }
+ if (!child->SendInitialize(aRootLayerTreeId)) {
+ return nullptr;
+ }
+
+ RefPtr<APZCTreeManagerChild> apz = nullptr;
+ if (aUseAPZ) {
+ PAPZCTreeManagerChild* papz = child->SendPAPZCTreeManagerConstructor(0);
+ if (!papz) {
+ return nullptr;
+ }
+ apz = static_cast<APZCTreeManagerChild*>(papz);
+ }
+
+ RefPtr<RemoteCompositorSession> session =
+ new RemoteCompositorSession(aWidget, child, widget, apz, aRootLayerTreeId);
+ return session.forget();
+#else
+ gfxCriticalNote << "Platform does not support out-of-process compositing";
+ return nullptr;
+#endif
+}
+
+bool
+GPUProcessManager::CreateContentBridges(base::ProcessId aOtherProcess,
+ ipc::Endpoint<PCompositorBridgeChild>* aOutCompositor,
+ ipc::Endpoint<PImageBridgeChild>* aOutImageBridge,
+ ipc::Endpoint<PVRManagerChild>* aOutVRBridge,
+ ipc::Endpoint<dom::PVideoDecoderManagerChild>* aOutVideoManager)
+{
+ if (!CreateContentCompositorBridge(aOtherProcess, aOutCompositor) ||
+ !CreateContentImageBridge(aOtherProcess, aOutImageBridge) ||
+ !CreateContentVRManager(aOtherProcess, aOutVRBridge))
+ {
+ return false;
+ }
+ // VideoDeocderManager is only supported in the GPU process, so we allow this to be
+ // fallible.
+ CreateContentVideoDecoderManager(aOtherProcess, aOutVideoManager);
+ return true;
+}
+
+bool
+GPUProcessManager::CreateContentCompositorBridge(base::ProcessId aOtherProcess,
+ ipc::Endpoint<PCompositorBridgeChild>* aOutEndpoint)
+{
+ EnsureGPUReady();
+
+ ipc::Endpoint<PCompositorBridgeParent> parentPipe;
+ ipc::Endpoint<PCompositorBridgeChild> childPipe;
+
+ base::ProcessId gpuPid = mGPUChild
+ ? mGPUChild->OtherPid()
+ : base::GetCurrentProcId();
+
+ nsresult rv = PCompositorBridge::CreateEndpoints(
+ gpuPid,
+ aOtherProcess,
+ &parentPipe,
+ &childPipe);
+ if (NS_FAILED(rv)) {
+ gfxCriticalNote << "Could not create content compositor bridge: " << hexa(int(rv));
+ return false;
+ }
+
+ if (mGPUChild) {
+ mGPUChild->SendNewContentCompositorBridge(Move(parentPipe));
+ } else {
+ if (!CompositorBridgeParent::CreateForContent(Move(parentPipe))) {
+ return false;
+ }
+ }
+
+ *aOutEndpoint = Move(childPipe);
+ return true;
+}
+
+bool
+GPUProcessManager::CreateContentImageBridge(base::ProcessId aOtherProcess,
+ ipc::Endpoint<PImageBridgeChild>* aOutEndpoint)
+{
+ EnsureImageBridgeChild();
+
+ base::ProcessId gpuPid = mGPUChild
+ ? mGPUChild->OtherPid()
+ : base::GetCurrentProcId();
+
+ ipc::Endpoint<PImageBridgeParent> parentPipe;
+ ipc::Endpoint<PImageBridgeChild> childPipe;
+ nsresult rv = PImageBridge::CreateEndpoints(
+ gpuPid,
+ aOtherProcess,
+ &parentPipe,
+ &childPipe);
+ if (NS_FAILED(rv)) {
+ gfxCriticalNote << "Could not create content compositor bridge: " << hexa(int(rv));
+ return false;
+ }
+
+ if (mGPUChild) {
+ mGPUChild->SendNewContentImageBridge(Move(parentPipe));
+ } else {
+ if (!ImageBridgeParent::CreateForContent(Move(parentPipe))) {
+ return false;
+ }
+ }
+
+ *aOutEndpoint = Move(childPipe);
+ return true;
+}
+
+base::ProcessId
+GPUProcessManager::GPUProcessPid()
+{
+ base::ProcessId gpuPid = mGPUChild
+ ? mGPUChild->OtherPid()
+ : -1;
+ return gpuPid;
+}
+
+bool
+GPUProcessManager::CreateContentVRManager(base::ProcessId aOtherProcess,
+ ipc::Endpoint<PVRManagerChild>* aOutEndpoint)
+{
+ EnsureVRManager();
+
+ base::ProcessId gpuPid = mGPUChild
+ ? mGPUChild->OtherPid()
+ : base::GetCurrentProcId();
+
+ ipc::Endpoint<PVRManagerParent> parentPipe;
+ ipc::Endpoint<PVRManagerChild> childPipe;
+ nsresult rv = PVRManager::CreateEndpoints(
+ gpuPid,
+ aOtherProcess,
+ &parentPipe,
+ &childPipe);
+ if (NS_FAILED(rv)) {
+ gfxCriticalNote << "Could not create content compositor bridge: " << hexa(int(rv));
+ return false;
+ }
+
+ if (mGPUChild) {
+ mGPUChild->SendNewContentVRManager(Move(parentPipe));
+ } else {
+ if (!VRManagerParent::CreateForContent(Move(parentPipe))) {
+ return false;
+ }
+ }
+
+ *aOutEndpoint = Move(childPipe);
+ return true;
+}
+
+void
+GPUProcessManager::CreateContentVideoDecoderManager(base::ProcessId aOtherProcess,
+ ipc::Endpoint<dom::PVideoDecoderManagerChild>* aOutEndpoint)
+{
+ if (!mGPUChild || !MediaPrefs::PDMUseGPUDecoder()) {
+ return;
+ }
+
+ ipc::Endpoint<dom::PVideoDecoderManagerParent> parentPipe;
+ ipc::Endpoint<dom::PVideoDecoderManagerChild> childPipe;
+
+ nsresult rv = dom::PVideoDecoderManager::CreateEndpoints(
+ mGPUChild->OtherPid(),
+ aOtherProcess,
+ &parentPipe,
+ &childPipe);
+ if (NS_FAILED(rv)) {
+ gfxCriticalNote << "Could not create content video decoder: " << hexa(int(rv));
+ return;
+ }
+
+ mGPUChild->SendNewContentVideoDecoderManager(Move(parentPipe));
+
+ *aOutEndpoint = Move(childPipe);
+ return;
+}
+
+already_AddRefed<IAPZCTreeManager>
+GPUProcessManager::GetAPZCTreeManagerForLayers(uint64_t aLayersId)
+{
+ return CompositorBridgeParent::GetAPZCTreeManager(aLayersId);
+}
+
+void
+GPUProcessManager::MapLayerTreeId(uint64_t aLayersId, base::ProcessId aOwningId)
+{
+ LayerTreeOwnerTracker::Get()->Map(aLayersId, aOwningId);
+
+ if (mGPUChild) {
+ AutoTArray<LayerTreeIdMapping, 1> mappings;
+ mappings.AppendElement(LayerTreeIdMapping(aLayersId, aOwningId));
+ mGPUChild->SendAddLayerTreeIdMapping(mappings);
+ }
+}
+
+void
+GPUProcessManager::UnmapLayerTreeId(uint64_t aLayersId, base::ProcessId aOwningId)
+{
+ LayerTreeOwnerTracker::Get()->Unmap(aLayersId, aOwningId);
+
+ if (mGPUChild) {
+ mGPUChild->SendRemoveLayerTreeIdMapping(LayerTreeIdMapping(aLayersId, aOwningId));
+ return;
+ }
+ CompositorBridgeParent::DeallocateLayerTreeId(aLayersId);
+}
+
+bool
+GPUProcessManager::IsLayerTreeIdMapped(uint64_t aLayersId, base::ProcessId aRequestingId)
+{
+ return LayerTreeOwnerTracker::Get()->IsMapped(aLayersId, aRequestingId);
+}
+
+uint64_t
+GPUProcessManager::AllocateLayerTreeId()
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ return ++mNextLayerTreeId;
+}
+
+void
+GPUProcessManager::EnsureVsyncIOThread()
+{
+ if (mVsyncIOThread) {
+ return;
+ }
+
+ mVsyncIOThread = new VsyncIOThreadHolder();
+ MOZ_RELEASE_ASSERT(mVsyncIOThread->Start());
+}
+
+void
+GPUProcessManager::ShutdownVsyncIOThread()
+{
+ mVsyncIOThread = nullptr;
+}
+
+void
+GPUProcessManager::RegisterSession(RemoteCompositorSession* aSession)
+{
+ mRemoteSessions.AppendElement(aSession);
+}
+
+void
+GPUProcessManager::UnregisterSession(RemoteCompositorSession* aSession)
+{
+ mRemoteSessions.RemoveElement(aSession);
+}
+
+void
+GPUProcessManager::AddListener(GPUProcessListener* aListener)
+{
+ mListeners.AppendElement(aListener);
+}
+
+void
+GPUProcessManager::RemoveListener(GPUProcessListener* aListener)
+{
+ mListeners.RemoveElement(aListener);
+}
+
+bool
+GPUProcessManager::NotifyGpuObservers(const char* aTopic)
+{
+ if (!mGPUChild) {
+ return false;
+ }
+ nsCString topic(aTopic);
+ mGPUChild->SendNotifyGpuObservers(topic);
+ return true;
+}
+
+} // namespace gfx
+} // namespace mozilla
diff --git a/gfx/ipc/GPUProcessManager.h b/gfx/ipc/GPUProcessManager.h
new file mode 100644
index 0000000000..84ed03609e
--- /dev/null
+++ b/gfx/ipc/GPUProcessManager.h
@@ -0,0 +1,234 @@
+/* -*- 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_GPUProcessManager_h_
+#define _include_mozilla_gfx_ipc_GPUProcessManager_h_
+
+#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"
+#include "mozilla/ipc/ProtocolUtils.h"
+#include "mozilla/ipc/TaskFactory.h"
+#include "mozilla/ipc/Transport.h"
+#include "nsIObserverService.h"
+#include "nsThreadUtils.h"
+class nsBaseWidget;
+
+
+namespace mozilla {
+namespace layers {
+class IAPZCTreeManager;
+class CompositorSession;
+class CompositorUpdateObserver;
+class PCompositorBridgeChild;
+class PImageBridgeChild;
+class RemoteCompositorSession;
+} // namespace layers
+namespace widget {
+class CompositorWidget;
+} // namespace widget
+namespace dom {
+class ContentParent;
+class TabParent;
+class PVideoDecoderManagerChild;
+} // namespace dom
+namespace ipc {
+class GeckoChildProcessHost;
+} // namespace ipc
+namespace gfx {
+
+class GPUChild;
+class GPUProcessListener;
+class PVRManagerChild;
+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
+// to the compositor via CompositorBridgeParent.
+class GPUProcessManager final : public GPUProcessHost::Listener
+{
+ friend class layers::RemoteCompositorSession;
+
+ typedef layers::CompositorSession CompositorSession;
+ typedef layers::CompositorUpdateObserver CompositorUpdateObserver;
+ typedef layers::IAPZCTreeManager IAPZCTreeManager;
+ typedef layers::LayerManager LayerManager;
+ typedef layers::PCompositorBridgeChild PCompositorBridgeChild;
+ typedef layers::PImageBridgeChild PImageBridgeChild;
+ typedef layers::RemoteCompositorSession RemoteCompositorSession;
+
+public:
+ static void Initialize();
+ static void Shutdown();
+ static GPUProcessManager* Get();
+
+ ~GPUProcessManager();
+
+ // If not using a GPU process, launch a new GPU process asynchronously.
+ void LaunchGPUProcess();
+
+ // Ensure that GPU-bound methods can be used. If no GPU process is being
+ // used, or one is launched and ready, this function returns immediately.
+ // Otherwise it blocks until the GPU process has finished launching.
+ void EnsureGPUReady();
+
+ RefPtr<CompositorSession> CreateTopLevelCompositor(
+ nsBaseWidget* aWidget,
+ LayerManager* aLayerManager,
+ CSSToLayoutDeviceScale aScale,
+ bool aUseAPZ,
+ bool aUseExternalSurfaceSize,
+ const gfx::IntSize& aSurfaceSize);
+
+ bool CreateContentBridges(
+ base::ProcessId aOtherProcess,
+ ipc::Endpoint<PCompositorBridgeChild>* aOutCompositor,
+ ipc::Endpoint<PImageBridgeChild>* aOutImageBridge,
+ ipc::Endpoint<PVRManagerChild>* aOutVRBridge,
+ ipc::Endpoint<dom::PVideoDecoderManagerChild>* aOutVideoManager);
+
+ // This returns a reference to the APZCTreeManager to which
+ // pan/zoom-related events can be sent.
+ already_AddRefed<IAPZCTreeManager> GetAPZCTreeManagerForLayers(uint64_t aLayersId);
+
+ // Maps the layer tree and process together so that aOwningPID is allowed
+ // to access aLayersId across process.
+ void MapLayerTreeId(uint64_t aLayersId, base::ProcessId aOwningId);
+
+ // Release compositor-thread resources referred to by |aID|.
+ //
+ // Must run on the content main thread.
+ void UnmapLayerTreeId(uint64_t aLayersId, base::ProcessId aOwningId);
+
+ // Checks to see if aLayersId and aRequestingPID have been mapped by MapLayerTreeId
+ bool IsLayerTreeIdMapped(uint64_t aLayersId, base::ProcessId aRequestingId);
+
+ // Allocate an ID that can be used to refer to a layer tree and
+ // associated resources that live only on the compositor thread.
+ //
+ // Must run on the content main thread.
+ uint64_t AllocateLayerTreeId();
+
+
+ void OnProcessLaunchComplete(GPUProcessHost* aHost) override;
+ void OnProcessUnexpectedShutdown(GPUProcessHost* aHost) override;
+ void OnProcessDeviceReset(GPUProcessHost* aHost) override;
+
+ // Notify the GPUProcessManager that a top-level PGPU protocol has been
+ // terminated. This may be called from any thread.
+ void NotifyRemoteActorDestroyed(const uint64_t& aProcessToken);
+
+ void AddListener(GPUProcessListener* aListener);
+ void RemoveListener(GPUProcessListener* aListener);
+
+ // Send a message to the GPU process observer service to broadcast. Returns
+ // true if the message was sent, false if not.
+ bool NotifyGpuObservers(const char* aTopic);
+
+ // Used for tests and diagnostics
+ void KillProcess();
+
+ // Returns -1 if there is no GPU process, or the platform pid for it.
+ base::ProcessId GPUProcessPid();
+
+ // Returns access to the PGPU protocol if a GPU process is present.
+ GPUChild* GetGPUChild() {
+ return mGPUChild;
+ }
+
+ // Returns whether or not a GPU process was ever launched.
+ bool AttemptedGPUProcess() const {
+ return mNumProcessAttempts > 0;
+ }
+
+private:
+ // Called from our xpcom-shutdown observer.
+ void OnXPCOMShutdown();
+
+ bool CreateContentCompositorBridge(base::ProcessId aOtherProcess,
+ ipc::Endpoint<PCompositorBridgeChild>* aOutEndpoint);
+ bool CreateContentImageBridge(base::ProcessId aOtherProcess,
+ ipc::Endpoint<PImageBridgeChild>* aOutEndpoint);
+ bool CreateContentVRManager(base::ProcessId aOtherProcess,
+ ipc::Endpoint<PVRManagerChild>* aOutEndpoint);
+ void CreateContentVideoDecoderManager(base::ProcessId aOtherProcess,
+ ipc::Endpoint<dom::PVideoDecoderManagerChild>* aOutEndPoint);
+
+ // Called from RemoteCompositorSession. We track remote sessions so we can
+ // notify their owning widgets that the session must be restarted.
+ void RegisterSession(RemoteCompositorSession* aSession);
+ void UnregisterSession(RemoteCompositorSession* aSession);
+
+private:
+ GPUProcessManager();
+
+ // Permanently disable the GPU process and record a message why.
+ void DisableGPUProcess(const char* aMessage);
+
+ // Shutdown the GPU process.
+ void CleanShutdown();
+ void DestroyProcess();
+
+ void HandleProcessLost();
+
+ void EnsureVsyncIOThread();
+ void ShutdownVsyncIOThread();
+
+ void EnsureImageBridgeChild();
+ void EnsureVRManager();
+
+ RefPtr<CompositorSession> CreateRemoteSession(
+ nsBaseWidget* aWidget,
+ LayerManager* 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 {
+ public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIOBSERVER
+ explicit Observer(GPUProcessManager* aManager);
+
+ protected:
+ ~Observer() {}
+
+ GPUProcessManager* mManager;
+ };
+ friend class Observer;
+
+private:
+ RefPtr<Observer> mObserver;
+ ipc::TaskFactory<GPUProcessManager> mTaskFactory;
+ RefPtr<VsyncIOThreadHolder> mVsyncIOThread;
+ uint64_t mNextLayerTreeId;
+ uint32_t mNumProcessAttempts;
+
+ nsTArray<RefPtr<RemoteCompositorSession>> mRemoteSessions;
+ nsTArray<GPUProcessListener*> mListeners;
+
+ uint32_t mDeviceResetCount;
+ TimeStamp mDeviceResetLastTime;
+
+ // Fields that are associated with the current GPU process.
+ GPUProcessHost* mProcess;
+ MOZ_INIT_OUTSIDE_CTOR uint64_t mProcessToken;
+ GPUChild* mGPUChild;
+ RefPtr<VsyncBridgeChild> mVsyncBridge;
+};
+
+} // namespace gfx
+} // namespace mozilla
+
+#endif // _include_mozilla_gfx_ipc_GPUProcessManager_h_
diff --git a/gfx/ipc/GfxMessageUtils.h b/gfx/ipc/GfxMessageUtils.h
new file mode 100644
index 0000000000..e45aa7040c
--- /dev/null
+++ b/gfx/ipc/GfxMessageUtils.h
@@ -0,0 +1,1273 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=8 et 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 __GFXMESSAGEUTILS_H__
+#define __GFXMESSAGEUTILS_H__
+
+#include "FilterSupport.h"
+#include "FrameMetrics.h"
+#include "ImageTypes.h"
+#include "RegionBuilder.h"
+#include "base/process_util.h"
+#include "chrome/common/ipc_message_utils.h"
+#include "gfxPoint.h"
+#include "gfxRect.h"
+#include "gfxTelemetry.h"
+#include "gfxTypes.h"
+#include "ipc/IPCMessageUtils.h"
+#include "mozilla/gfx/Matrix.h"
+#include "mozilla/layers/AsyncDragMetrics.h"
+#include "mozilla/layers/CompositorTypes.h"
+#include "mozilla/layers/GeckoContentController.h"
+#include "mozilla/layers/LayersTypes.h"
+#include "nsRect.h"
+#include "nsRegion.h"
+
+#include <stdint.h>
+
+#ifdef _MSC_VER
+#pragma warning( disable : 4800 )
+#endif
+
+namespace mozilla {
+
+typedef gfxImageFormat PixelFormat;
+
+} // namespace mozilla
+
+namespace IPC {
+
+template<>
+struct ParamTraits<mozilla::gfx::Matrix>
+{
+ typedef mozilla::gfx::Matrix paramType;
+
+ static void Write(Message* aMsg, const paramType& aParam)
+ {
+ WriteParam(aMsg, aParam._11);
+ WriteParam(aMsg, aParam._12);
+ WriteParam(aMsg, aParam._21);
+ WriteParam(aMsg, aParam._22);
+ WriteParam(aMsg, aParam._31);
+ WriteParam(aMsg, aParam._32);
+ }
+
+ static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
+ {
+ if (ReadParam(aMsg, aIter, &aResult->_11) &&
+ ReadParam(aMsg, aIter, &aResult->_12) &&
+ ReadParam(aMsg, aIter, &aResult->_21) &&
+ ReadParam(aMsg, aIter, &aResult->_22) &&
+ ReadParam(aMsg, aIter, &aResult->_31) &&
+ ReadParam(aMsg, aIter, &aResult->_32))
+ return true;
+
+ return false;
+ }
+
+ static void Log(const paramType& aParam, std::wstring* aLog)
+ {
+ aLog->append(StringPrintf(L"[[%g %g] [%g %g] [%g %g]]", aParam._11, aParam._12, aParam._21, aParam._22,
+ aParam._31, aParam._32));
+ }
+};
+
+template<>
+struct ParamTraits<mozilla::gfx::Matrix4x4>
+{
+ typedef mozilla::gfx::Matrix4x4 paramType;
+
+ static void Write(Message* msg, const paramType& param)
+ {
+#define Wr(_f) WriteParam(msg, param. _f)
+ Wr(_11); Wr(_12); Wr(_13); Wr(_14);
+ Wr(_21); Wr(_22); Wr(_23); Wr(_24);
+ Wr(_31); Wr(_32); Wr(_33); Wr(_34);
+ Wr(_41); Wr(_42); Wr(_43); Wr(_44);
+#undef Wr
+ }
+
+ static bool Read(const Message* msg, PickleIterator* iter, paramType* result)
+ {
+#define Rd(_f) ReadParam(msg, iter, &result-> _f)
+ return (Rd(_11) && Rd(_12) && Rd(_13) && Rd(_14) &&
+ Rd(_21) && Rd(_22) && Rd(_23) && Rd(_24) &&
+ Rd(_31) && Rd(_32) && Rd(_33) && Rd(_34) &&
+ Rd(_41) && Rd(_42) && Rd(_43) && Rd(_44));
+#undef Rd
+ }
+};
+
+template<>
+struct ParamTraits<mozilla::gfx::Matrix5x4>
+{
+ typedef mozilla::gfx::Matrix5x4 paramType;
+
+ static void Write(Message* msg, const paramType& param)
+ {
+#define Wr(_f) WriteParam(msg, param. _f)
+ Wr(_11); Wr(_12); Wr(_13); Wr(_14);
+ Wr(_21); Wr(_22); Wr(_23); Wr(_24);
+ Wr(_31); Wr(_32); Wr(_33); Wr(_34);
+ Wr(_41); Wr(_42); Wr(_43); Wr(_44);
+ Wr(_51); Wr(_52); Wr(_53); Wr(_54);
+#undef Wr
+ }
+
+ static bool Read(const Message* msg, PickleIterator* iter, paramType* result)
+ {
+#define Rd(_f) ReadParam(msg, iter, &result-> _f)
+ return (Rd(_11) && Rd(_12) && Rd(_13) && Rd(_14) &&
+ Rd(_21) && Rd(_22) && Rd(_23) && Rd(_24) &&
+ Rd(_31) && Rd(_32) && Rd(_33) && Rd(_34) &&
+ Rd(_41) && Rd(_42) && Rd(_43) && Rd(_44) &&
+ Rd(_51) && Rd(_52) && Rd(_53) && Rd(_54));
+#undef Rd
+ }
+};
+
+template<>
+struct ParamTraits<gfxPoint>
+{
+ typedef gfxPoint paramType;
+
+ static void Write(Message* aMsg, const paramType& aParam)
+ {
+ WriteParam(aMsg, aParam.x);
+ WriteParam(aMsg, aParam.y);
+ }
+
+ static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
+ {
+ return (ReadParam(aMsg, aIter, &aResult->x) &&
+ ReadParam(aMsg, aIter, &aResult->y));
+ }
+};
+
+template<>
+struct ParamTraits<gfxSize>
+{
+ typedef gfxSize paramType;
+
+ static void Write(Message* aMsg, const paramType& aParam)
+ {
+ WriteParam(aMsg, aParam.width);
+ WriteParam(aMsg, aParam.height);
+ }
+
+ static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
+ {
+ if (ReadParam(aMsg, aIter, &aResult->width) &&
+ ReadParam(aMsg, aIter, &aResult->height))
+ return true;
+
+ return false;
+ }
+};
+
+template<>
+struct ParamTraits<gfxRect>
+{
+ typedef gfxRect paramType;
+
+ static void Write(Message* aMsg, const paramType& aParam)
+ {
+ WriteParam(aMsg, aParam.x);
+ WriteParam(aMsg, aParam.y);
+ WriteParam(aMsg, aParam.width);
+ WriteParam(aMsg, aParam.height);
+ }
+
+ static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
+ {
+ return ReadParam(aMsg, aIter, &aResult->x) &&
+ ReadParam(aMsg, aIter, &aResult->y) &&
+ ReadParam(aMsg, aIter, &aResult->width) &&
+ ReadParam(aMsg, aIter, &aResult->height);
+ }
+};
+
+template <>
+struct ParamTraits<gfxContentType>
+ : public ContiguousEnumSerializer<
+ gfxContentType,
+ gfxContentType::COLOR,
+ gfxContentType::SENTINEL>
+{};
+
+template <>
+struct ParamTraits<gfxSurfaceType>
+ : public ContiguousEnumSerializer<
+ gfxSurfaceType,
+ gfxSurfaceType::Image,
+ gfxSurfaceType::Max>
+{};
+
+template <>
+struct ParamTraits<mozilla::gfx::SamplingFilter>
+ : public ContiguousEnumSerializer<
+ mozilla::gfx::SamplingFilter,
+ mozilla::gfx::SamplingFilter::GOOD,
+ mozilla::gfx::SamplingFilter::SENTINEL>
+{};
+
+template <>
+struct ParamTraits<mozilla::layers::LayersBackend>
+ : public ContiguousEnumSerializer<
+ mozilla::layers::LayersBackend,
+ mozilla::layers::LayersBackend::LAYERS_NONE,
+ mozilla::layers::LayersBackend::LAYERS_LAST>
+{};
+
+template <>
+struct ParamTraits<mozilla::gfx::BackendType>
+ : public ContiguousEnumSerializer<
+ mozilla::gfx::BackendType,
+ mozilla::gfx::BackendType::NONE,
+ mozilla::gfx::BackendType::BACKEND_LAST>
+{};
+
+template <>
+struct ParamTraits<mozilla::gfx::FeatureStatus>
+ : public ContiguousEnumSerializer<
+ mozilla::gfx::FeatureStatus,
+ mozilla::gfx::FeatureStatus::Unused,
+ mozilla::gfx::FeatureStatus::LAST>
+{};
+
+template <>
+struct ParamTraits<mozilla::layers::ScaleMode>
+ : public ContiguousEnumSerializer<
+ mozilla::layers::ScaleMode,
+ mozilla::layers::ScaleMode::SCALE_NONE,
+ mozilla::layers::ScaleMode::SENTINEL>
+{};
+
+template <>
+struct ParamTraits<mozilla::gfx::AttributeName>
+ : public ContiguousEnumSerializer<
+ mozilla::gfx::AttributeName,
+ mozilla::gfx::eBlendBlendmode,
+ mozilla::gfx::eLastAttributeName>
+{};
+
+template <>
+struct ParamTraits<mozilla::gfx::AttributeType>
+ : public ContiguousEnumSerializer<
+ mozilla::gfx::AttributeType,
+ mozilla::gfx::AttributeType::eBool,
+ mozilla::gfx::AttributeType::Max>
+{};
+
+template <>
+struct ParamTraits<mozilla::gfx::PrimitiveType>
+ : public ContiguousEnumSerializer<
+ mozilla::gfx::PrimitiveType,
+ mozilla::gfx::PrimitiveType::Empty,
+ mozilla::gfx::PrimitiveType::Max>
+{};
+
+template <>
+struct ParamTraits<mozilla::gfx::ColorSpace>
+ : public ContiguousEnumSerializer<
+ mozilla::gfx::ColorSpace,
+ mozilla::gfx::ColorSpace::SRGB,
+ mozilla::gfx::ColorSpace::Max>
+{};
+
+template <>
+struct ParamTraits<mozilla::layers::TextureFlags>
+ : public BitFlagsEnumSerializer<
+ mozilla::layers::TextureFlags,
+ mozilla::layers::TextureFlags::ALL_BITS>
+{};
+
+template <>
+struct ParamTraits<mozilla::layers::DiagnosticTypes>
+ : public BitFlagsEnumSerializer<
+ mozilla::layers::DiagnosticTypes,
+ mozilla::layers::DiagnosticTypes::ALL_BITS>
+{};
+
+/*
+template <>
+struct ParamTraits<mozilla::PixelFormat>
+ : public EnumSerializer<mozilla::PixelFormat,
+ SurfaceFormat::A8R8G8B8_UINT32,
+ SurfaceFormat::UNKNOWN>
+{};
+*/
+
+template<>
+struct ParamTraits<mozilla::gfx::Color>
+{
+ typedef mozilla::gfx::Color paramType;
+
+ static void Write(Message* msg, const paramType& param)
+ {
+ WriteParam(msg, param.r);
+ WriteParam(msg, param.g);
+ WriteParam(msg, param.b);
+ WriteParam(msg, param.a);
+ }
+
+ static bool Read(const Message* msg, PickleIterator* iter, paramType* result)
+ {
+ return (ReadParam(msg, iter, &result->r) &&
+ ReadParam(msg, iter, &result->g) &&
+ ReadParam(msg, iter, &result->b) &&
+ ReadParam(msg, iter, &result->a));
+ }
+};
+
+template<>
+struct ParamTraits<nsPoint>
+{
+ typedef nsPoint paramType;
+
+ static void Write(Message* msg, const paramType& param)
+ {
+ WriteParam(msg, param.x);
+ WriteParam(msg, param.y);
+ }
+
+ static bool Read(const Message* msg, PickleIterator* iter, paramType* result)
+ {
+ return (ReadParam(msg, iter, &result->x) &&
+ ReadParam(msg, iter, &result->y));
+ }
+};
+
+template<>
+struct ParamTraits<nsIntPoint>
+{
+ typedef nsIntPoint paramType;
+
+ static void Write(Message* msg, const paramType& param)
+ {
+ WriteParam(msg, param.x);
+ WriteParam(msg, param.y);
+ }
+
+ static bool Read(const Message* msg, PickleIterator* iter, paramType* result)
+ {
+ return (ReadParam(msg, iter, &result->x) &&
+ ReadParam(msg, iter, &result->y));
+ }
+};
+
+template<typename T>
+struct ParamTraits<mozilla::gfx::IntSizeTyped<T> >
+{
+ typedef mozilla::gfx::IntSizeTyped<T> paramType;
+
+ static void Write(Message* msg, const paramType& param)
+ {
+ WriteParam(msg, param.width);
+ WriteParam(msg, param.height);
+ }
+
+ static bool Read(const Message* msg, PickleIterator* iter, paramType* result)
+ {
+ return (ReadParam(msg, iter, &result->width) &&
+ ReadParam(msg, iter, &result->height));
+ }
+};
+
+template<typename Region, typename Rect, typename Iter>
+struct RegionParamTraits
+{
+ typedef Region paramType;
+
+ static void Write(Message* msg, const paramType& param)
+ {
+
+ for (auto iter = param.RectIter(); !iter.Done(); iter.Next()) {
+ const Rect& r = iter.Get();
+ MOZ_RELEASE_ASSERT(!r.IsEmpty(), "GFX: rect is empty.");
+ WriteParam(msg, r);
+ }
+ // empty rects are sentinel values because nsRegions will never
+ // contain them
+ WriteParam(msg, Rect());
+ }
+
+ static bool Read(const Message* msg, PickleIterator* iter, paramType* result)
+ {
+ RegionBuilder<Region> builder;
+ Rect rect;
+ while (ReadParam(msg, iter, &rect)) {
+ if (rect.IsEmpty()) {
+ *result = builder.ToRegion();
+ return true;
+ }
+ builder.OrWith(rect);
+ }
+
+ return false;
+ }
+};
+
+template<class Units>
+struct ParamTraits<mozilla::gfx::IntRegionTyped<Units>>
+ : RegionParamTraits<mozilla::gfx::IntRegionTyped<Units>,
+ mozilla::gfx::IntRectTyped<Units>,
+ typename mozilla::gfx::IntRegionTyped<Units>::RectIterator>
+{};
+
+template<>
+struct ParamTraits<mozilla::gfx::IntSize>
+{
+ typedef mozilla::gfx::IntSize paramType;
+
+ static void Write(Message* msg, const paramType& param)
+ {
+ WriteParam(msg, param.width);
+ WriteParam(msg, param.height);
+ }
+
+ static bool Read(const Message* msg, PickleIterator* iter, paramType* result)
+ {
+ return (ReadParam(msg, iter, &result->width) &&
+ ReadParam(msg, iter, &result->height));
+ }
+};
+
+template<class T>
+struct ParamTraits< mozilla::gfx::CoordTyped<T> >
+{
+ typedef mozilla::gfx::CoordTyped<T> paramType;
+
+ static void Write(Message* msg, const paramType& param)
+ {
+ WriteParam(msg, param.value);
+ }
+
+ static bool Read(const Message* msg, PickleIterator* iter, paramType* result)
+ {
+ return (ReadParam(msg, iter, &result->value));
+ }
+};
+
+template<class T>
+struct ParamTraits< mozilla::gfx::IntCoordTyped<T> >
+{
+ typedef mozilla::gfx::IntCoordTyped<T> paramType;
+
+ static void Write(Message* msg, const paramType& param)
+ {
+ WriteParam(msg, param.value);
+ }
+
+ static bool Read(const Message* msg, PickleIterator* iter, paramType* result)
+ {
+ return (ReadParam(msg, iter, &result->value));
+ }
+};
+
+template<class T, class U>
+struct ParamTraits< mozilla::gfx::ScaleFactor<T, U> >
+{
+ typedef mozilla::gfx::ScaleFactor<T, U> paramType;
+
+ static void Write(Message* msg, const paramType& param)
+ {
+ WriteParam(msg, param.scale);
+ }
+
+ static bool Read(const Message* msg, PickleIterator* iter, paramType* result)
+ {
+ return (ReadParam(msg, iter, &result->scale));
+ }
+};
+
+template<class T, class U>
+struct ParamTraits< mozilla::gfx::ScaleFactors2D<T, U> >
+{
+ typedef mozilla::gfx::ScaleFactors2D<T, U> paramType;
+
+ static void Write(Message* msg, const paramType& param)
+ {
+ WriteParam(msg, param.xScale);
+ WriteParam(msg, param.yScale);
+ }
+
+ static bool Read(const Message* msg, PickleIterator* iter, paramType* result)
+ {
+ return (ReadParam(msg, iter, &result->xScale) &&
+ ReadParam(msg, iter, &result->yScale));
+ }
+};
+
+template<class T>
+struct ParamTraits< mozilla::gfx::PointTyped<T> >
+{
+ typedef mozilla::gfx::PointTyped<T> paramType;
+
+ static void Write(Message* msg, const paramType& param)
+ {
+ WriteParam(msg, param.x);
+ WriteParam(msg, param.y);
+ }
+
+ static bool Read(const Message* msg, PickleIterator* iter, paramType* result)
+ {
+ return (ReadParam(msg, iter, &result->x) &&
+ ReadParam(msg, iter, &result->y));
+ }
+};
+
+template<class F, class T>
+struct ParamTraits< mozilla::gfx::Point3DTyped<F, T> >
+{
+ typedef mozilla::gfx::Point3DTyped<F, T> paramType;
+
+ static void Write(Message* msg, const paramType& param)
+ {
+ WriteParam(msg, param.x);
+ WriteParam(msg, param.y);
+ WriteParam(msg, param.z);
+ }
+
+ static bool Read(const Message* msg, PickleIterator* iter, paramType* result)
+ {
+ return (ReadParam(msg, iter, &result->x) &&
+ ReadParam(msg, iter, &result->y) &&
+ ReadParam(msg, iter, &result->z));
+ }
+};
+
+template<class T>
+struct ParamTraits< mozilla::gfx::IntPointTyped<T> >
+{
+ typedef mozilla::gfx::IntPointTyped<T> paramType;
+
+ static void Write(Message* msg, const paramType& param)
+ {
+ WriteParam(msg, param.x);
+ WriteParam(msg, param.y);
+ }
+
+ static bool Read(const Message* msg, PickleIterator* iter, paramType* result)
+ {
+ return (ReadParam(msg, iter, &result->x) &&
+ ReadParam(msg, iter, &result->y));
+ }
+};
+
+template<class T>
+struct ParamTraits< mozilla::gfx::SizeTyped<T> >
+{
+ typedef mozilla::gfx::SizeTyped<T> paramType;
+
+ static void Write(Message* msg, const paramType& param)
+ {
+ WriteParam(msg, param.width);
+ WriteParam(msg, param.height);
+ }
+
+ static bool Read(const Message* msg, PickleIterator* iter, paramType* result)
+ {
+ return (ReadParam(msg, iter, &result->width) &&
+ ReadParam(msg, iter, &result->height));
+ }
+};
+
+template<class T>
+struct ParamTraits< mozilla::gfx::RectTyped<T> >
+{
+ typedef mozilla::gfx::RectTyped<T> paramType;
+
+ static void Write(Message* msg, const paramType& param)
+ {
+ WriteParam(msg, param.x);
+ WriteParam(msg, param.y);
+ WriteParam(msg, param.width);
+ WriteParam(msg, param.height);
+ }
+
+ static bool Read(const Message* msg, PickleIterator* iter, paramType* result)
+ {
+ return (ReadParam(msg, iter, &result->x) &&
+ ReadParam(msg, iter, &result->y) &&
+ ReadParam(msg, iter, &result->width) &&
+ ReadParam(msg, iter, &result->height));
+ }
+};
+
+template<class T>
+struct ParamTraits< mozilla::gfx::IntRectTyped<T> >
+{
+ typedef mozilla::gfx::IntRectTyped<T> paramType;
+
+ static void Write(Message* msg, const paramType& param)
+ {
+ WriteParam(msg, param.x);
+ WriteParam(msg, param.y);
+ WriteParam(msg, param.width);
+ WriteParam(msg, param.height);
+ }
+
+ static bool Read(const Message* msg, PickleIterator* iter, paramType* result)
+ {
+ return (ReadParam(msg, iter, &result->x) &&
+ ReadParam(msg, iter, &result->y) &&
+ ReadParam(msg, iter, &result->width) &&
+ ReadParam(msg, iter, &result->height));
+ }
+};
+
+template<>
+struct ParamTraits<mozilla::gfx::Margin>
+{
+ typedef mozilla::gfx::Margin paramType;
+
+ static void Write(Message* msg, const paramType& param)
+ {
+ WriteParam(msg, param.top);
+ WriteParam(msg, param.right);
+ WriteParam(msg, param.bottom);
+ WriteParam(msg, param.left);
+ }
+
+ static bool Read(const Message* msg, PickleIterator* iter, paramType* result)
+ {
+ return (ReadParam(msg, iter, &result->top) &&
+ ReadParam(msg, iter, &result->right) &&
+ ReadParam(msg, iter, &result->bottom) &&
+ ReadParam(msg, iter, &result->left));
+ }
+};
+
+template<class T>
+struct ParamTraits< mozilla::gfx::MarginTyped<T> >
+{
+ typedef mozilla::gfx::MarginTyped<T> paramType;
+
+ static void Write(Message* msg, const paramType& param)
+ {
+ WriteParam(msg, param.top);
+ WriteParam(msg, param.right);
+ WriteParam(msg, param.bottom);
+ WriteParam(msg, param.left);
+ }
+
+ static bool Read(const Message* msg, PickleIterator* iter, paramType* result)
+ {
+ return (ReadParam(msg, iter, &result->top) &&
+ ReadParam(msg, iter, &result->right) &&
+ ReadParam(msg, iter, &result->bottom) &&
+ ReadParam(msg, iter, &result->left));
+ }
+};
+
+template<>
+struct ParamTraits<nsRect>
+{
+ typedef nsRect paramType;
+
+ static void Write(Message* msg, const paramType& param)
+ {
+ WriteParam(msg, param.x);
+ WriteParam(msg, param.y);
+ WriteParam(msg, param.width);
+ WriteParam(msg, param.height);
+ }
+
+ static bool Read(const Message* msg, PickleIterator* iter, paramType* result)
+ {
+ return (ReadParam(msg, iter, &result->x) &&
+ ReadParam(msg, iter, &result->y) &&
+ ReadParam(msg, iter, &result->width) &&
+ ReadParam(msg, iter, &result->height));
+ }
+};
+
+template<>
+struct ParamTraits<nsRegion>
+ : RegionParamTraits<nsRegion, nsRect, nsRegion::RectIterator>
+{};
+
+template<>
+struct ParamTraits<mozilla::layers::FrameMetrics::ScrollOffsetUpdateType>
+ : public ContiguousEnumSerializer<
+ mozilla::layers::FrameMetrics::ScrollOffsetUpdateType,
+ mozilla::layers::FrameMetrics::ScrollOffsetUpdateType::eNone,
+ mozilla::layers::FrameMetrics::ScrollOffsetUpdateType::eSentinel>
+{};
+
+// Helper class for reading bitfields.
+// If T has bitfields members, derive ParamTraits<T> from BitfieldHelper<T>.
+template <typename ParamType>
+struct BitfieldHelper
+{
+ // We need this helper because we can't get the address of a bitfield to
+ // pass directly to ReadParam. So instead we read it into a temporary bool
+ // and set the bitfield using a setter function
+ static bool ReadBoolForBitfield(const Message* aMsg, PickleIterator* aIter,
+ ParamType* aResult, void (ParamType::*aSetter)(bool))
+ {
+ bool value;
+ if (ReadParam(aMsg, aIter, &value)) {
+ (aResult->*aSetter)(value);
+ return true;
+ }
+ return false;
+ }
+};
+
+template <>
+struct ParamTraits<mozilla::layers::FrameMetrics>
+ : BitfieldHelper<mozilla::layers::FrameMetrics>
+{
+ typedef mozilla::layers::FrameMetrics paramType;
+
+ static void Write(Message* aMsg, const paramType& aParam)
+ {
+ WriteParam(aMsg, aParam.mScrollId);
+ WriteParam(aMsg, aParam.mPresShellResolution);
+ WriteParam(aMsg, aParam.mCompositionBounds);
+ WriteParam(aMsg, aParam.mDisplayPort);
+ WriteParam(aMsg, aParam.mCriticalDisplayPort);
+ WriteParam(aMsg, aParam.mScrollableRect);
+ WriteParam(aMsg, aParam.mCumulativeResolution);
+ WriteParam(aMsg, aParam.mDevPixelsPerCSSPixel);
+ WriteParam(aMsg, aParam.mScrollOffset);
+ WriteParam(aMsg, aParam.mZoom);
+ WriteParam(aMsg, aParam.mScrollGeneration);
+ WriteParam(aMsg, aParam.mSmoothScrollOffset);
+ WriteParam(aMsg, aParam.mRootCompositionSize);
+ WriteParam(aMsg, aParam.mDisplayPortMargins);
+ WriteParam(aMsg, aParam.mPresShellId);
+ WriteParam(aMsg, aParam.mViewport);
+ WriteParam(aMsg, aParam.mExtraResolution);
+ WriteParam(aMsg, aParam.mPaintRequestTime);
+ WriteParam(aMsg, aParam.mScrollUpdateType);
+ WriteParam(aMsg, aParam.mIsRootContent);
+ WriteParam(aMsg, aParam.mDoSmoothScroll);
+ WriteParam(aMsg, aParam.mUseDisplayPortMargins);
+ WriteParam(aMsg, aParam.mIsScrollInfoLayer);
+ }
+
+ static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
+ {
+ return (ReadParam(aMsg, aIter, &aResult->mScrollId) &&
+ ReadParam(aMsg, aIter, &aResult->mPresShellResolution) &&
+ ReadParam(aMsg, aIter, &aResult->mCompositionBounds) &&
+ ReadParam(aMsg, aIter, &aResult->mDisplayPort) &&
+ ReadParam(aMsg, aIter, &aResult->mCriticalDisplayPort) &&
+ ReadParam(aMsg, aIter, &aResult->mScrollableRect) &&
+ ReadParam(aMsg, aIter, &aResult->mCumulativeResolution) &&
+ ReadParam(aMsg, aIter, &aResult->mDevPixelsPerCSSPixel) &&
+ ReadParam(aMsg, aIter, &aResult->mScrollOffset) &&
+ ReadParam(aMsg, aIter, &aResult->mZoom) &&
+ ReadParam(aMsg, aIter, &aResult->mScrollGeneration) &&
+ ReadParam(aMsg, aIter, &aResult->mSmoothScrollOffset) &&
+ ReadParam(aMsg, aIter, &aResult->mRootCompositionSize) &&
+ ReadParam(aMsg, aIter, &aResult->mDisplayPortMargins) &&
+ ReadParam(aMsg, aIter, &aResult->mPresShellId) &&
+ ReadParam(aMsg, aIter, &aResult->mViewport) &&
+ ReadParam(aMsg, aIter, &aResult->mExtraResolution) &&
+ ReadParam(aMsg, aIter, &aResult->mPaintRequestTime) &&
+ ReadParam(aMsg, aIter, &aResult->mScrollUpdateType) &&
+ ReadBoolForBitfield(aMsg, aIter, aResult, &paramType::SetIsRootContent) &&
+ ReadBoolForBitfield(aMsg, aIter, aResult, &paramType::SetDoSmoothScroll) &&
+ ReadBoolForBitfield(aMsg, aIter, aResult, &paramType::SetUseDisplayPortMargins) &&
+ ReadBoolForBitfield(aMsg, aIter, aResult, &paramType::SetIsScrollInfoLayer));
+ }
+};
+
+template <>
+struct ParamTraits<mozilla::layers::ScrollSnapInfo>
+{
+ typedef mozilla::layers::ScrollSnapInfo paramType;
+
+ static void Write(Message* aMsg, const paramType& aParam)
+ {
+ WriteParam(aMsg, aParam.mScrollSnapTypeX);
+ WriteParam(aMsg, aParam.mScrollSnapTypeY);
+ WriteParam(aMsg, aParam.mScrollSnapIntervalX);
+ WriteParam(aMsg, aParam.mScrollSnapIntervalY);
+ WriteParam(aMsg, aParam.mScrollSnapDestination);
+ WriteParam(aMsg, aParam.mScrollSnapCoordinates);
+ }
+
+ static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
+ {
+ return (ReadParam(aMsg, aIter, &aResult->mScrollSnapTypeX) &&
+ ReadParam(aMsg, aIter, &aResult->mScrollSnapTypeY) &&
+ ReadParam(aMsg, aIter, &aResult->mScrollSnapIntervalX) &&
+ ReadParam(aMsg, aIter, &aResult->mScrollSnapIntervalY) &&
+ ReadParam(aMsg, aIter, &aResult->mScrollSnapDestination) &&
+ ReadParam(aMsg, aIter, &aResult->mScrollSnapCoordinates));
+ }
+};
+
+template <>
+struct ParamTraits<mozilla::layers::LayerClip>
+{
+ typedef mozilla::layers::LayerClip paramType;
+
+ static void Write(Message* aMsg, const paramType& aParam)
+ {
+ WriteParam(aMsg, aParam.mClipRect);
+ WriteParam(aMsg, aParam.mMaskLayerIndex);
+ }
+
+ static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
+ {
+ return (ReadParam(aMsg, aIter, &aResult->mClipRect) &&
+ ReadParam(aMsg, aIter, &aResult->mMaskLayerIndex));
+ }
+};
+
+template <>
+struct ParamTraits<mozilla::layers::ScrollMetadata>
+ : BitfieldHelper<mozilla::layers::ScrollMetadata>
+{
+ typedef mozilla::layers::ScrollMetadata paramType;
+
+ static void Write(Message* aMsg, const paramType& aParam)
+ {
+ WriteParam(aMsg, aParam.mMetrics);
+ WriteParam(aMsg, aParam.mSnapInfo);
+ WriteParam(aMsg, aParam.mScrollParentId);
+ WriteParam(aMsg, aParam.mBackgroundColor);
+ WriteParam(aMsg, aParam.GetContentDescription());
+ WriteParam(aMsg, aParam.mLineScrollAmount);
+ WriteParam(aMsg, aParam.mPageScrollAmount);
+ WriteParam(aMsg, aParam.mScrollClip);
+ WriteParam(aMsg, aParam.mHasScrollgrab);
+ WriteParam(aMsg, aParam.mAllowVerticalScrollWithWheel);
+ WriteParam(aMsg, aParam.mIsLayersIdRoot);
+ WriteParam(aMsg, aParam.mUsesContainerScrolling);
+ WriteParam(aMsg, aParam.mForceDisableApz);
+ }
+
+ static bool ReadContentDescription(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
+ {
+ nsCString str;
+ if (!ReadParam(aMsg, aIter, &str)) {
+ return false;
+ }
+ aResult->SetContentDescription(str);
+ return true;
+ }
+
+ static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
+ {
+ return (ReadParam(aMsg, aIter, &aResult->mMetrics) &&
+ ReadParam(aMsg, aIter, &aResult->mSnapInfo) &&
+ ReadParam(aMsg, aIter, &aResult->mScrollParentId) &&
+ ReadParam(aMsg, aIter, &aResult->mBackgroundColor) &&
+ ReadContentDescription(aMsg, aIter, aResult) &&
+ ReadParam(aMsg, aIter, &aResult->mLineScrollAmount) &&
+ ReadParam(aMsg, aIter, &aResult->mPageScrollAmount) &&
+ ReadParam(aMsg, aIter, &aResult->mScrollClip) &&
+ ReadBoolForBitfield(aMsg, aIter, aResult, &paramType::SetHasScrollgrab) &&
+ ReadBoolForBitfield(aMsg, aIter, aResult, &paramType::SetAllowVerticalScrollWithWheel) &&
+ ReadBoolForBitfield(aMsg, aIter, aResult, &paramType::SetIsLayersIdRoot) &&
+ ReadBoolForBitfield(aMsg, aIter, aResult, &paramType::SetUsesContainerScrolling) &&
+ ReadBoolForBitfield(aMsg, aIter, aResult, &paramType::SetForceDisableApz));
+ }
+};
+
+template<>
+struct ParamTraits<GeckoProcessType>
+ : public ContiguousEnumSerializer<
+ GeckoProcessType,
+ GeckoProcessType_Default,
+ GeckoProcessType_End>
+{};
+
+template<>
+struct ParamTraits<mozilla::layers::TextureFactoryIdentifier>
+{
+ typedef mozilla::layers::TextureFactoryIdentifier paramType;
+
+ static void Write(Message* aMsg, const paramType& aParam)
+ {
+ WriteParam(aMsg, aParam.mParentBackend);
+ WriteParam(aMsg, aParam.mParentProcessType);
+ WriteParam(aMsg, aParam.mMaxTextureSize);
+ WriteParam(aMsg, aParam.mSupportsTextureBlitting);
+ WriteParam(aMsg, aParam.mSupportsPartialUploads);
+ WriteParam(aMsg, aParam.mSupportsComponentAlpha);
+ WriteParam(aMsg, aParam.mSyncHandle);
+ }
+
+ static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
+ {
+ bool result = ReadParam(aMsg, aIter, &aResult->mParentBackend) &&
+ ReadParam(aMsg, aIter, &aResult->mParentProcessType) &&
+ ReadParam(aMsg, aIter, &aResult->mMaxTextureSize) &&
+ ReadParam(aMsg, aIter, &aResult->mSupportsTextureBlitting) &&
+ ReadParam(aMsg, aIter, &aResult->mSupportsPartialUploads) &&
+ ReadParam(aMsg, aIter, &aResult->mSupportsComponentAlpha) &&
+ ReadParam(aMsg, aIter, &aResult->mSyncHandle);
+ return result;
+ }
+};
+
+template<>
+struct ParamTraits<mozilla::layers::TextureInfo>
+{
+ typedef mozilla::layers::TextureInfo paramType;
+
+ static void Write(Message* aMsg, const paramType& aParam)
+ {
+ WriteParam(aMsg, aParam.mCompositableType);
+ WriteParam(aMsg, aParam.mTextureFlags);
+ }
+
+ static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
+ {
+ return ReadParam(aMsg, aIter, &aResult->mCompositableType) &&
+ ReadParam(aMsg, aIter, &aResult->mTextureFlags);
+ }
+};
+
+template <>
+struct ParamTraits<mozilla::layers::CompositableType>
+ : public ContiguousEnumSerializer<
+ mozilla::layers::CompositableType,
+ mozilla::layers::CompositableType::UNKNOWN,
+ mozilla::layers::CompositableType::COUNT>
+{};
+
+template <>
+struct ParamTraits<mozilla::gfx::SurfaceFormat>
+ : public ContiguousEnumSerializer<
+ mozilla::gfx::SurfaceFormat,
+ mozilla::gfx::SurfaceFormat::B8G8R8A8,
+ mozilla::gfx::SurfaceFormat::UNKNOWN>
+{};
+
+template <>
+struct ParamTraits<mozilla::StereoMode>
+ : public ContiguousEnumSerializer<
+ mozilla::StereoMode,
+ mozilla::StereoMode::MONO,
+ mozilla::StereoMode::MAX>
+{};
+
+template <>
+struct ParamTraits<mozilla::YUVColorSpace>
+ : public ContiguousEnumSerializer<
+ mozilla::YUVColorSpace,
+ mozilla::YUVColorSpace::BT601,
+ mozilla::YUVColorSpace::UNKNOWN>
+{};
+
+template <>
+struct ParamTraits<mozilla::layers::ScrollableLayerGuid>
+{
+ typedef mozilla::layers::ScrollableLayerGuid paramType;
+
+ static void Write(Message* aMsg, const paramType& aParam)
+ {
+ WriteParam(aMsg, aParam.mLayersId);
+ WriteParam(aMsg, aParam.mPresShellId);
+ WriteParam(aMsg, aParam.mScrollId);
+ }
+
+ static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
+ {
+ return (ReadParam(aMsg, aIter, &aResult->mLayersId) &&
+ ReadParam(aMsg, aIter, &aResult->mPresShellId) &&
+ ReadParam(aMsg, aIter, &aResult->mScrollId));
+ }
+};
+
+
+template <>
+struct ParamTraits<mozilla::layers::ZoomConstraints>
+{
+ typedef mozilla::layers::ZoomConstraints paramType;
+
+ static void Write(Message* aMsg, const paramType& aParam)
+ {
+ WriteParam(aMsg, aParam.mAllowZoom);
+ WriteParam(aMsg, aParam.mAllowDoubleTapZoom);
+ WriteParam(aMsg, aParam.mMinZoom);
+ WriteParam(aMsg, aParam.mMaxZoom);
+ }
+
+ static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
+ {
+ return (ReadParam(aMsg, aIter, &aResult->mAllowZoom) &&
+ ReadParam(aMsg, aIter, &aResult->mAllowDoubleTapZoom) &&
+ ReadParam(aMsg, aIter, &aResult->mMinZoom) &&
+ ReadParam(aMsg, aIter, &aResult->mMaxZoom));
+ }
+};
+
+template <>
+struct ParamTraits<mozilla::layers::EventRegions>
+{
+ typedef mozilla::layers::EventRegions paramType;
+
+ static void Write(Message* aMsg, const paramType& aParam)
+ {
+ WriteParam(aMsg, aParam.mHitRegion);
+ WriteParam(aMsg, aParam.mDispatchToContentHitRegion);
+ WriteParam(aMsg, aParam.mNoActionRegion);
+ WriteParam(aMsg, aParam.mHorizontalPanRegion);
+ WriteParam(aMsg, aParam.mVerticalPanRegion);
+ }
+
+ static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
+ {
+ return (ReadParam(aMsg, aIter, &aResult->mHitRegion) &&
+ ReadParam(aMsg, aIter, &aResult->mDispatchToContentHitRegion) &&
+ ReadParam(aMsg, aIter, &aResult->mNoActionRegion) &&
+ ReadParam(aMsg, aIter, &aResult->mHorizontalPanRegion) &&
+ ReadParam(aMsg, aIter, &aResult->mVerticalPanRegion));
+ }
+};
+
+template <>
+struct ParamTraits<mozilla::gfx::AttributeMap>
+{
+ typedef mozilla::gfx::AttributeMap paramType;
+
+ static void Write(Message* aMsg, const paramType& aParam)
+ {
+ WriteParam(aMsg, aParam.Count());
+ for (auto iter = aParam.ConstIter(); !iter.Done(); iter.Next()) {
+ mozilla::gfx::AttributeName name =
+ mozilla::gfx::AttributeName(iter.Key());
+ mozilla::gfx::AttributeType type =
+ mozilla::gfx::AttributeMap::GetType(iter.UserData());
+
+ WriteParam(aMsg, type);
+ WriteParam(aMsg, name);
+
+ switch (type) {
+
+#define CASE_TYPE(typeName) \
+ case mozilla::gfx::AttributeType::e##typeName: \
+ WriteParam(aMsg, aParam.Get##typeName(name)); \
+ break;
+
+ CASE_TYPE(Bool)
+ CASE_TYPE(Uint)
+ CASE_TYPE(Float)
+ CASE_TYPE(Size)
+ CASE_TYPE(IntSize)
+ CASE_TYPE(IntPoint)
+ CASE_TYPE(Matrix)
+ CASE_TYPE(Matrix5x4)
+ CASE_TYPE(Point3D)
+ CASE_TYPE(Color)
+ CASE_TYPE(AttributeMap)
+ CASE_TYPE(Floats)
+
+#undef CASE_TYPE
+
+ default:
+ MOZ_CRASH("GFX: unhandled attribute type");
+ }
+ }
+ }
+
+ static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
+ {
+ uint32_t count;
+ if (!ReadParam(aMsg, aIter, &count)) {
+ return false;
+ }
+ for (uint32_t i = 0; i < count; i++) {
+ mozilla::gfx::AttributeType type;
+ if (!ReadParam(aMsg, aIter, &type)) {
+ return false;
+ }
+ mozilla::gfx::AttributeName name;
+ if (!ReadParam(aMsg, aIter, &name)) {
+ return false;
+ }
+ switch (type) {
+
+#define HANDLE_TYPE(type, typeName) \
+ case mozilla::gfx::AttributeType::e##typeName: \
+ { \
+ type value; \
+ if (!ReadParam(aMsg, aIter, &value)) { \
+ return false; \
+ } \
+ aResult->Set(name, value); \
+ break; \
+ }
+
+ HANDLE_TYPE(bool, Bool)
+ HANDLE_TYPE(uint32_t, Uint)
+ HANDLE_TYPE(float, Float)
+ HANDLE_TYPE(mozilla::gfx::Size, Size)
+ HANDLE_TYPE(mozilla::gfx::IntSize, IntSize)
+ HANDLE_TYPE(mozilla::gfx::IntPoint, IntPoint)
+ HANDLE_TYPE(mozilla::gfx::Matrix, Matrix)
+ HANDLE_TYPE(mozilla::gfx::Matrix5x4, Matrix5x4)
+ HANDLE_TYPE(mozilla::gfx::Point3D, Point3D)
+ HANDLE_TYPE(mozilla::gfx::Color, Color)
+ HANDLE_TYPE(mozilla::gfx::AttributeMap, AttributeMap)
+
+#undef HANDLE_TYPE
+
+ case mozilla::gfx::AttributeType::eFloats:
+ {
+ nsTArray<float> value;
+ if (!ReadParam(aMsg, aIter, &value)) {
+ return false;
+ }
+ aResult->Set(name, &value[0], value.Length());
+ break;
+ }
+ default:
+ MOZ_CRASH("GFX: unhandled attribute type");
+ }
+ }
+ return true;
+ }
+};
+
+template <>
+struct ParamTraits<mozilla::gfx::FilterPrimitiveDescription>
+{
+ typedef mozilla::gfx::FilterPrimitiveDescription paramType;
+
+ static void Write(Message* aMsg, const paramType& aParam)
+ {
+ WriteParam(aMsg, aParam.Type());
+ WriteParam(aMsg, aParam.PrimitiveSubregion());
+ WriteParam(aMsg, aParam.FilterSpaceBounds());
+ WriteParam(aMsg, aParam.IsTainted());
+ WriteParam(aMsg, aParam.OutputColorSpace());
+ WriteParam(aMsg, aParam.NumberOfInputs());
+ for (size_t i = 0; i < aParam.NumberOfInputs(); i++) {
+ WriteParam(aMsg, aParam.InputPrimitiveIndex(i));
+ WriteParam(aMsg, aParam.InputColorSpace(i));
+ }
+ WriteParam(aMsg, aParam.Attributes());
+ }
+
+ static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
+ {
+ mozilla::gfx::PrimitiveType type;
+ mozilla::gfx::IntRect primitiveSubregion;
+ mozilla::gfx::IntRect filterSpaceBounds;
+ bool isTainted = false;
+ mozilla::gfx::ColorSpace outputColorSpace;
+ size_t numberOfInputs = 0;
+ if (!ReadParam(aMsg, aIter, &type) ||
+ !ReadParam(aMsg, aIter, &primitiveSubregion) ||
+ !ReadParam(aMsg, aIter, &filterSpaceBounds) ||
+ !ReadParam(aMsg, aIter, &isTainted) ||
+ !ReadParam(aMsg, aIter, &outputColorSpace) ||
+ !ReadParam(aMsg, aIter, &numberOfInputs)) {
+ return false;
+ }
+
+ aResult->SetType(type);
+ aResult->SetPrimitiveSubregion(primitiveSubregion);
+ aResult->SetFilterSpaceBounds(filterSpaceBounds);
+ aResult->SetIsTainted(isTainted);
+ aResult->SetOutputColorSpace(outputColorSpace);
+
+ for (size_t i = 0; i < numberOfInputs; i++) {
+ int32_t inputPrimitiveIndex = 0;
+ mozilla::gfx::ColorSpace inputColorSpace;
+ if (!ReadParam(aMsg, aIter, &inputPrimitiveIndex) ||
+ !ReadParam(aMsg, aIter, &inputColorSpace)) {
+ return false;
+ }
+ aResult->SetInputPrimitive(i, inputPrimitiveIndex);
+ aResult->SetInputColorSpace(i, inputColorSpace);
+ }
+
+ return ReadParam(aMsg, aIter, &aResult->Attributes());
+ }
+};
+
+template <>
+struct ParamTraits<mozilla::gfx::FilterDescription>
+{
+ typedef mozilla::gfx::FilterDescription paramType;
+
+ static void Write(Message* aMsg, const paramType& aParam)
+ {
+ WriteParam(aMsg, aParam.mPrimitives);
+ }
+
+ static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
+ {
+ return (ReadParam(aMsg, aIter, &aResult->mPrimitives));
+ }
+};
+
+typedef mozilla::layers::GeckoContentController::TapType TapType;
+
+template <>
+struct ParamTraits<TapType>
+ : public ContiguousEnumSerializer<
+ TapType,
+ TapType::eSingleTap,
+ TapType::eSentinel>
+{};
+
+typedef mozilla::layers::GeckoContentController::APZStateChange APZStateChange;
+
+template <>
+struct ParamTraits<APZStateChange>
+ : public ContiguousEnumSerializer<
+ APZStateChange,
+ APZStateChange::eTransformBegin,
+ APZStateChange::eSentinel>
+{};
+
+template<>
+struct ParamTraits<mozilla::layers::EventRegionsOverride>
+ : public BitFlagsEnumSerializer<
+ mozilla::layers::EventRegionsOverride,
+ mozilla::layers::EventRegionsOverride::ALL_BITS>
+{};
+
+template<>
+struct ParamTraits<mozilla::layers::AsyncDragMetrics::DragDirection>
+ : public ContiguousEnumSerializer<
+ mozilla::layers::AsyncDragMetrics::DragDirection,
+ mozilla::layers::AsyncDragMetrics::DragDirection::NONE,
+ mozilla::layers::AsyncDragMetrics::DragDirection::SENTINEL>
+{};
+
+template<>
+struct ParamTraits<mozilla::layers::AsyncDragMetrics>
+{
+ typedef mozilla::layers::AsyncDragMetrics paramType;
+
+ static void Write(Message* aMsg, const paramType& aParam)
+ {
+ WriteParam(aMsg, aParam.mViewId);
+ WriteParam(aMsg, aParam.mPresShellId);
+ WriteParam(aMsg, aParam.mDragStartSequenceNumber);
+ WriteParam(aMsg, aParam.mScrollbarDragOffset);
+ WriteParam(aMsg, aParam.mScrollTrack);
+ WriteParam(aMsg, aParam.mDirection);
+ }
+
+ static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
+ {
+ return (ReadParam(aMsg, aIter, &aResult->mViewId) &&
+ ReadParam(aMsg, aIter, &aResult->mPresShellId) &&
+ ReadParam(aMsg, aIter, &aResult->mDragStartSequenceNumber) &&
+ ReadParam(aMsg, aIter, &aResult->mScrollbarDragOffset) &&
+ ReadParam(aMsg, aIter, &aResult->mScrollTrack) &&
+ ReadParam(aMsg, aIter, &aResult->mDirection));
+ }
+};
+
+} /* namespace IPC */
+
+#endif /* __GFXMESSAGEUTILS_H__ */
diff --git a/gfx/ipc/GraphicsMessages.ipdlh b/gfx/ipc/GraphicsMessages.ipdlh
new file mode 100644
index 0000000000..cc4115d425
--- /dev/null
+++ b/gfx/ipc/GraphicsMessages.ipdlh
@@ -0,0 +1,87 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: sw=2 ts=8 et :
+ */
+/* 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 struct DxgiAdapterDesc from "mozilla/D3DMessageUtils.h";
+using struct mozilla::null_t from "ipc/IPCMessageUtils.h";
+using mozilla::gfx::FeatureStatus from "gfxTelemetry.h";
+using mozilla::gfx::BackendType from "mozilla/gfx/Types.h";
+using mozilla::gfx::IntSize from "mozilla/gfx/Point.h";
+using gfxImageFormat from "mozilla/gfx/Types.h";
+
+namespace mozilla {
+namespace gfx {
+
+struct D3D11DeviceStatus
+{
+ bool isWARP;
+ bool textureSharingWorks;
+ uint32_t featureLevel;
+ DxgiAdapterDesc adapter;
+};
+
+struct DevicePrefs
+{
+ FeatureStatus hwCompositing;
+ FeatureStatus d3d11Compositing;
+ FeatureStatus d3d9Compositing;
+ FeatureStatus oglCompositing;
+ FeatureStatus useD2D1;
+};
+
+struct ContentDeviceData
+{
+ DevicePrefs prefs;
+ D3D11DeviceStatus d3d11;
+};
+
+// Represents the state of a feature that has failed to initialize.
+struct FeatureFailure
+{
+ FeatureStatus status;
+ nsCString message;
+ nsCString failureId;
+};
+
+// If a feature state has changed from Enabled -> Failure, this will be non-
+// null.
+union FeatureChange
+{
+ null_t;
+ FeatureFailure;
+};
+
+union GPUDeviceStatus
+{
+ null_t;
+ D3D11DeviceStatus;
+};
+
+struct GPUDeviceData
+{
+ FeatureChange d3d11Compositing;
+ FeatureChange d3d9Compositing;
+ FeatureChange oglCompositing;
+ GPUDeviceStatus gpuDevice;
+};
+
+union GfxVarValue
+{
+ BackendType;
+ bool;
+ gfxImageFormat;
+ IntSize;
+ nsCString;
+};
+
+struct GfxVarUpdate
+{
+ size_t index;
+ GfxVarValue value;
+};
+
+} // namespace gfx
+} // namespace mozilla
diff --git a/gfx/ipc/InProcessCompositorSession.cpp b/gfx/ipc/InProcessCompositorSession.cpp
new file mode 100644
index 0000000000..fd85250853
--- /dev/null
+++ b/gfx/ipc/InProcessCompositorSession.cpp
@@ -0,0 +1,83 @@
+/* -*- 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 "InProcessCompositorSession.h"
+
+// so we can cast an APZCTreeManager to an IAPZCTreeManager
+#include "mozilla/layers/APZCTreeManager.h"
+#include "mozilla/layers/IAPZCTreeManager.h"
+
+namespace mozilla {
+namespace layers {
+
+InProcessCompositorSession::InProcessCompositorSession(widget::CompositorWidget* aWidget,
+ CompositorBridgeChild* aChild,
+ CompositorBridgeParent* aParent)
+ : CompositorSession(aWidget->AsDelegate(), aChild, aParent->RootLayerTreeId()),
+ mCompositorBridgeParent(aParent),
+ mCompositorWidget(aWidget)
+{
+}
+
+/* static */ RefPtr<InProcessCompositorSession>
+InProcessCompositorSession::Create(nsIWidget* aWidget,
+ LayerManager* aLayerManager,
+ const uint64_t& aRootLayerTreeId,
+ CSSToLayoutDeviceScale aScale,
+ bool aUseAPZ,
+ bool aUseExternalSurfaceSize,
+ const gfx::IntSize& aSurfaceSize)
+{
+ CompositorWidgetInitData initData;
+ aWidget->GetCompositorWidgetInitData(&initData);
+
+ RefPtr<CompositorWidget> widget = CompositorWidget::CreateLocal(initData, aWidget);
+ RefPtr<CompositorBridgeChild> child = new CompositorBridgeChild(aLayerManager);
+ RefPtr<CompositorBridgeParent> parent =
+ child->InitSameProcess(widget, aRootLayerTreeId, aScale, aUseAPZ, aUseExternalSurfaceSize, aSurfaceSize);
+
+ return new InProcessCompositorSession(widget, child, parent);
+}
+
+CompositorBridgeParent*
+InProcessCompositorSession::GetInProcessBridge() const
+{
+ return mCompositorBridgeParent;
+}
+
+void
+InProcessCompositorSession::SetContentController(GeckoContentController* aController)
+{
+ mCompositorBridgeParent->SetControllerForLayerTree(mRootLayerTreeId, aController);
+}
+
+RefPtr<IAPZCTreeManager>
+InProcessCompositorSession::GetAPZCTreeManager() const
+{
+ return mCompositorBridgeParent->GetAPZCTreeManager(mRootLayerTreeId);
+}
+
+bool
+InProcessCompositorSession::Reset(const nsTArray<LayersBackend>& aBackendHints, TextureFactoryIdentifier* aOutIdentifier)
+{
+ return mCompositorBridgeParent->ResetCompositor(aBackendHints, aOutIdentifier);
+}
+
+void
+InProcessCompositorSession::Shutdown()
+{
+ // Destroy will synchronously wait for the parent to acknowledge shutdown,
+ // at which point CBP will defer a Release on the compositor thread. We
+ // can safely release our reference now, and let the destructor run on either
+ // thread.
+ mCompositorBridgeChild->Destroy();
+ mCompositorBridgeChild = nullptr;
+ mCompositorBridgeParent = nullptr;
+ mCompositorWidget = nullptr;
+}
+
+} // namespace layers
+} // namespace mozilla
diff --git a/gfx/ipc/InProcessCompositorSession.h b/gfx/ipc/InProcessCompositorSession.h
new file mode 100644
index 0000000000..deb642da22
--- /dev/null
+++ b/gfx/ipc/InProcessCompositorSession.h
@@ -0,0 +1,49 @@
+/* -*- 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_InProcessCompositorSession_h_
+#define _include_mozilla_gfx_ipc_InProcessCompositorSession_h_
+
+#include "CompositorSession.h"
+#include "mozilla/gfx/Point.h"
+#include "Units.h"
+
+namespace mozilla {
+namespace layers {
+
+// A CompositorSession where both the child and parent CompositorBridge reside
+// in the same process.
+class InProcessCompositorSession final : public CompositorSession
+{
+public:
+ static RefPtr<InProcessCompositorSession> Create(
+ nsIWidget* aWidget,
+ LayerManager* aLayerManager,
+ const uint64_t& aRootLayerTreeId,
+ CSSToLayoutDeviceScale aScale,
+ bool aUseAPZ,
+ bool aUseExternalSurfaceSize,
+ const gfx::IntSize& aSurfaceSize);
+
+ CompositorBridgeParent* GetInProcessBridge() const override;
+ void SetContentController(GeckoContentController* aController) override;
+ RefPtr<IAPZCTreeManager> GetAPZCTreeManager() const override;
+ bool Reset(const nsTArray<LayersBackend>& aBackendHints, TextureFactoryIdentifier* aOutIdentifier) override;
+ void Shutdown() override;
+
+private:
+ InProcessCompositorSession(widget::CompositorWidget* aWidget,
+ CompositorBridgeChild* aChild,
+ CompositorBridgeParent* aParent);
+
+private:
+ RefPtr<CompositorBridgeParent> mCompositorBridgeParent;
+ RefPtr<CompositorWidget> mCompositorWidget;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif // _include_mozilla_gfx_ipc_InProcessCompositorSession_h_
diff --git a/gfx/ipc/PGPU.ipdl b/gfx/ipc/PGPU.ipdl
new file mode 100644
index 0000000000..c442335c98
--- /dev/null
+++ b/gfx/ipc/PGPU.ipdl
@@ -0,0 +1,106 @@
+/* -*- 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/. */
+
+include GraphicsMessages;
+include protocol PCompositorBridge;
+include protocol PImageBridge;
+include protocol PVRManager;
+include protocol PVsyncBridge;
+include protocol PVideoDecoderManager;
+
+using base::ProcessId from "base/process.h";
+using mozilla::TimeDuration from "mozilla/TimeStamp.h";
+using mozilla::CSSToLayoutDeviceScale from "Units.h";
+using mozilla::gfx::IntSize from "mozilla/gfx/2D.h";
+using mozilla::Telemetry::Accumulation from "mozilla/TelemetryComms.h";
+using mozilla::Telemetry::KeyedAccumulation from "mozilla/TelemetryComms.h";
+
+namespace mozilla {
+namespace gfx {
+
+union GfxPrefValue {
+ bool;
+ int32_t;
+ uint32_t;
+ float;
+};
+
+struct GfxPrefSetting {
+ int32_t index;
+ GfxPrefValue value;
+};
+
+struct LayerTreeIdMapping {
+ uint64_t layersId;
+ ProcessId ownerId;
+};
+
+sync protocol PGPU
+{
+parent:
+ // Sent by the UI process to initiate core settings.
+ async Init(GfxPrefSetting[] prefs,
+ GfxVarUpdate[] vars,
+ DevicePrefs devicePrefs);
+
+ async InitVsyncBridge(Endpoint<PVsyncBridgeParent> endpoint);
+ async InitImageBridge(Endpoint<PImageBridgeParent> endpoint);
+ async InitVRManager(Endpoint<PVRManagerParent> endpoint);
+
+ // Called to update a gfx preference or variable.
+ async UpdatePref(GfxPrefSetting pref);
+ async UpdateVar(GfxVarUpdate var);
+
+ // Create a new top-level compositor.
+ async NewWidgetCompositor(Endpoint<PCompositorBridgeParent> endpoint,
+ CSSToLayoutDeviceScale scale,
+ TimeDuration vsyncRate,
+ bool useExternalSurface,
+ IntSize surfaceSize);
+
+ // Create a new content-process compositor bridge.
+ async NewContentCompositorBridge(Endpoint<PCompositorBridgeParent> endpoint);
+ async NewContentImageBridge(Endpoint<PImageBridgeParent> endpoint);
+ async NewContentVRManager(Endpoint<PVRManagerParent> endpoint);
+ async NewContentVideoDecoderManager(Endpoint<PVideoDecoderManagerParent> endpoint);
+
+ // Called to notify the GPU process of who owns a layersId.
+ sync AddLayerTreeIdMapping(LayerTreeIdMapping[] mapping);
+ async RemoveLayerTreeIdMapping(LayerTreeIdMapping mapping);
+
+ // Request the current DeviceStatus from the GPU process. This blocks until
+ // one is available (i.e., Init has completed).
+ sync GetDeviceStatus() returns (GPUDeviceData status);
+
+ // Have a message be broadcasted to the GPU process by the GPU process
+ // observer service.
+ async NotifyGpuObservers(nsCString aTopic);
+
+child:
+ // Sent when the GPU process has initialized devices. This occurs once, after
+ // Init().
+ async InitComplete(GPUDeviceData data);
+
+ // Sent when APZ detects checkerboarding and apz checkerboard reporting is enabled.
+ async ReportCheckerboard(uint32_t severity, nsCString log);
+
+ // Graphics errors, analogous to PContent::GraphicsError
+ async GraphicsError(nsCString aError);
+
+ async InitCrashReporter(Shmem shmem);
+
+ // Have a message be broadcasted to the UI process by the UI process
+ // observer service.
+ async NotifyUiObservers(nsCString aTopic);
+
+ // Messages for reporting telemetry to the UI process.
+ async AccumulateChildHistogram(Accumulation[] accumulations);
+ async AccumulateChildKeyedHistogram(KeyedAccumulation[] accumulations);
+
+ async NotifyDeviceReset();
+};
+
+} // namespace gfx
+} // namespace mozilla
diff --git a/gfx/ipc/PVsyncBridge.ipdl b/gfx/ipc/PVsyncBridge.ipdl
new file mode 100644
index 0000000000..03c68bbde6
--- /dev/null
+++ b/gfx/ipc/PVsyncBridge.ipdl
@@ -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, uint64_t layersId);
+};
+
+} // namespace gfx
+} // namespace mozilla
diff --git a/gfx/ipc/RemoteCompositorSession.cpp b/gfx/ipc/RemoteCompositorSession.cpp
new file mode 100644
index 0000000000..6e5ad975a2
--- /dev/null
+++ b/gfx/ipc/RemoteCompositorSession.cpp
@@ -0,0 +1,112 @@
+/* -*- 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"
+#include "mozilla/VsyncDispatcher.h"
+#include "mozilla/layers/APZChild.h"
+#include "mozilla/layers/APZCTreeManagerChild.h"
+#include "mozilla/Unused.h"
+#include "nsBaseWidget.h"
+
+namespace mozilla {
+namespace layers {
+
+using namespace gfx;
+using namespace widget;
+
+RemoteCompositorSession::RemoteCompositorSession(nsBaseWidget* aWidget,
+ CompositorBridgeChild* aChild,
+ CompositorWidgetDelegate* aWidgetDelegate,
+ APZCTreeManagerChild* aAPZ,
+ const uint64_t& aRootLayerTreeId)
+ : CompositorSession(aWidgetDelegate, aChild, aRootLayerTreeId),
+ mWidget(aWidget),
+ mAPZ(aAPZ)
+{
+ GPUProcessManager::Get()->RegisterSession(this);
+ if (mAPZ) {
+ mAPZ->SetCompositorSession(this);
+ }
+}
+
+RemoteCompositorSession::~RemoteCompositorSession()
+{
+ // This should have been shutdown first.
+ MOZ_ASSERT(!mCompositorBridgeChild);
+}
+
+void
+RemoteCompositorSession::NotifyDeviceReset()
+{
+ MOZ_ASSERT(mWidget);
+ mWidget->OnRenderingDeviceReset();
+}
+
+void
+RemoteCompositorSession::NotifySessionLost()
+{
+ // Re-entrancy should be impossible: when we are being notified of a lost
+ // session, we have by definition not shut down yet. We will shutdown, but
+ // then will be removed from the notification list.
+ MOZ_ASSERT(mWidget);
+ mWidget->NotifyRemoteCompositorSessionLost(this);
+}
+
+CompositorBridgeParent*
+RemoteCompositorSession::GetInProcessBridge() const
+{
+ return nullptr;
+}
+
+void
+RemoteCompositorSession::SetContentController(GeckoContentController* aController)
+{
+ mContentController = aController;
+ mCompositorBridgeChild->SendPAPZConstructor(new APZChild(aController), 0);
+}
+
+GeckoContentController*
+RemoteCompositorSession::GetContentController()
+{
+ return mContentController.get();
+}
+
+nsIWidget*
+RemoteCompositorSession::GetWidget()
+{
+ return mWidget;
+}
+
+RefPtr<IAPZCTreeManager>
+RemoteCompositorSession::GetAPZCTreeManager() const
+{
+ return mAPZ;
+}
+
+bool
+RemoteCompositorSession::Reset(const nsTArray<LayersBackend>& aBackendHints, TextureFactoryIdentifier* aOutIdentifier)
+{
+ bool didReset;
+ Unused << mCompositorBridgeChild->SendReset(aBackendHints, &didReset, aOutIdentifier);
+ return didReset;
+}
+
+void
+RemoteCompositorSession::Shutdown()
+{
+ mContentController = nullptr;
+ if (mAPZ) {
+ mAPZ->SetCompositorSession(nullptr);
+ }
+ mCompositorBridgeChild->Destroy();
+ mCompositorBridgeChild = nullptr;
+ mCompositorWidgetDelegate = nullptr;
+ mWidget = nullptr;
+ GPUProcessManager::Get()->UnregisterSession(this);
+}
+
+} // namespace layers
+} // namespace mozilla
diff --git a/gfx/ipc/RemoteCompositorSession.h b/gfx/ipc/RemoteCompositorSession.h
new file mode 100644
index 0000000000..b4731c5c24
--- /dev/null
+++ b/gfx/ipc/RemoteCompositorSession.h
@@ -0,0 +1,46 @@
+/* -*- 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(nsBaseWidget* aWidget,
+ CompositorBridgeChild* aChild,
+ CompositorWidgetDelegate* aWidgetDelegate,
+ APZCTreeManagerChild* aAPZ,
+ const uint64_t& aRootLayerTreeId);
+ ~RemoteCompositorSession() override;
+
+ CompositorBridgeParent* GetInProcessBridge() const override;
+ void SetContentController(GeckoContentController* aController) override;
+ GeckoContentController* GetContentController();
+ nsIWidget* GetWidget();
+ RefPtr<IAPZCTreeManager> GetAPZCTreeManager() const override;
+ bool Reset(const nsTArray<LayersBackend>& aBackendHints, TextureFactoryIdentifier* aOutIdentifier) override;
+ void Shutdown() override;
+
+ void NotifyDeviceReset();
+ void NotifySessionLost();
+
+private:
+ nsBaseWidget* mWidget;
+ RefPtr<APZCTreeManagerChild> mAPZ;
+ RefPtr<GeckoContentController> mContentController;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif // include_mozilla_gfx_ipc_RemoteCompositorSession_h
diff --git a/gfx/ipc/SharedDIB.cpp b/gfx/ipc/SharedDIB.cpp
new file mode 100644
index 0000000000..ec68a61fa2
--- /dev/null
+++ b/gfx/ipc/SharedDIB.cpp
@@ -0,0 +1,77 @@
+/* -*- Mode: C++; tab-width: 2; 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/. */
+
+#include "SharedDIB.h"
+
+namespace mozilla {
+namespace gfx {
+
+SharedDIB::SharedDIB() :
+ mShMem(nullptr)
+{
+}
+
+SharedDIB::~SharedDIB()
+{
+ Close();
+}
+
+nsresult
+SharedDIB::Create(uint32_t aSize)
+{
+ Close();
+
+ mShMem = new base::SharedMemory();
+ if (!mShMem || !mShMem->Create("", false, false, aSize))
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ return NS_OK;
+}
+
+bool
+SharedDIB::IsValid()
+{
+ if (!mShMem)
+ return false;
+
+ return mShMem->IsHandleValid(mShMem->handle());
+}
+
+nsresult
+SharedDIB::Close()
+{
+ delete mShMem;
+
+ mShMem = nullptr;
+
+ return NS_OK;
+}
+
+nsresult
+SharedDIB::Attach(Handle aHandle, uint32_t aSize)
+{
+ Close();
+
+ mShMem = new base::SharedMemory(aHandle, false);
+ if(!mShMem)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ return NS_OK;
+}
+
+nsresult
+SharedDIB::ShareToProcess(base::ProcessId aTargetPid, Handle *aNewHandle)
+{
+ if (!mShMem)
+ return NS_ERROR_UNEXPECTED;
+
+ if (!mShMem->ShareToProcess(aTargetPid, aNewHandle))
+ return NS_ERROR_UNEXPECTED;
+
+ return NS_OK;
+}
+
+} // namespace gfx
+} // namespace mozilla
diff --git a/gfx/ipc/SharedDIB.h b/gfx/ipc/SharedDIB.h
new file mode 100644
index 0000000000..6c48b28756
--- /dev/null
+++ b/gfx/ipc/SharedDIB.h
@@ -0,0 +1,50 @@
+/* -*- Mode: C++; tab-width: 2; 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/. */
+
+#ifndef gfx_SharedDIB_h__
+#define gfx_SharedDIB_h__
+
+#include "base/shared_memory.h"
+#include "nscore.h"
+
+namespace mozilla {
+namespace gfx {
+
+class SharedDIB
+{
+public:
+ typedef base::SharedMemoryHandle Handle;
+
+ static const uint32_t kBytesPerPixel = 4;
+
+public:
+ SharedDIB();
+ ~SharedDIB();
+
+ // Create and allocate a new shared dib.
+ nsresult Create(uint32_t aSize);
+
+ // Destroy or release resources associated with this dib.
+ nsresult Close();
+
+ // Returns true if this object contains a valid dib.
+ bool IsValid();
+
+ // Wrap a new shared dib around allocated shared memory. Note aHandle must point
+ // to a memory section large enough to hold a dib of size aSize, otherwise this
+ // will fail.
+ nsresult Attach(Handle aHandle, uint32_t aSize);
+
+ // Returns a SharedMemoryHandle suitable for sharing with another process.
+ nsresult ShareToProcess(base::ProcessId aTargetPid, Handle *aNewHandle);
+
+protected:
+ base::SharedMemory *mShMem;
+};
+
+} // namespace gfx
+} // namespace mozilla
+
+#endif
diff --git a/gfx/ipc/SharedDIBSurface.cpp b/gfx/ipc/SharedDIBSurface.cpp
new file mode 100644
index 0000000000..696bb300cf
--- /dev/null
+++ b/gfx/ipc/SharedDIBSurface.cpp
@@ -0,0 +1,63 @@
+/* -*- Mode: C++; tab-width: 2; 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/. */
+
+#include "SharedDIBSurface.h"
+
+#include "cairo.h"
+
+namespace mozilla {
+namespace gfx {
+
+static const cairo_user_data_key_t SHAREDDIB_KEY = {0};
+
+bool
+SharedDIBSurface::Create(HDC adc, uint32_t aWidth, uint32_t aHeight,
+ bool aTransparent)
+{
+ nsresult rv = mSharedDIB.Create(adc, aWidth, aHeight, aTransparent);
+ if (NS_FAILED(rv) || !mSharedDIB.IsValid())
+ return false;
+
+ InitSurface(aWidth, aHeight, aTransparent);
+ return true;
+}
+
+bool
+SharedDIBSurface::Attach(Handle aHandle, uint32_t aWidth, uint32_t aHeight,
+ bool aTransparent)
+{
+ nsresult rv = mSharedDIB.Attach(aHandle, aWidth, aHeight, aTransparent);
+ if (NS_FAILED(rv) || !mSharedDIB.IsValid())
+ return false;
+
+ InitSurface(aWidth, aHeight, aTransparent);
+ return true;
+}
+
+void
+SharedDIBSurface::InitSurface(uint32_t aWidth, uint32_t aHeight,
+ bool aTransparent)
+{
+ long stride = long(aWidth * SharedDIB::kBytesPerPixel);
+ unsigned char* data = reinterpret_cast<unsigned char*>(mSharedDIB.GetBits());
+
+ gfxImageFormat format = aTransparent ? SurfaceFormat::A8R8G8B8_UINT32 : SurfaceFormat::X8R8G8B8_UINT32;
+
+ gfxImageSurface::InitWithData(data, IntSize(aWidth, aHeight),
+ stride, format);
+
+ cairo_surface_set_user_data(mSurface, &SHAREDDIB_KEY, this, nullptr);
+}
+
+bool
+SharedDIBSurface::IsSharedDIBSurface(gfxASurface* aSurface)
+{
+ return aSurface &&
+ aSurface->GetType() == gfxSurfaceType::Image &&
+ aSurface->GetData(&SHAREDDIB_KEY);
+}
+
+} // namespace gfx
+} // namespace mozilla
diff --git a/gfx/ipc/SharedDIBSurface.h b/gfx/ipc/SharedDIBSurface.h
new file mode 100644
index 0000000000..79f0c3bbea
--- /dev/null
+++ b/gfx/ipc/SharedDIBSurface.h
@@ -0,0 +1,62 @@
+/* -*- Mode: C++; tab-width: 2; 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/. */
+
+#ifndef mozilla_gfx_SharedDIBSurface_h
+#define mozilla_gfx_SharedDIBSurface_h
+
+#include "gfxImageSurface.h"
+#include "SharedDIBWin.h"
+
+#include <windows.h>
+
+namespace mozilla {
+namespace gfx {
+
+/**
+ * A SharedDIBSurface owns an underlying SharedDIBWin.
+ */
+class SharedDIBSurface : public gfxImageSurface
+{
+public:
+ typedef base::SharedMemoryHandle Handle;
+
+ SharedDIBSurface() { }
+ ~SharedDIBSurface() { }
+
+ /**
+ * Create this image surface backed by shared memory.
+ */
+ bool Create(HDC adc, uint32_t aWidth, uint32_t aHeight, bool aTransparent);
+
+ /**
+ * Attach this surface to shared memory from another process.
+ */
+ bool Attach(Handle aHandle, uint32_t aWidth, uint32_t aHeight,
+ bool aTransparent);
+
+ /**
+ * After drawing to a surface via GDI, GDI must be flushed before the bitmap
+ * is valid.
+ */
+ void Flush() { ::GdiFlush(); }
+
+ HDC GetHDC() { return mSharedDIB.GetHDC(); }
+
+ nsresult ShareToProcess(base::ProcessId aTargetPid, Handle* aNewHandle) {
+ return mSharedDIB.ShareToProcess(aTargetPid, aNewHandle);
+ }
+
+ static bool IsSharedDIBSurface(gfxASurface* aSurface);
+
+private:
+ SharedDIBWin mSharedDIB;
+
+ void InitSurface(uint32_t aWidth, uint32_t aHeight, bool aTransparent);
+};
+
+} // namespace gfx
+} // namespace mozilla
+
+#endif // mozilla_gfx_SharedDIBSurface_h
diff --git a/gfx/ipc/SharedDIBWin.cpp b/gfx/ipc/SharedDIBWin.cpp
new file mode 100644
index 0000000000..197e197d41
--- /dev/null
+++ b/gfx/ipc/SharedDIBWin.cpp
@@ -0,0 +1,139 @@
+/* -*- Mode: C++; tab-width: 2; 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/. */
+
+#include "SharedDIBWin.h"
+#include "gfxAlphaRecovery.h"
+#include "nsMathUtils.h"
+#include "nsDebug.h"
+
+namespace mozilla {
+namespace gfx {
+
+static const uint32_t kByteAlign = 1 << gfxAlphaRecovery::GoodAlignmentLog2();
+static const uint32_t kHeaderBytes =
+ (uint32_t(sizeof(BITMAPV4HEADER)) + kByteAlign - 1) & ~(kByteAlign - 1);
+
+SharedDIBWin::SharedDIBWin() :
+ mSharedHdc(nullptr)
+ , mSharedBmp(nullptr)
+ , mOldObj(nullptr)
+{
+}
+
+SharedDIBWin::~SharedDIBWin()
+{
+ Close();
+}
+
+nsresult
+SharedDIBWin::Close()
+{
+ if (mSharedHdc && mOldObj)
+ ::SelectObject(mSharedHdc, mOldObj);
+
+ if (mSharedHdc)
+ ::DeleteObject(mSharedHdc);
+
+ if (mSharedBmp)
+ ::DeleteObject(mSharedBmp);
+
+ mSharedHdc = nullptr;
+ mOldObj = mSharedBmp = nullptr;
+
+ SharedDIB::Close();
+
+ return NS_OK;
+}
+
+nsresult
+SharedDIBWin::Create(HDC aHdc, uint32_t aWidth, uint32_t aHeight,
+ bool aTransparent)
+{
+ Close();
+
+ // create the offscreen shared dib
+ BITMAPV4HEADER bmih;
+ uint32_t size = SetupBitmapHeader(aWidth, aHeight, aTransparent, &bmih);
+
+ nsresult rv = SharedDIB::Create(size);
+ if (NS_FAILED(rv))
+ return rv;
+
+ if (NS_FAILED(SetupSurface(aHdc, &bmih))) {
+ Close();
+ return NS_ERROR_FAILURE;
+ }
+
+ return NS_OK;
+}
+
+nsresult
+SharedDIBWin::Attach(Handle aHandle, uint32_t aWidth, uint32_t aHeight,
+ bool aTransparent)
+{
+ Close();
+
+ BITMAPV4HEADER bmih;
+ SetupBitmapHeader(aWidth, aHeight, aTransparent, &bmih);
+
+ nsresult rv = SharedDIB::Attach(aHandle, 0);
+ if (NS_FAILED(rv))
+ return rv;
+
+ if (NS_FAILED(SetupSurface(nullptr, &bmih))) {
+ Close();
+ return NS_ERROR_FAILURE;
+ }
+
+ return NS_OK;
+}
+
+uint32_t
+SharedDIBWin::SetupBitmapHeader(uint32_t aWidth, uint32_t aHeight,
+ bool aTransparent, BITMAPV4HEADER *aHeader)
+{
+ // D3D cannot handle an offscreen memory that pitch (SysMemPitch) is negative.
+ // So we create top-to-bottom DIB.
+ memset((void*)aHeader, 0, sizeof(BITMAPV4HEADER));
+ aHeader->bV4Size = sizeof(BITMAPV4HEADER);
+ aHeader->bV4Width = aWidth;
+ aHeader->bV4Height = -LONG(aHeight); // top-to-buttom DIB
+ aHeader->bV4Planes = 1;
+ aHeader->bV4BitCount = 32;
+ aHeader->bV4V4Compression = BI_BITFIELDS;
+ aHeader->bV4RedMask = 0x00FF0000;
+ aHeader->bV4GreenMask = 0x0000FF00;
+ aHeader->bV4BlueMask = 0x000000FF;
+
+ if (aTransparent)
+ aHeader->bV4AlphaMask = 0xFF000000;
+
+ return (kHeaderBytes + (-aHeader->bV4Height * aHeader->bV4Width * kBytesPerPixel));
+}
+
+nsresult
+SharedDIBWin::SetupSurface(HDC aHdc, BITMAPV4HEADER *aHdr)
+{
+ mSharedHdc = ::CreateCompatibleDC(aHdc);
+
+ if (!mSharedHdc)
+ return NS_ERROR_FAILURE;
+
+ mSharedBmp = ::CreateDIBSection(mSharedHdc,
+ (BITMAPINFO*)aHdr,
+ DIB_RGB_COLORS,
+ &mBitmapBits,
+ mShMem->handle(),
+ kHeaderBytes);
+ if (!mSharedBmp)
+ return NS_ERROR_FAILURE;
+
+ mOldObj = SelectObject(mSharedHdc, mSharedBmp);
+
+ return NS_OK;
+}
+
+} // gfx
+} // mozilla
diff --git a/gfx/ipc/SharedDIBWin.h b/gfx/ipc/SharedDIBWin.h
new file mode 100644
index 0000000000..06759662b2
--- /dev/null
+++ b/gfx/ipc/SharedDIBWin.h
@@ -0,0 +1,56 @@
+/* -*- Mode: C++; tab-width: 2; 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/. */
+
+#ifndef gfx_SharedDIBWin_h__
+#define gfx_SharedDIBWin_h__
+
+#include <windows.h>
+
+#include "SharedDIB.h"
+
+namespace mozilla {
+namespace gfx {
+
+class SharedDIBWin : public SharedDIB
+{
+public:
+ SharedDIBWin();
+ ~SharedDIBWin();
+
+ // Allocate a new win32 dib section compatible with an hdc. The dib will
+ // be selected into the hdc on return.
+ nsresult Create(HDC aHdc, uint32_t aWidth, uint32_t aHeight,
+ bool aTransparent);
+
+ // Wrap a dib section around an existing shared memory object. aHandle should
+ // point to a section large enough for the dib's memory, otherwise this call
+ // will fail.
+ nsresult Attach(Handle aHandle, uint32_t aWidth, uint32_t aHeight,
+ bool aTransparent);
+
+ // Destroy or release resources associated with this dib.
+ nsresult Close();
+
+ // Return the HDC of the shared dib.
+ HDC GetHDC() { return mSharedHdc; }
+
+ // Return the bitmap bits.
+ void* GetBits() { return mBitmapBits; }
+
+private:
+ HDC mSharedHdc;
+ HBITMAP mSharedBmp;
+ HGDIOBJ mOldObj;
+ void* mBitmapBits;
+
+ uint32_t SetupBitmapHeader(uint32_t aWidth, uint32_t aHeight,
+ bool aTransparent, BITMAPV4HEADER *aHeader);
+ nsresult SetupSurface(HDC aHdc, BITMAPV4HEADER *aHdr);
+};
+
+} // gfx
+} // mozilla
+
+#endif
diff --git a/gfx/ipc/VsyncBridgeChild.cpp b/gfx/ipc/VsyncBridgeChild.cpp
new file mode 100644
index 0000000000..a4be827ef9
--- /dev/null
+++ b/gfx/ipc/VsyncBridgeChild.cpp
@@ -0,0 +1,155 @@
+/* -*- 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"
+#include "mozilla/dom/ContentChild.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)) {
+ // 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();
+}
+
+class NotifyVsyncTask : public Runnable
+{
+public:
+ NotifyVsyncTask(RefPtr<VsyncBridgeChild> aVsyncBridge,
+ TimeStamp aTimeStamp,
+ const uint64_t& aLayersId)
+ : mVsyncBridge(aVsyncBridge),
+ mTimeStamp(aTimeStamp),
+ mLayersId(aLayersId)
+ {}
+
+ NS_IMETHOD Run() override {
+ mVsyncBridge->NotifyVsyncImpl(mTimeStamp, mLayersId);
+ return NS_OK;
+ }
+
+private:
+ RefPtr<VsyncBridgeChild> mVsyncBridge;
+ TimeStamp mTimeStamp;
+ uint64_t mLayersId;
+};
+
+bool
+VsyncBridgeChild::IsOnVsyncIOThread() const
+{
+ return MessageLoop::current() == mLoop;
+}
+
+void
+VsyncBridgeChild::NotifyVsync(TimeStamp aTimeStamp, const uint64_t& aLayersId)
+{
+ // This should be on the Vsync thread (not the Vsync I/O thread).
+ MOZ_ASSERT(!IsOnVsyncIOThread());
+
+ RefPtr<NotifyVsyncTask> task = new NotifyVsyncTask(this, aTimeStamp, aLayersId);
+ mLoop->PostTask(task.forget());
+}
+
+void
+VsyncBridgeChild::NotifyVsyncImpl(TimeStamp aTimeStamp, const uint64_t& aLayersId)
+{
+ // This should be on the Vsync I/O thread.
+ MOZ_ASSERT(IsOnVsyncIOThread());
+
+ if (!mProcessToken) {
+ return;
+ }
+ SendNotifyVsync(aTimeStamp, aLayersId);
+}
+
+void
+VsyncBridgeChild::Close()
+{
+ if (!IsOnVsyncIOThread()) {
+ mLoop->PostTask(NewRunnableMethod(this, &VsyncBridgeChild::Close));
+ return;
+ }
+
+ // We clear mProcessToken when the channel is closed.
+ if (!mProcessToken) {
+ return;
+ }
+
+ // Clear the process token so we don't notify the GPUProcessManager. It already
+ // knows we're closed since it manually called Close, and in fact the GPM could
+ // have already been destroyed during shutdown.
+ mProcessToken = 0;
+
+ // Close the underlying IPC channel.
+ PVsyncBridgeChild::Close();
+}
+
+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");
+}
+
+void
+VsyncBridgeChild::HandleFatalError(const char* aName, const char* aMsg) const
+{
+ dom::ContentChild::FatalErrorIfNotUsingGPUProcess(aName, aMsg, OtherPid());
+}
+
+} // namespace gfx
+} // namespace mozilla
diff --git a/gfx/ipc/VsyncBridgeChild.h b/gfx/ipc/VsyncBridgeChild.h
new file mode 100644
index 0000000000..8661380628
--- /dev/null
+++ b/gfx/ipc/VsyncBridgeChild.h
@@ -0,0 +1,57 @@
+/* -*- 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
+{
+ friend class NotifyVsyncTask;
+
+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;
+
+ void NotifyVsync(TimeStamp aTimeStamp, const uint64_t& aLayersId);
+
+ virtual void HandleFatalError(const char* aName, const char* aMsg) const override;
+
+private:
+ VsyncBridgeChild(RefPtr<VsyncIOThreadHolder>, const uint64_t& aProcessToken);
+ ~VsyncBridgeChild();
+
+ void Open(Endpoint<PVsyncBridgeChild>&& aEndpoint);
+
+ void NotifyVsyncImpl(TimeStamp aTimeStamp, const uint64_t& aLayersId);
+
+ bool IsOnVsyncIOThread() const;
+
+private:
+ RefPtr<VsyncIOThreadHolder> mThread;
+ MessageLoop* mLoop;
+ uint64_t mProcessToken;
+};
+
+} // namespace gfx
+} // namespace mozilla
+
+#endif // include_gfx_ipc_VsyncBridgeChild_h
diff --git a/gfx/ipc/VsyncBridgeParent.cpp b/gfx/ipc/VsyncBridgeParent.cpp
new file mode 100644
index 0000000000..96ef5de0ff
--- /dev/null
+++ b/gfx/ipc/VsyncBridgeParent.cpp
@@ -0,0 +1,87 @@
+/* -*- 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)) {
+ // We can't recover from this.
+ MOZ_CRASH("Failed to bind VsyncBridgeParent to endpoint");
+ }
+ AddRef();
+ mOpen = true;
+}
+
+bool
+VsyncBridgeParent::RecvNotifyVsync(const TimeStamp& aTimeStamp, const uint64_t& aLayersId)
+{
+ CompositorBridgeParent::NotifyVsync(aTimeStamp, aLayersId);
+ return true;
+}
+
+void
+VsyncBridgeParent::Shutdown()
+{
+ MessageLoop* ccloop = CompositorThreadHolder::Loop();
+ if (MessageLoop::current() != ccloop) {
+ ccloop->PostTask(NewRunnableMethod(this, &VsyncBridgeParent::ShutdownImpl));
+ return;
+ }
+
+ ShutdownImpl();
+}
+
+void
+VsyncBridgeParent::ShutdownImpl()
+{
+ if (mOpen) {
+ Close();
+ mOpen = false;
+ }
+}
+
+void
+VsyncBridgeParent::ActorDestroy(ActorDestroyReason aWhy)
+{
+ mOpen = false;
+}
+
+void
+VsyncBridgeParent::DeallocPVsyncBridgeParent()
+{
+ Release();
+}
+
+} // namespace gfx
+} // namespace mozilla
diff --git a/gfx/ipc/VsyncBridgeParent.h b/gfx/ipc/VsyncBridgeParent.h
new file mode 100644
index 0000000000..c194843eeb
--- /dev/null
+++ b/gfx/ipc/VsyncBridgeParent.h
@@ -0,0 +1,42 @@
+/* -*- 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, const uint64_t& aLayersId) override;
+ void ActorDestroy(ActorDestroyReason aWhy) override;
+ void DeallocPVsyncBridgeParent() override;
+
+ void Shutdown();
+
+private:
+ VsyncBridgeParent();
+ ~VsyncBridgeParent();
+
+ void Open(Endpoint<PVsyncBridgeParent>&& aEndpoint);
+ void ShutdownImpl();
+
+private:
+ bool mOpen;
+};
+
+} // namespace gfx
+} // namespace mozilla
+
+#endif // include_gfx_ipc_VsyncBridgeParent_h
diff --git a/gfx/ipc/VsyncIOThreadHolder.cpp b/gfx/ipc/VsyncIOThreadHolder.cpp
new file mode 100644
index 0000000000..8730b72131
--- /dev/null
+++ b/gfx/ipc/VsyncIOThreadHolder.cpp
@@ -0,0 +1,46 @@
+/* -*- 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()
+{
+ MOZ_COUNT_CTOR(VsyncIOThreadHolder);
+}
+
+VsyncIOThreadHolder::~VsyncIOThreadHolder()
+{
+ MOZ_COUNT_DTOR(VsyncIOThreadHolder);
+
+ if (!mThread) {
+ return;
+ }
+
+ if (NS_IsMainThread()) {
+ mThread->AsyncShutdown();
+ } else {
+ 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
diff --git a/gfx/ipc/VsyncIOThreadHolder.h b/gfx/ipc/VsyncIOThreadHolder.h
new file mode 100644
index 0000000000..e34f2896a8
--- /dev/null
+++ b/gfx/ipc/VsyncIOThreadHolder.h
@@ -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
diff --git a/gfx/ipc/moz.build b/gfx/ipc/moz.build
new file mode 100644
index 0000000000..ff3a812289
--- /dev/null
+++ b/gfx/ipc/moz.build
@@ -0,0 +1,82 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
+EXPORTS.mozilla += [
+ 'D3DMessageUtils.h',
+ 'GfxMessageUtils.h'
+]
+
+EXPORTS.mozilla.gfx += [
+ 'GPUChild.h',
+ 'GPUParent.h',
+ 'GPUProcessHost.h',
+ 'GPUProcessImpl.h',
+ 'GPUProcessListener.h',
+ 'GPUProcessManager.h',
+ 'SharedDIB.h',
+ 'VsyncBridgeChild.h',
+ 'VsyncBridgeParent.h',
+ 'VsyncIOThreadHolder.h',
+]
+
+EXPORTS.mozilla.layers += [
+ 'CompositorSession.h',
+ 'InProcessCompositorSession.h',
+ 'RemoteCompositorSession.h',
+]
+
+EXPORTS.mozilla.widget += [
+ 'CompositorWidgetVsyncObserver.h',
+]
+
+if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
+ EXPORTS.mozilla.gfx += [
+ 'SharedDIBSurface.h',
+ 'SharedDIBWin.h',
+ ]
+ UNIFIED_SOURCES += [
+ 'SharedDIBSurface.cpp',
+ 'SharedDIBWin.cpp',
+ ]
+
+UNIFIED_SOURCES += [
+ 'CompositorSession.cpp',
+ 'CompositorWidgetVsyncObserver.cpp',
+ 'D3DMessageUtils.cpp',
+ 'GPUChild.cpp',
+ 'GPUProcessHost.cpp',
+ 'GPUProcessImpl.cpp',
+ 'GPUProcessManager.cpp',
+ 'InProcessCompositorSession.cpp',
+ 'RemoteCompositorSession.cpp',
+ 'SharedDIB.cpp',
+ 'VsyncBridgeChild.cpp',
+ 'VsyncBridgeParent.cpp',
+ 'VsyncIOThreadHolder.cpp',
+]
+
+SOURCES += [
+ 'GPUParent.cpp',
+]
+
+IPDL_SOURCES = [
+ 'GraphicsMessages.ipdlh',
+ 'PGPU.ipdl',
+ 'PVsyncBridge.ipdl',
+]
+
+LOCAL_INCLUDES += [
+ '/dom/ipc',
+ '/toolkit/crashreporter',
+ '/xpcom/threads',
+]
+
+include('/ipc/chromium/chromium-config.mozbuild')
+
+FINAL_LIBRARY = 'xul'
+
+CXXFLAGS += CONFIG['MOZ_CAIRO_CFLAGS']
+CXXFLAGS += CONFIG['TK_CFLAGS']