Bug 830347 - Part 1: Initialize D3D11 device when needed. r=jrmuizel
authorBas Schouten <bschouten@mozilla.com>
Wed, 01 May 2013 16:27:09 +0200
changeset 142933 05762bbaf26800ed44e9020540b6397a7700e1b0
parent 142932 880dc52ab5192306c14a84137057413a8d35a9ae
child 142934 478c8b6a97364acfa1f03ea4d001efbbe5099d74
push id350
push userbbajaj@mozilla.com
push dateMon, 29 Jul 2013 23:00:49 +0000
treeherdermozilla-release@064965b37dbd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjrmuizel
bugs830347
milestone23.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
Bug 830347 - Part 1: Initialize D3D11 device when needed. r=jrmuizel
gfx/thebes/gfxWindowsPlatform.cpp
gfx/thebes/gfxWindowsPlatform.h
--- a/gfx/thebes/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/gfxWindowsPlatform.cpp
@@ -48,16 +48,18 @@ using namespace mozilla::gfx;
 
 #include <d3d10_1.h>
 
 #include "mozilla/gfx/2D.h"
 
 #include "nsMemory.h"
 #endif
 
+#include <d3d11.h>
+
 #include "nsIMemoryReporter.h"
 #include <winternl.h>
 #include "d3dkmtQueryStatistics.h"
 
 using namespace mozilla;
 
 #ifdef CAIRO_HAS_D2D_SURFACE
 
@@ -153,22 +155,35 @@ typedef HRESULT (WINAPI*D3D10CreateDevic
   IDXGIAdapter *pAdapter,
   D3D10_DRIVER_TYPE DriverType,
   HMODULE Software,
   UINT Flags,
   D3D10_FEATURE_LEVEL1 HardwareLevel,
   UINT SDKVersion,
   ID3D10Device1 **ppDevice
 );
+#endif
 
 typedef HRESULT(WINAPI*CreateDXGIFactory1Func)(
   REFIID riid,
   void **ppFactory
 );
-#endif
+
+typedef HRESULT (WINAPI*D3D11CreateDeviceFunc)(
+  IDXGIAdapter *pAdapter,
+  D3D_DRIVER_TYPE DriverType,
+  HMODULE Software,
+  UINT Flags,
+  D3D_FEATURE_LEVEL *pFeatureLevels,
+  UINT FeatureLevels,
+  UINT SDKVersion,
+  ID3D11Device **ppDevice,
+  D3D_FEATURE_LEVEL *pFeatureLevel,
+  ID3D11DeviceContext *ppImmediateContext
+);
 
 class GPUAdapterMultiReporter : public nsIMemoryMultiReporter {
 
     // Callers must Release the DXGIAdapter after use or risk mem-leak
     static bool GetDXGIAdapter(IDXGIAdapter **DXGIAdapter)
     {
         ID3D10Device1 *D2D10Device;
         IDXGIDevice *DXGIDevice;
@@ -312,16 +327,17 @@ static __inline void
 BuildKeyNameFromFontName(nsAString &aName)
 {
     if (aName.Length() >= LF_FACESIZE)
         aName.Truncate(LF_FACESIZE - 1);
     ToLowerCase(aName);
 }
 
 gfxWindowsPlatform::gfxWindowsPlatform()
+  : mD3D11DeviceInitialized(false)
 {
     mPrefFonts.Init(50);
 
     mUseClearTypeForDownloadableFonts = UNINITIALIZED_VALUE;
     mUseClearTypeAlways = UNINITIALIZED_VALUE;
 
     mUsingGDIFonts = false;
 
@@ -523,55 +539,36 @@ gfxWindowsPlatform::VerifyD2DDevice(bool
         }
         mD2DDevice = nullptr;
     }
 
     mozilla::ScopedGfxFeatureReporter reporter("D2D", aAttemptForce);
 
     nsRefPtr<ID3D10Device1> device;
 
-    nsModuleHandle dxgiModule(LoadLibrarySystem32(L"dxgi.dll"));
-    CreateDXGIFactory1Func createDXGIFactory1 = (CreateDXGIFactory1Func)
-        GetProcAddress(dxgiModule, "CreateDXGIFactory1");
-
     int supportedFeatureLevelsCount = ArrayLength(kSupportedFeatureLevels);
     // If we're not running in Metro don't allow DX9.3
     if (!IsRunningInWindowsMetro()) {
       supportedFeatureLevelsCount--;
     }
 
+    nsRefPtr<IDXGIAdapter1> adapter1 = GetDXGIAdapter();
+
+    if (!adapter1) {
+      // Unable to create adapter, abort acceleration.
+      return;
+    }
+
     // It takes a lot of time (5-10% of startup time or ~100ms) to do both
     // a createD3DDevice on D3D10_FEATURE_LEVEL_10_0.  We therefore store
     // the last used feature level to go direct to that.
     int featureLevelIndex = Preferences::GetInt(kFeatureLevelPref, 0);
     if (featureLevelIndex >= supportedFeatureLevelsCount || featureLevelIndex < 0)
       featureLevelIndex = 0;
 
-    // Try to use a DXGI 1.1 adapter in order to share resources
-    // across processes.
-    nsRefPtr<IDXGIAdapter1> adapter1;
-    if (createDXGIFactory1) {
-        nsRefPtr<IDXGIFactory1> factory1;
-        HRESULT hr = createDXGIFactory1(__uuidof(IDXGIFactory1),
-                                        getter_AddRefs(factory1));
-
-        if (FAILED(hr) || !factory1) {
-          // This seems to happen with some people running the iZ3D driver.
-          // They won't get acceleration.
-          return;
-        }
-
-        hr = factory1->EnumAdapters1(0, getter_AddRefs(adapter1));
-        if (FAILED(hr) || !adapter1) {
-          // We should return and not accelerate if we can't obtain
-          // an adapter.
-          return;
-        }
-    }
-
     // Start with the last used feature level, and move to lower DX versions
     // until we find one that works.
     HRESULT hr = E_FAIL;
     for (int i = featureLevelIndex; i < supportedFeatureLevelsCount; i++) {
       hr = CreateDevice(adapter1, i);
       // If it succeeded we found the first available feature level
       if (SUCCEEDED(hr))
         break;
@@ -1427,13 +1424,94 @@ gfxWindowsPlatform::SetupClearTypeParams
 
         GetDWriteFactory()->CreateCustomRenderingParams(gamma, contrast, level,
 	    dwriteGeometry, DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC,
             getter_AddRefs(mRenderingParams[TEXT_RENDERING_GDI_CLASSIC]));
     }
 #endif
 }
 
+ID3D11Device*
+gfxWindowsPlatform::GetD3D11Device()
+{
+  if (mD3D11DeviceInitialized) {
+    return mD3D11Device;
+  }
+
+  mD3D11DeviceInitialized = true;
+
+  nsModuleHandle d3d11Module(LoadLibrarySystem32(L"d3d11.dll"));
+  D3D11CreateDeviceFunc d3d11CreateDevice = (D3D11CreateDeviceFunc)
+    GetProcAddress(d3d11Module, "D3D11CreateDevice");
+
+  if (!d3d11CreateDevice) {
+    return nullptr;
+  }
+
+  D3D_FEATURE_LEVEL featureLevels[] = {
+    D3D_FEATURE_LEVEL_11_1,
+    D3D_FEATURE_LEVEL_11_0,
+    D3D_FEATURE_LEVEL_10_1,
+    D3D_FEATURE_LEVEL_10_0,
+    D3D_FEATURE_LEVEL_9_3
+  };
+
+  RefPtr<IDXGIAdapter1> adapter = GetDXGIAdapter();
+
+  if (!adapter) {
+    return nullptr;
+  }
+
+  HRESULT hr = d3d11CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, NULL,
+                                 D3D11_CREATE_DEVICE_BGRA_SUPPORT,
+                                 featureLevels, sizeof(featureLevels) / sizeof(D3D_FEATURE_LEVEL),
+                                 D3D11_SDK_VERSION, byRef(mD3D11Device), nullptr, nullptr);
+
+  // We leak these everywhere and we need them our entire runtime anyway, let's
+  // leak it here as well.
+  d3d11Module.disown();
+
+  return mD3D11Device;
+}
+
 bool
 gfxWindowsPlatform::IsOptimus()
 {
   return GetModuleHandleA("nvumdshim.dll");
 }
+
+IDXGIAdapter1*
+gfxWindowsPlatform::GetDXGIAdapter()
+{
+  if (mAdapter) {
+    return mAdapter;
+  }
+
+  nsModuleHandle dxgiModule(LoadLibrarySystem32(L"dxgi.dll"));
+  CreateDXGIFactory1Func createDXGIFactory1 = (CreateDXGIFactory1Func)
+    GetProcAddress(dxgiModule, "CreateDXGIFactory1");
+
+  // Try to use a DXGI 1.1 adapter in order to share resources
+  // across processes.
+  if (createDXGIFactory1) {
+    nsRefPtr<IDXGIFactory1> factory1;
+    HRESULT hr = createDXGIFactory1(__uuidof(IDXGIFactory1),
+                                    getter_AddRefs(factory1));
+
+    if (FAILED(hr) || !factory1) {
+      // This seems to happen with some people running the iZ3D driver.
+      // They won't get acceleration.
+      return nullptr;
+    }
+
+    hr = factory1->EnumAdapters1(0, byRef(mAdapter));
+    if (FAILED(hr)) {
+      // We should return and not accelerate if we can't obtain
+      // an adapter.
+      return nullptr;
+    }
+  }
+
+  // We leak this module everywhere, we might as well do so here as well.
+  dxgiModule.disown();
+
+  return mAdapter;
+}
--- a/gfx/thebes/gfxWindowsPlatform.h
+++ b/gfx/thebes/gfxWindowsPlatform.h
@@ -20,23 +20,28 @@
 #include "gfxDWriteFonts.h"
 #endif
 #include "gfxPlatform.h"
 #include "gfxContext.h"
 
 #include "nsTArray.h"
 #include "nsDataHashtable.h"
 
+#include "mozilla/RefPtr.h"
+
 #include <windows.h>
 #include <objbase.h>
 
 #ifdef CAIRO_HAS_D2D_SURFACE
 #include <dxgi.h>
 #endif
 
+class ID3D11Device;
+class IDXGIAdapter1;
+
 class nsIMemoryMultiReporter;
 
 // Utility to get a Windows HDC from a thebes context,
 // used by both GDI and Uniscribe font shapers
 struct DCFromContext {
     DCFromContext(gfxContext *aContext) {
         dc = NULL;
         nsRefPtr<gfxASurface> aSurface = aContext->CurrentSurface();
@@ -250,41 +255,46 @@ public:
     { return mRenderingParams[aRenderMode]; }
 #else
     inline bool DWriteEnabled() { return false; }
 #endif
 #ifdef CAIRO_HAS_D2D_SURFACE
     cairo_device_t *GetD2DDevice() { return mD2DDevice; }
     ID3D10Device1 *GetD3D10Device() { return mD2DDevice ? cairo_d2d_device_get_device(mD2DDevice) : nullptr; }
 #endif
+    ID3D11Device *GetD3D11Device();
 
     static bool IsOptimus();
 
 protected:
     RenderMode mRenderMode;
 
     int8_t mUseClearTypeForDownloadableFonts;
     int8_t mUseClearTypeAlways;
     HDC mScreenDC;
 
 private:
     void Init();
+    IDXGIAdapter1 *GetDXGIAdapter();
 
     bool mUseDirectWrite;
     bool mUsingGDIFonts;
 
 #ifdef CAIRO_HAS_DWRITE_FONT
     nsRefPtr<IDWriteFactory> mDWriteFactory;
     nsRefPtr<IDWriteTextAnalyzer> mDWriteAnalyzer;
     nsRefPtr<IDWriteRenderingParams> mRenderingParams[TEXT_RENDERING_COUNT];
     DWRITE_MEASURING_MODE mMeasuringMode;
 #endif
 #ifdef CAIRO_HAS_D2D_SURFACE
     cairo_device_t *mD2DDevice;
 #endif
+    mozilla::RefPtr<IDXGIAdapter1> mAdapter;
+    mozilla::RefPtr<ID3D11Device> mD3D11Device;
+    bool mD3D11DeviceInitialized;
 
     virtual qcms_profile* GetPlatformCMSOutputProfile();
 
     // TODO: unify this with mPrefFonts (NB: holds families, not fonts) in gfxPlatformFontList
     nsDataHashtable<nsCStringHashKey, nsTArray<nsRefPtr<gfxFontEntry> > > mPrefFonts;
 
     nsIMemoryMultiReporter* mGPUAdapterMultiReporter;
 };