Use the same graphics device parameters across processes. (bug 1183910 part 7, r=mattwoodrow)
authorDavid Anderson <danderson@mozilla.com>
Sun, 02 Aug 2015 13:59:33 -0700
changeset 255796 8003093a181ca7692aa777c778d03e26104d4ca2
parent 255795 87ff486a4b6afacf9e8dba60a61e17ce431e33b4
child 255797 de9cf19f0a9f01574cc6356e8043bb5033dbb727
push id29155
push usercbook@mozilla.com
push dateMon, 03 Aug 2015 11:59:12 +0000
treeherdermozilla-central@b9f166a815b2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmattwoodrow
bugs1183910
milestone42.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Use the same graphics device parameters across processes. (bug 1183910 part 7, r=mattwoodrow)
dom/cache/PCacheStorage.ipdl
dom/ipc/ContentChild.cpp
dom/ipc/ContentChild.h
dom/ipc/ContentParent.cpp
dom/ipc/ContentParent.h
dom/ipc/ContentProcess.cpp
dom/ipc/PContent.ipdl
gfx/ipc/GraphicsMessages.ipdlh
gfx/ipc/moz.build
gfx/thebes/gfxPlatform.cpp
gfx/thebes/gfxPlatform.h
gfx/thebes/gfxWindowsPlatform.cpp
gfx/thebes/gfxWindowsPlatform.h
--- a/dom/cache/PCacheStorage.ipdl
+++ b/dom/cache/PCacheStorage.ipdl
@@ -1,16 +1,17 @@
 /* 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 protocol PBackground;
 include protocol PBlob; // FIXME: bug 792908
 include protocol PCache;
 include protocol PCacheOp;
+include protocol PCachePushStream;
 include protocol PCacheStreamControl;
 include protocol PFileDescriptorSet;
 
 include CacheTypes;
 
 namespace mozilla {
 namespace dom {
 namespace cache {
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -759,16 +759,24 @@ ContentChild::AppendProcessId(nsACString
     if (!aName.IsEmpty()) {
         aName.Append(' ');
     }
     unsigned pid = getpid();
     aName.Append(nsPrintfCString("(pid %u)", pid));
 }
 
 void
+ContentChild::InitGraphicsDeviceData()
+{
+    // Initialize the graphics platform. This may contact the parent process
+    // to read device preferences.
+    gfxPlatform::GetPlatform();
+}
+
+void
 ContentChild::InitXPCOM()
 {
     // Do this as early as possible to get the parent process to initialize the
     // background thread since we'll likely need database information very soon.
     BackgroundChild::Startup();
 
     nsCOMPtr<nsIIPCBackgroundChildCreateCallback> callback =
         new BackgroundChildPrimer();
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -71,16 +71,17 @@ public:
         nsCString vendor;
     };
 
     bool Init(MessageLoop* aIOLoop,
               base::ProcessId aParentPid,
               IPC::Channel* aChannel);
     void InitProcessAttributes();
     void InitXPCOM();
+    void InitGraphicsDeviceData();
 
     static ContentChild* GetSingleton() {
         return sSingleton;
     }
 
     const AppInfo& GetAppInfo() {
         return mAppInfo;
     }
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -5143,16 +5143,23 @@ ContentParent::RecvProfile(const nsCStri
     }
     mProfile = aProfile;
     mGatherer->GatheredOOPProfile();
     mGatherer = nullptr;
 #endif
     return true;
 }
 
+bool
+ContentParent::RecvGetGraphicsDeviceInitData(DeviceInitData* aOut)
+{
+  gfxPlatform::GetPlatform()->GetDeviceInitData(aOut);
+  return true;
+}
+
 } // namespace dom
 } // namespace mozilla
 
 NS_IMPL_ISUPPORTS(ParentIdleListener, nsIObserver)
 
 NS_IMETHODIMP
 ParentIdleListener::Observe(nsISupports*, const char* aTopic, const char16_t* aData) {
     mozilla::unused << mParent->SendNotifyIdleObserver(mObserver,
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -857,16 +857,17 @@ private:
     virtual bool RecvUpdateDropEffect(const uint32_t& aDragAction,
                                       const uint32_t& aDropEffect) override;
 
     virtual bool RecvGetBrowserConfiguration(const nsCString& aURI, BrowserConfiguration* aConfig) override;
 
     virtual bool RecvGamepadListenerAdded() override;
     virtual bool RecvGamepadListenerRemoved() override;
     virtual bool RecvProfile(const nsCString& aProfile) override;
+    virtual bool RecvGetGraphicsDeviceInitData(DeviceInitData* aOut) override;
 
     // If you add strong pointers to cycle collected objects here, be sure to
     // release these objects in ShutDownProcess.  See the comment there for more
     // details.
 
     GeckoChildProcessHost* mSubprocess;
     ContentParent* mOpener;
 
--- a/dom/ipc/ContentProcess.cpp
+++ b/dom/ipc/ContentProcess.cpp
@@ -71,20 +71,21 @@ ContentProcess::SetAppDir(const nsACStri
 {
   mXREEmbed.SetAppDir(aPath);
 }
 
 bool
 ContentProcess::Init()
 {
     mContent.Init(IOThreadChild::message_loop(),
-                         ParentPid(),
-                         IOThreadChild::channel());
+                  ParentPid(),
+                  IOThreadChild::channel());
     mXREEmbed.Start();
     mContent.InitXPCOM();
+    mContent.InitGraphicsDeviceData();
 
 #if defined(XP_WIN) && defined(MOZ_CONTENT_SANDBOX)
     SetUpSandboxEnvironment();
 #endif
     
     return true;
 }
 
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -55,16 +55,17 @@ include DOMTypes;
 include JavaScriptTypes;
 include InputStreamParams;
 include PTabContext;
 include URIParams;
 include PluginTypes;
 include ProtocolTypes;
 include PContentPermission;
 include BrowserConfiguration;
+include GraphicsMessages;
 
 // Workaround to prevent error if PContentChild.cpp & PContentBridgeParent.cpp
 // are put into different UnifiedProtocolsXX.cpp files.
 // XXX Remove this once bug 1069073 is fixed
 include "mozilla/dom/PContentBridgeParent.h";
 
 include "mozilla/dom/indexedDB/SerializationHelpers.h";
 
@@ -1048,15 +1049,21 @@ parent:
 
     /**
      * Tells the parent to stop the gamepad listening service if it hasn't already.
      */
     GamepadListenerRemoved();
 
     async Profile(nsCString aProfile);
 
+    /**
+     * Request graphics initialization information from the parent.
+     */
+    sync GetGraphicsDeviceInitData()
+        returns (DeviceInitData aData);
+
 both:
      AsyncMessage(nsString aMessage, ClonedMessageData aData,
                   CpowEntry[] aCpows, Principal aPrincipal);
 };
 
 }
 }
new file mode 100644
--- /dev/null
+++ b/gfx/ipc/GraphicsMessages.ipdlh
@@ -0,0 +1,25 @@
+/* -*- 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/. */
+
+namespace mozilla {
+namespace gfx {
+
+struct DeviceInitData
+{
+  bool useAcceleration;
+
+  // Windows only.
+  bool useD3D11;
+  bool useD3D11WARP;
+  bool useD3D11ImageBridge;
+  bool d3d11TextureSharingWorks;
+  bool useD2D;
+  bool useD2D1;
+};
+
+} // namespace gfx
+} // namespace mozilla
--- a/gfx/ipc/moz.build
+++ b/gfx/ipc/moz.build
@@ -21,14 +21,18 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'wind
         'SharedDIBSurface.cpp',
         'SharedDIBWin.cpp',
     ]
 
 SOURCES += [
     'SharedDIB.cpp',
 ]
 
+IPDL_SOURCES = [
+    'GraphicsMessages.ipdlh',
+]
+
 include('/ipc/chromium/chromium-config.mozbuild')
 
 FINAL_LIBRARY = 'xul'
 
 CXXFLAGS += CONFIG['MOZ_CAIRO_CFLAGS']
 CXXFLAGS += CONFIG['TK_CFLAGS']
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -107,16 +107,17 @@ class mozilla::gl::SkiaGLGlue : public G
 #include "mozilla/Attributes.h"
 #include "mozilla/Mutex.h"
 
 #include "nsIGfxInfo.h"
 #include "nsIXULRuntime.h"
 #include "VsyncSource.h"
 #include "SoftwareVsyncSource.h"
 #include "nscore.h" // for NS_FREE_PERMANENT_DATA
+#include "mozilla/dom/ContentChild.h"
 
 namespace mozilla {
 namespace layers {
 #ifdef MOZ_WIDGET_GONK
 void InitGralloc();
 #endif
 void ShutdownTileCache();
 } // namespace layers
@@ -2483,8 +2484,29 @@ gfxPlatform::NotifyCompositorCreated(Lay
   // Set the backend before we notify so it's available immediately.
   mCompositorBackend = aBackend;
 
   // Notify that we created a compositor, so telemetry can update.
   if (nsCOMPtr<nsIObserverService> obsvc = services::GetObserverService()) {
     obsvc->NotifyObservers(nullptr, "compositor:created", nullptr);
   }
 }
+
+void
+gfxPlatform::GetDeviceInitData(mozilla::gfx::DeviceInitData* aOut)
+{
+  MOZ_ASSERT(XRE_IsParentProcess());
+  aOut->useAcceleration() = ShouldUseLayersAcceleration();
+}
+
+void
+gfxPlatform::UpdateDeviceInitData()
+{
+  if (XRE_IsParentProcess()) {
+    // The parent process figures out device initialization on its own.
+    return;
+  }
+
+  mozilla::gfx::DeviceInitData data;
+  mozilla::dom::ContentChild::GetSingleton()->SendGetGraphicsDeviceInitData(&data);
+
+  SetDeviceInitData(data);
+}
--- a/gfx/thebes/gfxPlatform.h
+++ b/gfx/thebes/gfxPlatform.h
@@ -44,16 +44,17 @@ class SkiaGLGlue;
 } // namespace gl
 namespace gfx {
 class DrawTarget;
 class SourceSurface;
 class DataSourceSurface;
 class ScaledFont;
 class DrawEventRecorder;
 class VsyncSource;
+class DeviceInitData;
 
 inline uint32_t
 BackendTypeBit(BackendType b)
 {
   return 1 << uint8_t(b);
 }
 
 } // namespace gfx
@@ -480,17 +481,18 @@ public:
 
     static bool OffMainThreadCompositingEnabled();
 
     static bool CanUseDirect3D9();
     static bool CanUseDirect3D11();
     virtual bool CanUseHardwareVideoDecoding();
     static bool CanUseDirect3D11ANGLE();
 
-    // Returns whether or not layers acceleration should be used.
+    // Returns whether or not layers acceleration should be used. This should
+    // only be called on the parent process.
     bool ShouldUseLayersAcceleration();
 
     // Returns a prioritized list of all available compositor backends.
     void GetCompositorBackends(bool useAcceleration, nsTArray<mozilla::layers::LayersBackend>& aBackends);
 
     /**
      * Is it possible to use buffer rotation.  Note that these
      * check the preference, but also allow for the override to
@@ -641,16 +643,20 @@ public:
     mozilla::layers::LayersBackend GetCompositorBackend() const {
       return mCompositorBackend;
     }
 
     // Trigger a test-driven graphics device reset.
     virtual void TestDeviceReset(DeviceResetReason aReason)
     {}
 
+    // Return information on how child processes should initialize graphics
+    // devices. Currently this is only used on Windows.
+    virtual void GetDeviceInitData(mozilla::gfx::DeviceInitData* aOut);
+
 protected:
     gfxPlatform();
     virtual ~gfxPlatform();
 
     void AppendCJKPrefLangs(eFontPrefLang aPrefLangs[], uint32_t &aLen,
                             eFontPrefLang aCharLang, eFontPrefLang aPageLang);
 
     /**
@@ -674,16 +680,27 @@ protected:
      * aBackendBitmask specifies the backends which are acceptable to the caller.
      * The backend used is determined by aBackendBitmask and the order specified
      * by the gfx.canvas.azure.backends pref.
      */
     void InitBackendPrefs(uint32_t aCanvasBitmask, mozilla::gfx::BackendType aCanvasDefault,
                           uint32_t aContentBitmask, mozilla::gfx::BackendType aContentDefault);
 
     /**
+     * If in a child process, triggers a refresh of device preferences.
+     */
+    void UpdateDeviceInitData();
+
+    /**
+     * Called when new device preferences are available.
+     */
+    virtual void SetDeviceInitData(mozilla::gfx::DeviceInitData& aData)
+    {}
+
+    /**
      * returns the first backend named in the pref gfx.canvas.azure.backends
      * which is a component of aBackendBitmask, a bitmask of backend types
      */
     static mozilla::gfx::BackendType GetCanvasBackendPref(uint32_t aBackendBitmask);
 
     /**
      * returns the first backend named in the pref gfx.content.azure.backend
      * which is a component of aBackendBitmask, a bitmask of backend types
--- a/gfx/thebes/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/gfxWindowsPlatform.cpp
@@ -368,16 +368,26 @@ public:
     return MOZ_COLLECT_REPORT("d3d9-shared-texture", KIND_OTHER, UNITS_BYTES,
                               gfxWindowsPlatform::sD3D9SharedTextureUsed,
                               "Memory used for D3D9 shared textures");
   }
 };
 
 NS_IMPL_ISUPPORTS(D3D9SharedTextureReporter, nsIMemoryReporter)
 
+// Device init data should only be used on child processes, so we protect it
+// behind a getter here.
+static DeviceInitData sDeviceInitDataDoNotUseDirectly;
+static inline DeviceInitData&
+GetParentDevicePrefs()
+{
+  MOZ_ASSERT(XRE_IsContentProcess());
+  return sDeviceInitDataDoNotUseDirectly;
+}
+
 gfxWindowsPlatform::gfxWindowsPlatform()
   : mRenderMode(RENDER_GDI)
   , mIsWARP(false)
   , mHasDeviceReset(false)
   , mHasFakeDeviceReset(false)
   , mDoesD3D11TextureSharingWork(false)
   , mAcceleration(FeatureStatus::Unused)
   , mD3D11Status(FeatureStatus::Unused)
@@ -398,16 +408,17 @@ gfxWindowsPlatform::gfxWindowsPlatform()
     if (IsWin8OrLater()) {
       mFeatureLevels.AppendElement(D3D_FEATURE_LEVEL_11_1);
     }
     mFeatureLevels.AppendElement(D3D_FEATURE_LEVEL_11_0);
     mFeatureLevels.AppendElement(D3D_FEATURE_LEVEL_10_1);
     mFeatureLevels.AppendElement(D3D_FEATURE_LEVEL_10_0);
     mFeatureLevels.AppendElement(D3D_FEATURE_LEVEL_9_3);
 
+    UpdateDeviceInitData();
     InitializeDevices();
     UpdateRenderMode();
 
     RegisterStrongMemoryReporter(new GPUAdapterReporter());
     RegisterStrongMemoryReporter(new D3D11TextureReporter());
     RegisterStrongMemoryReporter(new D3D9TextureReporter());
     RegisterStrongMemoryReporter(new D3D9SurfaceImageReporter());
     RegisterStrongMemoryReporter(new D3D9SharedTextureReporter());
@@ -513,16 +524,19 @@ gfxWindowsPlatform::HandleDeviceReset()
   mHasFakeDeviceReset = false;
   mDoesD3D11TextureSharingWork = false;
   mDeviceResetReason = DeviceResetReason::OK;
 
   imgLoader::Singleton()->ClearCache(true);
   imgLoader::Singleton()->ClearCache(false);
   gfxAlphaBoxBlur::ShutdownBlurCache();
 
+  // Since we got a device reset, we must ask the parent process for an updated
+  // list of which devices to create.
+  UpdateDeviceInitData();
   InitializeDevices();
   return true;
 }
 
 void
 gfxWindowsPlatform::UpdateBackendPrefs()
 {
   uint32_t canvasMask = BackendTypeBit(BackendType::CAIRO);
@@ -1895,16 +1909,22 @@ bool DoesD3D11AlphaTextureSharingWork(ID
 
 static inline bool
 CanUseWARP()
 {
   if (gfxPrefs::LayersD3D11ForceWARP()) {
     return true;
   }
 
+  // The child process can only use WARP if the parent process is also using
+  // WARP.
+  if (XRE_IsContentProcess()) {
+    return GetParentDevicePrefs().useD3D11WARP();
+  }
+
   // It seems like nvdxgiwrap makes a mess of WARP. See bug 1154703.
   if (!IsWin8OrLater() ||
       gfxPrefs::LayersD3D11DisableWARP() ||
       GetModuleHandleA("nvdxgiwrap.dll"))
   {
     return false;
   }
   return true;
@@ -1913,16 +1933,24 @@ CanUseWARP()
 FeatureStatus
 gfxWindowsPlatform::CheckD3D11Support(bool* aCanUseHardware)
 {
   // Don't revive D3D11 support after a failure.
   if (IsFeatureStatusFailure(mD3D11Status)) {
     return mD3D11Status;
   }
 
+  if (XRE_IsContentProcess()) {
+    if (!GetParentDevicePrefs().useD3D11()) {
+      return FeatureStatus::Blocked;
+    }
+    *aCanUseHardware = !GetParentDevicePrefs().useD3D11WARP();
+    return FeatureStatus::Available;
+  }
+
   if (gfxPrefs::LayersD3D11ForceWARP()) {
     *aCanUseHardware = false;
     return FeatureStatus::Available;
   }
 
   if (nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo()) {
     int32_t status;
     if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS, &status))) {
@@ -1977,16 +2005,22 @@ gfxWindowsPlatform::AttemptD3D11DeviceCr
     return;
   }
 
   CheckIfRenderTargetViewNeedsRecreating(mD3D11Device);
 
   // Only test this when not using WARP since it can fail and cause
   // GetDeviceRemovedReason to return weird values.
   mDoesD3D11TextureSharingWork = ::DoesD3D11TextureSharingWork(mD3D11Device);
+
+  // Assert that the child and parent process both computed texture sharing
+  // properly.
+  MOZ_ASSERT_IF(XRE_IsContentProcess(),
+                mDoesD3D11TextureSharingWork == GetParentDevicePrefs().d3d11TextureSharingWorks());
+
   mD3D11Device->SetExceptionMode(0);
   mIsWARP = false;
 }
 
 void
 gfxWindowsPlatform::AttemptWARPDeviceCreation()
 {
   ScopedGfxFeatureReporter reporterWARP("D3D11-WARP", gfxPrefs::LayersD3D11ForceWARP());
@@ -2074,54 +2108,86 @@ gfxWindowsPlatform::AttemptD3D11ImageBri
   mD3D11ImageBridgeDevice->SetExceptionMode(0);
   if (!DoesD3D11AlphaTextureSharingWork(mD3D11ImageBridgeDevice)) {
     mD3D11ImageBridgeDevice = nullptr;
     return;
   }
 }
 
 void
+gfxWindowsPlatform::SetDeviceInitData(mozilla::gfx::DeviceInitData& aData)
+{
+  MOZ_ASSERT(XRE_IsContentProcess());
+  sDeviceInitDataDoNotUseDirectly = aData;
+}
+
+void
 gfxWindowsPlatform::InitializeDevices()
 {
-  // Don't retry acceleration if it failed earlier.
+  // If acceleration is disabled, we refuse to initialize anything.
+  mAcceleration = CheckAccelerationSupport();
   if (IsFeatureStatusFailure(mAcceleration)) {
     return;
   }
 
-  // If we previously crashed initializing devices, or if we're in safe mode,
-  // bail out now.
+  // If we previously crashed initializing devices, bail out now. This is
+  // effectively a parent-process only check, since the content process
+  // cannot create a lock file.
   DriverInitCrashDetection detectCrashes;
-  if (detectCrashes.DisableAcceleration() || InSafeMode()) {
+  if (detectCrashes.DisableAcceleration()) {
     mAcceleration = FeatureStatus::Blocked;
     return;
   }
 
-  // If acceleration is disabled, we refuse to initialize anything.
-  if (!ShouldUseLayersAcceleration()) {
-    mAcceleration = FeatureStatus::Disabled;
-    return;
-  }
-
-  // At this point, as far as we know, we can probably accelerate.
-  mAcceleration = FeatureStatus::Available;
-
   // If we're going to prefer D3D9, stop here. The rest of this function
   // attempts to use D3D11 features.
   if (gfxPrefs::LayersPreferD3D9()) {
     mD3D11Status = FeatureStatus::Disabled;
     return;
   }
 
   // First, initialize D3D11. If this succeeds we attempt to use Direct2D.
   InitializeD3D11();
   if (mD3D11Status == FeatureStatus::Available) {
     InitializeD2D();
   }
 }
 
+FeatureStatus
+gfxWindowsPlatform::CheckAccelerationSupport()
+{
+  // Don't retry acceleration if it failed earlier.
+  if (IsFeatureStatusFailure(mAcceleration)) {
+    return mAcceleration;
+  }
+  if (XRE_IsContentProcess()) {
+    return GetParentDevicePrefs().useAcceleration()
+           ? FeatureStatus::Available
+           : FeatureStatus::Blocked;
+  }
+  if (InSafeMode()) {
+    return FeatureStatus::Blocked;
+  }
+  if (!ShouldUseLayersAcceleration()) {
+    return FeatureStatus::Disabled;
+  }
+  return FeatureStatus::Available;
+}
+
+bool
+gfxWindowsPlatform::CanUseD3D11ImageBridge()
+{
+  if (XRE_IsContentProcess()) {
+    if (!GetParentDevicePrefs().useD3D11ImageBridge()) {
+      return false;
+    }
+  }
+  return !mIsWARP;
+}
+
 void
 gfxWindowsPlatform::InitializeD3D11()
 {
   // This function attempts to initialize our D3D11 devices, if the hardware
   // is not blacklisted for D3D11 layers. This first attempt will try to create
   // a hardware accelerated device. If this creation fails or the hardware is
   // blacklisted, then this function will abort if WARP is disabled, causing us
   // to fallback to D3D9 or Basic layers. If WARP is not disabled it will use
@@ -2165,17 +2231,17 @@ gfxWindowsPlatform::InitializeD3D11()
     mD3D11Status = FeatureStatus::Failed;
     return;
   }
 
   // If we got here, we successfully got a D3D11 device.
   mD3D11Status = FeatureStatus::Available;
   MOZ_ASSERT(mD3D11Device);
 
-  if (!mIsWARP) {
+  if (CanUseD3D11ImageBridge()) {
     AttemptD3D11ImageBridgeDeviceCreation();
   }
 
   // We leak these everywhere and we need them our entire runtime anyway, let's
   // leak it here as well. We keep the pointer to sD3D11CreateDeviceFn around
   // as well for D2D1 and device resets.
   d3d11Module.disown();
 }
@@ -2201,16 +2267,22 @@ IsD2DBlacklisted()
 FeatureStatus
 gfxWindowsPlatform::CheckD2DSupport()
 {
   // Don't revive D2D support after a failure.
   if (IsFeatureStatusFailure(mD2DStatus)) {
     return mD2DStatus;
   }
 
+  if (XRE_IsContentProcess()) {
+    return GetParentDevicePrefs().useD2D()
+           ? FeatureStatus::Available
+           : FeatureStatus::Blocked;
+  }
+
   if (!gfxPrefs::Direct2DForceEnabled() && IsD2DBlacklisted()) {
     return FeatureStatus::Blacklisted;
   }
 
   // Do not ever try to use D2D if it's explicitly disabled.
   if (gfxPrefs::Direct2DDisabled()) {
     return FeatureStatus::Disabled;
   }
@@ -2261,16 +2333,21 @@ gfxWindowsPlatform::CheckD2D1Support()
 {
   // Don't revive D2D1 support after a failure.
   if (IsFeatureStatusFailure(mD2D1Status)) {
     return mD2D1Status;
   }
   if (!Factory::SupportsD2D1()) {
     return FeatureStatus::Unavailable;
   }
+  if (XRE_IsContentProcess()) {
+    return GetParentDevicePrefs().useD2D1()
+           ? FeatureStatus::Available
+           : FeatureStatus::Blocked;
+  }
   if (!gfxPrefs::Direct2DUse1_1()) {
     return FeatureStatus::Disabled;
   }
   // Normally we don't use D2D content drawing when using WARP. However if
   // WARP is force-enabled, we will let Direct2D use WARP as well.
   if (mIsWARP && !gfxPrefs::LayersD3D11ForceWARP()) {
     return FeatureStatus::Blocked;
   }
@@ -2604,8 +2681,29 @@ unsigned
 gfxWindowsPlatform::GetD3D11Version()
 {
   ID3D11Device* device = GetD3D11Device();
   if (!device) {
     return 0;
   }
   return device->GetFeatureLevel();
 }
+
+void
+gfxWindowsPlatform::GetDeviceInitData(DeviceInitData* aOut)
+{
+  // Check for device resets before giving back new graphics information.
+  UpdateRenderMode();
+
+  gfxPlatform::GetDeviceInitData(aOut);
+
+  // IPDL initializes each field to false for us so we can early return.
+  if (GetD3D11Status() != FeatureStatus::Available) {
+    return;
+  }
+
+  aOut->useD3D11() = true;
+  aOut->useD3D11ImageBridge() = !!mD3D11ImageBridgeDevice;
+  aOut->d3d11TextureSharingWorks() = mDoesD3D11TextureSharingWork;
+  aOut->useD3D11WARP() = mIsWARP;
+  aOut->useD2D() = (GetD2DStatus() == FeatureStatus::Available);
+  aOut->useD2D1() = (GetD2D1Status() == FeatureStatus::Available);
+}
--- a/gfx/thebes/gfxWindowsPlatform.h
+++ b/gfx/thebes/gfxWindowsPlatform.h
@@ -278,22 +278,25 @@ public:
     void TestDeviceReset(DeviceResetReason aReason) override;
 
     virtual already_AddRefed<mozilla::gfx::VsyncSource> CreateHardwareVsyncSource() override;
     static mozilla::Atomic<size_t> sD3D11MemoryUsed;
     static mozilla::Atomic<size_t> sD3D9MemoryUsed;
     static mozilla::Atomic<size_t> sD3D9SurfaceImageUsed;
     static mozilla::Atomic<size_t> sD3D9SharedTextureUsed;
 
+    void GetDeviceInitData(mozilla::gfx::DeviceInitData* aOut) override;
+
 protected:
     bool AccelerateLayersByDefault() override {
       return true;
     }
     void GetAcceleratedCompositorBackends(nsTArray<mozilla::layers::LayersBackend>& aBackends);
     virtual void GetPlatformCMSOutputProfile(void* &mem, size_t &size);
+    void SetDeviceInitData(mozilla::gfx::DeviceInitData& aData) override;
 
 protected:
     RenderMode mRenderMode;
 
     int8_t mUseClearTypeForDownloadableFonts;
     int8_t mUseClearTypeAlways;
 
 private:
@@ -302,23 +305,25 @@ private:
     void InitializeDevices();
     void InitializeD3D11();
     void InitializeD2D();
     void InitializeD2D1();
     bool InitDWriteSupport();
 
     void DisableD2D();
 
+    mozilla::gfx::FeatureStatus CheckAccelerationSupport();
     mozilla::gfx::FeatureStatus CheckD3D11Support(bool* aCanUseHardware);
     mozilla::gfx::FeatureStatus CheckD2DSupport();
     mozilla::gfx::FeatureStatus CheckD2D1Support();
     void AttemptD3D11DeviceCreation();
     void AttemptWARPDeviceCreation();
     void AttemptD3D11ImageBridgeDeviceCreation();
     bool AttemptD3D11ContentDeviceCreation();
+    bool CanUseD3D11ImageBridge();
 
     IDXGIAdapter1 *GetDXGIAdapter();
     bool IsDeviceReset(HRESULT hr, DeviceResetReason* aReason);
 
 #ifdef CAIRO_HAS_DWRITE_FONT
     nsRefPtr<IDWriteFactory> mDWriteFactory;
     nsRefPtr<IDWriteRenderingParams> mRenderingParams[TEXT_RENDERING_COUNT];
     DWRITE_MEASURING_MODE mMeasuringMode;