Don't create a D3D11 compositor device on content processes. (bug 1183910 part 8, r=bas,mattwoodrow)
authorDavid Anderson <danderson@mozilla.com>
Wed, 05 Aug 2015 02:45:06 -0700
changeset 287945 88b05f9375e7129af939098ee817953b9f9c3a9a
parent 287944 6f16a41f231879b3149db607362513889964604e
child 287946 0a7ace2ffb9bb466975ea09e08beb879e3328133
push id5067
push userraliiev@mozilla.com
push dateMon, 21 Sep 2015 14:04:52 +0000
treeherdermozilla-beta@14221ffe5b2f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbas, mattwoodrow
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
Don't create a D3D11 compositor device on content processes. (bug 1183910 part 8, r=bas,mattwoodrow)
gfx/layers/client/ClientCanvasLayer.cpp
gfx/thebes/gfxWindowsPlatform.cpp
gfx/thebes/gfxWindowsPlatform.h
widget/windows/GfxInfo.cpp
--- a/gfx/layers/client/ClientCanvasLayer.cpp
+++ b/gfx/layers/client/ClientCanvasLayer.cpp
@@ -105,17 +105,17 @@ ClientCanvasLayer::Initialize(const Data
         break;
       }
       case mozilla::layers::LayersBackend::LAYERS_D3D11: {
 #ifdef XP_WIN
         // Enable surface sharing only if ANGLE and compositing devices
         // are both WARP or both not WARP
         if (mGLContext->IsANGLE() &&
             (mGLContext->IsWARP() == gfxWindowsPlatform::GetPlatform()->IsWARP()) &&
-            gfxWindowsPlatform::GetPlatform()->DoesD3D11TextureSharingWork())
+            gfxWindowsPlatform::GetPlatform()->CompositorD3D11TextureSharingWorks())
         {
           factory = SurfaceFactory_ANGLEShareHandle::Create(mGLContext, caps, forwarder,
                                                             mFlags);
         }
 #endif
         break;
       }
       default:
--- a/gfx/thebes/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/gfxWindowsPlatform.cpp
@@ -383,17 +383,17 @@ GetParentDevicePrefs()
   return sDeviceInitDataDoNotUseDirectly;
 }
 
 gfxWindowsPlatform::gfxWindowsPlatform()
   : mRenderMode(RENDER_GDI)
   , mIsWARP(false)
   , mHasDeviceReset(false)
   , mHasFakeDeviceReset(false)
-  , mDoesD3D11TextureSharingWork(false)
+  , mCompositorD3D11TextureSharingWorks(false)
   , mAcceleration(FeatureStatus::Unused)
   , mD3D11Status(FeatureStatus::Unused)
   , mD2DStatus(FeatureStatus::Unused)
   , mD2D1Status(FeatureStatus::Unused)
 {
     mUseClearTypeForDownloadableFonts = UNINITIALIZED_VALUE;
     mUseClearTypeAlways = UNINITIALIZED_VALUE;
 
@@ -446,20 +446,20 @@ double
 gfxWindowsPlatform::GetDPIScale()
 {
   return WinUtils::LogToPhysFactor();
 }
 
 bool
 gfxWindowsPlatform::CanUseHardwareVideoDecoding()
 {
-    if (!gfxPrefs::LayersPreferD3D9() && !mDoesD3D11TextureSharingWork) {
-        return false;
-    }
-    return !IsWARP() && gfxPlatform::CanUseHardwareVideoDecoding();
+  if (!gfxPrefs::LayersPreferD3D9() && !mCompositorD3D11TextureSharingWorks) {
+    return false;
+  }
+  return !IsWARP() && gfxPlatform::CanUseHardwareVideoDecoding();
 }
 
 bool
 gfxWindowsPlatform::InitDWriteSupport()
 {
   MOZ_ASSERT(!mDWriteFactory && IsVistaOrLater());
 
   mozilla::ScopedGfxFeatureReporter reporter("DWrite");
@@ -517,17 +517,17 @@ gfxWindowsPlatform::HandleDeviceReset()
   mAdapter = nullptr;
   Factory::SetDirect3D11Device(nullptr);
   Factory::SetDirect3D10Device(nullptr);
 
   // Reset local state. Note: we leave feature status variables as-is. They
   // will be recomputed by InitializeDevices().
   mHasDeviceReset = false;
   mHasFakeDeviceReset = false;
-  mDoesD3D11TextureSharingWork = false;
+  mCompositorD3D11TextureSharingWorks = 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.
@@ -1960,32 +1960,32 @@ gfxWindowsPlatform::CheckD3D11Support(bo
           return FeatureStatus::Available;
         }
         return FeatureStatus::Blacklisted;
       }
     }
   }
 
   // If we've used WARP once, we continue to use it after device resets.
-  if (!GetDXGIAdapter() || mIsWARP) {
-    *aCanUseHardware = false;
-  }
+  *aCanUseHardware = !mIsWARP;
   return FeatureStatus::Available;
 }
 
 // We don't have access to the D3D11CreateDevice type in gfxWindowsPlatform.h,
 // since it doesn't include d3d11.h, so we use a static here. It should only
 // be used within InitializeD3D11.
 decltype(D3D11CreateDevice)* sD3D11CreateDeviceFn = nullptr;
 
 void
 gfxWindowsPlatform::AttemptD3D11DeviceCreation()
 {
   RefPtr<IDXGIAdapter1> adapter = GetDXGIAdapter();
-  MOZ_ASSERT(adapter);
+  if (!adapter) {
+    return;
+  }
 
   HRESULT hr = E_INVALIDARG;
   MOZ_SEH_TRY {
     hr =
       sD3D11CreateDeviceFn(adapter, D3D_DRIVER_TYPE_UNKNOWN, nullptr,
                            // Use
                            // D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS
                            // to prevent bug 1092260. IE 11 also uses this flag.
@@ -2004,23 +2004,17 @@ gfxWindowsPlatform::AttemptD3D11DeviceCr
   if (!mD3D11Device) {
     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());
-
+  mCompositorD3D11TextureSharingWorks = ::DoesD3D11TextureSharingWork(mD3D11Device);
   mD3D11Device->SetExceptionMode(0);
   mIsWARP = false;
 }
 
 void
 gfxWindowsPlatform::AttemptWARPDeviceCreation()
 {
   ScopedGfxFeatureReporter reporterWARP("D3D11-WARP", gfxPrefs::LayersD3D11ForceWARP());
@@ -2046,42 +2040,61 @@ gfxWindowsPlatform::AttemptWARPDeviceCre
     gfxCriticalError() << "Exception occurred initializing WARP D3D11 device!";
     return;
 
   }
 
   // Only test for texture sharing on Windows 8 since it puts the device into
   // an unusable state if used on Windows 7
   if (IsWin8OrLater()) {
-    mDoesD3D11TextureSharingWork = ::DoesD3D11TextureSharingWork(mD3D11Device);
+    mCompositorD3D11TextureSharingWorks = ::DoesD3D11TextureSharingWork(mD3D11Device);
   }
   mD3D11Device->SetExceptionMode(0);
   mIsWARP = true;
 }
 
 bool
 gfxWindowsPlatform::AttemptD3D11ContentDeviceCreation()
 {
+  RefPtr<IDXGIAdapter1> adapter;
+  if (!mIsWARP) {
+    adapter = GetDXGIAdapter();
+    if (!adapter) {
+      return false;
+    }
+  }
+
   HRESULT hr = E_INVALIDARG;
   MOZ_SEH_TRY {
     hr =
-      sD3D11CreateDeviceFn(mIsWARP ? nullptr : GetDXGIAdapter(),
+      sD3D11CreateDeviceFn(adapter,
                            mIsWARP ? D3D_DRIVER_TYPE_WARP : D3D_DRIVER_TYPE_UNKNOWN,
                            nullptr,
                            D3D11_CREATE_DEVICE_BGRA_SUPPORT,
                            mFeatureLevels.Elements(), mFeatureLevels.Length(),
                            D3D11_SDK_VERSION, byRef(mD3D11ContentDevice), nullptr, nullptr);
   } MOZ_SEH_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
     return false;
   }
 
   if (FAILED(hr)) {
     return false;
   }
 
+  // InitializeD2D() will abort early if the compositor device did not support
+  // texture sharing. If we're in the content process, we can't rely on the
+  // parent device alone: some systems have dual GPUs that are capable of
+  // binding the parent and child processes to different GPUs. As a safety net,
+  // we re-check texture sharing against the newly created D3D11 content device.
+  // If it fails, we won't use Direct2D.
+  if (XRE_IsContentProcess() && !DoesD3D11TextureSharingWork(mD3D11ContentDevice)) {
+    mD3D11ContentDevice = nullptr;
+    return false;
+  }
+
   mD3D11ContentDevice->SetExceptionMode(0);
 
   nsRefPtr<ID3D10Multithread> multi;
   mD3D11ContentDevice->QueryInterface(__uuidof(ID3D10Multithread), getter_AddRefs(multi));
   multi->SetMultithreadProtected(TRUE);
 
   Factory::SetDirect3D11Device(mD3D11ContentDevice);
   return true;
@@ -2211,35 +2224,41 @@ gfxWindowsPlatform::InitializeD3D11()
   }
 
   // Check if a failure was injected for testing.
   if (gfxPrefs::DeviceFailForTesting()) {
     mD3D11Status = FeatureStatus::Failed;
     return;
   }
 
-  // First try to create a hardware accelerated device.
-  if (canUseHardware) {
-    AttemptD3D11DeviceCreation();
-  }
-
-  // If that failed, see if we can use WARP.
-  if (!mD3D11Device && CanUseWARP()) {
-    AttemptWARPDeviceCreation();
+  if (XRE_IsParentProcess()) {
+    // First try to create a hardware accelerated device.
+    if (canUseHardware) {
+      AttemptD3D11DeviceCreation();
+    }
+
+    // If that failed, see if we can use WARP.
+    if (!mD3D11Device && CanUseWARP()) {
+      AttemptWARPDeviceCreation();
+    }
+
+    if (!mD3D11Device) {
+      // Nothing more we can do.
+      mD3D11Status = FeatureStatus::Failed;
+      return;
+    }
+  } else {
+    // Child processes do not need a compositor, but they do need to know
+    // whether the parent process is using WARP and whether or not texture
+    // sharing works.
+    mIsWARP = !canUseHardware;
+    mCompositorD3D11TextureSharingWorks = GetParentDevicePrefs().d3d11TextureSharingWorks();
   }
 
-  if (!mD3D11Device) {
-    // Nothing more we can do.
-    mD3D11Status = FeatureStatus::Failed;
-    return;
-  }
-
-  // If we got here, we successfully got a D3D11 device.
   mD3D11Status = FeatureStatus::Available;
-  MOZ_ASSERT(mD3D11Device);
 
   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.
@@ -2299,17 +2318,17 @@ gfxWindowsPlatform::CheckD2DSupport()
 void
 gfxWindowsPlatform::InitializeD2D()
 {
   mD2DStatus = CheckD2DSupport();
   if (IsFeatureStatusFailure(mD2DStatus)) {
     return;
   }
 
-  if (!mDoesD3D11TextureSharingWork) {
+  if (!mCompositorD3D11TextureSharingWorks) {
     mD2DStatus = FeatureStatus::Failed;
     return;
   }
 
   // Using Direct2D depends on DWrite support.
   if (!mDWriteFactory && !InitDWriteSupport()) {
     mD2DStatus = FeatureStatus::Failed;
     return;
@@ -2697,13 +2716,13 @@ gfxWindowsPlatform::GetDeviceInitData(De
 
   // 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->d3d11TextureSharingWorks() = mCompositorD3D11TextureSharingWorks;
   aOut->useD3D11WARP() = mIsWARP;
   aOut->useD2D() = (GetD2DStatus() == FeatureStatus::Available);
   aOut->useD2D1() = (GetD2D1Status() == FeatureStatus::Available);
 }
--- a/gfx/thebes/gfxWindowsPlatform.h
+++ b/gfx/thebes/gfxWindowsPlatform.h
@@ -250,17 +250,21 @@ public:
     // Create a D3D11 device to be used for DXVA decoding.
     already_AddRefed<ID3D11Device> CreateD3D11DecoderDevice();
 
     mozilla::layers::ReadbackManagerD3D11* GetReadbackManager();
 
     static bool IsOptimus();
 
     bool IsWARP() { return mIsWARP; }
-    bool DoesD3D11TextureSharingWork() { return mDoesD3D11TextureSharingWork; }
+
+    // Returns whether the compositor's D3D11 device supports texture sharing.
+    bool CompositorD3D11TextureSharingWorks() const {
+      return mCompositorD3D11TextureSharingWorks;
+    }
 
     bool SupportsApzWheelInput() const override {
       return true;
     }
     bool SupportsApzTouchInput() const override;
 
     // Recreate devices as needed for a device reset. Returns true if a device
     // reset occurred.
@@ -333,17 +337,17 @@ private:
     mozilla::RefPtr<ID3D10Device1> mD3D10Device;
     mozilla::RefPtr<ID3D11Device> mD3D11Device;
     mozilla::RefPtr<ID3D11Device> mD3D11ContentDevice;
     mozilla::RefPtr<ID3D11Device> mD3D11ImageBridgeDevice;
     mozilla::RefPtr<mozilla::layers::ReadbackManagerD3D11> mD3D11ReadbackManager;
     bool mIsWARP;
     bool mHasDeviceReset;
     bool mHasFakeDeviceReset;
-    bool mDoesD3D11TextureSharingWork;
+    bool mCompositorD3D11TextureSharingWorks;
     DeviceResetReason mDeviceResetReason;
 
     // These should not be accessed directly. Use the Get[Feature]Status
     // accessors instead.
     mozilla::gfx::FeatureStatus mAcceleration;
     mozilla::gfx::FeatureStatus mD3D11Status;
     mozilla::gfx::FeatureStatus mD2DStatus;
     mozilla::gfx::FeatureStatus mD2D1Status;
--- a/widget/windows/GfxInfo.cpp
+++ b/widget/windows/GfxInfo.cpp
@@ -1265,17 +1265,17 @@ GfxInfo::DescribeFeatures(JSContext* aCx
   }
   if (d3d11 == gfx::FeatureStatus::Available) {
     JS::Rooted<JS::Value> val(aCx, JS::Int32Value(platform->GetD3D11Version()));
     JS_SetProperty(aCx, obj, "version", val);
 
     val = JS::BooleanValue(platform->IsWARP());
     JS_SetProperty(aCx, obj, "warp", val);
 
-    val = JS::BooleanValue(platform->DoesD3D11TextureSharingWork());
+    val = JS::BooleanValue(platform->CompositorD3D11TextureSharingWorks());
     JS_SetProperty(aCx, obj, "textureSharing", val);
 
     val = JS::BooleanValue(!platform->CanUseDirect3D11());
     JS_SetProperty(aCx, obj, "blacklisted", val);
   }
 
   gfx::FeatureStatus d2d = platform->GetD2DStatus();
   if (!InitFeatureObject(aCx, aObj, "d2d", d2d, &obj)) {