Bug 969831 - Share code for checking minumum d3d feature level required for running metro and expose this information (including cached check results) via nsIWinMetroUtils. r=bbondy

This commit is contained in:
Jim Mathies 2014-02-28 07:37:30 -06:00
parent 93c8254d5f
commit 5c647f1701
7 changed files with 174 additions and 73 deletions

View File

@ -5,6 +5,7 @@
#include "CEHHelper.h"
#include <tlhelp32.h>
#include "mozilla/widget/MetroD3DCheckHelper.h"
#ifdef SHOW_CONSOLE
#include <io.h> // _open_osfhandle
@ -139,73 +140,9 @@ IsDX10Available()
if (GetDWORDRegKey(metroDX10Available, isDX10Available)) {
return isDX10Available;
}
HMODULE dxgiModule = LoadLibraryA("dxgi.dll");
if (!dxgiModule) {
SetDWORDRegKey(metroDX10Available, 0);
return false;
}
decltype(CreateDXGIFactory1)* createDXGIFactory1 =
(decltype(CreateDXGIFactory1)*) GetProcAddress(dxgiModule, "CreateDXGIFactory1");
if (!createDXGIFactory1) {
SetDWORDRegKey(metroDX10Available, 0);
return false;
}
HMODULE d3d10module = LoadLibraryA("d3d10_1.dll");
if (!d3d10module) {
SetDWORDRegKey(metroDX10Available, 0);
return false;
}
decltype(D3D10CreateDevice1)* createD3DDevice =
(decltype(D3D10CreateDevice1)*) GetProcAddress(d3d10module,
"D3D10CreateDevice1");
if (!createD3DDevice) {
SetDWORDRegKey(metroDX10Available, 0);
return false;
}
CComPtr<IDXGIFactory1> factory1;
if (FAILED(createDXGIFactory1(__uuidof(IDXGIFactory1), (void**)&factory1))) {
SetDWORDRegKey(metroDX10Available, 0);
return false;
}
CComPtr<IDXGIAdapter1> adapter1;
if (FAILED(factory1->EnumAdapters1(0, &adapter1))) {
SetDWORDRegKey(metroDX10Available, 0);
return false;
}
CComPtr<ID3D10Device1> device;
// Try for DX10.1
if (FAILED(createD3DDevice(adapter1, D3D10_DRIVER_TYPE_HARDWARE, nullptr,
D3D10_CREATE_DEVICE_BGRA_SUPPORT |
D3D10_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS,
D3D10_FEATURE_LEVEL_10_1,
D3D10_1_SDK_VERSION, &device))) {
// Try for DX10
if (FAILED(createD3DDevice(adapter1, D3D10_DRIVER_TYPE_HARDWARE, nullptr,
D3D10_CREATE_DEVICE_BGRA_SUPPORT |
D3D10_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS,
D3D10_FEATURE_LEVEL_10_0,
D3D10_1_SDK_VERSION, &device))) {
// Try for DX9.3 (we fall back to cairo and cairo has support for D3D 9.3)
if (FAILED(createD3DDevice(adapter1, D3D10_DRIVER_TYPE_HARDWARE, nullptr,
D3D10_CREATE_DEVICE_BGRA_SUPPORT |
D3D10_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS,
D3D10_FEATURE_LEVEL_9_3,
D3D10_1_SDK_VERSION, &device))) {
SetDWORDRegKey(metroDX10Available, 0);
return false;
}
}
}
SetDWORDRegKey(metroDX10Available, 1);
return true;
bool check = D3DFeatureLevelCheck();
SetDWORDRegKey(metroDX10Available, check);
return check;
}
bool

View File

@ -9,15 +9,11 @@
#define _WIN32_WINNT 0x602
#include <windows.h>
#include <d3d10_1.h>
#include <dxgi.h>
#include <d3d10misc.h>
#include <atlbase.h>
#include <shlobj.h>
//#define SHOW_CONSOLE 1
extern HANDLE sCon;
extern LPCWSTR metroDX10Available;
void Log(const wchar_t *fmt, ...);

View File

@ -765,6 +765,11 @@ IFACEMETHODIMP CExecuteCommandVerb::Execute()
return E_FAIL;
}
if (!IsDX10Available()) {
Log(L"Can't launch in metro due to missing hardware acceleration features.");
mRequestType = DESKTOP_RESTART;
}
// Deal with metro restart for an update - launch desktop with a command
// that tells it to run updater then launch the metro browser.
if (mRequestType == METRO_UPDATE) {

View File

@ -8,13 +8,19 @@
/**
* Integration with the "Metro"/"Modern" UI environment in Windows 8.
*
* Note: browser/metro/base/content/browser-scripts.js contains a stub
* Note: browser/metro/base/content/browser.js contains a stub
* implementation of this interface for non-Windows systems, for testing and
* development purposes only.
*/
[scriptable, uuid(dde6eee6-ad11-475b-b7d7-bee8e46e5756)]
[scriptable, uuid(319faae0-82ca-4c2f-8a24-2b2445e5a72a)]
interface nsIWinMetroUtils : nsISupports
{
/**
* Determine if the current device has the hardware capabilities to run
* in metro mode.
*/
readonly attribute boolean supported;
/**
* Determine if the current browser is running in the metro immersive
* environment.

View File

@ -0,0 +1,96 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
#pragma once
/* this file is included by exe stubs, don't pull xpcom into it. */
#include <d3d10_1.h>
#include <dxgi.h>
#include <d3d10misc.h>
/*
* Checks to see if the d3d implementation supports feature level 9.3 or
* above. Metrofx can't run on systems that fail this check.
*
* Note, this can hit perf, don't call this unless you absolutely have to.
* Both the ceh and winrt widget code save a cached result in the registry.
*/
static bool D3DFeatureLevelCheck()
{
HMODULE dxgiModule = LoadLibraryA("dxgi.dll");
if (!dxgiModule) {
return false;
}
decltype(CreateDXGIFactory1)* createDXGIFactory1 =
(decltype(CreateDXGIFactory1)*) GetProcAddress(dxgiModule, "CreateDXGIFactory1");
if (!createDXGIFactory1) {
FreeLibrary(dxgiModule);
return false;
}
HMODULE d3d10module = LoadLibraryA("d3d10_1.dll");
if (!d3d10module) {
FreeLibrary(dxgiModule);
return false;
}
decltype(D3D10CreateDevice1)* createD3DDevice =
(decltype(D3D10CreateDevice1)*) GetProcAddress(d3d10module,
"D3D10CreateDevice1");
if (!createD3DDevice) {
FreeLibrary(d3d10module);
FreeLibrary(dxgiModule);
return false;
}
IDXGIFactory1* factory1;
if (FAILED(createDXGIFactory1(__uuidof(IDXGIFactory1), (void**)&factory1))) {
FreeLibrary(d3d10module);
FreeLibrary(dxgiModule);
return false;
}
IDXGIAdapter1* adapter1;
if (FAILED(factory1->EnumAdapters1(0, &adapter1))) {
factory1->Release();
FreeLibrary(d3d10module);
FreeLibrary(dxgiModule);
return false;
}
// Try for DX10.1
ID3D10Device1* device;
if (FAILED(createD3DDevice(adapter1, D3D10_DRIVER_TYPE_HARDWARE, nullptr,
D3D10_CREATE_DEVICE_BGRA_SUPPORT |
D3D10_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS,
D3D10_FEATURE_LEVEL_10_1,
D3D10_1_SDK_VERSION, &device))) {
// Try for DX10
if (FAILED(createD3DDevice(adapter1, D3D10_DRIVER_TYPE_HARDWARE, nullptr,
D3D10_CREATE_DEVICE_BGRA_SUPPORT |
D3D10_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS,
D3D10_FEATURE_LEVEL_10_0,
D3D10_1_SDK_VERSION, &device))) {
// Try for DX9.3 (we fall back to cairo and cairo has support for D3D 9.3)
if (FAILED(createD3DDevice(adapter1, D3D10_DRIVER_TYPE_HARDWARE, nullptr,
D3D10_CREATE_DEVICE_BGRA_SUPPORT |
D3D10_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS,
D3D10_FEATURE_LEVEL_9_3,
D3D10_1_SDK_VERSION, &device))) {
adapter1->Release();
factory1->Release();
FreeLibrary(d3d10module);
FreeLibrary(dxgiModule);
return false;
}
}
}
device->Release();
adapter1->Release();
factory1->Release();
FreeLibrary(d3d10module);
FreeLibrary(dxgiModule);
return true;
}

View File

@ -25,6 +25,10 @@ EXTRA_COMPONENTS += [
'MetroUIUtils.manifest',
]
EXPORTS.mozilla.widget += [
'MetroD3DCheckHelper.h',
]
include('/ipc/chromium/chromium-config.mozbuild')
FINAL_LIBRARY = 'xul'

View File

@ -9,6 +9,10 @@
#include "FrameworkView.h"
#include "MetroApp.h"
#include "ToastNotificationHandler.h"
#include "mozilla/Preferences.h"
#include "mozilla/WindowsVersion.h"
#include "nsIWindowsRegKey.h"
#include "mozilla/widget/MetroD3DCheckHelper.h"
#include <shldisp.h>
#include <shellapi.h>
@ -341,5 +345,58 @@ nsWinMetroUtils::GetForeground(bool* aForeground)
return NS_OK;
}
NS_IMETHODIMP
nsWinMetroUtils::GetSupported(bool *aSupported)
{
*aSupported = false;
if (!IsWin8OrLater()) {
return NS_OK;
}
// if last_used_feature_level_idx is set, we've previously created a
// d3d device that's compatible. See gfxEindowsPlatform for details.
if (Preferences::GetInt("gfx.direct3d.last_used_feature_level_idx", -1) != -1) {
*aSupported = true;
return NS_OK;
}
// if last_used_feature_level_idx isn't set, gfx hasn't attempted to create
// a device yet. This could be a case where d2d is pref'd off or blacklisted
// on desktop, or we tried to create a device and failed. This could also be
// a first run case where we haven't created an accelerated top level window
// yet.
NS_NAMED_LITERAL_STRING(metroRegValueName, "MetroD3DAvailable");
NS_NAMED_LITERAL_STRING(metroRegValuePath, "Software\\Mozilla\\Firefox");
// Check to see if the ceh launched us, it also does this check and caches
// a flag in the registry.
nsresult rv;
uint32_t value = 0;
nsCOMPtr<nsIWindowsRegKey> regKey =
do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv);
if (NS_SUCCEEDED(rv)) {
rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER,
metroRegValuePath,
nsIWindowsRegKey::ACCESS_WRITE);
if (NS_SUCCEEDED(rv)) {
rv = regKey->ReadIntValue(metroRegValueName, &value);
if (NS_SUCCEEDED(rv)) {
*aSupported = (bool)value;
return NS_OK;
}
// If all else fails, do the check here. This call is costly but
// we shouldn't hit this except in rare situations where the
// ceh never launched the browser that's running.
value = D3DFeatureLevelCheck();
regKey->WriteIntValue(metroRegValueName, value);
*aSupported = (bool)value;
return NS_OK;
}
}
return NS_OK;
}
} // widget
} // mozilla