Communicate GPU process device information across processes. (bug 1294988 part 5, r=mattwoodrow)
authorDavid Anderson <danderson@mozilla.com>
Sat, 20 Aug 2016 20:59:11 -0700
changeset 336256 6c00e4ee0d0cda70c0573352e7070130d7ec2767
parent 336255 ecd47b2b03d4c3698b79c45805528a5b4b352693
child 336257 627439e91cb90047f21d28eb1f5a241789ee8712
push id10033
push userraliiev@mozilla.com
push dateMon, 19 Sep 2016 13:50:26 +0000
treeherdermozilla-aurora@5dddbefdf759 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmattwoodrow
bugs1294988
milestone51.0a1
Communicate GPU process device information across processes. (bug 1294988 part 5, r=mattwoodrow)
gfx/config/gfxConfig.cpp
gfx/config/gfxConfig.h
gfx/config/gfxFeature.cpp
gfx/config/gfxFeature.h
gfx/ipc/GPUChild.cpp
gfx/ipc/GPUChild.h
gfx/ipc/GPUParent.cpp
gfx/ipc/GPUParent.h
gfx/ipc/GPUProcessManager.cpp
gfx/ipc/GraphicsMessages.ipdlh
gfx/ipc/PGPU.ipdl
gfx/thebes/DeviceManagerD3D11.cpp
gfx/thebes/gfxPlatform.cpp
gfx/thebes/gfxPlatform.h
gfx/thebes/gfxWindowsPlatform.cpp
gfx/thebes/gfxWindowsPlatform.h
--- a/gfx/config/gfxConfig.cpp
+++ b/gfx/config/gfxConfig.cpp
@@ -1,15 +1,16 @@
 /* -*- Mode: C++; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* vim: set sts=2 ts=8 sw=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 "gfxConfig.h"
 #include "mozilla/UniquePtr.h"
+#include "mozilla/gfx/GraphicsMessages.h"
 #include "plstr.h"
 
 namespace mozilla {
 namespace gfx {
 
 static UniquePtr<gfxConfig> sConfig;
 
 /* static */ FeatureState&
@@ -245,24 +246,39 @@ void
 gfxConfig::ForEachFallbackImpl(const FallbackIterCallback& aCallback)
 {
   for (size_t i = 0; i < mNumFallbackLogEntries; i++) {
     const FallbackLogEntry& entry = mFallbackLog[i];
     aCallback(sFallbackNames[size_t(entry.mFallback)], entry.mMessage);
   }
 }
 
-/* static */ const nsACString&
+/* static */ const nsCString&
 gfxConfig::GetFailureId(Feature aFeature)
 {
   const FeatureState& state = sConfig->GetState(aFeature);
   return state.GetFailureId();
 }
 
 /* static */ void
+gfxConfig::ImportChange(Feature aFeature, const FeatureChange& aChange)
+{
+  if (aChange.type() == FeatureChange::Tnull_t) {
+    return;
+  }
+
+  const FeatureFailure& failure = aChange.get_FeatureFailure();
+  gfxConfig::SetFailed(
+    aFeature,
+    failure.status(),
+    failure.message().get(),
+    failure.failureId());
+}
+
+/* static */ void
 gfxConfig::Init()
 {
   sConfig = mozilla::MakeUnique<gfxConfig>();
 }
 
 /* static */ void
 gfxConfig::Shutdown()
 {
--- a/gfx/config/gfxConfig.h
+++ b/gfx/config/gfxConfig.h
@@ -9,16 +9,19 @@
 #include "gfxFeature.h"
 #include "gfxFallback.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/Function.h"
 
 namespace mozilla {
 namespace gfx {
 
+// Defined in GraphicsMessages.ipdlh.
+class FeatureChange;
+
 // Manages the history and state of a graphics feature. The flow of a feature
 // is:
 //   - A default value, set by all.js, gfxPrefs, or gfxPlatform.
 //   - A user value, set by an external value or user pref.
 //   - An environment value, determined by system/hardware factors or nsIGfxInfo.
 //   - A runtime value, determined by any failures encountered after enabling
 //     the feature.
 //
@@ -39,16 +42,19 @@ public:
   //  5. Return the base setting for the feature.
   static bool IsEnabled(Feature aFeature);
 
   // Query the history of a parameter. ForcedOnByUser returns whether or not
   // the user specifically used a "force" preference to enable the parameter.
   // IsDisabledByDefault returns whether or not the initial status of the
   // feature, before adding user prefs and runtime decisions, was disabled.
   static bool IsForcedOnByUser(Feature aFeature);
+
+  // This returns true if the feature was disabled by default, or was never
+  // initialized to begin with.
   static bool IsDisabledByDefault(Feature aFeature);
 
   // Query the status value of a parameter. This is computed similar to
   // IsEnabled:
   //
   //  1. If a runtime failure was set, return it.
   //  2. If the user force-enabled the feature, return ForceEnabled.
   //  3. If an environment status was set, return it.
@@ -168,17 +174,19 @@ public:
   static void ForEachFeature(const FeatureIterCallback& aCallback);
 
   // Run a callback for each enabled fallback.
   typedef mozilla::function<void(const char* aName, const char* aMsg)> 
     FallbackIterCallback;
   static void ForEachFallback(const FallbackIterCallback& aCallback);
 
   // Get the most descriptive failure id message for this feature.
-  static const nsACString& GetFailureId(Feature aFeature);
+  static const nsCString& GetFailureId(Feature aFeature);
+
+  static void ImportChange(Feature aFeature, const FeatureChange& aChange);
 
   static void Init();
   static void Shutdown();
 
 private:
   void ForEachFallbackImpl(const FallbackIterCallback& aCallback);
 
 private:
--- a/gfx/config/gfxFeature.cpp
+++ b/gfx/config/gfxFeature.cpp
@@ -155,17 +155,16 @@ FeatureState::MaybeSetFailed(FeatureStat
 {
   return MaybeSetFailed(IsFeatureStatusSuccess(aStatus), aStatus, aMessage,
                         aFailureId);
 }
 
 bool
 FeatureState::DisabledByDefault() const
 {
-  AssertInitialized();
   return mDefault.mStatus != FeatureStatus::Available;
 }
 
 bool
 FeatureState::IsForcedOnByUser() const
 {
   AssertInitialized();
   return mUser.mStatus == FeatureStatus::ForceEnabled;
@@ -251,17 +250,43 @@ FeatureState::ForEachStatusChange(const 
 void
 FeatureState::SetFailureId(const nsACString& aFailureId)
 {
   if (mFailureId.IsEmpty()) {
     mFailureId = aFailureId;
   }
 }
 
-const nsACString&
+const char*
+FeatureState::GetFailureMessage() const
+{
+  AssertInitialized();
+  MOZ_ASSERT(!IsEnabled());
+
+  if (mRuntime.mStatus != FeatureStatus::Unused &&
+      IsFeatureStatusFailure(mRuntime.mStatus))
+  {
+    return mRuntime.mMessage;
+  }
+  if (mEnvironment.mStatus != FeatureStatus::Unused &&
+      IsFeatureStatusFailure(mEnvironment.mStatus))
+  {
+    return mEnvironment.mMessage;
+  }
+  if (mUser.mStatus != FeatureStatus::Unused &&
+      IsFeatureStatusFailure(mUser.mStatus))
+  {
+    return mUser.mMessage;
+  }
+
+  MOZ_ASSERT(IsFeatureStatusFailure(mDefault.mStatus));
+  return mDefault.mMessage;
+}
+
+const nsCString&
 FeatureState::GetFailureId() const
 {
   MOZ_ASSERT(!IsEnabled());
   return mFailureId;
 }
 
 void
 FeatureState::Reset()
--- a/gfx/config/gfxFeature.h
+++ b/gfx/config/gfxFeature.h
@@ -63,24 +63,26 @@ class FeatureState
 
   // aType is "base", "user", "env", or "runtime".
   // aMessage may be null.
   typedef mozilla::function<void(const char* aType,
                                  FeatureStatus aStatus,
                                  const char* aMessage)> StatusIterCallback;
   void ForEachStatusChange(const StatusIterCallback& aCallback) const;
 
-  const nsACString& GetFailureId() const;
+  const char* GetFailureMessage() const;
+  const nsCString& GetFailureId() const;
+
+  bool DisabledByDefault() const;
 
  private:
   void SetUser(FeatureStatus aStatus, const char* aMessage);
   void SetEnvironment(FeatureStatus aStatus, const char* aMessage);
   void SetRuntime(FeatureStatus aStatus, const char* aMessage);
   bool IsForcedOnByUser() const;
-  bool DisabledByDefault() const;
   const char* GetRuntimeMessage() const;
   bool IsInitialized() const {
     return mDefault.IsInitialized();
   }
 
   void AssertInitialized() const {
     MOZ_ASSERT(IsInitialized());
   }
--- a/gfx/ipc/GPUChild.cpp
+++ b/gfx/ipc/GPUChild.cpp
@@ -3,22 +3,26 @@
 /* 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 "mozilla/gfx/gfxVars.h"
+#if defined(XP_WIN)
+# include "mozilla/gfx/DeviceManagerD3D11.h"
+#endif
 
 namespace mozilla {
 namespace gfx {
 
 GPUChild::GPUChild(GPUProcessHost* aHost)
- : mHost(aHost)
+ : mHost(aHost),
+   mGPUReady(false)
 {
   MOZ_COUNT_CTOR(GPUChild);
 }
 
 GPUChild::~GPUChild()
 {
   MOZ_COUNT_DTOR(GPUChild);
 }
@@ -58,16 +62,43 @@ GPUChild::Init()
 
 void
 GPUChild::OnVarChanged(const GfxVarUpdate& aVar)
 {
   SendUpdateVar(aVar);
 }
 
 void
+GPUChild::EnsureGPUReady()
+{
+  if (mGPUReady) {
+    return;
+  }
+
+  GPUDeviceData data;
+  SendGetDeviceStatus(&data);
+
+  gfxPlatform::GetPlatform()->ImportGPUDeviceData(data);
+  mGPUReady = true;
+}
+
+bool
+GPUChild::RecvInitComplete(const GPUDeviceData& aData)
+{
+  // We synchronously requested GPU parameters before this arrived.
+  if (mGPUReady) {
+    return true;
+  }
+
+  gfxPlatform::GetPlatform()->ImportGPUDeviceData(aData);
+  mGPUReady = true;
+  return true;
+}
+
+void
 GPUChild::ActorDestroy(ActorDestroyReason aWhy)
 {
   gfxVars::RemoveReceiver(this);
   mHost->OnChannelClosed();
 }
 
 class DeferredDeleteGPUChild : public Runnable
 {
--- a/gfx/ipc/GPUChild.h
+++ b/gfx/ipc/GPUChild.h
@@ -21,24 +21,28 @@ class GPUChild final
     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;
   void ActorDestroy(ActorDestroyReason aWhy) override;
 
   static void Destroy(UniquePtr<GPUChild>&& aChild);
 
 private:
   GPUProcessHost* mHost;
+  bool mGPUReady;
 };
 
 } // namespace gfx
 } // namespace mozilla
 
 #endif // _include_mozilla_gfx_ipc_GPUChild_h_
--- a/gfx/ipc/GPUParent.cpp
+++ b/gfx/ipc/GPUParent.cpp
@@ -79,16 +79,21 @@ GPUParent::RecvInit(nsTArray<GfxPrefSett
   gfxConfig::Inherit(Feature::DIRECT2D, devicePrefs.useD2D1());
 
 #if defined(XP_WIN)
   if (gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) {
     DeviceManagerD3D11::Get()->CreateCompositorDevices();
   }
 #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)
 {
   VsyncBridgeParent::Start(Move(aVsyncEndpoint));
   return true;
@@ -119,16 +124,53 @@ GPUParent::RecvUpdatePref(const GfxPrefS
 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 (DeviceManagerD3D11* dm = DeviceManagerD3D11::Get()) {
+    dm->ExportDeviceInfo(&aOut->d3d11Device());
+  }
+#endif
+
+  return true;
+}
+
+static void
 OpenParent(RefPtr<CompositorBridgeParent> aParent,
            Endpoint<PCompositorBridgeParent>&& aEndpoint)
 {
   if (!aParent->Bind(Move(aEndpoint))) {
     MOZ_CRASH("Failed to bind compositor");
   }
 }
 
--- a/gfx/ipc/GPUParent.h
+++ b/gfx/ipc/GPUParent.h
@@ -37,16 +37,17 @@ public:
     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 RecvDeallocateLayerTreeId(const uint64_t& aLayersId) override;
+  bool RecvGetDeviceStatus(GPUDeviceData* aOutStatus) override;
 
   void ActorDestroy(ActorDestroyReason aWhy) override;
 
 private:
   RefPtr<VsyncBridgeParent> mVsyncBridge;
 };
 
 } // namespace gfx
--- a/gfx/ipc/GPUProcessManager.cpp
+++ b/gfx/ipc/GPUProcessManager.cpp
@@ -129,25 +129,31 @@ 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::IsCreated()) {
     return;
   }
 
+  EnsureGPUReady();
+
   if (!mGPUChild) {
     ImageBridgeChild::InitSameProcess();
     return;
   }
 
   ipc::Endpoint<PImageBridgeParent> parentPipe;
   ipc::Endpoint<PImageBridgeChild> childPipe;
   nsresult rv = PImageBridge::CreateEndpoints(
@@ -166,16 +172,18 @@ GPUProcessManager::EnsureImageBridgeChil
 
 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(
@@ -283,16 +291,17 @@ GPUProcessManager::CreateTopLevelComposi
                                             ClientLayerManager* 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,
@@ -386,16 +395,18 @@ GPUProcessManager::CreateRemoteSession(n
   return nullptr;
 #endif
 }
 
 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(
--- a/gfx/ipc/GraphicsMessages.ipdlh
+++ b/gfx/ipc/GraphicsMessages.ipdlh
@@ -1,16 +1,17 @@
 /* -*- 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";
 
 namespace mozilla {
 namespace gfx {
 
 struct D3D11DeviceStatus
@@ -30,16 +31,40 @@ struct DevicePrefs
 };
 
 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;
+};
+
+struct GPUDeviceData
+{
+  FeatureChange d3d11Compositing;
+  FeatureChange d3d9Compositing;
+  FeatureChange oglCompositing;
+  D3D11DeviceStatus d3d11Device;
+};
+
 union GfxVarValue
 {
   BackendType;
   bool;
   IntSize;
 };
 
 struct GfxVarUpdate
--- a/gfx/ipc/PGPU.ipdl
+++ b/gfx/ipc/PGPU.ipdl
@@ -52,12 +52,21 @@ parent:
                             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 DeallocateLayerTreeId(uint64_t layersId);
+
+  // Request the current DeviceStatus from the GPU process. This blocks until
+  // one is available (i.e., Init has completed).
+  sync GetDeviceStatus() returns (GPUDeviceData status);
+
+child:
+  // Sent when the GPU process has initialized devices. This occurs once, after
+  // Init().
+  async InitComplete(GPUDeviceData data);
 };
 
 } // namespace gfx
 } // namespace mozilla
--- a/gfx/thebes/DeviceManagerD3D11.cpp
+++ b/gfx/thebes/DeviceManagerD3D11.cpp
@@ -137,18 +137,20 @@ DeviceManagerD3D11::ImportDeviceInfo(con
   MOZ_ASSERT(!ProcessOwnsCompositor());
 
   mDeviceStatus = Some(aDeviceStatus);
 }
 
 void
 DeviceManagerD3D11::ExportDeviceInfo(D3D11DeviceStatus* aOut)
 {
-  MOZ_ASSERT(ProcessOwnsCompositor());
-  MOZ_ASSERT(!!mCompositorDevice == !!mDeviceStatus);
+  // Even though the parent process might not own the compositor, we still
+  // populate DeviceManagerD3D11 with device statistics (for simplicity).
+  // That means it still gets queried for compositor information.
+  MOZ_ASSERT(XRE_IsParentProcess() || XRE_GetProcessType() == GeckoProcessType_GPU);
 
   if (mDeviceStatus) {
     *aOut = mDeviceStatus.value();
   }
 }
 
 void
 DeviceManagerD3D11::CreateContentDevices()
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -2442,20 +2442,32 @@ gfxPlatform::ImportContentDeviceData(con
   gfxConfig::Inherit(Feature::HW_COMPOSITING, prefs.hwCompositing());
   gfxConfig::Inherit(Feature::OPENGL_COMPOSITING, prefs.oglCompositing());
 }
 
 void
 gfxPlatform::BuildContentDeviceData(mozilla::gfx::ContentDeviceData* aOut)
 {
   MOZ_ASSERT(XRE_IsParentProcess());
+
+  // Make sure our settings are synchronized from the GPU process.
+  GPUProcessManager::Get()->EnsureGPUReady();
+
   aOut->prefs().hwCompositing() = gfxConfig::GetValue(Feature::HW_COMPOSITING);
   aOut->prefs().oglCompositing() = gfxConfig::GetValue(Feature::OPENGL_COMPOSITING);
 }
 
+void
+gfxPlatform::ImportGPUDeviceData(const mozilla::gfx::GPUDeviceData& aData)
+{
+  MOZ_ASSERT(XRE_IsParentProcess());
+
+  gfxConfig::ImportChange(Feature::OPENGL_COMPOSITING, aData.oglCompositing());
+}
+
 bool
 gfxPlatform::SupportsApzDragInput() const
 {
   return gfxPrefs::APZDragEnabled();
 }
 
 void
 gfxPlatform::BumpDeviceCounter()
--- a/gfx/thebes/gfxPlatform.h
+++ b/gfx/thebes/gfxPlatform.h
@@ -47,16 +47,17 @@ class SkiaGLGlue;
 namespace gfx {
 class DrawTarget;
 class SourceSurface;
 class DataSourceSurface;
 class ScaledFont;
 class DrawEventRecorder;
 class VsyncSource;
 class ContentDeviceData;
+class GPUDeviceData;
 
 inline uint32_t
 BackendTypeBit(BackendType b)
 {
   return 1 << uint8_t(b);
 }
 
 } // namespace gfx
@@ -669,16 +670,22 @@ public:
     const gfxSkipChars& EmptySkipChars() const { return kEmptySkipChars; }
 
     /**
      * Return information on how child processes should initialize graphics
      * devices.
      */
     virtual void BuildContentDeviceData(mozilla::gfx::ContentDeviceData* aOut);
 
+    /**
+     * Imports settings from the GPU process. This should only be called through
+     * GPUProcessManager, in the UI process.
+     */
+    virtual void ImportGPUDeviceData(const mozilla::gfx::GPUDeviceData& aData);
+
 protected:
     gfxPlatform();
     virtual ~gfxPlatform();
 
     virtual void InitAcceleration();
 
     /**
      * Called immediately before deleting the gfxPlatform object.
--- a/gfx/thebes/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/gfxWindowsPlatform.cpp
@@ -2025,16 +2025,49 @@ gfxWindowsPlatform::GetAcceleratedCompos
   }
 
   if (gfxConfig::IsEnabled(Feature::D3D9_COMPOSITING) && !gfxPrefs::LayersPreferD3D9()) {
     aBackends.AppendElement(LayersBackend::LAYERS_D3D9);
   }
 }
 
 void
+gfxWindowsPlatform::ImportGPUDeviceData(const mozilla::gfx::GPUDeviceData& aData)
+{
+  MOZ_ASSERT(XRE_IsParentProcess());
+
+  gfxPlatform::ImportGPUDeviceData(aData);
+
+  gfxConfig::ImportChange(Feature::D3D11_COMPOSITING, aData.d3d11Compositing());
+  gfxConfig::ImportChange(Feature::D3D9_COMPOSITING, aData.d3d9Compositing());
+
+  DeviceManagerD3D11* dm = DeviceManagerD3D11::Get();
+  if (gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) {
+    dm->ImportDeviceInfo(aData.d3d11Device());
+  } else {
+    // There should be no devices, so this just takes away the device status.
+    dm->ResetDevices();
+
+    // Make sure we disable D2D if content processes might use it.
+    FeatureState& d2d1 = gfxConfig::GetFeature(Feature::DIRECT2D);
+    if (d2d1.IsEnabled()) {
+      d2d1.SetFailed(
+        FeatureStatus::Unavailable,
+        "Direct2D requires Direct3D 11 compositing",
+        NS_LITERAL_CSTRING("FEATURE_FAILURE_D2D_D3D11_COMP"));
+    }
+  }
+
+  // For completeness (and messaging in about:support). Content recomputes this
+  // on its own, and we won't use ANGLE in the UI process if we're using a GPU
+  // process.
+  UpdateANGLEConfig();
+}
+
+void
 gfxWindowsPlatform::ImportContentDeviceData(const mozilla::gfx::ContentDeviceData& aData)
 {
   MOZ_ASSERT(XRE_IsContentProcess());
 
   gfxPlatform::ImportContentDeviceData(aData);
 
   const DevicePrefs& prefs = aData.prefs();
   gfxConfig::Inherit(Feature::D3D11_COMPOSITING, prefs.d3d11Compositing());
--- a/gfx/thebes/gfxWindowsPlatform.h
+++ b/gfx/thebes/gfxWindowsPlatform.h
@@ -247,16 +247,17 @@ public:
 
 protected:
     bool AccelerateLayersByDefault() override {
       return true;
     }
     void GetAcceleratedCompositorBackends(nsTArray<mozilla::layers::LayersBackend>& aBackends) override;
     virtual void GetPlatformCMSOutputProfile(void* &mem, size_t &size) override;
 
+    void ImportGPUDeviceData(const mozilla::gfx::GPUDeviceData& aData) override;
     void ImportContentDeviceData(const mozilla::gfx::ContentDeviceData& aData) override;
     void BuildContentDeviceData(mozilla::gfx::ContentDeviceData* aOut) override;
 
 protected:
     RenderMode mRenderMode;
 
     int8_t mUseClearTypeForDownloadableFonts;
     int8_t mUseClearTypeAlways;