Don't mix GPU adapters across processes. (bug 1183910 part 10, r=jmuizelaar)
authorDavid Anderson <danderson@mozilla.com>
Mon, 10 Aug 2015 20:27:06 -0700
changeset 257158 9fda40f7a0d8a4857d387b3038bab500bfdc7534
parent 257157 9091e62b06468dc052b9dd257d8f71db1f24694c
child 257159 4f222c9dca5bf50909dac9819317d8816da3ce29
push id29207
push userryanvm@gmail.com
push dateTue, 11 Aug 2015 14:27:25 +0000
treeherdermozilla-central@d82b5a78686a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjmuizelaar
bugs1183910
milestone43.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 mix GPU adapters across processes. (bug 1183910 part 10, r=jmuizelaar)
gfx/ipc/GraphicsMessages.ipdlh
gfx/thebes/gfxWindowsPlatform.cpp
gfx/thebes/gfxWindowsPlatform.h
--- a/gfx/ipc/GraphicsMessages.ipdlh
+++ b/gfx/ipc/GraphicsMessages.ipdlh
@@ -3,23 +3,38 @@
  */
 /* 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 DxgiLUID
+{
+  uint32_t LowPart;
+  int32_t HighPart;
+};
+
+struct DxgiDesc
+{
+  uint32_t vendorID;
+  uint32_t deviceID;
+  uint32_t subSysID;
+  DxgiLUID luid;
+};
+
 struct DeviceInitData
 {
   bool useAcceleration;
 
   // Windows only.
   bool useD3D11;
   bool useD3D11WARP;
   bool useD3D11ImageBridge;
   bool d3d11TextureSharingWorks;
   bool useD2D;
   bool useD2D1;
+  DxgiDesc dxgiDesc;
 };
 
 } // namespace gfx
 } // namespace mozilla
--- a/gfx/thebes/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/gfxWindowsPlatform.cpp
@@ -1703,35 +1703,45 @@ bool DoesD3D11DeviceWork(ID3D11Device *d
       gANGLESupportsD3D11 = false;
       return false;
     }
   }
   result = true;
   return true;
 }
 
+static bool
+GetDxgiDesc(ID3D11Device* device, DXGI_ADAPTER_DESC* out)
+{
+  nsRefPtr<IDXGIDevice> dxgiDevice;
+  HRESULT hr = device->QueryInterface(__uuidof(IDXGIDevice), getter_AddRefs(dxgiDevice));
+  if (FAILED(hr)) {
+    return false;
+  }
+
+  nsRefPtr<IDXGIAdapter> dxgiAdapter;
+  if (FAILED(dxgiDevice->GetAdapter(getter_AddRefs(dxgiAdapter)))) {
+    return false;
+  }
+
+  return SUCCEEDED(dxgiAdapter->GetDesc(out));
+}
+
 static void
 CheckForAdapterMismatch(ID3D11Device *device)
 {
-  nsRefPtr<IDXGIDevice> dxgiDevice;
-  if (FAILED(device->QueryInterface(__uuidof(IDXGIDevice),
-                                    getter_AddRefs(dxgiDevice)))) {
-      return;
-  }
-  nsRefPtr<IDXGIAdapter> dxgiAdapter;
-  if (FAILED(dxgiDevice->GetAdapter(getter_AddRefs(dxgiAdapter)))) {
-      return;
-  }
+  DXGI_ADAPTER_DESC desc;
+  PodZero(&desc);
+  GetDxgiDesc(device, &desc);
+
   nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
   nsString vendorID;
   gfxInfo->GetAdapterVendorID(vendorID);
   nsresult ec;
   int32_t vendor = vendorID.ToInteger(&ec, 16);
-  DXGI_ADAPTER_DESC desc;
-  dxgiAdapter->GetDesc(&desc);
   if (vendor != desc.VendorId) {
       gfxCriticalNote << "VendorIDMismatch " << hexa(vendor) << " " << hexa(desc.VendorId);
   }
 }
 
 void CheckIfRenderTargetViewNeedsRecreating(ID3D11Device *device)
 {
     // CreateTexture2D is known to crash on lower feature levels, see bugs
@@ -2047,16 +2057,39 @@ gfxWindowsPlatform::AttemptWARPDeviceCre
   if (IsWin8OrLater()) {
     mCompositorD3D11TextureSharingWorks = ::DoesD3D11TextureSharingWork(mD3D11Device);
   }
   mD3D11Device->SetExceptionMode(0);
   mIsWARP = true;
 }
 
 bool
+gfxWindowsPlatform::ContentAdapterIsParentAdapter(ID3D11Device* device)
+{
+  DXGI_ADAPTER_DESC desc;
+  if (!GetDxgiDesc(device, &desc)) {
+    gfxCriticalNote << "Could not query device DXGI adapter info";
+    return false;
+  }
+
+  const DxgiDesc& parent = GetParentDevicePrefs().dxgiDesc();
+  if (desc.VendorId != parent.vendorID() ||
+      desc.DeviceId != parent.deviceID() ||
+      desc.SubSysId != parent.subSysID() ||
+      desc.AdapterLuid.HighPart != parent.luid().HighPart() ||
+      desc.AdapterLuid.LowPart != parent.luid().LowPart())
+  {
+    gfxCriticalNote << "VendorIDMismatch " << hexa(parent.vendorID()) << " " << hexa(desc.VendorId);
+    return false;
+  }
+
+  return true;
+}
+
+bool
 gfxWindowsPlatform::AttemptD3D11ContentDeviceCreation()
 {
   RefPtr<IDXGIAdapter1> adapter;
   if (!mIsWARP) {
     adapter = GetDXGIAdapter();
     if (!adapter) {
       return false;
     }
@@ -2080,19 +2113,23 @@ gfxWindowsPlatform::AttemptD3D11ContentD
   }
 
   // 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;
+  if (XRE_IsContentProcess()) {
+    if (!DoesD3D11TextureSharingWork(mD3D11ContentDevice) ||
+        !ContentAdapterIsParentAdapter(mD3D11ContentDevice))
+    {
+      mD3D11ContentDevice = nullptr;
+      return false;
+    }
   }
 
   mD3D11ContentDevice->SetExceptionMode(0);
 
   nsRefPtr<ID3D10Multithread> multi;
   mD3D11ContentDevice->QueryInterface(__uuidof(ID3D10Multithread), getter_AddRefs(multi));
   multi->SetMultithreadProtected(TRUE);
 
@@ -2114,17 +2151,19 @@ gfxWindowsPlatform::AttemptD3D11ImageBri
     return;
   }
 
   if (FAILED(hr)) {
     return;
   }
 
   mD3D11ImageBridgeDevice->SetExceptionMode(0);
-  if (!DoesD3D11AlphaTextureSharingWork(mD3D11ImageBridgeDevice)) {
+  if (!DoesD3D11AlphaTextureSharingWork(mD3D11ImageBridgeDevice) ||
+      (XRE_IsContentProcess() && !ContentAdapterIsParentAdapter(mD3D11ImageBridgeDevice)))
+  {
     mD3D11ImageBridgeDevice = nullptr;
     return;
   }
 }
 
 void
 gfxWindowsPlatform::SetDeviceInitData(mozilla::gfx::DeviceInitData& aData)
 {
@@ -2720,9 +2759,22 @@ gfxWindowsPlatform::GetDeviceInitData(De
   }
 
   aOut->useD3D11() = true;
   aOut->useD3D11ImageBridge() = !!mD3D11ImageBridgeDevice;
   aOut->d3d11TextureSharingWorks() = mCompositorD3D11TextureSharingWorks;
   aOut->useD3D11WARP() = mIsWARP;
   aOut->useD2D() = (GetD2DStatus() == FeatureStatus::Available);
   aOut->useD2D1() = (GetD2D1Status() == FeatureStatus::Available);
+
+  if (mD3D11Device) {
+    DXGI_ADAPTER_DESC desc;
+    if (!GetDxgiDesc(mD3D11Device, &desc)) {
+      return;
+    }
+
+    aOut->dxgiDesc().vendorID() = desc.VendorId;
+    aOut->dxgiDesc().deviceID() = desc.DeviceId;
+    aOut->dxgiDesc().subSysID() = desc.SubSysId;
+    aOut->dxgiDesc().luid().LowPart() = desc.AdapterLuid.LowPart;
+    aOut->dxgiDesc().luid().HighPart() = desc.AdapterLuid.HighPart;
+  }
 }
--- a/gfx/thebes/gfxWindowsPlatform.h
+++ b/gfx/thebes/gfxWindowsPlatform.h
@@ -318,16 +318,17 @@ private:
     mozilla::gfx::FeatureStatus CheckD3D11Support(bool* aCanUseHardware);
     mozilla::gfx::FeatureStatus CheckD2DSupport();
     mozilla::gfx::FeatureStatus CheckD2D1Support();
     void AttemptD3D11DeviceCreation();
     void AttemptWARPDeviceCreation();
     void AttemptD3D11ImageBridgeDeviceCreation();
     bool AttemptD3D11ContentDeviceCreation();
     bool CanUseD3D11ImageBridge();
+    bool ContentAdapterIsParentAdapter(ID3D11Device* device);
 
     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;