Refactor graphics device initialization on Windows. (bug 1183910 part 1, r=mattwoodrow,bas)

This patch addresses a number of inconsistencies in the device initialization process, as well as simplifying it for future use. All device decisions are now explicitly made up-front during startup, rather than implicitly or on-demand. In addition a number of restrictions have been placed on when we can construct devices.

Full change list:
 (1) We no longer attempt to use D3D11 if acceleration is disabled or D3D9 is preferred. This is a departure from our previous behavior, where we would construct these devices but then not use them as a compositor backend.
 (2) D3D11 startup no longer creates a content device (this is reserved for D2D initialization).
 (3) D2D is only attempted if we managed to create a D3D11 compositor device. This is a departure from previous behavior where if D3D11 was not used for compositing, we could still create its machinery to use D2D as a content backend.
 (4) D2D 1.1 initialization is now directly responsible for creating a D3D11 content device.
 (5) D2D 1.0 and 1.1 logic have been disentangled for clarity.
 (6) UpdateRenderMode() has been split up, so we can update backend prefs out of band with device resets.
 (7) mUseGDIFonts and mUseDirectWrite have been removed as their state was confusing. Instead, D2D now depends on DWrite initialization succeeding. If later we fail to get a DWrite font list, we revert our decision to use Direct2D.
 (8) Device resets now clear a little more state, including the devices set in Moz2D Factory.
 (9) We no longer create a DWrite text analyzer as it was unused.
This commit is contained in:
David Anderson 2015-07-28 16:52:54 -07:00
parent 40d2777ac4
commit a10ad42d90
5 changed files with 361 additions and 294 deletions

View File

@ -621,7 +621,9 @@ Factory::SetDirect3D10Device(ID3D10Device1 *aDevice)
// do not throw on failure; return error codes and disconnect the device
// On Windows 8 error codes are the default, but on Windows 7 the
// default is to throw (or perhaps only with some drivers?)
aDevice->SetExceptionMode(0);
if (aDevice) {
aDevice->SetExceptionMode(0);
}
mD3D10Device = aDevice;
}

View File

@ -342,11 +342,11 @@ TextureClient::CreateForDrawing(ISurfaceAllocator* aAllocator,
#ifdef XP_WIN
LayersBackend parentBackend = aAllocator->GetCompositorBackendType();
if (parentBackend == LayersBackend::LAYERS_D3D11 &&
(aMoz2DBackend == gfx::BackendType::DIRECT2D ||
aMoz2DBackend == gfx::BackendType::DIRECT2D1_1) &&
gfxWindowsPlatform::GetPlatform()->GetD3D10Device() &&
((aMoz2DBackend == gfx::BackendType::DIRECT2D && Factory::GetDirect3D10Device()) ||
(aMoz2DBackend == gfx::BackendType::DIRECT2D1_1 && Factory::GetDirect3D11Device())) &&
aSize.width <= maxTextureSize &&
aSize.height <= maxTextureSize) {
aSize.height <= maxTextureSize)
{
texture = new TextureClientD3D11(aAllocator, aFormat, aTextureFlags);
}
if (parentBackend == LayersBackend::LAYERS_D3D9 &&

View File

@ -2237,7 +2237,7 @@ gfxPlatform::ShouldUseLayersAcceleration()
if (gfxPrefs::LayersAccelerationForceEnabled()) {
return true;
}
if (gfxPlatform::GetPlatform()->AccelerateLayersByDefault()) {
if (AccelerateLayersByDefault()) {
return true;
}
if (acceleratedEnv && *acceleratedEnv != '0') {

View File

@ -373,18 +373,18 @@ public:
NS_IMPL_ISUPPORTS(D3D9SharedTextureReporter, nsIMemoryReporter)
gfxWindowsPlatform::gfxWindowsPlatform()
: mD3D11DeviceInitialized(false)
: mRenderMode(RENDER_GDI)
, mIsWARP(false)
, mHasDeviceReset(false)
, mDoesD3D11TextureSharingWork(false)
, mAcceleration(FeatureStatus::Unused)
, mD3D11Status(FeatureStatus::Unused)
, mD2DStatus(FeatureStatus::Unused)
, mD2D1Status(FeatureStatus::Unused)
{
mUseClearTypeForDownloadableFonts = UNINITIALIZED_VALUE;
mUseClearTypeAlways = UNINITIALIZED_VALUE;
mUsingGDIFonts = false;
/*
* Initialize COM
*/
@ -392,10 +392,16 @@ gfxWindowsPlatform::gfxWindowsPlatform()
RegisterStrongMemoryReporter(new GfxD2DVramReporter());
if (gfxPrefs::Direct2DUse1_1()) {
InitD3D11Devices();
// Set up the D3D11 feature levels we can ask for.
if (IsWin8OrLater()) {
mFeatureLevels.AppendElement(D3D_FEATURE_LEVEL_11_1);
}
mFeatureLevels.AppendElement(D3D_FEATURE_LEVEL_11_0);
mFeatureLevels.AppendElement(D3D_FEATURE_LEVEL_10_1);
mFeatureLevels.AppendElement(D3D_FEATURE_LEVEL_10_0);
mFeatureLevels.AppendElement(D3D_FEATURE_LEVEL_9_3);
InitializeDevices();
UpdateRenderMode();
RegisterStrongMemoryReporter(new GPUAdapterReporter());
@ -438,161 +444,106 @@ gfxWindowsPlatform::CanUseHardwareVideoDecoding()
return !IsWARP() && gfxPlatform::CanUseHardwareVideoDecoding();
}
FeatureStatus
gfxWindowsPlatform::InitD2DSupport()
{
#ifdef CAIRO_HAS_D2D_SURFACE
bool d2dBlocked = false;
nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
if (gfxInfo) {
int32_t status;
if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT2D, &status))) {
if (status != nsIGfxInfo::FEATURE_STATUS_OK) {
d2dBlocked = true;
}
}
if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS, &status))) {
if (status != nsIGfxInfo::FEATURE_STATUS_OK) {
d2dBlocked = true;
}
}
}
// If D2D is blocked or D3D9 is prefered, and D2D is not force-enabled, then
// we don't attempt to use D2D.
if (!gfxPrefs::Direct2DForceEnabled()) {
if (d2dBlocked) {
return FeatureStatus::Blacklisted;
}
if (gfxPrefs::LayersPreferD3D9()) {
return FeatureStatus::Disabled;
}
}
// Do not ever try to use D2D if it's explicitly disabled or if we're not
// using DWrite fonts.
if (gfxPrefs::Direct2DDisabled() || mUsingGDIFonts) {
return FeatureStatus::Disabled;
}
if (!IsVistaOrLater() || !GetD3D11Device()) {
return FeatureStatus::Unavailable;
}
if (!mDoesD3D11TextureSharingWork) {
return FeatureStatus::Failed;
}
if (InSafeMode()) {
return FeatureStatus::Blocked;
}
VerifyD2DDevice(gfxPrefs::Direct2DForceEnabled());
if (!mD3D10Device || !GetD3D11Device()) {
return FeatureStatus::Failed;
}
mRenderMode = RENDER_DIRECT2D;
mUseDirectWrite = true;
return FeatureStatus::Available;
#else
return FeatureStatus::Unavailable;
#endif
}
void
bool
gfxWindowsPlatform::InitDWriteSupport()
{
#ifdef CAIRO_HAS_DWRITE_FONT
// Enable when it's preffed on -and- we're using Vista or higher. Or when
// we're going to use D2D.
if (mDWriteFactory || (!mUseDirectWrite || !IsVistaOrLater())) {
return;
}
MOZ_ASSERT(!mDWriteFactory && IsVistaOrLater());
mozilla::ScopedGfxFeatureReporter reporter("DWrite");
decltype(DWriteCreateFactory)* createDWriteFactory = (decltype(DWriteCreateFactory)*)
GetProcAddress(LoadLibraryW(L"dwrite.dll"), "DWriteCreateFactory");
if (!createDWriteFactory) {
return;
return false;
}
// I need a direct pointer to be able to cast to IUnknown**, I also need to
// remember to release this because the nsRefPtr will AddRef it.
IDWriteFactory *factory;
RefPtr<IDWriteFactory> factory;
HRESULT hr = createDWriteFactory(
DWRITE_FACTORY_TYPE_SHARED,
__uuidof(IDWriteFactory),
reinterpret_cast<IUnknown**>(&factory));
if (SUCCEEDED(hr) && factory) {
mDWriteFactory = factory;
factory->Release();
hr = mDWriteFactory->CreateTextAnalyzer(getter_AddRefs(mDWriteAnalyzer));
(IUnknown **)((IDWriteFactory **)byRef(factory)));
if (FAILED(hr) || !factory) {
return false;
}
mDWriteFactory = factory;
SetupClearTypeParams();
reporter.SetSuccessful();
return true;
}
if (hr == S_OK) {
reporter.SetSuccessful();
bool
gfxWindowsPlatform::HandleDeviceReset()
{
DeviceResetReason resetReason = DeviceResetReason::OK;
if (!DidRenderingDeviceReset(&resetReason)) {
return false;
}
#endif
Telemetry::Accumulate(Telemetry::DEVICE_RESET_REASON, uint32_t(resetReason));
// Remove devices and adapters.
mD3D10Device = nullptr;
mD3D11Device = nullptr;
mD3D11ContentDevice = nullptr;
mD3D11ImageBridgeDevice = nullptr;
mAdapter = nullptr;
Factory::SetDirect3D11Device(nullptr);
Factory::SetDirect3D10Device(nullptr);
// Reset local state. Note: we leave feature status variables as-is. They
// will be recomputed by InitializeDevices().
mIsWARP = false;
mHasDeviceReset = false;
mDoesD3D11TextureSharingWork = false;
mDeviceResetReason = DeviceResetReason::OK;
imgLoader::Singleton()->ClearCache(true);
imgLoader::Singleton()->ClearCache(false);
gfxAlphaBoxBlur::ShutdownBlurCache();
InitializeDevices();
return true;
}
void
gfxWindowsPlatform::UpdateBackendPrefs()
{
uint32_t canvasMask = BackendTypeBit(BackendType::CAIRO);
uint32_t contentMask = BackendTypeBit(BackendType::CAIRO);
BackendType defaultBackend = BackendType::CAIRO;
if (GetD2DStatus() == FeatureStatus::Available) {
mRenderMode = RENDER_DIRECT2D;
canvasMask |= BackendTypeBit(BackendType::DIRECT2D);
contentMask |= BackendTypeBit(BackendType::DIRECT2D);
if (GetD2D1Status() == FeatureStatus::Available) {
contentMask |= BackendTypeBit(BackendType::DIRECT2D1_1);
canvasMask |= BackendTypeBit(BackendType::DIRECT2D1_1);
defaultBackend = BackendType::DIRECT2D1_1;
} else {
defaultBackend = BackendType::DIRECT2D;
}
} else {
mRenderMode = RENDER_GDI;
canvasMask |= BackendTypeBit(BackendType::SKIA);
}
contentMask |= BackendTypeBit(BackendType::SKIA);
InitBackendPrefs(canvasMask, defaultBackend, contentMask, defaultBackend);
}
void
gfxWindowsPlatform::UpdateRenderMode()
{
/* Pick the default render mode for
* desktop.
*/
bool didReset = false;
DeviceResetReason resetReason = DeviceResetReason::OK;
if (DidRenderingDeviceReset(&resetReason)) {
Telemetry::Accumulate(Telemetry::DEVICE_RESET_REASON, uint32_t(resetReason));
mD3D11DeviceInitialized = false;
mD3D11Device = nullptr;
mD3D11ContentDevice = nullptr;
mAdapter = nullptr;
mDeviceResetReason = DeviceResetReason::OK;
mHasDeviceReset = false;
bool didReset = HandleDeviceReset();
imgLoader::Singleton()->ClearCache(true);
imgLoader::Singleton()->ClearCache(false);
gfxAlphaBoxBlur::ShutdownBlurCache();
Factory::SetDirect3D11Device(nullptr);
UpdateBackendPrefs();
didReset = true;
}
mRenderMode = RENDER_GDI;
mUseDirectWrite = gfxPrefs::DirectWriteFontRenderingEnabled();
mD2DStatus = InitD2DSupport();
InitDWriteSupport();
uint32_t canvasMask = BackendTypeBit(BackendType::CAIRO);
uint32_t contentMask = BackendTypeBit(BackendType::CAIRO);
BackendType defaultBackend = BackendType::CAIRO;
if (mRenderMode == RENDER_DIRECT2D) {
canvasMask |= BackendTypeBit(BackendType::DIRECT2D);
contentMask |= BackendTypeBit(BackendType::DIRECT2D);
if (gfxPrefs::Direct2DUse1_1() && Factory::SupportsD2D1() &&
GetD3D11ContentDevice()) {
contentMask |= BackendTypeBit(BackendType::DIRECT2D1_1);
canvasMask |= BackendTypeBit(BackendType::DIRECT2D1_1);
defaultBackend = BackendType::DIRECT2D1_1;
} else {
defaultBackend = BackendType::DIRECT2D;
}
} else {
canvasMask |= BackendTypeBit(BackendType::SKIA);
}
contentMask |= BackendTypeBit(BackendType::SKIA);
InitBackendPrefs(canvasMask, defaultBackend,
contentMask, defaultBackend);
if (didReset) {
mScreenReferenceDrawTarget = CreateOffscreenContentDrawTarget(IntSize(1, 1), SurfaceFormat::B8G8R8A8);
}
if (didReset) {
mScreenReferenceDrawTarget =
CreateOffscreenContentDrawTarget(IntSize(1, 1), SurfaceFormat::B8G8R8A8);
}
}
#ifdef CAIRO_HAS_D2D_SURFACE
@ -644,11 +595,6 @@ void
gfxWindowsPlatform::VerifyD2DDevice(bool aAttemptForce)
{
#ifdef CAIRO_HAS_D2D_SURFACE
DriverInitCrashDetection detectCrashes;
if (detectCrashes.DisableAcceleration()) {
return;
}
if (mD3D10Device) {
if (SUCCEEDED(mD3D10Device->GetDeviceRemovedReason())) {
return;
@ -716,7 +662,6 @@ gfxWindowsPlatform::VerifyD2DDevice(bool aAttemptForce)
gfxPlatformFontList*
gfxWindowsPlatform::CreatePlatformFontList()
{
mUsingGDIFonts = false;
gfxPlatformFontList *pfl;
#ifdef CAIRO_HAS_DWRITE_FONT
// bug 630201 - older pre-RTM versions of Direct2D/DirectWrite cause odd
@ -730,11 +675,10 @@ gfxWindowsPlatform::CreatePlatformFontList()
// but apparently it can - see bug 594865.
// So we're going to fall back to GDI fonts & rendering.
gfxPlatformFontList::Shutdown();
SetRenderMode(RENDER_GDI);
DisableD2D();
}
#endif
pfl = new gfxGDIFontList();
mUsingGDIFonts = true;
if (NS_SUCCEEDED(pfl->InitFontList())) {
return pfl;
@ -744,6 +688,22 @@ gfxWindowsPlatform::CreatePlatformFontList()
return nullptr;
}
// This function will permanently disable D2D for the session. It's intended to
// be used when, after initially chosing to use Direct2D, we encounter a
// scenario we can't support.
//
// This is called during gfxPlatform::Init() so at this point there should be no
// DrawTargetD2D/1 instances.
void
gfxWindowsPlatform::DisableD2D()
{
mD2DStatus = FeatureStatus::Failed;
mD2D1Status = FeatureStatus::Failed;
Factory::SetDirect3D11Device(nullptr);
Factory::SetDirect3D10Device(nullptr);
UpdateBackendPrefs();
}
already_AddRefed<gfxASurface>
gfxWindowsPlatform::CreateOffscreenSurface(const IntSize& aSize,
gfxImageFormat aFormat)
@ -1556,36 +1516,18 @@ gfxWindowsPlatform::GetD3D9DeviceManager()
ID3D11Device*
gfxWindowsPlatform::GetD3D11Device()
{
if (mD3D11DeviceInitialized) {
return mD3D11Device;
}
InitD3D11Devices();
return mD3D11Device;
}
ID3D11Device*
gfxWindowsPlatform::GetD3D11ContentDevice()
{
if (mD3D11DeviceInitialized) {
return mD3D11ContentDevice;
}
InitD3D11Devices();
return mD3D11ContentDevice;
}
ID3D11Device*
gfxWindowsPlatform::GetD3D11ImageBridgeDevice()
{
if (mD3D11DeviceInitialized) {
return mD3D11ImageBridgeDevice;
}
InitD3D11Devices();
return mD3D11ImageBridgeDevice;
}
@ -1918,31 +1860,42 @@ bool DoesD3D11AlphaTextureSharingWork(ID3D11Device *device)
return DoesD3D11TextureSharingWorkInternal(device, DXGI_FORMAT_R8_UNORM, D3D11_BIND_SHADER_RESOURCE);
}
static inline bool
CanUseWARP()
{
if (gfxPrefs::LayersD3D11ForceWARP()) {
return true;
}
// It seems like nvdxgiwrap makes a mess of WARP. See bug 1154703.
if (!IsWin8OrLater() ||
gfxPrefs::LayersD3D11DisableWARP() ||
GetModuleHandleA("nvdxgiwrap.dll"))
{
return false;
}
return true;
}
auto
gfxWindowsPlatform::CheckD3D11Support() -> D3D11Status
{
if (gfxPrefs::LayersD3D11ForceWARP()) {
return D3D11Status::ForceWARP;
return D3D11Status::OnlyWARP;
}
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")) {
if (!CanUseWARP()) {
return D3D11Status::Blocked;
}
return D3D11Status::TryWARP;
return D3D11Status::OnlyWARP;
}
}
}
// Either nsIGfxInfo was bugged or we're not blacklisted.
if (!GetDXGIAdapter()) {
return D3D11Status::TryWARP;
return D3D11Status::OnlyWARP;
}
return D3D11Status::Ok;
}
@ -1953,7 +1906,7 @@ gfxWindowsPlatform::CheckD3D11Support() -> D3D11Status
decltype(D3D11CreateDevice)* sD3D11CreateDeviceFn = nullptr;
bool
gfxWindowsPlatform::AttemptD3D11DeviceCreation(const nsTArray<D3D_FEATURE_LEVEL>& aFeatureLevels)
gfxWindowsPlatform::AttemptD3D11DeviceCreation()
{
RefPtr<IDXGIAdapter1> adapter = GetDXGIAdapter();
MOZ_ASSERT(adapter);
@ -1966,7 +1919,7 @@ gfxWindowsPlatform::AttemptD3D11DeviceCreation(const nsTArray<D3D_FEATURE_LEVEL>
// 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(),
mFeatureLevels.Elements(), mFeatureLevels.Length(),
D3D11_SDK_VERSION, byRef(mD3D11Device), nullptr, nullptr);
} MOZ_SEH_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
gfxCriticalError() << "Crash during D3D11 device creation";
@ -1986,15 +1939,14 @@ gfxWindowsPlatform::AttemptD3D11DeviceCreation(const nsTArray<D3D_FEATURE_LEVEL>
// Only test this when not using WARP since it can fail and cause
// GetDeviceRemovedReason to return weird values.
mDoesD3D11TextureSharingWork = ::DoesD3D11TextureSharingWork(mD3D11Device);
mD3D11Device->SetExceptionMode(0);
mIsWARP = false;
return true;
}
bool
gfxWindowsPlatform::AttemptWARPDeviceCreation(const nsTArray<D3D_FEATURE_LEVEL>& aFeatureLevels)
gfxWindowsPlatform::AttemptWARPDeviceCreation()
{
MOZ_ASSERT(!mD3D11Device);
ScopedGfxFeatureReporter reporterWARP("D3D11-WARP", gfxPrefs::LayersD3D11ForceWARP());
MOZ_SEH_TRY {
@ -2004,7 +1956,7 @@ gfxWindowsPlatform::AttemptWARPDeviceCreation(const nsTArray<D3D_FEATURE_LEVEL>&
// 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(),
mFeatureLevels.Elements(), mFeatureLevels.Length(),
D3D11_SDK_VERSION, byRef(mD3D11Device), nullptr, nullptr);
if (FAILED(hr)) {
@ -2017,14 +1969,21 @@ gfxWindowsPlatform::AttemptWARPDeviceCreation(const nsTArray<D3D_FEATURE_LEVEL>&
} MOZ_SEH_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
gfxCriticalError() << "Exception occurred initializing WARP D3D11 device!";
return false;
}
// Only test for texture sharing on Windows 8 since it puts the device into
// an unusable state if used on Windows 7
if (IsWin8OrLater()) {
mDoesD3D11TextureSharingWork = ::DoesD3D11TextureSharingWork(mD3D11Device);
}
mD3D11Device->SetExceptionMode(0);
mIsWARP = true;
return true;
}
bool
gfxWindowsPlatform::AttemptD3D11ContentDeviceCreation(const nsTArray<D3D_FEATURE_LEVEL>& aFeatureLevels)
gfxWindowsPlatform::AttemptD3D11ContentDeviceCreation()
{
HRESULT hr = E_INVALIDARG;
MOZ_SEH_TRY {
@ -2033,24 +1992,35 @@ gfxWindowsPlatform::AttemptD3D11ContentDeviceCreation(const nsTArray<D3D_FEATURE
mIsWARP ? D3D_DRIVER_TYPE_WARP : D3D_DRIVER_TYPE_UNKNOWN,
nullptr,
D3D11_CREATE_DEVICE_BGRA_SUPPORT,
aFeatureLevels.Elements(), aFeatureLevels.Length(),
mFeatureLevels.Elements(), mFeatureLevels.Length(),
D3D11_SDK_VERSION, byRef(mD3D11ContentDevice), nullptr, nullptr);
} MOZ_SEH_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
return false;
}
return SUCCEEDED(hr);
if (FAILED(hr)) {
return false;
}
mD3D11ContentDevice->SetExceptionMode(0);
nsRefPtr<ID3D10Multithread> multi;
mD3D11ContentDevice->QueryInterface(__uuidof(ID3D10Multithread), getter_AddRefs(multi));
multi->SetMultithreadProtected(TRUE);
Factory::SetDirect3D11Device(mD3D11ContentDevice);
return true;
}
bool
gfxWindowsPlatform::AttemptD3D11ImageBridgeDeviceCreation(const nsTArray<D3D_FEATURE_LEVEL>& aFeatureLevels)
gfxWindowsPlatform::AttemptD3D11ImageBridgeDeviceCreation()
{
HRESULT hr = E_INVALIDARG;
MOZ_SEH_TRY{
hr =
sD3D11CreateDeviceFn(GetDXGIAdapter(), D3D_DRIVER_TYPE_UNKNOWN, nullptr,
D3D11_CREATE_DEVICE_BGRA_SUPPORT,
aFeatureLevels.Elements(), aFeatureLevels.Length(),
mFeatureLevels.Elements(), mFeatureLevels.Length(),
D3D11_SDK_VERSION, byRef(mD3D11ImageBridgeDevice), nullptr, nullptr);
} MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
return false;
@ -2061,112 +2031,196 @@ gfxWindowsPlatform::AttemptD3D11ImageBridgeDeviceCreation(const nsTArray<D3D_FEA
}
mD3D11ImageBridgeDevice->SetExceptionMode(0);
return DoesD3D11AlphaTextureSharingWork(mD3D11ImageBridgeDevice);
if (!DoesD3D11AlphaTextureSharingWork(mD3D11ImageBridgeDevice)) {
mD3D11ImageBridgeDevice = nullptr;
return false;
}
return true;
}
void
gfxWindowsPlatform::InitD3D11Devices()
gfxWindowsPlatform::InitializeDevices()
{
// 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);
// If we previously crashed initializing devices, or if we're in safe mode,
// bail out now.
DriverInitCrashDetection detectCrashes;
if (InSafeMode() || detectCrashes.DisableAcceleration()) {
mD3D11Status = FeatureStatus::Blocked;
if (detectCrashes.DisableAcceleration() || InSafeMode()) {
mAcceleration = FeatureStatus::Blocked;
return;
}
D3D11Status status = CheckD3D11Support();
if (status == D3D11Status::Blocked) {
// If acceleration is disabled, we refuse to initialize anything.
if (!ShouldUseLayersAcceleration()) {
mAcceleration = FeatureStatus::Disabled;
return;
}
// At this point, as far as we know, we can probably accelerate.
mAcceleration = FeatureStatus::Available;
// If we're going to prefer D3D9, stop here. The rest of this function
// attempts to use D3D11 features.
if (gfxPrefs::LayersPreferD3D9()) {
mD3D11Status = FeatureStatus::Disabled;
return;
}
// First, initialize D3D11. If this succeeds we attempt to use Direct2D.
InitializeD3D11();
if (mD3D11Status == FeatureStatus::Available) {
InitializeD2D();
}
}
void
gfxWindowsPlatform::InitializeD3D11()
{
// This function attempts to initialize our D3D11 devices, if the hardware
// is not blacklisted for D3D11 layers. This first attempt will try 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.
// Check if D3D11 is supported on this hardware.
D3D11Status support = CheckD3D11Support();
if (support == D3D11Status::Blocked) {
mD3D11Status = FeatureStatus::Blacklisted;
return;
}
// Check if D3D11 is available on this system.
nsModuleHandle d3d11Module(LoadLibrarySystem32(L"d3d11.dll"));
sD3D11CreateDeviceFn =
(decltype(D3D11CreateDevice)*)GetProcAddress(d3d11Module, "D3D11CreateDevice");
if (!sD3D11CreateDeviceFn) {
// We should just be on Windows Vista or XP in this case.
mD3D11Status = FeatureStatus::Unavailable;
return;
}
nsTArray<D3D_FEATURE_LEVEL> featureLevels;
if (IsWin8OrLater()) {
featureLevels.AppendElement(D3D_FEATURE_LEVEL_11_1);
// If hardware acceleration is allowed, attempt to create a device. If this
// fails, we fall back to WARP.
if (support == D3D11Status::Ok && !AttemptD3D11DeviceCreation()) {
support = D3D11Status::OnlyWARP;
}
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);
if (status == D3D11Status::Ok) {
if (!AttemptD3D11DeviceCreation(featureLevels)) {
status = D3D11Status::TryWARP;
}
}
if (IsWin8OrLater() &&
!gfxPrefs::LayersD3D11DisableWARP() &&
(status == D3D11Status::TryWARP || status == D3D11Status::ForceWARP))
{
AttemptWARPDeviceCreation(featureLevels);
mD3D11Status = FeatureStatus::Failed;
}
// Only test for texture sharing on Windows 8 since it puts the device into
// an unusable state if used on Windows 7
if (mD3D11Device && IsWin8OrLater()) {
mDoesD3D11TextureSharingWork = ::DoesD3D11TextureSharingWork(mD3D11Device);
if (support == D3D11Status::OnlyWARP && CanUseWARP()) {
AttemptWARPDeviceCreation();
}
if (!mD3D11Device) {
// We could not get a D3D11 compositor, and there's nothing more we can try.
// Nothing more we can do.
mD3D11Status = FeatureStatus::Failed;
return;
}
mD3D11Device->SetExceptionMode(0);
// If we got here, we successfully got a D3D11 device.
mD3D11Status = FeatureStatus::Available;
// 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() && (!mIsWARP || (status == D3D11Status::ForceWARP))) {
if (!AttemptD3D11ContentDeviceCreation(featureLevels)) {
mD3D11ContentDevice = nullptr;
d3d11Module.disown();
return;
}
mD3D11ContentDevice->SetExceptionMode(0);
nsRefPtr<ID3D10Multithread> multi;
mD3D11ContentDevice->QueryInterface(__uuidof(ID3D10Multithread), getter_AddRefs(multi));
multi->SetMultithreadProtected(TRUE);
Factory::SetDirect3D11Device(mD3D11ContentDevice);
}
MOZ_ASSERT(mD3D11Device);
if (!mIsWARP) {
if (!AttemptD3D11ImageBridgeDeviceCreation(featureLevels)) {
mD3D11ImageBridgeDevice = nullptr;
}
AttemptD3D11ImageBridgeDeviceCreation();
}
// We leak these everywhere and we need them our entire runtime anyway, let's
// leak it here as well.
// leak it here as well. We keep the pointer to sD3D11CreateDeviceFn around
// as well for D2D1 and device resets.
d3d11Module.disown();
}
static bool
IsD2DBlacklisted()
{
nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
if (gfxInfo) {
int32_t status;
if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT2D, &status))) {
if (status != nsIGfxInfo::FEATURE_STATUS_OK) {
return true;
}
}
}
return false;
}
void
gfxWindowsPlatform::InitializeD2D()
{
if (!gfxPrefs::Direct2DForceEnabled()) {
if (IsD2DBlacklisted()) {
mD2DStatus = FeatureStatus::Blacklisted;
return;
}
}
// Do not ever try to use D2D if it's explicitly disabled.
if (gfxPrefs::Direct2DDisabled()) {
mD2DStatus = FeatureStatus::Disabled;
return;
}
// Direct2D is only Vista or higher, but we require a D3D11 compositor to
// use it. (This check may be implied by the fact that we do not get here
// without a D3D11 compositor device.)
if (!IsVistaOrLater()) {
mD2DStatus = FeatureStatus::Unavailable;
return;
}
if (!mDoesD3D11TextureSharingWork) {
mD2DStatus = FeatureStatus::Failed;
return;
}
// Using Direct2D depends on DWrite support.
if (!mDWriteFactory && !InitDWriteSupport()) {
mD2DStatus = FeatureStatus::Failed;
return;
}
// Initialize D2D 1.1.
InitializeD2D1();
// Initialize D2D 1.0.
VerifyD2DDevice(gfxPrefs::Direct2DForceEnabled());
if (!mD3D10Device) {
mD2DStatus = FeatureStatus::Failed;
return;
}
mD2DStatus = FeatureStatus::Available;
}
bool
gfxWindowsPlatform::InitializeD2D1()
{
ScopedGfxFeatureReporter d2d1_1("D2D1.1");
if (!Factory::SupportsD2D1()) {
mD2D1Status = FeatureStatus::Unavailable;
return false;
}
if (!gfxPrefs::Direct2DUse1_1()) {
mD2D1Status = FeatureStatus::Disabled;
return false;
}
// Normally we don't use D2D content drawing when using WARP. However if
// WARP is force-enabled, we wlil let Direct2D use WARP as well.
if (mIsWARP && !gfxPrefs::LayersD3D11ForceWARP()) {
mD2D1Status = FeatureStatus::Blocked;
return false;
}
if (!AttemptD3D11ContentDeviceCreation()) {
mD2D1Status = FeatureStatus::Failed;
return false;
}
mD2D1Status = FeatureStatus::Available;
d2d1_1.SetSuccessful();
return true;
}
already_AddRefed<ID3D11Device>
gfxWindowsPlatform::CreateD3D11DecoderDevice()
{
@ -2442,23 +2496,33 @@ gfxWindowsPlatform::GetAcceleratedCompositorBackends(nsTArray<LayersBackend>& aB
}
}
// Some features are dependent on other features. If this is the case, we
// try to propagate the status of the parent feature if it wasn't available.
FeatureStatus
gfxWindowsPlatform::GetD2D1Status()
gfxWindowsPlatform::GetD3D11Status() const
{
if (GetD2DStatus() != FeatureStatus::Available ||
!Factory::SupportsD2D1())
{
if (mAcceleration != FeatureStatus::Available) {
return mAcceleration;
}
return mD3D11Status;
}
FeatureStatus
gfxWindowsPlatform::GetD2DStatus() const
{
if (GetD3D11Status() != FeatureStatus::Available) {
return FeatureStatus::Unavailable;
}
return mD2DStatus;
}
if (!GetD3D11ContentDevice()) {
return FeatureStatus::Failed;
FeatureStatus
gfxWindowsPlatform::GetD2D1Status() const
{
if (GetD3D11Status() != FeatureStatus::Available) {
return FeatureStatus::Unavailable;
}
if (!gfxPrefs::Direct2DUse1_1()) {
return FeatureStatus::Disabled;
}
return FeatureStatus::Available;
return mD2D1Status;
}
unsigned

View File

@ -229,9 +229,8 @@ public:
#ifdef CAIRO_HAS_DWRITE_FONT
IDWriteFactory *GetDWriteFactory() { return mDWriteFactory; }
inline bool DWriteEnabled() { return mUseDirectWrite; }
inline bool DWriteEnabled() { return !!mDWriteFactory; }
inline DWRITE_MEASURING_MODE DWriteMeasuringMode() { return mMeasuringMode; }
IDWriteTextAnalyzer *GetDWriteAnalyzer() { return mDWriteAnalyzer; }
IDWriteRenderingParams *GetRenderingParams(TextRenderingMode aRenderMode)
{ return mRenderingParams[aRenderMode]; }
@ -263,17 +262,18 @@ public:
}
bool SupportsApzTouchInput() const override;
// Recreate devices as needed for a device reset. Returns true if a device
// reset occurred.
bool HandleDeviceReset();
void UpdateBackendPrefs();
// Return the diagnostic status of DirectX initialization. If
// initialization has not been attempted, this returns
// FeatureStatus::Unused.
mozilla::gfx::FeatureStatus GetD3D11Status() const {
return mD3D11Status;
}
mozilla::gfx::FeatureStatus GetD2DStatus() const {
return mD2DStatus;
}
mozilla::gfx::FeatureStatus GetD3D11Status() const;
mozilla::gfx::FeatureStatus GetD2DStatus() const;
mozilla::gfx::FeatureStatus GetD2D1Status() const;
unsigned GetD3D11Version();
mozilla::gfx::FeatureStatus GetD2D1Status();
virtual already_AddRefed<mozilla::gfx::VsyncSource> CreateHardwareVsyncSource() override;
static mozilla::Atomic<size_t> sD3D11MemoryUsed;
@ -286,6 +286,7 @@ protected:
return true;
}
void GetAcceleratedCompositorBackends(nsTArray<mozilla::layers::LayersBackend>& aBackends);
virtual void GetPlatformCMSOutputProfile(void* &mem, size_t &size);
protected:
RenderMode mRenderMode;
@ -296,34 +297,31 @@ protected:
private:
void Init();
void InitD3D11Devices();
void InitializeDevices();
void InitializeD3D11();
void InitializeD2D();
bool InitializeD2D1();
bool InitDWriteSupport();
// Used by InitD3D11Devices().
void DisableD2D();
// Used by InitializeD3D11().
enum class D3D11Status {
Ok,
TryWARP,
ForceWARP,
OnlyWARP,
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().
mozilla::gfx::FeatureStatus InitD2DSupport();
void InitDWriteSupport();
bool AttemptD3D11DeviceCreation();
bool AttemptWARPDeviceCreation();
bool AttemptD3D11ImageBridgeDeviceCreation();
bool AttemptD3D11ContentDeviceCreation();
IDXGIAdapter1 *GetDXGIAdapter();
bool IsDeviceReset(HRESULT hr, DeviceResetReason* aReason);
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
@ -333,17 +331,20 @@ private:
mozilla::RefPtr<ID3D11Device> mD3D11Device;
mozilla::RefPtr<ID3D11Device> mD3D11ContentDevice;
mozilla::RefPtr<ID3D11Device> mD3D11ImageBridgeDevice;
bool mD3D11DeviceInitialized;
mozilla::RefPtr<mozilla::layers::ReadbackManagerD3D11> mD3D11ReadbackManager;
bool mIsWARP;
bool mHasDeviceReset;
bool mDoesD3D11TextureSharingWork;
DeviceResetReason mDeviceResetReason;
// These should not be accessed directly. Use the Get[Feature]Status
// accessors instead.
mozilla::gfx::FeatureStatus mAcceleration;
mozilla::gfx::FeatureStatus mD3D11Status;
mozilla::gfx::FeatureStatus mD2DStatus;
mozilla::gfx::FeatureStatus mD2D1Status;
virtual void GetPlatformCMSOutputProfile(void* &mem, size_t &size);
nsTArray<D3D_FEATURE_LEVEL> mFeatureLevels;
};
#endif /* GFX_WINDOWS_PLATFORM_H */