diff --git a/gfx/2d/Factory.cpp b/gfx/2d/Factory.cpp index bb6fab7d195..76ae17e2e29 100644 --- a/gfx/2d/Factory.cpp +++ b/gfx/2d/Factory.cpp @@ -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; } diff --git a/gfx/layers/client/TextureClient.cpp b/gfx/layers/client/TextureClient.cpp index afa4f53af9a..e0f6334d8f8 100644 --- a/gfx/layers/client/TextureClient.cpp +++ b/gfx/layers/client/TextureClient.cpp @@ -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 && diff --git a/gfx/thebes/gfxPlatform.cpp b/gfx/thebes/gfxPlatform.cpp index 041e90d77cf..8a986768a5a 100644 --- a/gfx/thebes/gfxPlatform.cpp +++ b/gfx/thebes/gfxPlatform.cpp @@ -2237,7 +2237,7 @@ gfxPlatform::ShouldUseLayersAcceleration() if (gfxPrefs::LayersAccelerationForceEnabled()) { return true; } - if (gfxPlatform::GetPlatform()->AccelerateLayersByDefault()) { + if (AccelerateLayersByDefault()) { return true; } if (acceleratedEnv && *acceleratedEnv != '0') { diff --git a/gfx/thebes/gfxWindowsPlatform.cpp b/gfx/thebes/gfxWindowsPlatform.cpp index 1a2a4c8f01b..79c5fcb34b5 100755 --- a/gfx/thebes/gfxWindowsPlatform.cpp +++ b/gfx/thebes/gfxWindowsPlatform.cpp @@ -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 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 factory; HRESULT hr = createDWriteFactory( DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), - reinterpret_cast(&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 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 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& aFeatureLevels) +gfxWindowsPlatform::AttemptD3D11DeviceCreation() { RefPtr adapter = GetDXGIAdapter(); MOZ_ASSERT(adapter); @@ -1966,7 +1919,7 @@ gfxWindowsPlatform::AttemptD3D11DeviceCreation(const nsTArray // 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 // 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& aFeatureLevels) +gfxWindowsPlatform::AttemptWARPDeviceCreation() { - MOZ_ASSERT(!mD3D11Device); - ScopedGfxFeatureReporter reporterWARP("D3D11-WARP", gfxPrefs::LayersD3D11ForceWARP()); MOZ_SEH_TRY { @@ -2004,7 +1956,7 @@ gfxWindowsPlatform::AttemptWARPDeviceCreation(const nsTArray& // 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& } 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& aFeatureLevels) +gfxWindowsPlatform::AttemptD3D11ContentDeviceCreation() { HRESULT hr = E_INVALIDARG; MOZ_SEH_TRY { @@ -2033,24 +1992,35 @@ gfxWindowsPlatform::AttemptD3D11ContentDeviceCreation(const nsTArraySetExceptionMode(0); + + nsRefPtr multi; + mD3D11ContentDevice->QueryInterface(__uuidof(ID3D10Multithread), getter_AddRefs(multi)); + multi->SetMultithreadProtected(TRUE); + + Factory::SetDirect3D11Device(mD3D11ContentDevice); + return true; } bool -gfxWindowsPlatform::AttemptD3D11ImageBridgeDeviceCreation(const nsTArray& 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 nsTArraySetExceptionMode(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 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 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 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 gfxWindowsPlatform::CreateD3D11DecoderDevice() { @@ -2442,23 +2496,33 @@ gfxWindowsPlatform::GetAcceleratedCompositorBackends(nsTArray& 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 diff --git a/gfx/thebes/gfxWindowsPlatform.h b/gfx/thebes/gfxWindowsPlatform.h index 3cfcc85dceb..127e7189f39 100644 --- a/gfx/thebes/gfxWindowsPlatform.h +++ b/gfx/thebes/gfxWindowsPlatform.h @@ -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 CreateHardwareVsyncSource() override; static mozilla::Atomic sD3D11MemoryUsed; @@ -286,6 +286,7 @@ protected: return true; } void GetAcceleratedCompositorBackends(nsTArray& 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& aFeatureLevels); - bool AttemptWARPDeviceCreation(const nsTArray& aFeatureLevels); - bool AttemptD3D11ImageBridgeDeviceCreation(const nsTArray& aFeatureLevels); - bool AttemptD3D11ContentDeviceCreation(const nsTArray& 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 mDWriteFactory; - nsRefPtr mDWriteAnalyzer; nsRefPtr mRenderingParams[TEXT_RENDERING_COUNT]; DWRITE_MEASURING_MODE mMeasuringMode; #endif @@ -333,17 +331,20 @@ private: mozilla::RefPtr mD3D11Device; mozilla::RefPtr mD3D11ContentDevice; mozilla::RefPtr mD3D11ImageBridgeDevice; - bool mD3D11DeviceInitialized; mozilla::RefPtr 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 mFeatureLevels; }; #endif /* GFX_WINDOWS_PLATFORM_H */