diff options
author | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
---|---|---|
committer | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
commit | 5f8de423f190bbb79a62f804151bc24824fa32d8 (patch) | |
tree | 10027f336435511475e392454359edea8e25895d /gfx/thebes/gfxWindowsPlatform.cpp | |
parent | 49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff) | |
download | UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip |
Add m-esr52 at 52.6.0
Diffstat (limited to 'gfx/thebes/gfxWindowsPlatform.cpp')
-rwxr-xr-x | gfx/thebes/gfxWindowsPlatform.cpp | 2139 |
1 files changed, 2139 insertions, 0 deletions
diff --git a/gfx/thebes/gfxWindowsPlatform.cpp b/gfx/thebes/gfxWindowsPlatform.cpp new file mode 100755 index 000000000..be1780797 --- /dev/null +++ b/gfx/thebes/gfxWindowsPlatform.cpp @@ -0,0 +1,2139 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* vim: set ts=8 sts=4 et sw=4 tw=80: */ +/* 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/. */ + +#include "gfxWindowsPlatform.h" + +#include "cairo.h" +#include "mozilla/ArrayUtils.h" + +#include "gfxImageSurface.h" +#include "gfxWindowsSurface.h" + +#include "nsUnicharUtils.h" + +#include "mozilla/Preferences.h" +#include "mozilla/Services.h" +#include "mozilla/Sprintf.h" +#include "mozilla/WindowsVersion.h" +#include "nsIGfxInfo.h" +#include "nsServiceManagerUtils.h" +#include "nsTArray.h" +#include "mozilla/Telemetry.h" +#include "GeckoProfiler.h" + +#include "nsIWindowsRegKey.h" +#include "nsIFile.h" +#include "plbase64.h" +#include "nsIXULRuntime.h" +#include "imgLoader.h" + +#include "nsIGfxInfo.h" + +#include "gfxCrashReporterUtils.h" + +#include "gfxGDIFontList.h" +#include "gfxGDIFont.h" + +#include "mozilla/layers/CompositorThread.h" +#include "DeviceManagerD3D9.h" +#include "mozilla/layers/ReadbackManagerD3D11.h" + +#include "WinUtils.h" + +#include "gfxDWriteFontList.h" +#include "gfxDWriteFonts.h" +#include "gfxDWriteCommon.h" +#include <dwrite.h> + +#include "gfxTextRun.h" +#include "gfxUserFontSet.h" +#include "nsWindowsHelpers.h" +#include "gfx2DGlue.h" + +#include <string> + +#include <d3d10_1.h> + +#include "mozilla/gfx/2D.h" + +#include "nsMemory.h" + +#include <d3d11.h> + +#include "nsIMemoryReporter.h" +#include <winternl.h> +#include "d3dkmtQueryStatistics.h" + +#include "base/thread.h" +#include "gfxPrefs.h" +#include "gfxConfig.h" +#include "VsyncSource.h" +#include "DriverCrashGuard.h" +#include "mozilla/dom/ContentParent.h" +#include "mozilla/gfx/DeviceManagerDx.h" +#include "D3D11Checks.h" + +using namespace mozilla; +using namespace mozilla::gfx; +using namespace mozilla::layers; +using namespace mozilla::widget; +using namespace mozilla::image; + +IDWriteRenderingParams* GetDwriteRenderingParams(bool aGDI) +{ + gfxWindowsPlatform::TextRenderingMode mode = aGDI ? + gfxWindowsPlatform::TEXT_RENDERING_GDI_CLASSIC : + gfxWindowsPlatform::TEXT_RENDERING_NORMAL; + return gfxWindowsPlatform::GetPlatform()->GetRenderingParams(mode); +} + +DCFromDrawTarget::DCFromDrawTarget(DrawTarget& aDrawTarget) +{ + mDC = nullptr; + if (aDrawTarget.GetBackendType() == BackendType::CAIRO) { + cairo_t* ctx = static_cast<cairo_t*> + (aDrawTarget.GetNativeSurface(NativeSurfaceType::CAIRO_CONTEXT)); + if (ctx) { + cairo_surface_t* surf = cairo_get_group_target(ctx); + if (surf) { + cairo_surface_type_t surfaceType = cairo_surface_get_type(surf); + if (surfaceType == CAIRO_SURFACE_TYPE_WIN32 || + surfaceType == CAIRO_SURFACE_TYPE_WIN32_PRINTING) { + mDC = cairo_win32_surface_get_dc(surf); + mNeedsRelease = false; + SaveDC(mDC); + cairo_scaled_font_t* scaled = cairo_get_scaled_font(ctx); + cairo_win32_scaled_font_select_font(scaled, mDC); + } + } + } + } + + if (!mDC) { + // Get the whole screen DC: + mDC = GetDC(nullptr); + SetGraphicsMode(mDC, GM_ADVANCED); + mNeedsRelease = true; + } +} + +class GfxD2DVramReporter final : public nsIMemoryReporter +{ + ~GfxD2DVramReporter() {} + +public: + NS_DECL_ISUPPORTS + + NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport, + nsISupports* aData, bool aAnonymize) override + { + MOZ_COLLECT_REPORT( + "gfx-d2d-vram-draw-target", KIND_OTHER, UNITS_BYTES, + Factory::GetD2DVRAMUsageDrawTarget(), + "Video memory used by D2D DrawTargets."); + + MOZ_COLLECT_REPORT( + "gfx-d2d-vram-source-surface", KIND_OTHER, UNITS_BYTES, + Factory::GetD2DVRAMUsageSourceSurface(), + "Video memory used by D2D SourceSurfaces."); + + return NS_OK; + } +}; + +NS_IMPL_ISUPPORTS(GfxD2DVramReporter, nsIMemoryReporter) + +#define GFX_USE_CLEARTYPE_ALWAYS "gfx.font_rendering.cleartype.always_use_for_content" +#define GFX_DOWNLOADABLE_FONTS_USE_CLEARTYPE "gfx.font_rendering.cleartype.use_for_downloadable_fonts" + +#define GFX_CLEARTYPE_PARAMS "gfx.font_rendering.cleartype_params." +#define GFX_CLEARTYPE_PARAMS_GAMMA "gfx.font_rendering.cleartype_params.gamma" +#define GFX_CLEARTYPE_PARAMS_CONTRAST "gfx.font_rendering.cleartype_params.enhanced_contrast" +#define GFX_CLEARTYPE_PARAMS_LEVEL "gfx.font_rendering.cleartype_params.cleartype_level" +#define GFX_CLEARTYPE_PARAMS_STRUCTURE "gfx.font_rendering.cleartype_params.pixel_structure" +#define GFX_CLEARTYPE_PARAMS_MODE "gfx.font_rendering.cleartype_params.rendering_mode" + +class GPUAdapterReporter final : public nsIMemoryReporter +{ + // Callers must Release the DXGIAdapter after use or risk mem-leak + static bool GetDXGIAdapter(IDXGIAdapter **aDXGIAdapter) + { + ID3D11Device *d3d11Device; + IDXGIDevice *dxgiDevice; + bool result = false; + + if ((d3d11Device = mozilla::gfx::Factory::GetDirect3D11Device())) { + if (d3d11Device->QueryInterface(__uuidof(IDXGIDevice), (void **)&dxgiDevice) == S_OK) { + result = (dxgiDevice->GetAdapter(aDXGIAdapter) == S_OK); + dxgiDevice->Release(); + } + } + + return result; + } + + ~GPUAdapterReporter() {} + +public: + NS_DECL_ISUPPORTS + + NS_IMETHOD + CollectReports(nsIHandleReportCallback* aHandleReport, nsISupports* aData, + bool aAnonymize) override + { + HANDLE ProcessHandle = GetCurrentProcess(); + + int64_t dedicatedBytesUsed = 0; + int64_t sharedBytesUsed = 0; + int64_t committedBytesUsed = 0; + IDXGIAdapter *DXGIAdapter; + + HMODULE gdi32Handle; + PFND3DKMTQS queryD3DKMTStatistics = nullptr; + + // GPU memory reporting is not available before Windows 7 + if (!IsWin7OrLater()) + return NS_OK; + + if ((gdi32Handle = LoadLibrary(TEXT("gdi32.dll")))) + queryD3DKMTStatistics = (PFND3DKMTQS)GetProcAddress(gdi32Handle, "D3DKMTQueryStatistics"); + + if (queryD3DKMTStatistics && GetDXGIAdapter(&DXGIAdapter)) { + // Most of this block is understood thanks to wj32's work on Process Hacker + + DXGI_ADAPTER_DESC adapterDesc; + D3DKMTQS queryStatistics; + + DXGIAdapter->GetDesc(&adapterDesc); + DXGIAdapter->Release(); + + memset(&queryStatistics, 0, sizeof(D3DKMTQS)); + queryStatistics.Type = D3DKMTQS_PROCESS; + queryStatistics.AdapterLuid = adapterDesc.AdapterLuid; + queryStatistics.hProcess = ProcessHandle; + if (NT_SUCCESS(queryD3DKMTStatistics(&queryStatistics))) { + committedBytesUsed = queryStatistics.QueryResult.ProcessInfo.SystemMemory.BytesAllocated; + } + + memset(&queryStatistics, 0, sizeof(D3DKMTQS)); + queryStatistics.Type = D3DKMTQS_ADAPTER; + queryStatistics.AdapterLuid = adapterDesc.AdapterLuid; + if (NT_SUCCESS(queryD3DKMTStatistics(&queryStatistics))) { + ULONG i; + ULONG segmentCount = queryStatistics.QueryResult.AdapterInfo.NbSegments; + + for (i = 0; i < segmentCount; i++) { + memset(&queryStatistics, 0, sizeof(D3DKMTQS)); + queryStatistics.Type = D3DKMTQS_SEGMENT; + queryStatistics.AdapterLuid = adapterDesc.AdapterLuid; + queryStatistics.QuerySegment.SegmentId = i; + + if (NT_SUCCESS(queryD3DKMTStatistics(&queryStatistics))) { + bool aperture; + + // SegmentInformation has a different definition in Win7 than later versions + if (!IsWin8OrLater()) + aperture = queryStatistics.QueryResult.SegmentInfoWin7.Aperture; + else + aperture = queryStatistics.QueryResult.SegmentInfoWin8.Aperture; + + memset(&queryStatistics, 0, sizeof(D3DKMTQS)); + queryStatistics.Type = D3DKMTQS_PROCESS_SEGMENT; + queryStatistics.AdapterLuid = adapterDesc.AdapterLuid; + queryStatistics.hProcess = ProcessHandle; + queryStatistics.QueryProcessSegment.SegmentId = i; + if (NT_SUCCESS(queryD3DKMTStatistics(&queryStatistics))) { + ULONGLONG bytesCommitted; + if (!IsWin8OrLater()) + bytesCommitted = queryStatistics.QueryResult.ProcessSegmentInfo.Win7.BytesCommitted; + else + bytesCommitted = queryStatistics.QueryResult.ProcessSegmentInfo.Win8.BytesCommitted; + if (aperture) + sharedBytesUsed += bytesCommitted; + else + dedicatedBytesUsed += bytesCommitted; + } + } + } + } + } + + FreeLibrary(gdi32Handle); + + MOZ_COLLECT_REPORT( + "gpu-committed", KIND_OTHER, UNITS_BYTES, committedBytesUsed, + "Memory committed by the Windows graphics system."); + + MOZ_COLLECT_REPORT( + "gpu-dedicated", KIND_OTHER, UNITS_BYTES, + dedicatedBytesUsed, + "Out-of-process memory allocated for this process in a physical " + "GPU adapter's memory."); + + MOZ_COLLECT_REPORT( + "gpu-shared", KIND_OTHER, UNITS_BYTES, + sharedBytesUsed, + "In-process memory that is shared with the GPU."); + + return NS_OK; + } +}; + +NS_IMPL_ISUPPORTS(GPUAdapterReporter, nsIMemoryReporter) + +Atomic<size_t> gfxWindowsPlatform::sD3D11SharedTextures; +Atomic<size_t> gfxWindowsPlatform::sD3D9SharedTextures; + +class D3DSharedTexturesReporter final : public nsIMemoryReporter +{ + ~D3DSharedTexturesReporter() {} + +public: + NS_DECL_ISUPPORTS + + NS_IMETHOD CollectReports(nsIHandleReportCallback *aHandleReport, + nsISupports* aData, bool aAnonymize) override + { + if (gfxWindowsPlatform::sD3D11SharedTextures > 0) { + MOZ_COLLECT_REPORT( + "d3d11-shared-textures", KIND_OTHER, UNITS_BYTES, + gfxWindowsPlatform::sD3D11SharedTextures, + "D3D11 shared textures."); + } + + if (gfxWindowsPlatform::sD3D9SharedTextures > 0) { + MOZ_COLLECT_REPORT( + "d3d9-shared-textures", KIND_OTHER, UNITS_BYTES, + gfxWindowsPlatform::sD3D9SharedTextures, + "D3D9 shared textures."); + } + + return NS_OK; + } +}; + +NS_IMPL_ISUPPORTS(D3DSharedTexturesReporter, nsIMemoryReporter) + +gfxWindowsPlatform::gfxWindowsPlatform() + : mRenderMode(RENDER_GDI) +{ + mUseClearTypeForDownloadableFonts = UNINITIALIZED_VALUE; + mUseClearTypeAlways = UNINITIALIZED_VALUE; + + /* + * Initialize COM + */ + CoInitialize(nullptr); + + RegisterStrongMemoryReporter(new GfxD2DVramReporter()); + RegisterStrongMemoryReporter(new GPUAdapterReporter()); + RegisterStrongMemoryReporter(new D3DSharedTexturesReporter()); +} + +gfxWindowsPlatform::~gfxWindowsPlatform() +{ + mozilla::gfx::Factory::D2DCleanup(); + + DeviceManagerD3D9::Shutdown(); + DeviceManagerDx::Shutdown(); + + /* + * Uninitialize COM + */ + CoUninitialize(); +} + +static void +UpdateANGLEConfig() +{ + if (!gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) { + gfxConfig::Disable(Feature::D3D11_HW_ANGLE, FeatureStatus::Disabled, "D3D11 compositing is disabled"); + } +} + +void +gfxWindowsPlatform::InitAcceleration() +{ + gfxPlatform::InitAcceleration(); + + // 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); + + DeviceManagerDx::Init(); + DeviceManagerD3D9::Init(); + + InitializeConfig(); + InitializeDevices(); + UpdateANGLEConfig(); + UpdateRenderMode(); + + // If we have Skia and we didn't init dwrite already, do it now. + if (!mDWriteFactory && GetDefaultContentBackend() == BackendType::SKIA) { + InitDWriteSupport(); + } + + // CanUseHardwareVideoDecoding depends on DeviceManagerDx state, + // so update the cached value now. + UpdateCanUseHardwareVideoDecoding(); +} + +bool +gfxWindowsPlatform::CanUseHardwareVideoDecoding() +{ + DeviceManagerDx* dm = DeviceManagerDx::Get(); + if (!dm) { + return false; + } + if (!gfxPrefs::LayersPreferD3D9() && !dm->TextureSharingWorks()) { + return false; + } + return !dm->IsWARP() && gfxPlatform::CanUseHardwareVideoDecoding(); +} + +bool +gfxWindowsPlatform::InitDWriteSupport() +{ + if (!IsVistaOrLater()) { + return false; + } + + // DWrite is only supported on Windows 7 with the platform update and higher. + // We check this by seeing if D2D1 support is available. + if (!Factory::SupportsD2D1()) { + return false; + } + + mozilla::ScopedGfxFeatureReporter reporter("DWrite"); + decltype(DWriteCreateFactory)* createDWriteFactory = (decltype(DWriteCreateFactory)*) + GetProcAddress(LoadLibraryW(L"dwrite.dll"), "DWriteCreateFactory"); + if (!createDWriteFactory) { + 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. + RefPtr<IDWriteFactory> factory; + HRESULT hr = createDWriteFactory( + DWRITE_FACTORY_TYPE_SHARED, + __uuidof(IDWriteFactory), + (IUnknown **)((IDWriteFactory **)getter_AddRefs(factory))); + if (FAILED(hr) || !factory) { + return false; + } + + mDWriteFactory = factory; + Factory::SetDWriteFactory(mDWriteFactory); + + SetupClearTypeParams(); + reporter.SetSuccessful(); + return true; +} + +bool +gfxWindowsPlatform::HandleDeviceReset() +{ + DeviceResetReason resetReason = DeviceResetReason::OK; + if (!DidRenderingDeviceReset(&resetReason)) { + return false; + } + + if (resetReason != DeviceResetReason::FORCED_RESET) { + Telemetry::Accumulate(Telemetry::DEVICE_RESET_REASON, uint32_t(resetReason)); + } + + // Remove devices and adapters. + DeviceManagerDx::Get()->ResetDevices(); + + imgLoader::NormalLoader()->ClearCache(true); + imgLoader::NormalLoader()->ClearCache(false); + imgLoader::PrivateBrowsingLoader()->ClearCache(true); + imgLoader::PrivateBrowsingLoader()->ClearCache(false); + gfxAlphaBoxBlur::ShutdownBlurCache(); + + if (XRE_IsContentProcess()) { + // Fetch updated device parameters. + FetchAndImportContentDeviceData(); + UpdateANGLEConfig(); + } + + InitializeDevices(); + UpdateANGLEConfig(); + BumpDeviceCounter(); + return true; +} + +void +gfxWindowsPlatform::UpdateBackendPrefs() +{ + uint32_t canvasMask = BackendTypeBit(BackendType::CAIRO); + uint32_t contentMask = BackendTypeBit(BackendType::CAIRO); + BackendType defaultBackend = BackendType::CAIRO; + if (gfxConfig::IsEnabled(Feature::DIRECT2D) && Factory::GetD2D1Device()) { + contentMask |= BackendTypeBit(BackendType::DIRECT2D1_1); + canvasMask |= BackendTypeBit(BackendType::DIRECT2D1_1); + defaultBackend = BackendType::DIRECT2D1_1; + } else { + canvasMask |= BackendTypeBit(BackendType::SKIA); + } + contentMask |= BackendTypeBit(BackendType::SKIA); + InitBackendPrefs(canvasMask, defaultBackend, contentMask, defaultBackend); +} + +bool +gfxWindowsPlatform::IsDirect2DBackend() +{ + return GetDefaultContentBackend() == BackendType::DIRECT2D1_1; +} + +void +gfxWindowsPlatform::UpdateRenderMode() +{ + bool didReset = HandleDeviceReset(); + + UpdateBackendPrefs(); + + if (didReset) { + mScreenReferenceDrawTarget = + CreateOffscreenContentDrawTarget(IntSize(1, 1), SurfaceFormat::B8G8R8A8); + if (!mScreenReferenceDrawTarget) { + gfxCriticalNote << "Failed to update reference draw target after device reset" + << ", D3D11 device:" << hexa(Factory::GetDirect3D11Device()) + << ", D3D11 status:" << FeatureStatusToString(gfxConfig::GetValue(Feature::D3D11_COMPOSITING)) + << ", D2D1 device:" << hexa(Factory::GetD2D1Device()) + << ", D2D1 status:" << FeatureStatusToString(gfxConfig::GetValue(Feature::DIRECT2D)) + << ", content:" << int(GetDefaultContentBackend()) + << ", compositor:" << int(GetCompositorBackend()); + MOZ_CRASH("GFX: Failed to update reference draw target after device reset"); + } + } +} + +mozilla::gfx::BackendType +gfxWindowsPlatform::GetContentBackendFor(mozilla::layers::LayersBackend aLayers) +{ + mozilla::gfx::BackendType defaultBackend = gfxPlatform::GetDefaultContentBackend(); + if (aLayers == LayersBackend::LAYERS_D3D11) { + return defaultBackend; + } + + if (defaultBackend == BackendType::DIRECT2D1_1) { + // We can't have D2D without D3D11 layers, so fallback to Cairo. + return BackendType::CAIRO; + } + + // Otherwise we have some non-accelerated backend and that's ok. + return defaultBackend; +} + +gfxPlatformFontList* +gfxWindowsPlatform::CreatePlatformFontList() +{ + gfxPlatformFontList *pfl; + + // bug 630201 - older pre-RTM versions of Direct2D/DirectWrite cause odd + // crashers so blacklist them altogether + if (IsNotWin7PreRTM() && GetDWriteFactory()) { + pfl = new gfxDWriteFontList(); + if (NS_SUCCEEDED(pfl->InitFontList())) { + return pfl; + } + // DWrite font initialization failed! Don't know why this would happen, + // but apparently it can - see bug 594865. + // So we're going to fall back to GDI fonts & rendering. + gfxPlatformFontList::Shutdown(); + DisableD2D(FeatureStatus::Failed, "Failed to initialize fonts", + NS_LITERAL_CSTRING("FEATURE_FAILURE_FONT_FAIL")); + } + + pfl = new gfxGDIFontList(); + + if (NS_SUCCEEDED(pfl->InitFontList())) { + return pfl; + } + + gfxPlatformFontList::Shutdown(); + 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(FeatureStatus aStatus, const char* aMessage, + const nsACString& aFailureId) +{ + gfxConfig::SetFailed(Feature::DIRECT2D, aStatus, aMessage, aFailureId); + Factory::SetDirect3D11Device(nullptr); + UpdateBackendPrefs(); +} + +already_AddRefed<gfxASurface> +gfxWindowsPlatform::CreateOffscreenSurface(const IntSize& aSize, + gfxImageFormat aFormat) +{ + if (!Factory::AllowedSurfaceSize(aSize)) { + return nullptr; + } + + RefPtr<gfxASurface> surf = nullptr; + +#ifdef CAIRO_HAS_WIN32_SURFACE + if (mRenderMode == RENDER_GDI || mRenderMode == RENDER_DIRECT2D) + surf = new gfxWindowsSurface(aSize, aFormat); +#endif + + if (!surf || surf->CairoStatus()) { + surf = new gfxImageSurface(aSize, aFormat); + } + + return surf.forget(); +} + +already_AddRefed<ScaledFont> +gfxWindowsPlatform::GetScaledFontForFont(DrawTarget* aTarget, gfxFont *aFont) +{ + if (aFont->GetType() == gfxFont::FONT_TYPE_DWRITE) { + gfxDWriteFont *font = static_cast<gfxDWriteFont*>(aFont); + + NativeFont nativeFont; + nativeFont.mType = NativeFontType::DWRITE_FONT_FACE; + nativeFont.mFont = font->GetFontFace(); + + if (aTarget->GetBackendType() == BackendType::CAIRO) { + return Factory::CreateScaledFontWithCairo(nativeFont, + font->GetAdjustedSize(), + font->GetCairoScaledFont()); + } + + return Factory::CreateScaledFontForNativeFont(nativeFont, + font->GetAdjustedSize()); + } + + NS_ASSERTION(aFont->GetType() == gfxFont::FONT_TYPE_GDI, + "Fonts on windows should be GDI or DWrite!"); + + NativeFont nativeFont; + nativeFont.mType = NativeFontType::GDI_FONT_FACE; + LOGFONT lf; + GetObject(static_cast<gfxGDIFont*>(aFont)->GetHFONT(), sizeof(LOGFONT), &lf); + nativeFont.mFont = &lf; + + if (aTarget->GetBackendType() == BackendType::CAIRO) { + return Factory::CreateScaledFontWithCairo(nativeFont, + aFont->GetAdjustedSize(), + aFont->GetCairoScaledFont()); + } + + return Factory::CreateScaledFontForNativeFont(nativeFont, aFont->GetAdjustedSize()); +} + +static const char kFontAparajita[] = "Aparajita"; +static const char kFontArabicTypesetting[] = "Arabic Typesetting"; +static const char kFontArial[] = "Arial"; +static const char kFontArialUnicodeMS[] = "Arial Unicode MS"; +static const char kFontCambria[] = "Cambria"; +static const char kFontCambriaMath[] = "Cambria Math"; +static const char kFontEbrima[] = "Ebrima"; +static const char kFontEstrangeloEdessa[] = "Estrangelo Edessa"; +static const char kFontEuphemia[] = "Euphemia"; +static const char kFontEmojiOneMozilla[] = "EmojiOne Mozilla"; +static const char kFontGabriola[] = "Gabriola"; +static const char kFontJavaneseText[] = "Javanese Text"; +static const char kFontKhmerUI[] = "Khmer UI"; +static const char kFontLaoUI[] = "Lao UI"; +static const char kFontLeelawadeeUI[] = "Leelawadee UI"; +static const char kFontLucidaSansUnicode[] = "Lucida Sans Unicode"; +static const char kFontMVBoli[] = "MV Boli"; +static const char kFontMalgunGothic[] = "Malgun Gothic"; +static const char kFontMicrosoftJhengHei[] = "Microsoft JhengHei"; +static const char kFontMicrosoftNewTaiLue[] = "Microsoft New Tai Lue"; +static const char kFontMicrosoftPhagsPa[] = "Microsoft PhagsPa"; +static const char kFontMicrosoftTaiLe[] = "Microsoft Tai Le"; +static const char kFontMicrosoftUighur[] = "Microsoft Uighur"; +static const char kFontMicrosoftYaHei[] = "Microsoft YaHei"; +static const char kFontMicrosoftYiBaiti[] = "Microsoft Yi Baiti"; +static const char kFontMeiryo[] = "Meiryo"; +static const char kFontMongolianBaiti[] = "Mongolian Baiti"; +static const char kFontMyanmarText[] = "Myanmar Text"; +static const char kFontNirmalaUI[] = "Nirmala UI"; +static const char kFontNyala[] = "Nyala"; +static const char kFontPlantagenetCherokee[] = "Plantagenet Cherokee"; +static const char kFontSegoeUI[] = "Segoe UI"; +static const char kFontSegoeUIEmoji[] = "Segoe UI Emoji"; +static const char kFontSegoeUISymbol[] = "Segoe UI Symbol"; +static const char kFontSylfaen[] = "Sylfaen"; +static const char kFontTraditionalArabic[] = "Traditional Arabic"; +static const char kFontUtsaah[] = "Utsaah"; +static const char kFontYuGothic[] = "Yu Gothic"; + +void +gfxWindowsPlatform::GetCommonFallbackFonts(uint32_t aCh, uint32_t aNextCh, + Script aRunScript, + nsTArray<const char*>& aFontList) +{ + if (aNextCh == 0xfe0fu) { + aFontList.AppendElement(kFontSegoeUIEmoji); + aFontList.AppendElement(kFontEmojiOneMozilla); + } + + // Arial is used as the default fallback for system fallback + aFontList.AppendElement(kFontArial); + + if (!IS_IN_BMP(aCh)) { + uint32_t p = aCh >> 16; + if (p == 1) { // SMP plane + if (aNextCh == 0xfe0eu) { + aFontList.AppendElement(kFontSegoeUISymbol); + aFontList.AppendElement(kFontSegoeUIEmoji); + aFontList.AppendElement(kFontEmojiOneMozilla); + } else { + if (aNextCh != 0xfe0fu) { + aFontList.AppendElement(kFontSegoeUIEmoji); + aFontList.AppendElement(kFontEmojiOneMozilla); + } + aFontList.AppendElement(kFontSegoeUISymbol); + } + aFontList.AppendElement(kFontEbrima); + aFontList.AppendElement(kFontNirmalaUI); + aFontList.AppendElement(kFontCambriaMath); + } + } else { + uint32_t b = (aCh >> 8) & 0xff; + + switch (b) { + case 0x05: + aFontList.AppendElement(kFontEstrangeloEdessa); + aFontList.AppendElement(kFontCambria); + break; + case 0x06: + aFontList.AppendElement(kFontMicrosoftUighur); + break; + case 0x07: + aFontList.AppendElement(kFontEstrangeloEdessa); + aFontList.AppendElement(kFontMVBoli); + aFontList.AppendElement(kFontEbrima); + break; + case 0x09: + aFontList.AppendElement(kFontNirmalaUI); + aFontList.AppendElement(kFontUtsaah); + aFontList.AppendElement(kFontAparajita); + break; + case 0x0a: + case 0x0b: + case 0x0c: + case 0x0d: + aFontList.AppendElement(kFontNirmalaUI); + break; + case 0x0e: + aFontList.AppendElement(kFontLaoUI); + aFontList.AppendElement(kFontLeelawadeeUI); + break; + case 0x10: + aFontList.AppendElement(kFontMyanmarText); + break; + case 0x11: + aFontList.AppendElement(kFontMalgunGothic); + break; + case 0x12: + case 0x13: + aFontList.AppendElement(kFontNyala); + aFontList.AppendElement(kFontPlantagenetCherokee); + break; + case 0x14: + case 0x15: + case 0x16: + aFontList.AppendElement(kFontEuphemia); + aFontList.AppendElement(kFontSegoeUISymbol); + break; + case 0x17: + aFontList.AppendElement(kFontKhmerUI); + aFontList.AppendElement(kFontLeelawadeeUI); + break; + case 0x18: // Mongolian + aFontList.AppendElement(kFontMongolianBaiti); + aFontList.AppendElement(kFontEuphemia); + break; + case 0x19: + aFontList.AppendElement(kFontMicrosoftTaiLe); + aFontList.AppendElement(kFontMicrosoftNewTaiLue); + aFontList.AppendElement(kFontKhmerUI); + aFontList.AppendElement(kFontLeelawadeeUI); + break; + case 0x1a: + aFontList.AppendElement(kFontLeelawadeeUI); + break; + case 0x1c: + aFontList.AppendElement(kFontNirmalaUI); + break; + case 0x20: // Symbol ranges + case 0x21: + case 0x22: + case 0x23: + case 0x24: + case 0x25: + case 0x26: + case 0x27: + case 0x29: + case 0x2a: + case 0x2b: + case 0x2c: + aFontList.AppendElement(kFontSegoeUI); + aFontList.AppendElement(kFontSegoeUISymbol); + aFontList.AppendElement(kFontCambria); + aFontList.AppendElement(kFontMeiryo); + aFontList.AppendElement(kFontArial); + aFontList.AppendElement(kFontLucidaSansUnicode); + aFontList.AppendElement(kFontEbrima); + break; + case 0x2d: + case 0x2e: + case 0x2f: + aFontList.AppendElement(kFontEbrima); + aFontList.AppendElement(kFontNyala); + aFontList.AppendElement(kFontSegoeUI); + aFontList.AppendElement(kFontSegoeUISymbol); + aFontList.AppendElement(kFontMeiryo); + break; + case 0x28: // Braille + aFontList.AppendElement(kFontSegoeUISymbol); + break; + case 0x30: + case 0x31: + aFontList.AppendElement(kFontMicrosoftYaHei); + break; + case 0x32: + aFontList.AppendElement(kFontMalgunGothic); + break; + case 0x4d: + aFontList.AppendElement(kFontSegoeUISymbol); + break; + case 0x9f: + aFontList.AppendElement(kFontMicrosoftYaHei); + aFontList.AppendElement(kFontYuGothic); + break; + case 0xa0: // Yi + case 0xa1: + case 0xa2: + case 0xa3: + case 0xa4: + aFontList.AppendElement(kFontMicrosoftYiBaiti); + aFontList.AppendElement(kFontSegoeUI); + break; + case 0xa5: + case 0xa6: + case 0xa7: + aFontList.AppendElement(kFontEbrima); + aFontList.AppendElement(kFontSegoeUI); + aFontList.AppendElement(kFontCambriaMath); + break; + case 0xa8: + aFontList.AppendElement(kFontMicrosoftPhagsPa); + aFontList.AppendElement(kFontNirmalaUI); + break; + case 0xa9: + aFontList.AppendElement(kFontMalgunGothic); + aFontList.AppendElement(kFontJavaneseText); + aFontList.AppendElement(kFontLeelawadeeUI); + break; + case 0xaa: + aFontList.AppendElement(kFontMyanmarText); + break; + case 0xab: + aFontList.AppendElement(kFontEbrima); + aFontList.AppendElement(kFontNyala); + break; + case 0xd7: + aFontList.AppendElement(kFontMalgunGothic); + break; + case 0xfb: + aFontList.AppendElement(kFontMicrosoftUighur); + aFontList.AppendElement(kFontGabriola); + aFontList.AppendElement(kFontSylfaen); + break; + case 0xfc: + case 0xfd: + aFontList.AppendElement(kFontTraditionalArabic); + aFontList.AppendElement(kFontArabicTypesetting); + break; + case 0xfe: + aFontList.AppendElement(kFontTraditionalArabic); + aFontList.AppendElement(kFontMicrosoftJhengHei); + break; + case 0xff: + aFontList.AppendElement(kFontMicrosoftJhengHei); + break; + default: + break; + } + } + + // Arial Unicode MS has lots of glyphs for obscure characters, + // use it as a last resort + aFontList.AppendElement(kFontArialUnicodeMS); +} + +gfxFontGroup * +gfxWindowsPlatform::CreateFontGroup(const FontFamilyList& aFontFamilyList, + const gfxFontStyle *aStyle, + gfxTextPerfMetrics* aTextPerf, + gfxUserFontSet *aUserFontSet, + gfxFloat aDevToCssSize) +{ + return new gfxFontGroup(aFontFamilyList, aStyle, aTextPerf, + aUserFontSet, aDevToCssSize); +} + +bool +gfxWindowsPlatform::IsFontFormatSupported(nsIURI *aFontURI, uint32_t aFormatFlags) +{ + // check for strange format flags + NS_ASSERTION(!(aFormatFlags & gfxUserFontSet::FLAG_FORMAT_NOT_USED), + "strange font format hint set"); + + // accept supported formats + if (aFormatFlags & gfxUserFontSet::FLAG_FORMATS_COMMON) { + return true; + } + + // reject all other formats, known and unknown + if (aFormatFlags != 0) { + return false; + } + + // no format hint set, need to look at data + return true; +} + +bool +gfxWindowsPlatform::DidRenderingDeviceReset(DeviceResetReason* aResetReason) +{ + DeviceManagerDx* dm = DeviceManagerDx::Get(); + if (!dm) { + return false; + } + return dm->HasDeviceReset(aResetReason); +} + +void +gfxWindowsPlatform::CompositorUpdated() +{ + DeviceManagerDx::Get()->ForceDeviceReset(ForcedDeviceResetReason::COMPOSITOR_UPDATED); + UpdateRenderMode(); +} + +BOOL CALLBACK +InvalidateWindowForDeviceReset(HWND aWnd, LPARAM aMsg) +{ + RedrawWindow(aWnd, nullptr, nullptr, + RDW_INVALIDATE|RDW_INTERNALPAINT|RDW_FRAME); + return TRUE; +} + +void +gfxWindowsPlatform::SchedulePaintIfDeviceReset() +{ + PROFILER_LABEL_FUNC(js::ProfileEntry::Category::GRAPHICS); + + DeviceResetReason resetReason = DeviceResetReason::OK; + if (!DidRenderingDeviceReset(&resetReason)) { + return; + } + + gfxCriticalNote << "(gfxWindowsPlatform) Detected device reset: " << (int)resetReason; + + // Trigger an ::OnPaint for each window. + ::EnumThreadWindows(GetCurrentThreadId(), + InvalidateWindowForDeviceReset, + 0); + + gfxCriticalNote << "(gfxWindowsPlatform) Finished device reset."; +} + +void +gfxWindowsPlatform::GetPlatformCMSOutputProfile(void* &mem, size_t &mem_size) +{ + WCHAR str[MAX_PATH]; + DWORD size = MAX_PATH; + BOOL res; + + mem = nullptr; + mem_size = 0; + + HDC dc = GetDC(nullptr); + if (!dc) + return; + + MOZ_SEH_TRY { + res = GetICMProfileW(dc, &size, (LPWSTR)&str); + } MOZ_SEH_EXCEPT(GetExceptionCode() == EXCEPTION_ILLEGAL_INSTRUCTION) { + res = FALSE; + } + + ReleaseDC(nullptr, dc); + if (!res) + return; + +#ifdef _WIN32 + qcms_data_from_unicode_path(str, &mem, &mem_size); + +#ifdef DEBUG_tor + if (mem_size > 0) + fprintf(stderr, + "ICM profile read from %s successfully\n", + NS_ConvertUTF16toUTF8(str).get()); +#endif // DEBUG_tor +#endif // _WIN32 +} + +bool +gfxWindowsPlatform::UseClearTypeForDownloadableFonts() +{ + if (mUseClearTypeForDownloadableFonts == UNINITIALIZED_VALUE) { + mUseClearTypeForDownloadableFonts = Preferences::GetBool(GFX_DOWNLOADABLE_FONTS_USE_CLEARTYPE, true); + } + + return mUseClearTypeForDownloadableFonts; +} + +bool +gfxWindowsPlatform::UseClearTypeAlways() +{ + if (mUseClearTypeAlways == UNINITIALIZED_VALUE) { + mUseClearTypeAlways = Preferences::GetBool(GFX_USE_CLEARTYPE_ALWAYS, false); + } + + return mUseClearTypeAlways; +} + +void +gfxWindowsPlatform::GetDLLVersion(char16ptr_t aDLLPath, nsAString& aVersion) +{ + DWORD versInfoSize, vers[4] = {0}; + // version info not available case + aVersion.AssignLiteral(u"0.0.0.0"); + versInfoSize = GetFileVersionInfoSizeW(aDLLPath, nullptr); + AutoTArray<BYTE,512> versionInfo; + + if (versInfoSize == 0 || + !versionInfo.AppendElements(uint32_t(versInfoSize))) + { + return; + } + + if (!GetFileVersionInfoW(aDLLPath, 0, versInfoSize, + LPBYTE(versionInfo.Elements()))) + { + return; + } + + UINT len = 0; + VS_FIXEDFILEINFO *fileInfo = nullptr; + if (!VerQueryValue(LPBYTE(versionInfo.Elements()), TEXT("\\"), + (LPVOID *)&fileInfo, &len) || + len == 0 || + fileInfo == nullptr) + { + return; + } + + DWORD fileVersMS = fileInfo->dwFileVersionMS; + DWORD fileVersLS = fileInfo->dwFileVersionLS; + + vers[0] = HIWORD(fileVersMS); + vers[1] = LOWORD(fileVersMS); + vers[2] = HIWORD(fileVersLS); + vers[3] = LOWORD(fileVersLS); + + char buf[256]; + SprintfLiteral(buf, "%u.%u.%u.%u", vers[0], vers[1], vers[2], vers[3]); + aVersion.Assign(NS_ConvertUTF8toUTF16(buf)); +} + +void +gfxWindowsPlatform::GetCleartypeParams(nsTArray<ClearTypeParameterInfo>& aParams) +{ + HKEY hKey, subKey; + DWORD i, rv, size, type; + WCHAR displayName[256], subkeyName[256]; + + aParams.Clear(); + + // construct subkeys based on HKLM subkeys, assume they are same for HKCU + rv = RegOpenKeyExW(HKEY_LOCAL_MACHINE, + L"Software\\Microsoft\\Avalon.Graphics", + 0, KEY_READ, &hKey); + + if (rv != ERROR_SUCCESS) { + return; + } + + // enumerate over subkeys + for (i = 0, rv = ERROR_SUCCESS; rv != ERROR_NO_MORE_ITEMS; i++) { + size = ArrayLength(displayName); + rv = RegEnumKeyExW(hKey, i, displayName, &size, + nullptr, nullptr, nullptr, nullptr); + if (rv != ERROR_SUCCESS) { + continue; + } + + ClearTypeParameterInfo ctinfo; + ctinfo.displayName.Assign(displayName); + + DWORD subrv, value; + bool foundData = false; + + swprintf_s(subkeyName, ArrayLength(subkeyName), + L"Software\\Microsoft\\Avalon.Graphics\\%s", displayName); + + // subkey for gamma, pixel structure + subrv = RegOpenKeyExW(HKEY_LOCAL_MACHINE, + subkeyName, 0, KEY_QUERY_VALUE, &subKey); + + if (subrv == ERROR_SUCCESS) { + size = sizeof(value); + subrv = RegQueryValueExW(subKey, L"GammaLevel", nullptr, &type, + (LPBYTE)&value, &size); + if (subrv == ERROR_SUCCESS && type == REG_DWORD) { + foundData = true; + ctinfo.gamma = value; + } + + size = sizeof(value); + subrv = RegQueryValueExW(subKey, L"PixelStructure", nullptr, &type, + (LPBYTE)&value, &size); + if (subrv == ERROR_SUCCESS && type == REG_DWORD) { + foundData = true; + ctinfo.pixelStructure = value; + } + + RegCloseKey(subKey); + } + + // subkey for cleartype level, enhanced contrast + subrv = RegOpenKeyExW(HKEY_CURRENT_USER, + subkeyName, 0, KEY_QUERY_VALUE, &subKey); + + if (subrv == ERROR_SUCCESS) { + size = sizeof(value); + subrv = RegQueryValueExW(subKey, L"ClearTypeLevel", nullptr, &type, + (LPBYTE)&value, &size); + if (subrv == ERROR_SUCCESS && type == REG_DWORD) { + foundData = true; + ctinfo.clearTypeLevel = value; + } + + size = sizeof(value); + subrv = RegQueryValueExW(subKey, L"EnhancedContrastLevel", + nullptr, &type, (LPBYTE)&value, &size); + if (subrv == ERROR_SUCCESS && type == REG_DWORD) { + foundData = true; + ctinfo.enhancedContrast = value; + } + + RegCloseKey(subKey); + } + + if (foundData) { + aParams.AppendElement(ctinfo); + } + } + + RegCloseKey(hKey); +} + +void +gfxWindowsPlatform::FontsPrefsChanged(const char *aPref) +{ + bool clearTextFontCaches = true; + + gfxPlatform::FontsPrefsChanged(aPref); + + if (!aPref) { + mUseClearTypeForDownloadableFonts = UNINITIALIZED_VALUE; + mUseClearTypeAlways = UNINITIALIZED_VALUE; + } else if (!strcmp(GFX_DOWNLOADABLE_FONTS_USE_CLEARTYPE, aPref)) { + mUseClearTypeForDownloadableFonts = UNINITIALIZED_VALUE; + } else if (!strcmp(GFX_USE_CLEARTYPE_ALWAYS, aPref)) { + mUseClearTypeAlways = UNINITIALIZED_VALUE; + } else if (!strncmp(GFX_CLEARTYPE_PARAMS, aPref, strlen(GFX_CLEARTYPE_PARAMS))) { + SetupClearTypeParams(); + } else { + clearTextFontCaches = false; + } + + if (clearTextFontCaches) { + gfxFontCache *fc = gfxFontCache::GetCache(); + if (fc) { + fc->Flush(); + } + } +} + +#define DISPLAY1_REGISTRY_KEY \ + HKEY_CURRENT_USER, L"Software\\Microsoft\\Avalon.Graphics\\DISPLAY1" + +#define ENHANCED_CONTRAST_VALUE_NAME L"EnhancedContrastLevel" + +void +gfxWindowsPlatform::SetupClearTypeParams() +{ + if (GetDWriteFactory()) { + // any missing prefs will default to invalid (-1) and be ignored; + // out-of-range values will also be ignored + FLOAT gamma = -1.0; + FLOAT contrast = -1.0; + FLOAT level = -1.0; + int geometry = -1; + int mode = -1; + int32_t value; + if (NS_SUCCEEDED(Preferences::GetInt(GFX_CLEARTYPE_PARAMS_GAMMA, &value))) { + if (value >= 1000 && value <= 2200) { + gamma = FLOAT(value / 1000.0); + } + } + + if (NS_SUCCEEDED(Preferences::GetInt(GFX_CLEARTYPE_PARAMS_CONTRAST, &value))) { + if (value >= 0 && value <= 1000) { + contrast = FLOAT(value / 100.0); + } + } + + if (NS_SUCCEEDED(Preferences::GetInt(GFX_CLEARTYPE_PARAMS_LEVEL, &value))) { + if (value >= 0 && value <= 100) { + level = FLOAT(value / 100.0); + } + } + + if (NS_SUCCEEDED(Preferences::GetInt(GFX_CLEARTYPE_PARAMS_STRUCTURE, &value))) { + if (value >= 0 && value <= 2) { + geometry = value; + } + } + + if (NS_SUCCEEDED(Preferences::GetInt(GFX_CLEARTYPE_PARAMS_MODE, &value))) { + if (value >= 0 && value <= 5) { + mode = value; + } + } + + cairo_dwrite_set_cleartype_params(gamma, contrast, level, geometry, mode); + + switch (mode) { + case DWRITE_RENDERING_MODE_ALIASED: + case DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC: + mMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC; + break; + case DWRITE_RENDERING_MODE_CLEARTYPE_GDI_NATURAL: + mMeasuringMode = DWRITE_MEASURING_MODE_GDI_NATURAL; + break; + default: + mMeasuringMode = DWRITE_MEASURING_MODE_NATURAL; + break; + } + + RefPtr<IDWriteRenderingParams> defaultRenderingParams; + GetDWriteFactory()->CreateRenderingParams(getter_AddRefs(defaultRenderingParams)); + // For EnhancedContrast, we override the default if the user has not set it + // in the registry (by using the ClearType Tuner). + if (contrast < 0.0 || contrast > 10.0) { + HKEY hKey; + LONG res = RegOpenKeyExW(DISPLAY1_REGISTRY_KEY, + 0, KEY_READ, &hKey); + if (res == ERROR_SUCCESS) { + res = RegQueryValueExW(hKey, ENHANCED_CONTRAST_VALUE_NAME, + nullptr, nullptr, nullptr, nullptr); + if (res == ERROR_SUCCESS) { + contrast = defaultRenderingParams->GetEnhancedContrast(); + } + RegCloseKey(hKey); + } + + if (contrast < 0.0 || contrast > 10.0) { + contrast = 1.0; + } + } + + if (GetDefaultContentBackend() == BackendType::SKIA) { + // Skia doesn't support a contrast value outside of 0-1, so default to 1.0 + if (contrast < 0.0 || contrast > 1.0) { + NS_WARNING("Custom dwrite contrast not supported in Skia. Defaulting to 1.0."); + contrast = 1.0; + } + } + + // For parameters that have not been explicitly set, + // we copy values from default params (or our overridden value for contrast) + if (gamma < 1.0 || gamma > 2.2) { + gamma = defaultRenderingParams->GetGamma(); + } + + if (level < 0.0 || level > 1.0) { + level = defaultRenderingParams->GetClearTypeLevel(); + } + + DWRITE_PIXEL_GEOMETRY dwriteGeometry = + static_cast<DWRITE_PIXEL_GEOMETRY>(geometry); + DWRITE_RENDERING_MODE renderMode = + static_cast<DWRITE_RENDERING_MODE>(mode); + + if (dwriteGeometry < DWRITE_PIXEL_GEOMETRY_FLAT || + dwriteGeometry > DWRITE_PIXEL_GEOMETRY_BGR) { + dwriteGeometry = defaultRenderingParams->GetPixelGeometry(); + } + + if (renderMode < DWRITE_RENDERING_MODE_DEFAULT || + renderMode > DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC) { + renderMode = defaultRenderingParams->GetRenderingMode(); + } + + mRenderingParams[TEXT_RENDERING_NO_CLEARTYPE] = defaultRenderingParams; + + HRESULT hr = GetDWriteFactory()->CreateCustomRenderingParams( + gamma, contrast, level, dwriteGeometry, renderMode, + getter_AddRefs(mRenderingParams[TEXT_RENDERING_NORMAL])); + if (FAILED(hr) || !mRenderingParams[TEXT_RENDERING_NORMAL]) { + mRenderingParams[TEXT_RENDERING_NORMAL] = defaultRenderingParams; + } + + hr = GetDWriteFactory()->CreateCustomRenderingParams( + gamma, contrast, level, + dwriteGeometry, DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC, + getter_AddRefs(mRenderingParams[TEXT_RENDERING_GDI_CLASSIC])); + if (FAILED(hr) || !mRenderingParams[TEXT_RENDERING_GDI_CLASSIC]) { + mRenderingParams[TEXT_RENDERING_GDI_CLASSIC] = + defaultRenderingParams; + } + } +} + +ReadbackManagerD3D11* +gfxWindowsPlatform::GetReadbackManager() +{ + if (!mD3D11ReadbackManager) { + mD3D11ReadbackManager = new ReadbackManagerD3D11(); + } + + return mD3D11ReadbackManager; +} + +bool +gfxWindowsPlatform::IsOptimus() +{ + static int knowIsOptimus = -1; + if (knowIsOptimus == -1) { + // other potential optimus -- nvd3d9wrapx.dll & nvdxgiwrap.dll + if (GetModuleHandleA("nvumdshim.dll") || + GetModuleHandleA("nvumdshimx.dll")) + { + knowIsOptimus = 1; + } else { + knowIsOptimus = 0; + } + } + return knowIsOptimus; +} + +static inline bool +IsWARPStable() +{ + // It seems like nvdxgiwrap makes a mess of WARP. See bug 1154703. + if (!IsWin8OrLater() || GetModuleHandleA("nvdxgiwrap.dll")) { + return false; + } + return true; +} + +static void +InitializeANGLEConfig() +{ + FeatureState& d3d11ANGLE = gfxConfig::GetFeature(Feature::D3D11_HW_ANGLE); + + if (!gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) { + d3d11ANGLE.DisableByDefault(FeatureStatus::Unavailable, "D3D11 compositing is disabled", + NS_LITERAL_CSTRING("FEATURE_FAILURE_D3D11_DISABLED")); + return; + } + + d3d11ANGLE.EnableByDefault(); + + nsCString message; + nsCString failureId; + if (!gfxPlatform::IsGfxInfoStatusOkay(nsIGfxInfo::FEATURE_DIRECT3D_11_ANGLE, &message, + failureId)) { + d3d11ANGLE.Disable(FeatureStatus::Blacklisted, message.get(), failureId); + } + +} + +void +gfxWindowsPlatform::InitializeDirectDrawConfig() +{ + MOZ_ASSERT(XRE_IsParentProcess()); + + FeatureState& ddraw = gfxConfig::GetFeature(Feature::DIRECT_DRAW); + ddraw.EnableByDefault(); +} + +void +gfxWindowsPlatform::InitializeConfig() +{ + if (XRE_IsParentProcess()) { + // The parent process first determines which features can be attempted. + // This information is relayed to content processes and the GPU process. + InitializeD3D9Config(); + InitializeD3D11Config(); + InitializeANGLEConfig(); + InitializeD2DConfig(); + } else { + FetchAndImportContentDeviceData(); + InitializeANGLEConfig(); + } +} + +void +gfxWindowsPlatform::InitializeD3D9Config() +{ + MOZ_ASSERT(XRE_IsParentProcess()); + + FeatureState& d3d9 = gfxConfig::GetFeature(Feature::D3D9_COMPOSITING); + + if (!gfxConfig::IsEnabled(Feature::HW_COMPOSITING)) { + d3d9.DisableByDefault(FeatureStatus::Unavailable, "Hardware compositing is disabled", + NS_LITERAL_CSTRING("FEATURE_FAILURE_D3D9_NEED_HWCOMP")); + return; + } + + if (!IsVistaOrLater()) { + d3d9.EnableByDefault(); + } else { + d3d9.SetDefaultFromPref( + gfxPrefs::GetLayersAllowD3D9FallbackPrefName(), + true, + gfxPrefs::GetLayersAllowD3D9FallbackPrefDefault()); + + if (!d3d9.IsEnabled() && gfxPrefs::LayersPreferD3D9()) { + d3d9.UserEnable("Direct3D9 enabled via layers.prefer-d3d9"); + } + } + + nsCString message; + nsCString failureId; + if (!gfxPlatform::IsGfxInfoStatusOkay(nsIGfxInfo::FEATURE_DIRECT3D_9_LAYERS, &message, + failureId)) { + d3d9.Disable(FeatureStatus::Blacklisted, message.get(), failureId); + } + + if (gfxConfig::IsForcedOnByUser(Feature::HW_COMPOSITING)) { + d3d9.UserForceEnable("Hardware compositing is force-enabled"); + } +} + +void +gfxWindowsPlatform::InitializeD3D11Config() +{ + MOZ_ASSERT(XRE_IsParentProcess()); + + FeatureState& d3d11 = gfxConfig::GetFeature(Feature::D3D11_COMPOSITING); + + if (!gfxConfig::IsEnabled(Feature::HW_COMPOSITING)) { + d3d11.DisableByDefault(FeatureStatus::Unavailable, "Hardware compositing is disabled", + NS_LITERAL_CSTRING("FEATURE_FAILURE_D3D11_NEED_HWCOMP")); + return; + } + + d3d11.EnableByDefault(); + + if (!IsWin8OrLater() && + !DeviceManagerDx::Get()->CheckRemotePresentSupport()) { + nsCOMPtr<nsIGfxInfo> gfxInfo; + gfxInfo = services::GetGfxInfo(); + nsAutoString adaptorId; + gfxInfo->GetAdapterDeviceID(adaptorId); + // Blacklist Intel HD Graphics 510/520/530 on Windows 7 without platform + // update due to the crashes in Bug 1351349. + if (adaptorId.EqualsLiteral("0x1912") || adaptorId.EqualsLiteral("0x1916") || + adaptorId.EqualsLiteral("0x1902")) { + d3d11.Disable(FeatureStatus::Blacklisted, "Blacklisted, see bug 1351349", + NS_LITERAL_CSTRING("FEATURE_FAILURE_BUG_1351349")); + } + } + + // If the user prefers D3D9, act as though they disabled D3D11. + if (gfxPrefs::LayersPreferD3D9()) { + d3d11.UserDisable("Disabled due to user preference for Direct3D 9", + NS_LITERAL_CSTRING("FEATURE_FAILURE_D3D11_PREF")); + return; + } + + nsCString message; + nsCString failureId; + if (!gfxPlatform::IsGfxInfoStatusOkay(nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS, &message, failureId)) { + d3d11.Disable(FeatureStatus::Blacklisted, message.get(), failureId); + } + + // Check if the user really, really wants WARP. + if (gfxPrefs::LayersD3D11ForceWARP()) { + // Force D3D11 on even if we disabled it. + d3d11.UserForceEnable("User force-enabled WARP"); + } +} + +/* static */ void +gfxWindowsPlatform::RecordContentDeviceFailure(TelemetryDeviceCode aDevice) +{ + // If the parent process fails to acquire a device, we record this + // normally as part of the environment. The exceptional case we're + // looking for here is when the parent process successfully acquires + // a device, but the content process fails to acquire the same device. + // This would not normally be displayed in about:support. + if (!XRE_IsContentProcess()) { + return; + } + Telemetry::Accumulate(Telemetry::GFX_CONTENT_FAILED_TO_ACQUIRE_DEVICE, uint32_t(aDevice)); +} + +void +gfxWindowsPlatform::InitializeDevices() +{ + MOZ_ASSERT(!InSafeMode()); + + if (XRE_IsParentProcess()) { + // If we're the UI process, and the GPU process is enabled, then we don't + // initialize any DirectX devices. We do leave them enabled in gfxConfig + // though. If the GPU process fails to create these devices it will send + // a message back and we'll update their status. + if (InitGPUProcessSupport()) { + return; + } + + // No GPU process, continue initializing devices as normal. + } + + // If acceleration is disabled, we refuse to initialize anything. + if (!gfxConfig::IsEnabled(Feature::HW_COMPOSITING)) { + return; + } + + // If we previously crashed initializing devices, bail out now. + D3D11LayersCrashGuard detectCrashes; + if (detectCrashes.Crashed()) { + gfxConfig::SetFailed(Feature::HW_COMPOSITING, + FeatureStatus::CrashedOnStartup, + "Crashed during startup in a previous session"); + gfxConfig::SetFailed(Feature::D3D11_COMPOSITING, + FeatureStatus::CrashedOnStartup, + "Harware acceleration crashed during startup in a previous session"); + gfxConfig::SetFailed(Feature::DIRECT2D, + FeatureStatus::CrashedOnStartup, + "Harware acceleration crashed during startup in a previous session"); + return; + } + + bool shouldUseD2D = gfxConfig::IsEnabled(Feature::DIRECT2D); + + // First, initialize D3D11. If this succeeds we attempt to use Direct2D. + InitializeD3D11(); + InitializeD2D(); + + if (!gfxConfig::IsEnabled(Feature::DIRECT2D) && + XRE_IsContentProcess() && + shouldUseD2D) + { + RecordContentDeviceFailure(TelemetryDeviceCode::D2D1); + } +} + +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. + if (!gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) { + return; + } + + DeviceManagerDx* dm = DeviceManagerDx::Get(); + if (XRE_IsParentProcess()) { + if (!dm->CreateCompositorDevices()) { + return; + } + } + + dm->CreateContentDevices(); + + // Content process failed to create the d3d11 device while parent process + // succeed. + if (XRE_IsContentProcess() && + !gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) { + gfxCriticalError() << "[D3D11] Failed to create the D3D11 device in content \ + process."; + } +} + +void +gfxWindowsPlatform::InitializeD2DConfig() +{ + FeatureState& d2d1 = gfxConfig::GetFeature(Feature::DIRECT2D); + + if (!gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) { + d2d1.DisableByDefault(FeatureStatus::Unavailable, "Direct2D requires Direct3D 11 compositing", + NS_LITERAL_CSTRING("FEATURE_FAILURE_D2D_D3D11_COMP")); + return; + } + if (!IsVistaOrLater()) { + d2d1.DisableByDefault(FeatureStatus::Unavailable, "Direct2D is not available on Windows XP", + NS_LITERAL_CSTRING("FEATURE_FAILURE_D2D_XP")); + return; + } + + d2d1.SetDefaultFromPref( + gfxPrefs::GetDirect2DDisabledPrefName(), + false, + gfxPrefs::GetDirect2DDisabledPrefDefault()); + + nsCString message; + nsCString failureId; + if (!gfxPlatform::IsGfxInfoStatusOkay(nsIGfxInfo::FEATURE_DIRECT2D, &message, failureId)) { + d2d1.Disable(FeatureStatus::Blacklisted, message.get(), failureId); + } + + if (!d2d1.IsEnabled() && gfxPrefs::Direct2DForceEnabled()) { + d2d1.UserForceEnable("Force-enabled via user-preference"); + } +} + +void +gfxWindowsPlatform::InitializeD2D() +{ + ScopedGfxFeatureReporter d2d1_1("D2D1.1"); + + FeatureState& d2d1 = gfxConfig::GetFeature(Feature::DIRECT2D); + + DeviceManagerDx* dm = DeviceManagerDx::Get(); + + // We don't know this value ahead of time, but the user can force-override + // it, so we use Disable instead of SetFailed. + if (dm->IsWARP()) { + d2d1.Disable(FeatureStatus::Blocked, "Direct2D is not compatible with Direct3D11 WARP", + NS_LITERAL_CSTRING("FEATURE_FAILURE_D2D_WARP_BLOCK")); + } + + // If we pass all the initial checks, we can proceed to runtime decisions. + if (!d2d1.IsEnabled()) { + return; + } + + if (!Factory::SupportsD2D1()) { + d2d1.SetFailed(FeatureStatus::Unavailable, "Failed to acquire a Direct2D 1.1 factory", + NS_LITERAL_CSTRING("FEATURE_FAILURE_D2D_FACTORY")); + return; + } + + if (!dm->GetContentDevice()) { + d2d1.SetFailed(FeatureStatus::Failed, "Failed to acquire a Direct3D 11 content device", + NS_LITERAL_CSTRING("FEATURE_FAILURE_D2D_DEVICE")); + return; + } + + if (!dm->TextureSharingWorks()) { + d2d1.SetFailed(FeatureStatus::Failed, "Direct3D11 device does not support texture sharing", + NS_LITERAL_CSTRING("FEATURE_FAILURE_D2D_TXT_SHARING")); + return; + } + + // Using Direct2D depends on DWrite support. + if (!mDWriteFactory && !InitDWriteSupport()) { + d2d1.SetFailed(FeatureStatus::Failed, "Failed to initialize DirectWrite support", + NS_LITERAL_CSTRING("FEATURE_FAILURE_D2D_DWRITE")); + return; + } + + // Verify that Direct2D device creation succeeded. + RefPtr<ID3D11Device> contentDevice = dm->GetContentDevice(); + if (!Factory::SetDirect3D11Device(contentDevice)) { + d2d1.SetFailed(FeatureStatus::Failed, "Failed to create a Direct2D device", + NS_LITERAL_CSTRING("FEATURE_FAILURE_D2D_CREATE_FAILED")); + return; + } + + MOZ_ASSERT(d2d1.IsEnabled()); + d2d1_1.SetSuccessful(); +} + +bool +gfxWindowsPlatform::InitGPUProcessSupport() +{ + FeatureState& gpuProc = gfxConfig::GetFeature(Feature::GPU_PROCESS); + + if (!gpuProc.IsEnabled()) { + return false; + } + + if (!gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) { + // Don't use the GPU process if not using D3D11. + gpuProc.Disable( + FeatureStatus::Unavailable, + "Not using GPU Process since D3D11 is unavailable", + NS_LITERAL_CSTRING("FEATURE_FAILURE_NO_D3D11")); + } else if (!IsWin7SP1OrLater()) { + // For Windows XP, we simply don't care enough to support this + // configuration. On Windows Vista and 7 Pre-SP1, DXGI 1.2 is not + // available and remote presentation for D3D11 will not work. Rather + // than take a regression and use D3D9, we revert back to in-process + // rendering. + gpuProc.Disable( + FeatureStatus::Unavailable, + "Windows XP, Vista, and 7 Pre-SP1 cannot use the GPU process", + NS_LITERAL_CSTRING("FEATURE_FAILURE_OLD_WINDOWS")); + } else if (!IsWin8OrLater()) { + // Windows 7 SP1 can have DXGI 1.2 only via the Platform Update, so we + // explicitly check for that here. + if (!DeviceManagerDx::Get()->CheckRemotePresentSupport()) { + gpuProc.Disable( + FeatureStatus::Unavailable, + "GPU Process requires the Windows 7 Platform Update", + NS_LITERAL_CSTRING("FEATURE_FAILURE_PLATFORM_UPDATE")); + } else { + // Clear anything cached by the above call since we don't need it. + DeviceManagerDx::Get()->ResetDevices(); + } + } + + // If we're still enabled at this point, the user set the force-enabled pref. + return gpuProc.IsEnabled(); +} + +bool +gfxWindowsPlatform::DwmCompositionEnabled() +{ + if (!IsVistaOrLater()) { + return false; + } + + MOZ_ASSERT(WinUtils::dwmIsCompositionEnabledPtr); + BOOL dwmEnabled = false; + + if (FAILED(WinUtils::dwmIsCompositionEnabledPtr(&dwmEnabled))) { + return false; + } + + return dwmEnabled; +} + +class D3DVsyncSource final : public VsyncSource +{ +public: + + class D3DVsyncDisplay final : public VsyncSource::Display + { + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(D3DVsyncDisplay) + public: + D3DVsyncDisplay() + : mPrevVsync(TimeStamp::Now()) + , mVsyncEnabledLock("D3DVsyncEnabledLock") + , mVsyncEnabled(false) + { + mVsyncThread = new base::Thread("WindowsVsyncThread"); + MOZ_RELEASE_ASSERT(mVsyncThread->Start(), "GFX: Could not start Windows vsync thread"); + SetVsyncRate(); + } + + void SetVsyncRate() + { + if (!gfxWindowsPlatform::GetPlatform()->DwmCompositionEnabled()) { + mVsyncRate = TimeDuration::FromMilliseconds(1000.0 / 60.0); + return; + } + + DWM_TIMING_INFO vblankTime; + // Make sure to init the cbSize, otherwise GetCompositionTiming will fail + vblankTime.cbSize = sizeof(DWM_TIMING_INFO); + HRESULT hr = WinUtils::dwmGetCompositionTimingInfoPtr(0, &vblankTime); + if (SUCCEEDED(hr)) { + UNSIGNED_RATIO refreshRate = vblankTime.rateRefresh; + // We get the rate in hertz / time, but we want the rate in ms. + float rate = ((float) refreshRate.uiDenominator + / (float) refreshRate.uiNumerator) * 1000; + mVsyncRate = TimeDuration::FromMilliseconds(rate); + } else { + mVsyncRate = TimeDuration::FromMilliseconds(1000.0 / 60.0); + } + } + + virtual void Shutdown() override + { + MOZ_ASSERT(NS_IsMainThread()); + DisableVsync(); + mVsyncThread->Stop(); + delete mVsyncThread; + } + + virtual void EnableVsync() override + { + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(mVsyncThread->IsRunning()); + { // scope lock + MonitorAutoLock lock(mVsyncEnabledLock); + if (mVsyncEnabled) { + return; + } + mVsyncEnabled = true; + } + + mVsyncThread->message_loop()->PostTask( + NewRunnableMethod(this, &D3DVsyncDisplay::VBlankLoop)); + } + + virtual void DisableVsync() override + { + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(mVsyncThread->IsRunning()); + MonitorAutoLock lock(mVsyncEnabledLock); + if (!mVsyncEnabled) { + return; + } + mVsyncEnabled = false; + } + + virtual bool IsVsyncEnabled() override + { + MOZ_ASSERT(NS_IsMainThread()); + MonitorAutoLock lock(mVsyncEnabledLock); + return mVsyncEnabled; + } + + virtual TimeDuration GetVsyncRate() override + { + return mVsyncRate; + } + + void ScheduleSoftwareVsync(TimeStamp aVsyncTimestamp) + { + MOZ_ASSERT(IsInVsyncThread()); + NS_WARNING("DwmComposition dynamically disabled, falling back to software timers"); + + TimeStamp nextVsync = aVsyncTimestamp + mVsyncRate; + TimeDuration delay = nextVsync - TimeStamp::Now(); + if (delay.ToMilliseconds() < 0) { + delay = mozilla::TimeDuration::FromMilliseconds(0); + } + + mVsyncThread->message_loop()->PostDelayedTask( + NewRunnableMethod(this, &D3DVsyncDisplay::VBlankLoop), + delay.ToMilliseconds()); + } + + // Returns the timestamp for the just happened vsync + TimeStamp GetVBlankTime() + { + TimeStamp vsync = TimeStamp::Now(); + TimeStamp now = vsync; + + DWM_TIMING_INFO vblankTime; + // Make sure to init the cbSize, otherwise + // GetCompositionTiming will fail + vblankTime.cbSize = sizeof(DWM_TIMING_INFO); + HRESULT hr = WinUtils::dwmGetCompositionTimingInfoPtr(0, &vblankTime); + if (!SUCCEEDED(hr)) { + return vsync; + } + + LARGE_INTEGER frequency; + QueryPerformanceFrequency(&frequency); + + LARGE_INTEGER qpcNow; + QueryPerformanceCounter(&qpcNow); + + const int microseconds = 1000000; + int64_t adjust = qpcNow.QuadPart - vblankTime.qpcVBlank; + int64_t usAdjust = (adjust * microseconds) / frequency.QuadPart; + vsync -= TimeDuration::FromMicroseconds((double) usAdjust); + + if (IsWin10OrLater()) { + // On Windows 10 and on, DWMGetCompositionTimingInfo, mostly + // reports the upcoming vsync time, which is in the future. + // It can also sometimes report a vblank time in the past. + // Since large parts of Gecko assume TimeStamps can't be in future, + // use the previous vsync. + + // Windows 10 and Intel HD vsync timestamps are messy and + // all over the place once in a while. Most of the time, + // it reports the upcoming vsync. Sometimes, that upcoming + // vsync is in the past. Sometimes that upcoming vsync is before + // the previously seen vsync. + // In these error cases, normalize to Now(); + if (vsync >= now) { + vsync = vsync - mVsyncRate; + } + } + + // On Windows 7 and 8, DwmFlush wakes up AFTER qpcVBlankTime + // from DWMGetCompositionTimingInfo. We can return the adjusted vsync. + if (vsync >= now) { + vsync = now; + } + + // Our vsync time is some time very far in the past, adjust to Now. + // 4 ms is arbitrary, so feel free to pick something else if this isn't + // working. See the comment above within IsWin10OrLater(). + if ((now - vsync).ToMilliseconds() > 4.0) { + vsync = now; + } + + return vsync; + } + + void VBlankLoop() + { + MOZ_ASSERT(IsInVsyncThread()); + MOZ_ASSERT(sizeof(int64_t) == sizeof(QPC_TIME)); + + TimeStamp vsync = TimeStamp::Now(); + mPrevVsync = TimeStamp(); + TimeStamp flushTime = TimeStamp::Now(); + TimeDuration longVBlank = mVsyncRate * 2; + + for (;;) { + { // scope lock + MonitorAutoLock lock(mVsyncEnabledLock); + if (!mVsyncEnabled) return; + } + + // Large parts of gecko assume that the refresh driver timestamp + // must be <= Now() and cannot be in the future. + MOZ_ASSERT(vsync <= TimeStamp::Now()); + Display::NotifyVsync(vsync); + + // DwmComposition can be dynamically enabled/disabled + // so we have to check every time that it's available. + // When it is unavailable, we fallback to software but will try + // to get back to dwm rendering once it's re-enabled + if (!gfxWindowsPlatform::GetPlatform()->DwmCompositionEnabled()) { + ScheduleSoftwareVsync(vsync); + return; + } + + // Using WaitForVBlank, the whole system dies because WaitForVBlank + // only works if it's run on the same thread as the Present(); + HRESULT hr = WinUtils::dwmFlushProcPtr(); + if (!SUCCEEDED(hr)) { + // DWMFlush isn't working, fallback to software vsync. + ScheduleSoftwareVsync(TimeStamp::Now()); + return; + } + + TimeStamp now = TimeStamp::Now(); + TimeDuration flushDiff = now - flushTime; + flushTime = now; + if ((flushDiff > longVBlank) || mPrevVsync.IsNull()) { + // Our vblank took longer than 2 intervals, readjust our timestamps + vsync = GetVBlankTime(); + mPrevVsync = vsync; + } else { + // Instead of giving the actual vsync time, a constant interval + // between vblanks instead of the noise generated via hardware + // is actually what we want. Most apps just care about the diff + // between vblanks to animate, so a clean constant interval is + // smoother. + vsync = mPrevVsync + mVsyncRate; + if (vsync > now) { + // DWMFlush woke up very early, so readjust our times again + vsync = GetVBlankTime(); + } + + if (vsync <= mPrevVsync) { + vsync = TimeStamp::Now(); + } + + if ((now - vsync).ToMilliseconds() > 2.0) { + // Account for time drift here where vsync never quite catches up to + // Now and we'd fall ever so slightly further behind Now(). + vsync = GetVBlankTime(); + } + + mPrevVsync = vsync; + } + } // end for + } + + private: + virtual ~D3DVsyncDisplay() + { + MOZ_ASSERT(NS_IsMainThread()); + } + + bool IsInVsyncThread() + { + return mVsyncThread->thread_id() == PlatformThread::CurrentId(); + } + + TimeStamp mPrevVsync; + Monitor mVsyncEnabledLock; + base::Thread* mVsyncThread; + TimeDuration mVsyncRate; + bool mVsyncEnabled; + }; // end d3dvsyncdisplay + + D3DVsyncSource() + { + mPrimaryDisplay = new D3DVsyncDisplay(); + } + + virtual Display& GetGlobalDisplay() override + { + return *mPrimaryDisplay; + } + +private: + virtual ~D3DVsyncSource() + { + } + RefPtr<D3DVsyncDisplay> mPrimaryDisplay; +}; // end D3DVsyncSource + +already_AddRefed<mozilla::gfx::VsyncSource> +gfxWindowsPlatform::CreateHardwareVsyncSource() +{ + MOZ_RELEASE_ASSERT(NS_IsMainThread(), "GFX: Not in main thread."); + if (!WinUtils::dwmIsCompositionEnabledPtr) { + NS_WARNING("Dwm composition not available, falling back to software vsync"); + return gfxPlatform::CreateHardwareVsyncSource(); + } + + BOOL dwmEnabled = false; + WinUtils::dwmIsCompositionEnabledPtr(&dwmEnabled); + if (!dwmEnabled) { + NS_WARNING("DWM not enabled, falling back to software vsync"); + return gfxPlatform::CreateHardwareVsyncSource(); + } + + RefPtr<VsyncSource> d3dVsyncSource = new D3DVsyncSource(); + return d3dVsyncSource.forget(); +} + +bool +gfxWindowsPlatform::SupportsApzTouchInput() const +{ + int value = gfxPrefs::TouchEventsEnabled(); + return value == 1 || value == 2; +} + +void +gfxWindowsPlatform::GetAcceleratedCompositorBackends(nsTArray<LayersBackend>& aBackends) +{ + if (gfxConfig::IsEnabled(Feature::OPENGL_COMPOSITING) && gfxPrefs::LayersPreferOpenGL()) { + aBackends.AppendElement(LayersBackend::LAYERS_OPENGL); + } + + if (gfxConfig::IsEnabled(Feature::D3D9_COMPOSITING) && gfxPrefs::LayersPreferD3D9()) { + aBackends.AppendElement(LayersBackend::LAYERS_D3D9); + } + + if (gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) { + aBackends.AppendElement(LayersBackend::LAYERS_D3D11); + } + + if (gfxConfig::IsEnabled(Feature::D3D9_COMPOSITING) && !gfxPrefs::LayersPreferD3D9()) { + aBackends.AppendElement(LayersBackend::LAYERS_D3D9); + } +} + +void +gfxWindowsPlatform::ImportGPUDeviceData(const mozilla::gfx::GPUDeviceData& aData) +{ + MOZ_ASSERT(XRE_IsParentProcess()); + + gfxPlatform::ImportGPUDeviceData(aData); + + gfxConfig::ImportChange(Feature::D3D11_COMPOSITING, aData.d3d11Compositing()); + gfxConfig::ImportChange(Feature::D3D9_COMPOSITING, aData.d3d9Compositing()); + + DeviceManagerDx* dm = DeviceManagerDx::Get(); + if (gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) { + dm->ImportDeviceInfo(aData.gpuDevice().get_D3D11DeviceStatus()); + } else { + // There should be no devices, so this just takes away the device status. + dm->ResetDevices(); + + // Make sure we disable D2D if content processes might use it. + FeatureState& d2d1 = gfxConfig::GetFeature(Feature::DIRECT2D); + if (d2d1.IsEnabled()) { + d2d1.SetFailed( + FeatureStatus::Unavailable, + "Direct2D requires Direct3D 11 compositing", + NS_LITERAL_CSTRING("FEATURE_FAILURE_D2D_D3D11_COMP")); + } + } + + // CanUseHardwareVideoDecoding depends on d3d11 state, so update + // the cached value now. + UpdateCanUseHardwareVideoDecoding(); + + // For completeness (and messaging in about:support). Content recomputes this + // on its own, and we won't use ANGLE in the UI process if we're using a GPU + // process. + UpdateANGLEConfig(); +} + +void +gfxWindowsPlatform::ImportContentDeviceData(const mozilla::gfx::ContentDeviceData& aData) +{ + MOZ_ASSERT(XRE_IsContentProcess()); + + gfxPlatform::ImportContentDeviceData(aData); + + const DevicePrefs& prefs = aData.prefs(); + gfxConfig::Inherit(Feature::D3D11_COMPOSITING, prefs.d3d11Compositing()); + gfxConfig::Inherit(Feature::D3D9_COMPOSITING, prefs.d3d9Compositing()); + gfxConfig::Inherit(Feature::DIRECT2D, prefs.useD2D1()); + + if (gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) { + DeviceManagerDx* dm = DeviceManagerDx::Get(); + dm->ImportDeviceInfo(aData.d3d11()); + } +} + +void +gfxWindowsPlatform::BuildContentDeviceData(ContentDeviceData* aOut) +{ + // Check for device resets before giving back new graphics information. + UpdateRenderMode(); + + gfxPlatform::BuildContentDeviceData(aOut); + + const FeatureState& d3d11 = gfxConfig::GetFeature(Feature::D3D11_COMPOSITING); + aOut->prefs().d3d11Compositing() = d3d11.GetValue(); + aOut->prefs().d3d9Compositing() = gfxConfig::GetValue(Feature::D3D9_COMPOSITING); + aOut->prefs().useD2D1() = gfxConfig::GetValue(Feature::DIRECT2D); + + if (d3d11.IsEnabled()) { + DeviceManagerDx* dm = DeviceManagerDx::Get(); + dm->ExportDeviceInfo(&aOut->d3d11()); + } +} + +bool +gfxWindowsPlatform::SupportsPluginDirectDXGIDrawing() +{ + DeviceManagerDx* dm = DeviceManagerDx::Get(); + if (!dm->GetContentDevice() || !dm->TextureSharingWorks()) { + return false; + } + return true; +} |