Bug 844954 - Add support for DX9.3 feature level for Metro and cleanup CreateDevice code. r=bas

This commit is contained in:
Brian R. Bondy 2013-03-23 10:19:42 -04:00
Родитель f938c365b2
Коммит f096efb5b1
2 изменённых файлов: 101 добавлений и 137 удалений

Просмотреть файл

@ -49,7 +49,6 @@ using namespace mozilla::gfx;
#include "gfxD2DSurface.h" #include "gfxD2DSurface.h"
#include <d3d10_1.h> #include <d3d10_1.h>
#include <dxgi.h>
#include "mozilla/gfx/2D.h" #include "mozilla/gfx/2D.h"
@ -89,6 +88,12 @@ using namespace mozilla;
#ifdef CAIRO_HAS_D2D_SURFACE #ifdef CAIRO_HAS_D2D_SURFACE
static const char *kFeatureLevelPref =
"gfx.direct3d.last_used_feature_level_idx";
static const int kSupportedFeatureLevels[] =
{ D3D10_FEATURE_LEVEL_10_1, D3D10_FEATURE_LEVEL_10_0,
D3D10_FEATURE_LEVEL_9_3 };
NS_MEMORY_REPORTER_IMPLEMENT( NS_MEMORY_REPORTER_IMPLEMENT(
D2DCache, D2DCache,
"gfx-d2d-surfacecache", "gfx-d2d-surfacecache",
@ -504,6 +509,42 @@ gfxWindowsPlatform::UpdateRenderMode()
InitBackendPrefs(canvasMask, contentMask); InitBackendPrefs(canvasMask, contentMask);
} }
#ifdef CAIRO_HAS_D2D_SURFACE
HRESULT
gfxWindowsPlatform::CreateDevice(nsRefPtr<IDXGIAdapter1> &adapter1,
int featureLevelIndex)
{
nsModuleHandle d3d10module(LoadLibrarySystem32(L"d3d10_1.dll"));
if (!d3d10module)
return E_FAIL;
D3D10CreateDevice1Func createD3DDevice =
(D3D10CreateDevice1Func)GetProcAddress(d3d10module, "D3D10CreateDevice1");
if (!createD3DDevice)
return E_FAIL;
nsRefPtr<ID3D10Device1> device;
HRESULT hr =
createD3DDevice(adapter1, D3D10_DRIVER_TYPE_HARDWARE, NULL,
D3D10_CREATE_DEVICE_BGRA_SUPPORT |
D3D10_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS,
static_cast<D3D10_FEATURE_LEVEL1>(kSupportedFeatureLevels[featureLevelIndex]),
D3D10_1_SDK_VERSION, getter_AddRefs(device));
// If we fail here, the DirectX version or video card probably
// changed. We previously could use 10.1 but now we can't
// anymore. Revert back to doing a 10.0 check first before
// the 10.1 check.
if (device) {
mD2DDevice = cairo_d2d_create_device_from_d3d10device(device);
// Setup a pref for future launch optimizaitons
Preferences::SetInt(kFeatureLevelPref, featureLevelIndex);
}
return device ? S_OK : hr;
}
#endif
void void
gfxWindowsPlatform::VerifyD2DDevice(bool aAttemptForce) gfxWindowsPlatform::VerifyD2DDevice(bool aAttemptForce)
{ {
@ -519,154 +560,69 @@ gfxWindowsPlatform::VerifyD2DDevice(bool aAttemptForce)
mozilla::ScopedGfxFeatureReporter reporter("D2D", aAttemptForce); mozilla::ScopedGfxFeatureReporter reporter("D2D", aAttemptForce);
HMODULE d3d10module = LoadLibraryA("d3d10_1.dll");
D3D10CreateDevice1Func createD3DDevice = (D3D10CreateDevice1Func)
GetProcAddress(d3d10module, "D3D10CreateDevice1");
nsRefPtr<ID3D10Device1> device; nsRefPtr<ID3D10Device1> device;
if (createD3DDevice) { nsModuleHandle dxgiModule(LoadLibrarySystem32(L"dxgi.dll"));
HMODULE dxgiModule = LoadLibraryA("dxgi.dll"); CreateDXGIFactory1Func createDXGIFactory1 = (CreateDXGIFactory1Func)
CreateDXGIFactory1Func createDXGIFactory1 = (CreateDXGIFactory1Func) GetProcAddress(dxgiModule, "CreateDXGIFactory1");
GetProcAddress(dxgiModule, "CreateDXGIFactory1");
// Try to use a DXGI 1.1 adapter in order to share resources int supportedFeatureLevelsCount = ArrayLength(kSupportedFeatureLevels);
// across processes. // If we're not running in Metro don't allow DX9.3
nsRefPtr<IDXGIAdapter1> adapter1; if (!IsRunningInWindowsMetro()) {
if (createDXGIFactory1) { supportedFeatureLevelsCount--;
nsRefPtr<IDXGIFactory1> factory1; }
HRESULT hr = createDXGIFactory1(__uuidof(IDXGIFactory1),
getter_AddRefs(factory1));
if (FAILED(hr) || !factory1) { // It takes a lot of time (5-10% of startup time or ~100ms) to do both
// This seems to happen with some people running the iZ3D driver. // a createD3DDevice on D3D10_FEATURE_LEVEL_10_0. We therefore store
// They won't get acceleration. // the last used feature level to go direct to that.
return; int featureLevelIndex = Preferences::GetInt(kFeatureLevelPref, 0);
} if (featureLevelIndex >= supportedFeatureLevelsCount || featureLevelIndex < 0) {
featureLevelIndex = 0;
}
bool checkDX10 = // Try to use a DXGI 1.1 adapter in order to share resources
Preferences::GetBool("gfx.direct3d.checkDX10", true); // across processes.
hr = factory1->EnumAdapters1(0, getter_AddRefs(adapter1)); nsRefPtr<IDXGIAdapter1> adapter1;
if (SUCCEEDED(hr) && adapter1) { if (createDXGIFactory1) {
// We have an adapter, check if we've ever found that nsRefPtr<IDXGIFactory1> factory1;
// createD3DDevice fails for both DX10 and DX10.1. HRESULT hr = createDXGIFactory1(__uuidof(IDXGIFactory1),
if (!checkDX10) { getter_AddRefs(factory1));
// Even if the CheckInterfaceSupport call fails, the
// createD3DDevice call may still succeed.
// We only check it here to reset the pref which is used to skip
// the createD3DDevice calls. This is done in case hardware
// changes.
hr = adapter1->CheckInterfaceSupport(__uuidof(ID3D10Device),
nullptr);
if (SUCCEEDED(hr)) {
checkDX10 = true;
Preferences::SetBool("gfx.direct3d.checkDX10", true);
}
}
} else {
// We should return and not accelerate if we can't obtain
// an adapter.
return;
}
// If we know that the DX10 calls have failed in the past, just if (FAILED(hr) || !factory1) {
// bail out early. This value will be reset if the adapter's // This seems to happen with some people running the iZ3D driver.
// CheckInterfaceSupport call ever succeeds with ID3D10Device // They won't get acceleration.
if (!checkDX10) { return;
return;
}
} }
// It takes a lot of time (5-10% of startup time or ~100ms) to do both hr = factory1->EnumAdapters1(0, getter_AddRefs(adapter1));
// a createD3DDevice on D3D10_FEATURE_LEVEL_10_0 and if (FAILED(hr) || !adapter1) {
// D3D10_FEATURE_LEVEL_10_1. Therefore we set a pref if we ever get // We should return and not accelerate if we can't obtain
// 10.1 to work and we use that first if the pref is set. // an adapter.
// Going direct to a 10.1 check only takes 20-30ms. return;
// The initialization of hr doesn't matter here because it will get
// overwritten whether or not the preference is set.
// - If the preferD3D10_1 pref is set it gets overwritten immediately.
// - If the preferD3D10_1 pref is not set, the if condition after
// the one that follows us immediately will short circuit before
// checking FAILED(hr) and will again get overwritten immediately.
// We initialize it here just so it does not appear to be an
// uninitialized value.
HRESULT hr = E_FAIL;
bool preferD3D10_1 =
Preferences::GetBool("gfx.direct3d.prefer_10_1", false);
if (preferD3D10_1) {
hr = createD3DDevice(
adapter1,
D3D10_DRIVER_TYPE_HARDWARE,
NULL,
D3D10_CREATE_DEVICE_BGRA_SUPPORT |
D3D10_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS,
D3D10_FEATURE_LEVEL_10_1,
D3D10_1_SDK_VERSION,
getter_AddRefs(device));
// If we fail here, the DirectX version or video card probably
// changed. We previously could use 10.1 but now we can't
// anymore. Revert back to doing a 10.0 check first before
// the 10.1 check.
if (FAILED(hr)) {
Preferences::SetBool("gfx.direct3d.prefer_10_1", false);
} else {
mD2DDevice = cairo_d2d_create_device_from_d3d10device(device);
}
} }
}
if (!preferD3D10_1 || FAILED(hr)) { // Start with the last used feature level, and move to lower DX versions
// If preferD3D10_1 is set and 10.1 failed, fall back to 10.0. // until we find one that works.
// if preferD3D10_1 is not yet set, then first try to create HRESULT hr = E_FAIL;
// a 10.0 D3D device, then try to see if 10.1 works. for (int i = featureLevelIndex; i < supportedFeatureLevelsCount; i++) {
nsRefPtr<ID3D10Device1> device1; hr = CreateDevice(adapter1, i);
hr = createD3DDevice( // If it succeeded we found the first available feature level
adapter1, if (SUCCEEDED(hr)) {
D3D10_DRIVER_TYPE_HARDWARE, break;
NULL, }
D3D10_CREATE_DEVICE_BGRA_SUPPORT | }
D3D10_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS,
D3D10_FEATURE_LEVEL_10_0,
D3D10_1_SDK_VERSION,
getter_AddRefs(device1));
if (SUCCEEDED(hr)) { // If we succeeded in creating a device, try for a newer device
device = device1; // that we haven't tried yet.
if (preferD3D10_1) { if (SUCCEEDED(hr)) {
mD2DDevice = for (int i = featureLevelIndex - 1; i >= 0; i--) {
cairo_d2d_create_device_from_d3d10device(device); hr = CreateDevice(adapter1, i);
} // If it failed then we don't have new hardware
} if (FAILED(hr)) {
} break;
// If preferD3D10_1 is not yet set and 10.0 succeeded
if (!preferD3D10_1 && SUCCEEDED(hr)) {
// We have 10.0, let's try 10.1. This second check will only
// ever be done once if it succeeds. After that an option
// will be set to prefer using 10.1 before trying 10.0.
// In the case that 10.1 fails, it won't be a long operation
// like it is when 10.1 succeeds, so we don't need to optimize
// the case where 10.1 is not supported, but 10.0 is supported.
nsRefPtr<ID3D10Device1> device1;
hr = createD3DDevice(
adapter1,
D3D10_DRIVER_TYPE_HARDWARE,
NULL,
D3D10_CREATE_DEVICE_BGRA_SUPPORT |
D3D10_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS,
D3D10_FEATURE_LEVEL_10_1,
D3D10_1_SDK_VERSION,
getter_AddRefs(device1));
if (SUCCEEDED(hr)) {
device = device1;
Preferences::SetBool("gfx.direct3d.prefer_10_1", true);
}
mD2DDevice = cairo_d2d_create_device_from_d3d10device(device);
}
if (FAILED(hr) || !device) {
Preferences::SetBool("gfx.direct3d.checkDX10", false);
} }
}
} }
if (!mD2DDevice && aAttemptForce) { if (!mD2DDevice && aAttemptForce) {

Просмотреть файл

@ -28,6 +28,10 @@
#include <windows.h> #include <windows.h>
#include <objbase.h> #include <objbase.h>
#ifdef CAIRO_HAS_D2D_SURFACE
#include <dxgi.h>
#endif
class nsIMemoryMultiReporter; class nsIMemoryMultiReporter;
// Utility to get a Windows HDC from a thebes context, // Utility to get a Windows HDC from a thebes context,
@ -147,6 +151,10 @@ public:
*/ */
void VerifyD2DDevice(bool aAttemptForce); void VerifyD2DDevice(bool aAttemptForce);
#ifdef CAIRO_HAS_D2D_SURFACE
HRESULT CreateDevice(nsRefPtr<IDXGIAdapter1> &adapter1, int featureLevelIndex);
#endif
HDC GetScreenDC() { return mScreenDC; } HDC GetScreenDC() { return mScreenDC; }
nsresult GetFontList(nsIAtom *aLangGroup, nsresult GetFontList(nsIAtom *aLangGroup,