From 5f8de423f190bbb79a62f804151bc24824fa32d8 Mon Sep 17 00:00:00 2001
From: "Matt A. Tobin" <mattatobin@localhost.localdomain>
Date: Fri, 2 Feb 2018 04:16:08 -0500
Subject: Add m-esr52 at 52.6.0

---
 gfx/ipc/CompositorSession.cpp             |   41 +
 gfx/ipc/CompositorSession.h               |   92 +++
 gfx/ipc/CompositorWidgetVsyncObserver.cpp |   35 +
 gfx/ipc/CompositorWidgetVsyncObserver.h   |   37 +
 gfx/ipc/D3DMessageUtils.cpp               |   81 ++
 gfx/ipc/D3DMessageUtils.h                 |   48 ++
 gfx/ipc/GPUChild.cpp                      |  203 +++++
 gfx/ipc/GPUChild.h                        |   59 ++
 gfx/ipc/GPUParent.cpp                     |  390 +++++++++
 gfx/ipc/GPUParent.h                       |   62 ++
 gfx/ipc/GPUProcessHost.cpp                |  247 ++++++
 gfx/ipc/GPUProcessHost.h                  |  146 ++++
 gfx/ipc/GPUProcessImpl.cpp                |   39 +
 gfx/ipc/GPUProcessImpl.h                  |   44 +
 gfx/ipc/GPUProcessListener.h              |   27 +
 gfx/ipc/GPUProcessManager.cpp             |  852 +++++++++++++++++++
 gfx/ipc/GPUProcessManager.h               |  234 ++++++
 gfx/ipc/GfxMessageUtils.h                 | 1273 +++++++++++++++++++++++++++++
 gfx/ipc/GraphicsMessages.ipdlh            |   87 ++
 gfx/ipc/InProcessCompositorSession.cpp    |   83 ++
 gfx/ipc/InProcessCompositorSession.h      |   49 ++
 gfx/ipc/PGPU.ipdl                         |  106 +++
 gfx/ipc/PVsyncBridge.ipdl                 |   22 +
 gfx/ipc/RemoteCompositorSession.cpp       |  112 +++
 gfx/ipc/RemoteCompositorSession.h         |   46 ++
 gfx/ipc/SharedDIB.cpp                     |   77 ++
 gfx/ipc/SharedDIB.h                       |   50 ++
 gfx/ipc/SharedDIBSurface.cpp              |   63 ++
 gfx/ipc/SharedDIBSurface.h                |   62 ++
 gfx/ipc/SharedDIBWin.cpp                  |  139 ++++
 gfx/ipc/SharedDIBWin.h                    |   56 ++
 gfx/ipc/VsyncBridgeChild.cpp              |  155 ++++
 gfx/ipc/VsyncBridgeChild.h                |   57 ++
 gfx/ipc/VsyncBridgeParent.cpp             |   87 ++
 gfx/ipc/VsyncBridgeParent.h               |   42 +
 gfx/ipc/VsyncIOThreadHolder.cpp           |   46 ++
 gfx/ipc/VsyncIOThreadHolder.h             |   37 +
 gfx/ipc/moz.build                         |   82 ++
 38 files changed, 5368 insertions(+)
 create mode 100644 gfx/ipc/CompositorSession.cpp
 create mode 100644 gfx/ipc/CompositorSession.h
 create mode 100644 gfx/ipc/CompositorWidgetVsyncObserver.cpp
 create mode 100644 gfx/ipc/CompositorWidgetVsyncObserver.h
 create mode 100644 gfx/ipc/D3DMessageUtils.cpp
 create mode 100644 gfx/ipc/D3DMessageUtils.h
 create mode 100644 gfx/ipc/GPUChild.cpp
 create mode 100644 gfx/ipc/GPUChild.h
 create mode 100644 gfx/ipc/GPUParent.cpp
 create mode 100644 gfx/ipc/GPUParent.h
 create mode 100644 gfx/ipc/GPUProcessHost.cpp
 create mode 100644 gfx/ipc/GPUProcessHost.h
 create mode 100644 gfx/ipc/GPUProcessImpl.cpp
 create mode 100644 gfx/ipc/GPUProcessImpl.h
 create mode 100644 gfx/ipc/GPUProcessListener.h
 create mode 100644 gfx/ipc/GPUProcessManager.cpp
 create mode 100644 gfx/ipc/GPUProcessManager.h
 create mode 100644 gfx/ipc/GfxMessageUtils.h
 create mode 100644 gfx/ipc/GraphicsMessages.ipdlh
 create mode 100644 gfx/ipc/InProcessCompositorSession.cpp
 create mode 100644 gfx/ipc/InProcessCompositorSession.h
 create mode 100644 gfx/ipc/PGPU.ipdl
 create mode 100644 gfx/ipc/PVsyncBridge.ipdl
 create mode 100644 gfx/ipc/RemoteCompositorSession.cpp
 create mode 100644 gfx/ipc/RemoteCompositorSession.h
 create mode 100644 gfx/ipc/SharedDIB.cpp
 create mode 100644 gfx/ipc/SharedDIB.h
 create mode 100644 gfx/ipc/SharedDIBSurface.cpp
 create mode 100644 gfx/ipc/SharedDIBSurface.h
 create mode 100644 gfx/ipc/SharedDIBWin.cpp
 create mode 100644 gfx/ipc/SharedDIBWin.h
 create mode 100644 gfx/ipc/VsyncBridgeChild.cpp
 create mode 100644 gfx/ipc/VsyncBridgeChild.h
 create mode 100644 gfx/ipc/VsyncBridgeParent.cpp
 create mode 100644 gfx/ipc/VsyncBridgeParent.h
 create mode 100644 gfx/ipc/VsyncIOThreadHolder.cpp
 create mode 100644 gfx/ipc/VsyncIOThreadHolder.h
 create mode 100644 gfx/ipc/moz.build

(limited to 'gfx/ipc')

diff --git a/gfx/ipc/CompositorSession.cpp b/gfx/ipc/CompositorSession.cpp
new file mode 100644
index 000000000..b200b341c
--- /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 000000000..6205725c5
--- /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 000000000..767dc9da4
--- /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 000000000..c13662474
--- /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 000000000..f3895fdae
--- /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 000000000..0dc9b4843
--- /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 000000000..72328ac0b
--- /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 000000000..c0f7d076f
--- /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 000000000..d63e17e2f
--- /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 000000000..126efce50
--- /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 000000000..613f353a4
--- /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 000000000..d5c19f35d
--- /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 000000000..38d13484b
--- /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 000000000..5e8b6694a
--- /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 000000000..d69e912de
--- /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 000000000..0b55cd9b7
--- /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 000000000..84ed03609
--- /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 000000000..e45aa7040
--- /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 000000000..cc4115d42
--- /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 000000000..fd8525085
--- /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 000000000..deb642da2
--- /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 000000000..c442335c9
--- /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 000000000..03c68bbde
--- /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 000000000..6e5ad975a
--- /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 000000000..b4731c5c2
--- /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 000000000..ec68a61fa
--- /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 000000000..6c48b2875
--- /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 000000000..696bb300c
--- /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 000000000..79f0c3bbe
--- /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 000000000..197e197d4
--- /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 000000000..06759662b
--- /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 000000000..a4be827ef
--- /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 000000000..866138062
--- /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 000000000..96ef5de0f
--- /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 000000000..c194843ee
--- /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 000000000..8730b7213
--- /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 000000000..e34f2896a
--- /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 000000000..ff3a81228
--- /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']
-- 
cgit v1.2.3