Break InitD3D11Devices up into smaller functions. (bug 1179051 part 2, r=bas)
authorDavid Anderson <danderson@mozilla.com>
Wed, 15 Jul 2015 23:59:39 -0700
changeset 253149 bfea9da8cf9ac336157999b2f25d2a34898db188
parent 253148 94450f09642abfbf99e9609b28fd503f796ecead
child 253150 18e90871e991d576051a72d3b55166ead19a23b2
push id29061
push userryanvm@gmail.com
push dateThu, 16 Jul 2015 18:53:45 +0000
treeherdermozilla-central@a0f4a688433d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbas
bugs1179051
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
Break InitD3D11Devices up into smaller functions. (bug 1179051 part 2, r=bas)
gfx/thebes/gfxWindowsPlatform.cpp
gfx/thebes/gfxWindowsPlatform.h
--- a/gfx/thebes/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/gfxWindowsPlatform.cpp
@@ -1892,227 +1892,250 @@ bool DoesD3D11TextureSharingWork(ID3D11D
   return result;
 }
 
 bool DoesD3D11AlphaTextureSharingWork(ID3D11Device *device)
 {
   return DoesD3D11TextureSharingWorkInternal(device, DXGI_FORMAT_R8_UNORM, D3D11_BIND_SHADER_RESOURCE);
 }
 
+auto
+gfxWindowsPlatform::CheckD3D11Support() -> D3D11Status
+{
+  if (gfxPrefs::LayersD3D11ForceWARP()) {
+    return D3D11Status::ForceWARP;
+  }
+
+  if (nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo()) {
+    int32_t status;
+    if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS, &status))) {
+      if (status != nsIGfxInfo::FEATURE_STATUS_OK) {
+        // See if we can use WARP instead.
+        //
+        // It seems like nvdxgiwrap makes a mess of WARP. See bug 1154703 for more.
+        if (gfxPrefs::LayersD3D11DisableWARP() || GetModuleHandleA("nvdxgiwrap.dll")) {
+          return D3D11Status::Blocked;
+        }
+
+        if (!IsWin8OrLater()) {
+          // We do not use WARP on Windows 7 or earlier.
+          return D3D11Status::Blocked;
+        }
+
+        return D3D11Status::TryWARP;
+      }
+    }
+  }
+
+  // Either nsIGfxInfo was bugged or we're not blacklisted.
+  if (!GetDXGIAdapter()) {
+    return D3D11Status::TryWARP;
+  }
+  return D3D11Status::Ok;
+}
+
+// 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 InitD3D11Devices.
+decltype(D3D11CreateDevice)* sD3D11CreateDeviceFn = nullptr;
+
+bool
+gfxWindowsPlatform::AttemptD3D11DeviceCreation(const nsTArray<D3D_FEATURE_LEVEL>& aFeatureLevels)
+{
+  RefPtr<IDXGIAdapter1> adapter = GetDXGIAdapter();
+  MOZ_ASSERT(adapter);
+
+  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.
+                           D3D11_CREATE_DEVICE_BGRA_SUPPORT | D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS,
+                           aFeatureLevels.Elements(), aFeatureLevels.Length(),
+                           D3D11_SDK_VERSION, byRef(mD3D11Device), nullptr, nullptr);
+  } MOZ_SEH_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
+    gfxCriticalError() << "Crash during D3D11 device creation";
+    return false;
+  }
+
+  if (FAILED(hr) || !DoesD3D11DeviceWork(mD3D11Device)) {
+    gfxCriticalError() << "D3D11 device creation failed" << hexa(hr);
+    return false;
+  }
+  if (!mD3D11Device) {
+    return false;
+  }
+
+  CheckIfRenderTargetViewNeedsRecreating(mD3D11Device);
+
+  // Only test this when not using WARP since it can fail and cause
+  // GetDeviceRemovedReason to return weird values.
+  mDoesD3D11TextureSharingWork = ::DoesD3D11TextureSharingWork(mD3D11Device);
+  mIsWARP = false;
+  return true;
+}
+
+bool
+gfxWindowsPlatform::AttemptWARPDeviceCreation(const nsTArray<D3D_FEATURE_LEVEL>& aFeatureLevels)
+{
+  if (gfxPrefs::LayersD3D11DisableWARP()) {
+    return false;
+  }
+
+  MOZ_ASSERT(!mD3D11Device);
+
+  ScopedGfxFeatureReporter reporterWARP("D3D11-WARP", gfxPrefs::LayersD3D11ForceWARP());
+
+  MOZ_SEH_TRY {
+    HRESULT hr =
+      sD3D11CreateDeviceFn(nullptr, D3D_DRIVER_TYPE_WARP, nullptr,
+                           // Use
+                           // D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS
+                           // to prevent bug 1092260. IE 11 also uses this flag.
+                           D3D11_CREATE_DEVICE_BGRA_SUPPORT,
+                           aFeatureLevels.Elements(), aFeatureLevels.Length(),
+                           D3D11_SDK_VERSION, byRef(mD3D11Device), nullptr, nullptr);
+
+    if (FAILED(hr)) {
+      // This should always succeed... in theory.
+      gfxCriticalError() << "Failed to initialize WARP D3D11 device! " << hexa(hr);
+      return false;
+    }
+
+    reporterWARP.SetSuccessful();
+  } MOZ_SEH_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
+    gfxCriticalError() << "Exception occurred initializing WARP D3D11 device!";
+    return false;
+  }
+
+  mIsWARP = true;
+  return true;
+}
+
+bool
+gfxWindowsPlatform::AttemptD3D11ContentDeviceCreation(const nsTArray<D3D_FEATURE_LEVEL>& aFeatureLevels)
+{
+  HRESULT hr = E_INVALIDARG;
+  MOZ_SEH_TRY {
+    hr =
+      sD3D11CreateDeviceFn(mIsWARP ? nullptr : GetDXGIAdapter(),
+                           mIsWARP ? D3D_DRIVER_TYPE_WARP : D3D_DRIVER_TYPE_UNKNOWN,
+                           nullptr,
+                           D3D11_CREATE_DEVICE_BGRA_SUPPORT,
+                           aFeatureLevels.Elements(), aFeatureLevels.Length(),
+                           D3D11_SDK_VERSION, byRef(mD3D11ContentDevice), nullptr, nullptr);
+  } MOZ_SEH_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
+    return false;
+  }
+
+  return SUCCEEDED(hr);
+}
+
+bool
+gfxWindowsPlatform::AttemptD3D11ImageBridgeDeviceCreation(const nsTArray<D3D_FEATURE_LEVEL>& aFeatureLevels)
+{
+  HRESULT hr = E_INVALIDARG;
+  MOZ_SEH_TRY{
+    hr =
+      sD3D11CreateDeviceFn(GetDXGIAdapter(), D3D_DRIVER_TYPE_UNKNOWN, nullptr,
+                           D3D11_CREATE_DEVICE_BGRA_SUPPORT,
+                           aFeatureLevels.Elements(), aFeatureLevels.Length(),
+                           D3D11_SDK_VERSION, byRef(mD3D11ImageBridgeDevice), nullptr, nullptr);
+  } MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
+    return false;
+  }
+
+  if (FAILED(hr)) {
+    return false;
+  }
+
+  mD3D11ImageBridgeDevice->SetExceptionMode(0);
+
+  return DoesD3D11AlphaTextureSharingWork(mD3D11ImageBridgeDevice);
+}
+
 void
 gfxWindowsPlatform::InitD3D11Devices()
 {
   // This function attempts to initialize our D3D11 devices. If the hardware
   // is not blacklisted for D3D11 layers. This will first attempt 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
   // a WARP device which should always be available on Windows 7 and higher.
-
   mD3D11DeviceInitialized = true;
   mDoesD3D11TextureSharingWork = false;
 
   MOZ_ASSERT(!mD3D11Device); 
 
   DriverInitCrashDetection detectCrashes;
   if (InSafeMode() || detectCrashes.DisableAcceleration()) {
     return;
   }
 
-  bool useWARP = false;
-  bool allowWARP = false;
-
-  if (IsWin8OrLater()) {
-    allowWARP = true;
-  }
-
-  nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
-  if (gfxInfo) {
-    int32_t status;
-    if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS, &status))) {
-      if (status != nsIGfxInfo::FEATURE_STATUS_OK) {
-
-        // It seems like nvdxgiwrap makes a mess of WARP. See bug 1154703 for more.
-        if (gfxPrefs::LayersD3D11DisableWARP() || GetModuleHandleA("nvdxgiwrap.dll")) {
-          return;
-        }
-
-        if (!IsWin8OrLater()) {
-            /* On Windows 7 WARP runs very badly on the builtin vga driver */
-            nsString driver;
-            gfxInfo->GetAdapterDriver(driver);
-            // driver can start with vga or svga so only look for "framebuf..."
-            if (driver.Find("framebuf vga256 vga64k") != kNotFound) {
-                gfxCriticalError(CriticalLog::DefaultOptions(false)) << "Disabling WARP on builtin vga driver";
-                return;
-            }
-        }
-
-        useWARP = allowWARP;
-      }
-    }
-  }
-
-  if (gfxPrefs::LayersD3D11ForceWARP()) {
-    useWARP = true;
+  D3D11Status status = CheckD3D11Support();
+  if (status == D3D11Status::Blocked) {
+    return;
   }
 
   nsModuleHandle d3d11Module(LoadLibrarySystem32(L"d3d11.dll"));
-  decltype(D3D11CreateDevice)* d3d11CreateDevice = (decltype(D3D11CreateDevice)*)
-    GetProcAddress(d3d11Module, "D3D11CreateDevice");
+  sD3D11CreateDeviceFn =
+    (decltype(D3D11CreateDevice)*)GetProcAddress(d3d11Module, "D3D11CreateDevice");
 
-  if (!d3d11CreateDevice) {
+  if (!sD3D11CreateDeviceFn) {
     // We should just be on Windows Vista or XP in this case.
     return;
   }
 
   nsTArray<D3D_FEATURE_LEVEL> featureLevels;
   if (IsWin8OrLater()) {
     featureLevels.AppendElement(D3D_FEATURE_LEVEL_11_1);
   }
   featureLevels.AppendElement(D3D_FEATURE_LEVEL_11_0);
   featureLevels.AppendElement(D3D_FEATURE_LEVEL_10_1);
   featureLevels.AppendElement(D3D_FEATURE_LEVEL_10_0);
   featureLevels.AppendElement(D3D_FEATURE_LEVEL_9_3);
 
-  RefPtr<IDXGIAdapter1> adapter;
-
-  if (!useWARP) {
-    adapter = GetDXGIAdapter();
-
-    if (!adapter) {
-      if (!gfxPrefs::LayersD3D11DisableWARP()) {
-        return;
-      }
-      useWARP = allowWARP;
+  if (status == D3D11Status::Ok) {
+    if (!AttemptD3D11DeviceCreation(featureLevels)) {
+      status = D3D11Status::TryWARP;
     }
   }
 
-  HRESULT hr = E_INVALIDARG;
-
-  if (!useWARP) {
-    MOZ_SEH_TRY {
-      hr = d3d11CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, nullptr,
-                             // Use
-                             // D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS
-                             // to prevent bug 1092260. IE 11 also uses this flag.
-                             D3D11_CREATE_DEVICE_BGRA_SUPPORT | D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS,
-                             featureLevels.Elements(), featureLevels.Length(),
-                             D3D11_SDK_VERSION, byRef(mD3D11Device), nullptr, nullptr);
-    } MOZ_SEH_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
-      gfxCriticalError() << "Crash during D3D11 device creation";
-
-      if (gfxPrefs::LayersD3D11DisableWARP()) {
-        return;
-      }
-
-      useWARP = allowWARP;
-      adapter = nullptr;
-    }
-
-    if (FAILED(hr) || !DoesD3D11DeviceWork(mD3D11Device)) {
-      gfxCriticalError() << "D3D11 device creation failed" << hexa(hr);
-      if (gfxPrefs::LayersD3D11DisableWARP()) {
-        return;
-      }
-
-      useWARP = allowWARP;
-      adapter = nullptr;
-    }
-
-    if (mD3D11Device) {
-      CheckIfRenderTargetViewNeedsRecreating(mD3D11Device);
-      // Only test this when not using WARP since it can fail and cause GetDeviceRemovedReason to return
-      // weird values.
-      mDoesD3D11TextureSharingWork = ::DoesD3D11TextureSharingWork(mD3D11Device);
-    }
-  }
-
-  if (useWARP) {
-    MOZ_ASSERT(!gfxPrefs::LayersD3D11DisableWARP());
-    MOZ_ASSERT(!mD3D11Device);
-    MOZ_ASSERT(!adapter);
-
-    ScopedGfxFeatureReporter reporterWARP("D3D11-WARP", gfxPrefs::LayersD3D11ForceWARP());
-
-    MOZ_SEH_TRY {
-      hr = d3d11CreateDevice(nullptr, D3D_DRIVER_TYPE_WARP, nullptr,
-                             // Use
-                             // D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS
-                             // to prevent bug 1092260. IE 11 also uses this flag.
-                             D3D11_CREATE_DEVICE_BGRA_SUPPORT,
-                             featureLevels.Elements(), featureLevels.Length(),
-                             D3D11_SDK_VERSION, byRef(mD3D11Device), nullptr, nullptr);
-
-      if (FAILED(hr)) {
-        // This should always succeed... in theory.
-        gfxCriticalError() << "Failed to initialize WARP D3D11 device! " << hexa(hr);
-        return;
-      }
-
-      mIsWARP = true;
-      reporterWARP.SetSuccessful();
-    } MOZ_SEH_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
-      gfxCriticalError() << "Exception occurred initializing WARP D3D11 device!";
+  if (status == D3D11Status::TryWARP || status == D3D11Status::ForceWARP) {
+    if (!AttemptWARPDeviceCreation(featureLevels)) {
+      // Nothing more we can do.
       return;
     }
   }
 
   mD3D11Device->SetExceptionMode(0);
 
   // We create our device for D2D content drawing here. Normally we don't use
   // D2D content drawing when using WARP. However when WARP is forced by
   // default we will let Direct2D use WARP as well.
-  if (Factory::SupportsD2D1() && (!useWARP || gfxPrefs::LayersD3D11ForceWARP())) {
-    MOZ_ASSERT((useWARP && !adapter) || !useWARP);
-
-    hr = E_INVALIDARG;
-    MOZ_SEH_TRY {
-      hr = d3d11CreateDevice(adapter, useWARP ? D3D_DRIVER_TYPE_WARP : D3D_DRIVER_TYPE_UNKNOWN, nullptr,
-                             D3D11_CREATE_DEVICE_BGRA_SUPPORT,
-                             featureLevels.Elements(), featureLevels.Length(),
-                             D3D11_SDK_VERSION, byRef(mD3D11ContentDevice), nullptr, nullptr);
-    } MOZ_SEH_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
+  if (Factory::SupportsD2D1() && (!mIsWARP || (status == D3D11Status::ForceWARP))) {
+    if (!AttemptD3D11ContentDeviceCreation(featureLevels)) {
       mD3D11ContentDevice = nullptr;
-    }
-
-    if (FAILED(hr)) {
       d3d11Module.disown();
       return;
     }
 
     mD3D11ContentDevice->SetExceptionMode(0);
-
     nsRefPtr<ID3D10Multithread> multi;
     mD3D11ContentDevice->QueryInterface(__uuidof(ID3D10Multithread), getter_AddRefs(multi));
     multi->SetMultithreadProtected(TRUE);
 
     Factory::SetDirect3D11Device(mD3D11ContentDevice);
   }
 
-  if (!useWARP) {
-    hr = E_INVALIDARG;
-
-    MOZ_SEH_TRY{
-      hr = d3d11CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, nullptr,
-                             D3D11_CREATE_DEVICE_BGRA_SUPPORT,
-                             featureLevels.Elements(), featureLevels.Length(),
-                             D3D11_SDK_VERSION, byRef(mD3D11ImageBridgeDevice), nullptr, nullptr);
-    } MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
-      mD3D11ImageBridgeDevice = nullptr;
-    }
-
-    if (FAILED(hr)) {
-      d3d11Module.disown();
-      return;
-    }
-
-    mD3D11ImageBridgeDevice->SetExceptionMode(0);
-
-    if (!DoesD3D11AlphaTextureSharingWork(mD3D11ImageBridgeDevice)) {
+  if (!mIsWARP) {
+    if (!AttemptD3D11ImageBridgeDeviceCreation(featureLevels)) {
       mD3D11ImageBridgeDevice = nullptr;
     }
   }
 
   // We leak these everywhere and we need them our entire runtime anyway, let's
   // leak it here as well.
   d3d11Module.disown();
 }
--- a/gfx/thebes/gfxWindowsPlatform.h
+++ b/gfx/thebes/gfxWindowsPlatform.h
@@ -270,19 +270,36 @@ public:
 protected:
     RenderMode mRenderMode;
 
     int8_t mUseClearTypeForDownloadableFonts;
     int8_t mUseClearTypeAlways;
 
 private:
     void Init();
+
     void InitD3D11Devices();
+
+    // Used by InitD3D11Devices().
+    enum class D3D11Status {
+      Ok,
+      TryWARP,
+      ForceWARP,
+      Blocked
+    };
+    D3D11Status CheckD3D11Support();
+    bool AttemptD3D11DeviceCreation(const nsTArray<D3D_FEATURE_LEVEL>& aFeatureLevels);
+    bool AttemptWARPDeviceCreation(const nsTArray<D3D_FEATURE_LEVEL>& aFeatureLevels);
+    bool AttemptD3D11ImageBridgeDeviceCreation(const nsTArray<D3D_FEATURE_LEVEL>& aFeatureLevels);
+    bool AttemptD3D11ContentDeviceCreation(const nsTArray<D3D_FEATURE_LEVEL>& aFeatureLevels);
+
+    // Used by UpdateRenderMode().
     void InitD2DSupport();
     void InitDWriteSupport();
+
     IDXGIAdapter1 *GetDXGIAdapter();
     bool IsDeviceReset(HRESULT hr, DeviceResetReason* aReason);
 
     bool mUseDirectWrite;
     bool mUsingGDIFonts;
 
 #ifdef CAIRO_HAS_DWRITE_FONT
     nsRefPtr<IDWriteFactory> mDWriteFactory;