Move D3D11 checking logic out of gfxWindowsPlatform. (bug 1282364 part 2, r=mattwoodrow)
authorDavid Anderson <danderson@mozilla.com>
Tue, 26 Jul 2016 13:19:48 -0700
changeset 331860 007d791665b898246c13e1bfed3b8abc936a8bd6
parent 331859 d1cd9be20f92eaaaff800989122244ff44583c5c
child 331861 8508083db4ac4a33bfef56e35f3aa6a35b7e01a2
push id9858
push userjlund@mozilla.com
push dateMon, 01 Aug 2016 14:37:10 +0000
treeherdermozilla-aurora@203106ef6cb6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmattwoodrow
bugs1282364
milestone50.0a1
Move D3D11 checking logic out of gfxWindowsPlatform. (bug 1282364 part 2, r=mattwoodrow)
gfx/thebes/D3D11Checks.cpp
gfx/thebes/D3D11Checks.h
gfx/thebes/gfxFontUtils.cpp
gfx/thebes/gfxPlatformFontList.cpp
gfx/thebes/gfxUserFontSet.cpp
gfx/thebes/gfxWindowsPlatform.cpp
gfx/thebes/moz.build
new file mode 100644
--- /dev/null
+++ b/gfx/thebes/D3D11Checks.cpp
@@ -0,0 +1,394 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * 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 "D3D11Checks.h"
+#include "gfxConfig.h"
+#include "GfxDriverInfo.h"
+#include "gfxPrefs.h"
+#include "gfxWindowsPlatform.h"
+#include "mozilla/RefPtr.h"
+#include "mozilla/gfx/Logging.h"
+#include "nsIGfxInfo.h"
+#include <dxgi.h>
+#include <d3d10_1.h>
+#include <d3d11.h>
+
+namespace mozilla {
+namespace gfx {
+
+using namespace mozilla::widget;
+
+/* static */ bool
+D3D11Checks::DoesRenderTargetViewNeedRecreating(ID3D11Device *aDevice)
+{
+    bool result = false;
+    // CreateTexture2D is known to crash on lower feature levels, see bugs
+    // 1170211 and 1089413.
+    if (aDevice->GetFeatureLevel() < D3D_FEATURE_LEVEL_10_0) {
+        return true;
+    }
+
+    RefPtr<ID3D11DeviceContext> deviceContext;
+    aDevice->GetImmediateContext(getter_AddRefs(deviceContext));
+    int backbufferWidth = 32; int backbufferHeight = 32;
+    RefPtr<ID3D11Texture2D> offscreenTexture;
+    RefPtr<IDXGIKeyedMutex> keyedMutex;
+
+    D3D11_TEXTURE2D_DESC offscreenTextureDesc = { 0 };
+    offscreenTextureDesc.Width = backbufferWidth;
+    offscreenTextureDesc.Height = backbufferHeight;
+    offscreenTextureDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
+    offscreenTextureDesc.MipLevels = 0;
+    offscreenTextureDesc.ArraySize = 1;
+    offscreenTextureDesc.SampleDesc.Count = 1;
+    offscreenTextureDesc.SampleDesc.Quality = 0;
+    offscreenTextureDesc.Usage = D3D11_USAGE_DEFAULT;
+    offscreenTextureDesc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
+    offscreenTextureDesc.CPUAccessFlags = 0;
+    offscreenTextureDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX;
+
+    HRESULT hr = aDevice->CreateTexture2D(&offscreenTextureDesc, NULL, getter_AddRefs(offscreenTexture));
+    if (FAILED(hr)) {
+        gfxCriticalNote << "DoesRecreatingCreateTexture2DFail";
+        return false;
+    }
+
+    hr = offscreenTexture->QueryInterface(__uuidof(IDXGIKeyedMutex), (void**)getter_AddRefs(keyedMutex));
+    if (FAILED(hr)) {
+        gfxCriticalNote << "DoesRecreatingKeyedMutexFailed";
+        return false;
+    }
+    D3D11_RENDER_TARGET_VIEW_DESC offscreenRTVDesc;
+    offscreenRTVDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
+    offscreenRTVDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
+    offscreenRTVDesc.Texture2D.MipSlice = 0;
+
+    RefPtr<ID3D11RenderTargetView> offscreenRTView;
+    hr = aDevice->CreateRenderTargetView(offscreenTexture, &offscreenRTVDesc, getter_AddRefs(offscreenRTView));
+    if (FAILED(hr)) {
+        gfxCriticalNote << "DoesRecreatingCreateRenderTargetViewFailed";
+        return false;
+    }
+
+    // Acquire and clear
+    keyedMutex->AcquireSync(0, INFINITE);
+    FLOAT color1[4] = { 1, 1, 0.5, 1 };
+    deviceContext->ClearRenderTargetView(offscreenRTView, color1);
+    keyedMutex->ReleaseSync(0);
+
+
+    keyedMutex->AcquireSync(0, INFINITE);
+    FLOAT color2[4] = { 1, 1, 0, 1 };
+
+    deviceContext->ClearRenderTargetView(offscreenRTView, color2);
+    D3D11_TEXTURE2D_DESC desc;
+
+    offscreenTexture->GetDesc(&desc);
+    desc.Usage = D3D11_USAGE_STAGING;
+    desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
+    desc.MiscFlags = 0;
+    desc.BindFlags = 0;
+    ID3D11Texture2D* cpuTexture;
+    hr = aDevice->CreateTexture2D(&desc, NULL, &cpuTexture);
+    if (FAILED(hr)) {
+        gfxCriticalNote << "DoesRecreatingCreateCPUTextureFailed";
+        return false;
+    }
+
+    deviceContext->CopyResource(cpuTexture, offscreenTexture);
+
+    D3D11_MAPPED_SUBRESOURCE mapped;
+    hr = deviceContext->Map(cpuTexture, 0, D3D11_MAP_READ, 0, &mapped);
+    if (FAILED(hr)) {
+        gfxCriticalNote << "DoesRecreatingMapFailed " << hexa(hr);
+        return false;
+    }
+    int resultColor = *(int*)mapped.pData;
+    deviceContext->Unmap(cpuTexture, 0);
+    cpuTexture->Release();
+
+    // XXX on some drivers resultColor will not have changed to
+    // match the clear
+    if (resultColor != 0xffffff00) {
+        gfxCriticalNote << "RenderTargetViewNeedsRecreating";
+        result = true;
+    }
+
+    keyedMutex->ReleaseSync(0);
+    return result;
+}
+
+/* static */ bool
+D3D11Checks::DoesD3D11DeviceWork()
+{
+  static bool checked = false;
+  static bool result = false;
+
+  if (checked)
+      return result;
+  checked = true;
+
+  if (gfxPrefs::Direct2DForceEnabled() ||
+      gfxConfig::IsForcedOnByUser(Feature::HW_COMPOSITING))
+  {
+    result = true;
+    return true;
+  }
+
+  if (GetModuleHandleW(L"igd10umd32.dll")) {
+    const wchar_t* checkModules[] = {L"dlumd32.dll",
+                                     L"dlumd11.dll",
+                                     L"dlumd10.dll"};
+    for (int i=0; i<PR_ARRAY_SIZE(checkModules); i+=1) {
+      if (GetModuleHandleW(checkModules[i])) {
+        nsString displayLinkModuleVersionString;
+        gfxWindowsPlatform::GetDLLVersion(checkModules[i],
+                                          displayLinkModuleVersionString);
+        uint64_t displayLinkModuleVersion;
+        if (!ParseDriverVersion(displayLinkModuleVersionString,
+                                &displayLinkModuleVersion)) {
+          gfxCriticalError() << "DisplayLink: could not parse version "
+                             << checkModules[i];
+          return false;
+        }
+        if (displayLinkModuleVersion <= V(8,6,1,36484)) {
+          gfxCriticalError(CriticalLog::DefaultOptions(false)) << "DisplayLink: too old version " << displayLinkModuleVersionString.get();
+          return false;
+        }
+      }
+    }
+  }
+  result = true;
+  return true;
+}
+
+static bool
+TryCreateTexture2D(ID3D11Device *device,
+                   D3D11_TEXTURE2D_DESC* desc,
+                   D3D11_SUBRESOURCE_DATA* data,
+                   RefPtr<ID3D11Texture2D>& texture)
+{
+  // Older Intel driver version (see bug 1221348 for version #s) crash when
+  // creating a texture with shared keyed mutex and data.
+  MOZ_SEH_TRY {
+    return !FAILED(device->CreateTexture2D(desc, data, getter_AddRefs(texture)));
+  } MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
+    // For now we want to aggregrate all the crash signature to a known crash.
+    gfxDevCrash(LogReason::TextureCreation) << "Crash creating texture. See bug 1221348.";
+    return false;
+  }
+}
+
+// See bug 1083071. On some drivers, Direct3D 11 CreateShaderResourceView fails
+// with E_OUTOFMEMORY.
+static bool
+DoesTextureSharingWorkInternal(ID3D11Device *device, DXGI_FORMAT format, UINT bindflags)
+{
+  // CreateTexture2D is known to crash on lower feature levels, see bugs
+  // 1170211 and 1089413.
+  if (device->GetFeatureLevel() < D3D_FEATURE_LEVEL_10_0) {
+    return false;
+  }
+
+  if (gfxPrefs::Direct2DForceEnabled() ||
+      gfxConfig::IsForcedOnByUser(Feature::HW_COMPOSITING))
+  {
+    return true;
+  }
+
+  if (GetModuleHandleW(L"atidxx32.dll")) {
+    nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
+    if (gfxInfo) {
+      nsString vendorID, vendorID2;
+      gfxInfo->GetAdapterVendorID(vendorID);
+      gfxInfo->GetAdapterVendorID2(vendorID2);
+      if (vendorID.EqualsLiteral("0x8086") && vendorID2.IsEmpty()) {
+        if (!gfxPrefs::LayersAMDSwitchableGfxEnabled()) {
+          return false;
+        }
+        gfxCriticalError(CriticalLog::DefaultOptions(false)) << "PossiblyBrokenSurfaceSharing_UnexpectedAMDGPU";
+      }
+    }
+  }
+
+  RefPtr<ID3D11Texture2D> texture;
+  D3D11_TEXTURE2D_DESC desc;
+  const int texture_size = 32;
+  desc.Width = texture_size;
+  desc.Height = texture_size;
+  desc.MipLevels = 1;
+  desc.ArraySize = 1;
+  desc.Format = format;
+  desc.SampleDesc.Count = 1;
+  desc.SampleDesc.Quality = 0;
+  desc.Usage = D3D11_USAGE_DEFAULT;
+  desc.CPUAccessFlags = 0;
+  desc.MiscFlags = D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX;
+  desc.BindFlags = bindflags;
+
+  uint32_t color[texture_size * texture_size];
+  for (size_t i = 0; i < sizeof(color)/sizeof(color[0]); i++) {
+    color[i] = 0xff00ffff;
+  }
+  // XXX If we pass the data directly at texture creation time we
+  //     get a crash on Intel 8.5.10.[18xx-1994] drivers.
+  //     We can work around this issue by doing UpdateSubresource.
+  if (!TryCreateTexture2D(device, &desc, nullptr, texture)) {
+    gfxCriticalNote << "DoesD3D11TextureSharingWork_TryCreateTextureFailure";
+    return false;
+  }
+
+  RefPtr<IDXGIKeyedMutex> sourceSharedMutex;
+  texture->QueryInterface(__uuidof(IDXGIKeyedMutex), (void**)getter_AddRefs(sourceSharedMutex));
+  if (FAILED(sourceSharedMutex->AcquireSync(0, 30*1000))) {
+    gfxCriticalError() << "DoesD3D11TextureSharingWork_SourceMutexTimeout";
+    // only wait for 30 seconds
+    return false;
+  }
+
+  RefPtr<ID3D11DeviceContext> deviceContext;
+  device->GetImmediateContext(getter_AddRefs(deviceContext));
+
+  int stride = texture_size * 4;
+  deviceContext->UpdateSubresource(texture, 0, nullptr, color, stride, stride * texture_size);
+
+  if (FAILED(sourceSharedMutex->ReleaseSync(0))) {
+    gfxCriticalError() << "DoesD3D11TextureSharingWork_SourceReleaseSyncTimeout";
+    return false;
+  }
+
+  HANDLE shareHandle;
+  RefPtr<IDXGIResource> otherResource;
+  if (FAILED(texture->QueryInterface(__uuidof(IDXGIResource),
+                                     getter_AddRefs(otherResource))))
+  {
+    gfxCriticalError() << "DoesD3D11TextureSharingWork_GetResourceFailure";
+    return false;
+  }
+
+  if (FAILED(otherResource->GetSharedHandle(&shareHandle))) {
+    gfxCriticalError() << "DoesD3D11TextureSharingWork_GetSharedTextureFailure";
+    return false;
+  }
+
+  RefPtr<ID3D11Resource> sharedResource;
+  RefPtr<ID3D11Texture2D> sharedTexture;
+  if (FAILED(device->OpenSharedResource(shareHandle, __uuidof(ID3D11Resource),
+                                        getter_AddRefs(sharedResource))))
+  {
+    gfxCriticalError(CriticalLog::DefaultOptions(false)) << "OpenSharedResource failed for format " << format;
+    return false;
+  }
+
+  if (FAILED(sharedResource->QueryInterface(__uuidof(ID3D11Texture2D),
+                                            getter_AddRefs(sharedTexture))))
+  {
+    gfxCriticalError() << "DoesD3D11TextureSharingWork_GetSharedTextureFailure";
+    return false;
+  }
+
+  // create a staging texture for readback
+  RefPtr<ID3D11Texture2D> cpuTexture;
+  desc.Usage = D3D11_USAGE_STAGING;
+  desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
+  desc.MiscFlags = 0;
+  desc.BindFlags = 0;
+  if (FAILED(device->CreateTexture2D(&desc, nullptr, getter_AddRefs(cpuTexture)))) {
+    gfxCriticalError() << "DoesD3D11TextureSharingWork_CreateTextureFailure";
+    return false;
+  }
+
+  RefPtr<IDXGIKeyedMutex> sharedMutex;
+  sharedResource->QueryInterface(__uuidof(IDXGIKeyedMutex), (void**)getter_AddRefs(sharedMutex));
+  if (FAILED(sharedMutex->AcquireSync(0, 30*1000))) {
+    gfxCriticalError() << "DoesD3D11TextureSharingWork_AcquireSyncTimeout";
+    // only wait for 30 seconds
+    return false;
+  }
+
+  // Copy to the cpu texture so that we can readback
+  deviceContext->CopyResource(cpuTexture, sharedTexture);
+
+  D3D11_MAPPED_SUBRESOURCE mapped;
+  int resultColor = 0;
+  if (SUCCEEDED(deviceContext->Map(cpuTexture, 0, D3D11_MAP_READ, 0, &mapped))) {
+    // read the texture
+    resultColor = *(int*)mapped.pData;
+    deviceContext->Unmap(cpuTexture, 0);
+  } else {
+    gfxCriticalError() << "DoesD3D11TextureSharingWork_MapFailed";
+    return false;
+  }
+
+  sharedMutex->ReleaseSync(0);
+
+  // check that the color we put in is the color we get out
+  if (resultColor != color[0]) {
+    // Shared surfaces seem to be broken on dual AMD & Intel HW when using the
+    // AMD GPU
+    gfxCriticalNote << "DoesD3D11TextureSharingWork_ColorMismatch";
+    return false;
+  }
+
+  RefPtr<ID3D11ShaderResourceView> sharedView;
+
+  // This if(FAILED()) is the one that actually fails on systems affected by bug 1083071.
+  if (FAILED(device->CreateShaderResourceView(sharedTexture, NULL, getter_AddRefs(sharedView)))) {
+    gfxCriticalNote << "CreateShaderResourceView failed for format" << format;
+    return false;
+  }
+
+  return true;
+}
+
+/* static */ bool
+D3D11Checks::DoesTextureSharingWork(ID3D11Device *device)
+{
+  return DoesTextureSharingWorkInternal(device, DXGI_FORMAT_B8G8R8A8_UNORM, D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE);
+}
+
+/* static */ bool
+D3D11Checks::DoesAlphaTextureSharingWork(ID3D11Device *device)
+{
+  return DoesTextureSharingWorkInternal(device, DXGI_FORMAT_R8_UNORM, D3D11_BIND_SHADER_RESOURCE);
+}
+
+/* static */ bool
+D3D11Checks::GetDxgiDesc(ID3D11Device* device, DXGI_ADAPTER_DESC* out)
+{
+  RefPtr<IDXGIDevice> dxgiDevice;
+  HRESULT hr = device->QueryInterface(__uuidof(IDXGIDevice), getter_AddRefs(dxgiDevice));
+  if (FAILED(hr)) {
+    return false;
+  }
+
+  RefPtr<IDXGIAdapter> dxgiAdapter;
+  if (FAILED(dxgiDevice->GetAdapter(getter_AddRefs(dxgiAdapter)))) {
+    return false;
+  }
+
+  return SUCCEEDED(dxgiAdapter->GetDesc(out));
+}
+
+/* static */ void
+D3D11Checks::WarnOnAdapterMismatch(ID3D11Device *device)
+{
+  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);
+  if (vendor != desc.VendorId) {
+    gfxCriticalNote << "VendorIDMismatch V " << hexa(vendor) << " " << hexa(desc.VendorId);
+  }
+}
+
+
+} // namespace gfx
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/gfx/thebes/D3D11Checks.h
@@ -0,0 +1,28 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * 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_thebes_D3D11Checks_h
+#define mozilla_gfx_thebes_D3D11Checks_h
+
+struct ID3D11Device;
+struct DXGI_ADAPTER_DESC;
+
+namespace mozilla {
+namespace gfx {
+
+struct D3D11Checks
+{
+  static bool DoesRenderTargetViewNeedRecreating(ID3D11Device* aDevice);
+  static bool DoesD3D11DeviceWork();
+  static bool DoesTextureSharingWork(ID3D11Device *device);
+  static bool DoesAlphaTextureSharingWork(ID3D11Device *device);
+  static void WarnOnAdapterMismatch(ID3D11Device* device);
+  static bool GetDxgiDesc(ID3D11Device* device, DXGI_ADAPTER_DESC* out);
+};
+
+} // namespace gfx
+} // namespace mozilla
+
+#endif // mozilla_gfx_thebes_D3D11Checks_h
--- a/gfx/thebes/gfxFontUtils.cpp
+++ b/gfx/thebes/gfxFontUtils.cpp
@@ -1773,8 +1773,13 @@ gfxFontUtils::IsCffFont(const uint8_t* a
     // this is only called after aFontData has passed basic validation,
     // so we know there is enough data present to allow us to read the version!
     const SFNTHeader *sfntHeader = reinterpret_cast<const SFNTHeader*>(aFontData);
     return (sfntHeader->sfntVersion == TRUETYPE_TAG('O','T','T','O'));
 }
 
 #endif
 
+#undef acceptablePlatform
+#undef isSymbol
+#undef isUVSEncoding
+#undef LOG
+#undef LOG_ENABLED
--- a/gfx/thebes/gfxPlatformFontList.cpp
+++ b/gfx/thebes/gfxPlatformFontList.cpp
@@ -1598,8 +1598,11 @@ gfxPlatformFontList::AddSizeOfExcludingT
 
 void
 gfxPlatformFontList::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
                                             FontListSizes* aSizes) const
 {
     aSizes->mFontListSize += aMallocSizeOf(this);
     AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
 }
+
+#undef LOG
+#undef LOG_ENABLED
--- a/gfx/thebes/gfxUserFontSet.cpp
+++ b/gfx/thebes/gfxUserFontSet.cpp
@@ -1427,8 +1427,11 @@ gfxUserFontSet::UserFontCache::Dump()
     printf("userfontcache dump count: %d ========\n", sUserFonts->Count());
     for (auto it = sUserFonts->Iter(); !it.Done(); it.Next()) {
         it.Get()->Dump();
     }
     printf("userfontcache dump ==================\n");
 }
 
 #endif
+
+#undef LOG
+#undef LOG_ENABLED
--- a/gfx/thebes/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/gfxWindowsPlatform.cpp
@@ -25,17 +25,16 @@
 
 #include "nsIWindowsRegKey.h"
 #include "nsIFile.h"
 #include "plbase64.h"
 #include "nsIXULRuntime.h"
 #include "imgLoader.h"
 
 #include "nsIGfxInfo.h"
-#include "GfxDriverInfo.h"
 
 #include "gfxCrashReporterUtils.h"
 
 #include "gfxGDIFontList.h"
 #include "gfxGDIFont.h"
 
 #include "mozilla/layers/CompositorThread.h"
 #include "DeviceManagerD3D9.h"
@@ -70,16 +69,17 @@
 #include "base/thread.h"
 #include "SurfaceCache.h"
 #include "gfxPrefs.h"
 #include "gfxConfig.h"
 #include "VsyncSource.h"
 #include "DriverCrashGuard.h"
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/gfx/DeviceManagerD3D11.h"
+#include "D3D11Checks.h"
 
 using namespace mozilla;
 using namespace mozilla::gfx;
 using namespace mozilla::layers;
 using namespace mozilla::widget;
 using namespace mozilla::image;
 
 enum class TelemetryDeviceCode : uint32_t {
@@ -1534,384 +1534,16 @@ gfxWindowsPlatform::GetDXGIAdapter()
     return nullptr;
   }
 
   // We leak this module everywhere, we might as well do so here as well.
   dxgiModule.disown();
   return mAdapter;
 }
 
-bool DoesD3D11DeviceWork()
-{
-  static bool checked = false;
-  static bool result = false;
-
-  if (checked)
-      return result;
-  checked = true;
-
-  if (gfxPrefs::Direct2DForceEnabled() ||
-      gfxConfig::IsForcedOnByUser(Feature::HW_COMPOSITING))
-  {
-    result = true;
-    return true;
-  }
-
-  if (GetModuleHandleW(L"igd10umd32.dll")) {
-    const wchar_t* checkModules[] = {L"dlumd32.dll",
-                                     L"dlumd11.dll",
-                                     L"dlumd10.dll"};
-    for (int i=0; i<PR_ARRAY_SIZE(checkModules); i+=1) {
-      if (GetModuleHandleW(checkModules[i])) {
-        nsString displayLinkModuleVersionString;
-        gfxWindowsPlatform::GetDLLVersion(checkModules[i],
-                                          displayLinkModuleVersionString);
-        uint64_t displayLinkModuleVersion;
-        if (!ParseDriverVersion(displayLinkModuleVersionString,
-                                &displayLinkModuleVersion)) {
-          gfxCriticalError() << "DisplayLink: could not parse version "
-                             << checkModules[i];
-          return false;
-        }
-        if (displayLinkModuleVersion <= V(8,6,1,36484)) {
-          gfxCriticalError(CriticalLog::DefaultOptions(false)) << "DisplayLink: too old version " << displayLinkModuleVersionString.get();
-          return false;
-        }
-      }
-    }
-  }
-  result = true;
-  return true;
-}
-
-static bool
-GetDxgiDesc(ID3D11Device* device, DXGI_ADAPTER_DESC* out)
-{
-  RefPtr<IDXGIDevice> dxgiDevice;
-  HRESULT hr = device->QueryInterface(__uuidof(IDXGIDevice), getter_AddRefs(dxgiDevice));
-  if (FAILED(hr)) {
-    return false;
-  }
-
-  RefPtr<IDXGIAdapter> dxgiAdapter;
-  if (FAILED(dxgiDevice->GetAdapter(getter_AddRefs(dxgiAdapter)))) {
-    return false;
-  }
-
-  return SUCCEEDED(dxgiAdapter->GetDesc(out));
-}
-
-static void
-CheckForAdapterMismatch(ID3D11Device *device)
-{
-  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);
-  if (vendor != desc.VendorId) {
-      gfxCriticalNote << "VendorIDMismatch V " << hexa(vendor) << " " << hexa(desc.VendorId);
-  }
-}
-
-bool DoesRenderTargetViewNeedsRecreating(ID3D11Device *device)
-{
-    bool result = false;
-    // CreateTexture2D is known to crash on lower feature levels, see bugs
-    // 1170211 and 1089413.
-    if (device->GetFeatureLevel() < D3D_FEATURE_LEVEL_10_0) {
-        return true;
-    }
-
-    RefPtr<ID3D11DeviceContext> deviceContext;
-    device->GetImmediateContext(getter_AddRefs(deviceContext));
-    int backbufferWidth = 32; int backbufferHeight = 32;
-    RefPtr<ID3D11Texture2D> offscreenTexture;
-    RefPtr<IDXGIKeyedMutex> keyedMutex;
-
-    D3D11_TEXTURE2D_DESC offscreenTextureDesc = { 0 };
-    offscreenTextureDesc.Width = backbufferWidth;
-    offscreenTextureDesc.Height = backbufferHeight;
-    offscreenTextureDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
-    offscreenTextureDesc.MipLevels = 0;
-    offscreenTextureDesc.ArraySize = 1;
-    offscreenTextureDesc.SampleDesc.Count = 1;
-    offscreenTextureDesc.SampleDesc.Quality = 0;
-    offscreenTextureDesc.Usage = D3D11_USAGE_DEFAULT;
-    offscreenTextureDesc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
-    offscreenTextureDesc.CPUAccessFlags = 0;
-    offscreenTextureDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX;
-
-    HRESULT hr = device->CreateTexture2D(&offscreenTextureDesc, NULL, getter_AddRefs(offscreenTexture));
-    if (FAILED(hr)) {
-        gfxCriticalNote << "DoesRecreatingCreateTexture2DFail";
-        return false;
-    }
-
-    hr = offscreenTexture->QueryInterface(__uuidof(IDXGIKeyedMutex), (void**)getter_AddRefs(keyedMutex));
-    if (FAILED(hr)) {
-        gfxCriticalNote << "DoesRecreatingKeyedMutexFailed";
-        return false;
-    }
-    D3D11_RENDER_TARGET_VIEW_DESC offscreenRTVDesc;
-    offscreenRTVDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
-    offscreenRTVDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
-    offscreenRTVDesc.Texture2D.MipSlice = 0;
-
-    RefPtr<ID3D11RenderTargetView> offscreenRTView;
-    hr = device->CreateRenderTargetView(offscreenTexture, &offscreenRTVDesc, getter_AddRefs(offscreenRTView));
-    if (FAILED(hr)) {
-        gfxCriticalNote << "DoesRecreatingCreateRenderTargetViewFailed";
-        return false;
-    }
-
-    // Acquire and clear
-    keyedMutex->AcquireSync(0, INFINITE);
-    FLOAT color1[4] = { 1, 1, 0.5, 1 };
-    deviceContext->ClearRenderTargetView(offscreenRTView, color1);
-    keyedMutex->ReleaseSync(0);
-
-
-    keyedMutex->AcquireSync(0, INFINITE);
-    FLOAT color2[4] = { 1, 1, 0, 1 };
-
-    deviceContext->ClearRenderTargetView(offscreenRTView, color2);
-    D3D11_TEXTURE2D_DESC desc;
-
-    offscreenTexture->GetDesc(&desc);
-    desc.Usage = D3D11_USAGE_STAGING;
-    desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
-    desc.MiscFlags = 0;
-    desc.BindFlags = 0;
-    ID3D11Texture2D* cpuTexture;
-    hr = device->CreateTexture2D(&desc, NULL, &cpuTexture);
-    if (FAILED(hr)) {
-        gfxCriticalNote << "DoesRecreatingCreateCPUTextureFailed";
-        return false;
-    }
-
-    deviceContext->CopyResource(cpuTexture, offscreenTexture);
-
-    D3D11_MAPPED_SUBRESOURCE mapped;
-    hr = deviceContext->Map(cpuTexture, 0, D3D11_MAP_READ, 0, &mapped);
-    if (FAILED(hr)) {
-        gfxCriticalNote << "DoesRecreatingMapFailed " << hexa(hr);
-        return false;
-    }
-    int resultColor = *(int*)mapped.pData;
-    deviceContext->Unmap(cpuTexture, 0);
-    cpuTexture->Release();
-
-    // XXX on some drivers resultColor will not have changed to
-    // match the clear
-    if (resultColor != 0xffffff00) {
-        gfxCriticalNote << "RenderTargetViewNeedsRecreating";
-        result = true;
-    }
-
-    keyedMutex->ReleaseSync(0);
-
-    // It seems like this may only happen when we're using the NVIDIA gpu
-    CheckForAdapterMismatch(device);
-    return result;
-}
-
-static bool TryCreateTexture2D(ID3D11Device *device,
-                               D3D11_TEXTURE2D_DESC* desc,
-                               D3D11_SUBRESOURCE_DATA* data,
-                               RefPtr<ID3D11Texture2D>& texture)
-{
-  // Older Intel driver version (see bug 1221348 for version #s) crash when
-  // creating a texture with shared keyed mutex and data.
-  MOZ_SEH_TRY {
-    return !FAILED(device->CreateTexture2D(desc, data, getter_AddRefs(texture)));
-  } MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
-    // For now we want to aggregrate all the crash signature to a known crash.
-    gfxDevCrash(LogReason::TextureCreation) << "Crash creating texture. See bug 1221348.";
-    return false;
-  }
-}
-
-
-// See bug 1083071. On some drivers, Direct3D 11 CreateShaderResourceView fails
-// with E_OUTOFMEMORY.
-bool DoesD3D11TextureSharingWorkInternal(ID3D11Device *device, DXGI_FORMAT format, UINT bindflags)
-{
-  // CreateTexture2D is known to crash on lower feature levels, see bugs
-  // 1170211 and 1089413.
-  if (device->GetFeatureLevel() < D3D_FEATURE_LEVEL_10_0) {
-    return false;
-  }
-
-  if (gfxPrefs::Direct2DForceEnabled() ||
-      gfxConfig::IsForcedOnByUser(Feature::HW_COMPOSITING))
-  {
-    return true;
-  }
-
-  if (GetModuleHandleW(L"atidxx32.dll")) {
-    nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
-    if (gfxInfo) {
-      nsString vendorID, vendorID2;
-      gfxInfo->GetAdapterVendorID(vendorID);
-      gfxInfo->GetAdapterVendorID2(vendorID2);
-      if (vendorID.EqualsLiteral("0x8086") && vendorID2.IsEmpty()) {
-        if (!gfxPrefs::LayersAMDSwitchableGfxEnabled()) {
-          return false;
-        }
-        gfxCriticalError(CriticalLog::DefaultOptions(false)) << "PossiblyBrokenSurfaceSharing_UnexpectedAMDGPU";
-      }
-    }
-  }
-
-  RefPtr<ID3D11Texture2D> texture;
-  D3D11_TEXTURE2D_DESC desc;
-  const int texture_size = 32;
-  desc.Width = texture_size;
-  desc.Height = texture_size;
-  desc.MipLevels = 1;
-  desc.ArraySize = 1;
-  desc.Format = format;
-  desc.SampleDesc.Count = 1;
-  desc.SampleDesc.Quality = 0;
-  desc.Usage = D3D11_USAGE_DEFAULT;
-  desc.CPUAccessFlags = 0;
-  desc.MiscFlags = D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX;
-  desc.BindFlags = bindflags;
-
-  uint32_t color[texture_size * texture_size];
-  for (size_t i = 0; i < sizeof(color)/sizeof(color[0]); i++) {
-    color[i] = 0xff00ffff;
-  }
-  // XXX If we pass the data directly at texture creation time we
-  //     get a crash on Intel 8.5.10.[18xx-1994] drivers.
-  //     We can work around this issue by doing UpdateSubresource.
-  if (!TryCreateTexture2D(device, &desc, nullptr, texture)) {
-    gfxCriticalNote << "DoesD3D11TextureSharingWork_TryCreateTextureFailure";
-    return false;
-  }
-
-  RefPtr<IDXGIKeyedMutex> sourceSharedMutex;
-  texture->QueryInterface(__uuidof(IDXGIKeyedMutex), (void**)getter_AddRefs(sourceSharedMutex));
-  if (FAILED(sourceSharedMutex->AcquireSync(0, 30*1000))) {
-    gfxCriticalError() << "DoesD3D11TextureSharingWork_SourceMutexTimeout";
-    // only wait for 30 seconds
-    return false;
-  }
-
-  RefPtr<ID3D11DeviceContext> deviceContext;
-  device->GetImmediateContext(getter_AddRefs(deviceContext));
-
-  int stride = texture_size * 4;
-  deviceContext->UpdateSubresource(texture, 0, nullptr, color, stride, stride * texture_size);
-
-  if (FAILED(sourceSharedMutex->ReleaseSync(0))) {
-    gfxCriticalError() << "DoesD3D11TextureSharingWork_SourceReleaseSyncTimeout";
-    return false;
-  }
-
-  HANDLE shareHandle;
-  RefPtr<IDXGIResource> otherResource;
-  if (FAILED(texture->QueryInterface(__uuidof(IDXGIResource),
-                                     getter_AddRefs(otherResource))))
-  {
-    gfxCriticalError() << "DoesD3D11TextureSharingWork_GetResourceFailure";
-    return false;
-  }
-
-  if (FAILED(otherResource->GetSharedHandle(&shareHandle))) {
-    gfxCriticalError() << "DoesD3D11TextureSharingWork_GetSharedTextureFailure";
-    return false;
-  }
-
-  RefPtr<ID3D11Resource> sharedResource;
-  RefPtr<ID3D11Texture2D> sharedTexture;
-  if (FAILED(device->OpenSharedResource(shareHandle, __uuidof(ID3D11Resource),
-                                        getter_AddRefs(sharedResource))))
-  {
-    gfxCriticalError(CriticalLog::DefaultOptions(false)) << "OpenSharedResource failed for format " << format;
-    return false;
-  }
-
-  if (FAILED(sharedResource->QueryInterface(__uuidof(ID3D11Texture2D),
-                                            getter_AddRefs(sharedTexture))))
-  {
-    gfxCriticalError() << "DoesD3D11TextureSharingWork_GetSharedTextureFailure";
-    return false;
-  }
-
-  // create a staging texture for readback
-  RefPtr<ID3D11Texture2D> cpuTexture;
-  desc.Usage = D3D11_USAGE_STAGING;
-  desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
-  desc.MiscFlags = 0;
-  desc.BindFlags = 0;
-  if (FAILED(device->CreateTexture2D(&desc, nullptr, getter_AddRefs(cpuTexture)))) {
-    gfxCriticalError() << "DoesD3D11TextureSharingWork_CreateTextureFailure";
-    return false;
-  }
-
-  RefPtr<IDXGIKeyedMutex> sharedMutex;
-  sharedResource->QueryInterface(__uuidof(IDXGIKeyedMutex), (void**)getter_AddRefs(sharedMutex));
-  if (FAILED(sharedMutex->AcquireSync(0, 30*1000))) {
-    gfxCriticalError() << "DoesD3D11TextureSharingWork_AcquireSyncTimeout";
-    // only wait for 30 seconds
-    return false;
-  }
-
-  // Copy to the cpu texture so that we can readback
-  deviceContext->CopyResource(cpuTexture, sharedTexture);
-
-  D3D11_MAPPED_SUBRESOURCE mapped;
-  int resultColor = 0;
-  if (SUCCEEDED(deviceContext->Map(cpuTexture, 0, D3D11_MAP_READ, 0, &mapped))) {
-    // read the texture
-    resultColor = *(int*)mapped.pData;
-    deviceContext->Unmap(cpuTexture, 0);
-  } else {
-    gfxCriticalError() << "DoesD3D11TextureSharingWork_MapFailed";
-    return false;
-  }
-
-  sharedMutex->ReleaseSync(0);
-
-  // check that the color we put in is the color we get out
-  if (resultColor != color[0]) {
-    // Shared surfaces seem to be broken on dual AMD & Intel HW when using the
-    // AMD GPU
-    gfxCriticalNote << "DoesD3D11TextureSharingWork_ColorMismatch";
-    return false;
-  }
-
-  RefPtr<ID3D11ShaderResourceView> sharedView;
-
-  // This if(FAILED()) is the one that actually fails on systems affected by bug 1083071.
-  if (FAILED(device->CreateShaderResourceView(sharedTexture, NULL, getter_AddRefs(sharedView)))) {
-    gfxCriticalNote << "CreateShaderResourceView failed for format" << format;
-    return false;
-  }
-
-  return true;
-}
-
-bool DoesD3D11TextureSharingWork(ID3D11Device *device)
-{
-  return DoesD3D11TextureSharingWorkInternal(device, DXGI_FORMAT_B8G8R8A8_UNORM, D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE);
-}
-
-bool DoesD3D11AlphaTextureSharingWork(ID3D11Device *device)
-{
-  return DoesD3D11TextureSharingWorkInternal(device, DXGI_FORMAT_R8_UNORM, D3D11_BIND_SHADER_RESOURCE);
-}
-
-
 static inline bool
 IsWARPStable()
 {
   // It seems like nvdxgiwrap makes a mess of WARP. See bug 1154703.
   if (!IsWin8OrLater() || GetModuleHandleA("nvdxgiwrap.dll")) {
     return false;
   }
   return true;
@@ -2110,43 +1742,47 @@ gfxWindowsPlatform::AttemptD3D11DeviceCr
   }
 
   if (FAILED(hr) || !device) {
     gfxCriticalError() << "D3D11 device creation failed: " << hexa(hr);
     d3d11.SetFailed(FeatureStatus::Failed, "Failed to acquire a D3D11 device",
                     NS_LITERAL_CSTRING("FEATURE_FAILURE_D3D11_DEVICE2"));
     return;
   }
-  if (!DoesD3D11DeviceWork()) {
+  if (!D3D11Checks::DoesD3D11DeviceWork()) {
     d3d11.SetFailed(FeatureStatus::Broken, "Direct3D11 device was determined to be broken",
                     NS_LITERAL_CSTRING("FEATURE_FAILURE_D3D11_BROKEN"));
     return;
   }
 
   {
     MutexAutoLock lock(mDeviceLock);
     mD3D11Device = device;
   }
 
   // Only test this when not using WARP since it can fail and cause
   // GetDeviceRemovedReason to return weird values.
-  mCompositorD3D11TextureSharingWorks = ::DoesD3D11TextureSharingWork(mD3D11Device);
+  mCompositorD3D11TextureSharingWorks =
+    D3D11Checks::DoesTextureSharingWork(mD3D11Device);
 
   if (!mCompositorD3D11TextureSharingWorks) {
     gfxConfig::SetFailed(Feature::D3D11_HW_ANGLE,
                          FeatureStatus::Broken,
                          "Texture sharing doesn't work");
   }
 
-  if (DoesRenderTargetViewNeedsRecreating(mD3D11Device)) {
+  if (D3D11Checks::DoesRenderTargetViewNeedRecreating(mD3D11Device)) {
     gfxConfig::SetFailed(Feature::D3D11_HW_ANGLE,
                          FeatureStatus::Broken,
                          "RenderTargetViews need recreating");
   }
 
+  // It seems like this may only happen when we're using the NVIDIA gpu
+  D3D11Checks::WarnOnAdapterMismatch(mD3D11Device);
+
   mD3D11Device->SetExceptionMode(0);
   mIsWARP = false;
 }
 
 bool
 gfxWindowsPlatform::AttemptWARPDeviceCreationHelper(
   ScopedGfxFeatureReporter& aReporterWARP,
   RefPtr<ID3D11Device>& aOutDevice,
@@ -2195,27 +1831,28 @@ gfxWindowsPlatform::AttemptWARPDeviceCre
   {
     MutexAutoLock lock(mDeviceLock);
     mD3D11Device = device;
   }
 
   // Only test for texture sharing on Windows 8 since it puts the device into
   // an unusable state if used on Windows 7
   if (IsWin8OrLater()) {
-    mCompositorD3D11TextureSharingWorks = ::DoesD3D11TextureSharingWork(mD3D11Device);
+    mCompositorD3D11TextureSharingWorks =
+      D3D11Checks::DoesTextureSharingWork(mD3D11Device);
   }
   mD3D11Device->SetExceptionMode(0);
   mIsWARP = true;
 }
 
 bool
 gfxWindowsPlatform::ContentAdapterIsParentAdapter(ID3D11Device* device)
 {
   DXGI_ADAPTER_DESC desc;
-  if (!GetDxgiDesc(device, &desc)) {
+  if (!D3D11Checks::GetDxgiDesc(device, &desc)) {
     gfxCriticalNote << "Could not query device DXGI adapter info";
     return false;
   }
 
   const DxgiAdapterDesc& parent = GetParentDevicePrefs().adapter();
   if (desc.VendorId != parent.VendorId ||
       desc.DeviceId != parent.DeviceId ||
       desc.SubSysId != parent.SubSysId ||
@@ -2287,17 +1924,17 @@ 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()) {
-    if (!DoesD3D11TextureSharingWork(mD3D11ContentDevice)) {
+    if (!D3D11Checks::DoesTextureSharingWork(mD3D11ContentDevice)) {
       mD3D11ContentDevice = nullptr;
       return FeatureStatus::Failed;
     }
 
     DebugOnly<bool> ok = ContentAdapterIsParentAdapter(mD3D11ContentDevice);
     MOZ_ASSERT(ok);
   }
 
@@ -2340,17 +1977,17 @@ gfxWindowsPlatform::AttemptD3D11ImageBri
 
   if (FAILED(hr) || !mD3D11ImageBridgeDevice) {
     gfxCriticalNote << "Failed to create a content image bridge device: " << hexa(hr);
     RecordContentDeviceFailure(TelemetryDeviceCode::Image);
     return FeatureStatus::Failed;
   }
 
   mD3D11ImageBridgeDevice->SetExceptionMode(0);
-  if (!DoesD3D11AlphaTextureSharingWork(mD3D11ImageBridgeDevice)) {
+  if (!D3D11Checks::DoesAlphaTextureSharingWork(mD3D11ImageBridgeDevice)) {
     mD3D11ImageBridgeDevice = nullptr;
     return FeatureStatus::Failed;
   }
 
   if (XRE_IsContentProcess()) {
     ContentAdapterIsParentAdapter(mD3D11ImageBridgeDevice);
   }
   return FeatureStatus::Available;
@@ -2649,17 +2286,17 @@ gfxWindowsPlatform::CreateD3D11DecoderDe
 
   RefPtr<ID3D11Device> device;
 
   HRESULT hr;
   if (!CreateD3D11DecoderDeviceHelper(adapter, device, hr)) {
     return nullptr;
   }
 
-  if (FAILED(hr) || !device || !DoesD3D11DeviceWork()) {
+  if (FAILED(hr) || !device || !D3D11Checks::DoesD3D11DeviceWork()) {
     return nullptr;
   }
 
   RefPtr<ID3D10Multithread> multi;
   device->QueryInterface(__uuidof(ID3D10Multithread), getter_AddRefs(multi));
 
   multi->SetMultithreadProtected(TRUE);
 
@@ -3002,17 +2639,17 @@ gfxWindowsPlatform::GetDeviceInitData(De
   aOut->useD3D11() = true;
   aOut->useD3D11ImageBridge() = !!mD3D11ImageBridgeDevice;
   aOut->d3d11TextureSharingWorks() = mCompositorD3D11TextureSharingWorks;
   aOut->useD3D11WARP() = mIsWARP;
   aOut->useD2D1() = gfxConfig::IsEnabled(Feature::DIRECT2D);
 
   if (mD3D11Device) {
     DXGI_ADAPTER_DESC desc;
-    if (!GetDxgiDesc(mD3D11Device, &desc)) {
+    if (!D3D11Checks::GetDxgiDesc(mD3D11Device, &desc)) {
       return;
     }
     aOut->adapter() = DxgiAdapterDesc::From(desc);
   }
 }
 
 bool
 gfxWindowsPlatform::SupportsPluginDirectDXGIDrawing()
--- a/gfx/thebes/moz.build
+++ b/gfx/thebes/moz.build
@@ -230,16 +230,17 @@ UNIFIED_SOURCES += [
 ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
     UNIFIED_SOURCES += [
         'gfxMacPlatformFontList.mm',
     ]
 elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
     UNIFIED_SOURCES += [
+        'D3D11Checks.cpp',
         'DeviceManagerD3D11.cpp',
     ]
 
 # We prefer to use ICU for normalization functions, but currently it is only
 # available if we're building with the Intl API enabled:
 if CONFIG['ENABLE_INTL_API']:
     USE_LIBS += [
         'icu',