Backed out changeset 1b14354719c0 (bug 1895254) for causing bustages on NavigationTra...
[gecko.git] / gfx / thebes / gfxWindowsPlatform.cpp
blob7a98e18fd6a31447ae3572297b4db966d6fcb02d
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #define INITGUID // set before devguid.h
9 #include "gfxWindowsPlatform.h"
11 #include "cairo.h"
12 #include "mozilla/ArrayUtils.h"
13 #include "mozilla/layers/CompositorBridgeChild.h"
15 #include "gfxBlur.h"
16 #include "gfxImageSurface.h"
17 #include "gfxWindowsSurface.h"
19 #include "nsUnicharUtils.h"
20 #include "nsUnicodeProperties.h"
22 #include "mozilla/Preferences.h"
23 #include "mozilla/ProfilerLabels.h"
24 #include "mozilla/ProfilerThreadSleep.h"
25 #include "mozilla/Components.h"
26 #include "mozilla/Sprintf.h"
27 #include "mozilla/WindowsVersion.h"
28 #include "nsIGfxInfo.h"
29 #include "nsServiceManagerUtils.h"
30 #include "nsTArray.h"
31 #include "nsThreadUtils.h"
32 #include "mozilla/Telemetry.h"
34 #include "plbase64.h"
35 #include "nsIXULRuntime.h"
36 #include "imgLoader.h"
38 #include "nsIGfxInfo.h"
40 #include "gfxCrashReporterUtils.h"
42 #include "gfxGDIFontList.h"
43 #include "gfxGDIFont.h"
45 #include "mozilla/layers/CanvasChild.h"
46 #include "mozilla/layers/CompositorThread.h"
48 #include "gfxDWriteFontList.h"
49 #include "gfxDWriteFonts.h"
50 #include "gfxDWriteCommon.h"
51 #include <dwrite.h>
53 #include "gfxTextRun.h"
54 #include "gfxUserFontSet.h"
55 #include "nsWindowsHelpers.h"
56 #include "gfx2DGlue.h"
58 #include <string>
60 #include <d3d10_1.h>
62 #include "mozilla/gfx/2D.h"
63 #include "mozilla/gfx/gfxVars.h"
65 #include <dwmapi.h>
66 #include <d3d11.h>
67 #include <d2d1_1.h>
69 #include "nsIMemoryReporter.h"
70 #include <winternl.h>
71 #include "d3dkmtQueryStatistics.h"
73 #include "base/thread.h"
74 #include "mozilla/StaticPrefs_gfx.h"
75 #include "mozilla/StaticPrefs_layers.h"
76 #include "gfxConfig.h"
77 #include "VsyncSource.h"
78 #include "DriverCrashGuard.h"
79 #include "mozilla/dom/ContentChild.h"
80 #include "mozilla/gfx/DeviceManagerDx.h"
81 #include "mozilla/gfx/DisplayConfigWindows.h"
82 #include "mozilla/layers/DeviceAttachmentsD3D11.h"
83 #include "mozilla/WindowsProcessMitigations.h"
84 #include "D3D11Checks.h"
85 #include "mozilla/ScreenHelperWin.h"
87 using namespace mozilla;
88 using namespace mozilla::gfx;
89 using namespace mozilla::layers;
90 using namespace mozilla::widget;
91 using namespace mozilla::image;
92 using namespace mozilla::unicode;
94 DCForMetrics::DCForMetrics() {
95 // Get the whole screen DC:
96 mDC = GetDC(nullptr);
97 SetGraphicsMode(mDC, GM_ADVANCED);
100 class GfxD2DVramReporter final : public nsIMemoryReporter {
101 ~GfxD2DVramReporter() {}
103 public:
104 NS_DECL_ISUPPORTS
106 NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport,
107 nsISupports* aData, bool aAnonymize) override {
108 MOZ_COLLECT_REPORT("gfx-d2d-vram-draw-target", KIND_OTHER, UNITS_BYTES,
109 Factory::GetD2DVRAMUsageDrawTarget(),
110 "Video memory used by D2D DrawTargets.");
112 MOZ_COLLECT_REPORT("gfx-d2d-vram-source-surface", KIND_OTHER, UNITS_BYTES,
113 Factory::GetD2DVRAMUsageSourceSurface(),
114 "Video memory used by D2D SourceSurfaces.");
116 return NS_OK;
120 NS_IMPL_ISUPPORTS(GfxD2DVramReporter, nsIMemoryReporter)
122 class GPUAdapterReporter final : public nsIMemoryReporter {
123 // Callers must Release the DXGIAdapter after use or risk mem-leak
124 static bool GetDXGIAdapter(IDXGIAdapter** aDXGIAdapter) {
125 RefPtr<ID3D11Device> d3d11Device;
126 RefPtr<IDXGIDevice> dxgiDevice;
127 bool result = false;
129 if ((d3d11Device = mozilla::gfx::Factory::GetDirect3D11Device())) {
130 if (d3d11Device->QueryInterface(__uuidof(IDXGIDevice),
131 getter_AddRefs(dxgiDevice)) == S_OK) {
132 result = (dxgiDevice->GetAdapter(aDXGIAdapter) == S_OK);
136 return result;
139 ~GPUAdapterReporter() {}
141 public:
142 NS_DECL_ISUPPORTS
144 NS_IMETHOD
145 CollectReports(nsIHandleReportCallback* aHandleReport, nsISupports* aData,
146 bool aAnonymize) override {
147 HANDLE ProcessHandle = GetCurrentProcess();
149 int64_t dedicatedBytesUsed = 0;
150 int64_t sharedBytesUsed = 0;
151 int64_t committedBytesUsed = 0;
152 IDXGIAdapter* DXGIAdapter;
154 HMODULE gdi32Handle;
155 PFND3DKMTQS queryD3DKMTStatistics = nullptr;
157 if ((gdi32Handle = LoadLibrary(TEXT("gdi32.dll"))))
158 queryD3DKMTStatistics =
159 (PFND3DKMTQS)GetProcAddress(gdi32Handle, "D3DKMTQueryStatistics");
161 if (queryD3DKMTStatistics && GetDXGIAdapter(&DXGIAdapter)) {
162 // Most of this block is understood thanks to wj32's work on Process
163 // Hacker
165 DXGI_ADAPTER_DESC adapterDesc;
166 D3DKMTQS queryStatistics;
168 DXGIAdapter->GetDesc(&adapterDesc);
169 DXGIAdapter->Release();
171 memset(&queryStatistics, 0, sizeof(D3DKMTQS));
172 queryStatistics.Type = D3DKMTQS_PROCESS;
173 queryStatistics.AdapterLuid = adapterDesc.AdapterLuid;
174 queryStatistics.hProcess = ProcessHandle;
175 if (NT_SUCCESS(queryD3DKMTStatistics(&queryStatistics))) {
176 committedBytesUsed =
177 queryStatistics.QueryResult.ProcessInfo.SystemMemory.BytesAllocated;
180 memset(&queryStatistics, 0, sizeof(D3DKMTQS));
181 queryStatistics.Type = D3DKMTQS_ADAPTER;
182 queryStatistics.AdapterLuid = adapterDesc.AdapterLuid;
183 if (NT_SUCCESS(queryD3DKMTStatistics(&queryStatistics))) {
184 ULONG i;
185 ULONG segmentCount = queryStatistics.QueryResult.AdapterInfo.NbSegments;
187 for (i = 0; i < segmentCount; i++) {
188 memset(&queryStatistics, 0, sizeof(D3DKMTQS));
189 queryStatistics.Type = D3DKMTQS_SEGMENT;
190 queryStatistics.AdapterLuid = adapterDesc.AdapterLuid;
191 queryStatistics.QuerySegment.SegmentId = i;
193 if (NT_SUCCESS(queryD3DKMTStatistics(&queryStatistics))) {
194 bool aperture = queryStatistics.QueryResult.SegmentInfo.Aperture;
195 memset(&queryStatistics, 0, sizeof(D3DKMTQS));
196 queryStatistics.Type = D3DKMTQS_PROCESS_SEGMENT;
197 queryStatistics.AdapterLuid = adapterDesc.AdapterLuid;
198 queryStatistics.hProcess = ProcessHandle;
199 queryStatistics.QueryProcessSegment.SegmentId = i;
200 if (NT_SUCCESS(queryD3DKMTStatistics(&queryStatistics))) {
201 ULONGLONG bytesCommitted =
202 queryStatistics.QueryResult.ProcessSegmentInfo.BytesCommitted;
203 if (aperture)
204 sharedBytesUsed += bytesCommitted;
205 else
206 dedicatedBytesUsed += bytesCommitted;
213 FreeLibrary(gdi32Handle);
215 MOZ_COLLECT_REPORT("gpu-committed", KIND_OTHER, UNITS_BYTES,
216 committedBytesUsed,
217 "Memory committed by the Windows graphics system.");
219 MOZ_COLLECT_REPORT(
220 "gpu-dedicated", KIND_OTHER, UNITS_BYTES, dedicatedBytesUsed,
221 "Out-of-process memory allocated for this process in a physical "
222 "GPU adapter's memory.");
224 MOZ_COLLECT_REPORT("gpu-shared", KIND_OTHER, UNITS_BYTES, sharedBytesUsed,
225 "In-process memory that is shared with the GPU.");
227 return NS_OK;
231 NS_IMPL_ISUPPORTS(GPUAdapterReporter, nsIMemoryReporter)
233 Atomic<size_t> gfxWindowsPlatform::sD3D11SharedTextures;
234 Atomic<size_t> gfxWindowsPlatform::sD3D9SharedTextures;
236 class D3DSharedTexturesReporter final : public nsIMemoryReporter {
237 ~D3DSharedTexturesReporter() {}
239 public:
240 NS_DECL_ISUPPORTS
242 NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport,
243 nsISupports* aData, bool aAnonymize) override {
244 if (gfxWindowsPlatform::sD3D11SharedTextures > 0) {
245 MOZ_COLLECT_REPORT("d3d11-shared-textures", KIND_OTHER, UNITS_BYTES,
246 gfxWindowsPlatform::sD3D11SharedTextures,
247 "D3D11 shared textures.");
250 if (gfxWindowsPlatform::sD3D9SharedTextures > 0) {
251 MOZ_COLLECT_REPORT("d3d9-shared-textures", KIND_OTHER, UNITS_BYTES,
252 gfxWindowsPlatform::sD3D9SharedTextures,
253 "D3D9 shared textures.");
256 return NS_OK;
260 NS_IMPL_ISUPPORTS(D3DSharedTexturesReporter, nsIMemoryReporter)
262 gfxWindowsPlatform::gfxWindowsPlatform() : mRenderMode(RENDER_GDI) {
263 // If win32k is locked down then we can't use COM STA and shouldn't need it.
264 // Also, we won't be using any GPU memory in this process.
265 if (!IsWin32kLockedDown()) {
267 * Initialize COM
269 CoInitialize(nullptr);
271 RegisterStrongMemoryReporter(new GfxD2DVramReporter());
272 RegisterStrongMemoryReporter(new GPUAdapterReporter());
273 RegisterStrongMemoryReporter(new D3DSharedTexturesReporter());
277 gfxWindowsPlatform::~gfxWindowsPlatform() {
278 mozilla::gfx::Factory::D2DCleanup();
280 DeviceManagerDx::Shutdown();
282 // We don't initialize COM when win32k is locked down.
283 if (!IsWin32kLockedDown()) {
285 * Uninitialize COM
287 CoUninitialize();
291 /* static */
292 void gfxWindowsPlatform::InitMemoryReportersForGPUProcess() {
293 MOZ_RELEASE_ASSERT(XRE_IsGPUProcess());
295 RegisterStrongMemoryReporter(new GfxD2DVramReporter());
296 RegisterStrongMemoryReporter(new GPUAdapterReporter());
297 RegisterStrongMemoryReporter(new D3DSharedTexturesReporter());
300 /* static */
301 nsresult gfxWindowsPlatform::GetGpuTimeSinceProcessStartInMs(
302 uint64_t* aResult) {
303 // If win32k is locked down then we should not have any GPU processing and
304 // cannot use these APIs either way.
305 if (IsWin32kLockedDown()) {
306 *aResult = 0;
307 return NS_OK;
310 nsModuleHandle module(LoadLibrary(L"gdi32.dll"));
311 if (!module) {
312 return NS_ERROR_NOT_AVAILABLE;
315 PFND3DKMTQS queryD3DKMTStatistics =
316 (PFND3DKMTQS)GetProcAddress(module, "D3DKMTQueryStatistics");
317 if (!queryD3DKMTStatistics) {
318 return NS_ERROR_NOT_AVAILABLE;
321 gfx::DeviceManagerDx* dm = DeviceManagerDx::Get();
322 if (!dm) {
323 return NS_ERROR_NOT_AVAILABLE;
326 D3D11DeviceStatus status;
327 if (!dm->ExportDeviceInfo(&status)) {
328 // Assume that we used 0ms of GPU time if the device manager
329 // doesn't know the device status.
330 *aResult = 0;
331 return NS_OK;
334 const DxgiAdapterDesc& adapterDesc = status.adapter();
336 D3DKMTQS queryStatistics;
337 memset(&queryStatistics, 0, sizeof(D3DKMTQS));
338 queryStatistics.Type = D3DKMTQS_ADAPTER;
339 queryStatistics.AdapterLuid = adapterDesc.AdapterLuid;
340 if (!NT_SUCCESS(queryD3DKMTStatistics(&queryStatistics))) {
341 return NS_ERROR_FAILURE;
344 uint64_t result = 0;
345 ULONG nodeCount = queryStatistics.QueryResult.AdapterInfo.NodeCount;
346 for (ULONG i = 0; i < nodeCount; ++i) {
347 memset(&queryStatistics, 0, sizeof(D3DKMTQS));
348 queryStatistics.Type = D3DKMTQS_PROCESS_NODE;
349 queryStatistics.AdapterLuid = adapterDesc.AdapterLuid;
350 queryStatistics.hProcess = GetCurrentProcess();
351 queryStatistics.QueryProcessNode.NodeId = i;
352 if (NT_SUCCESS(queryD3DKMTStatistics(&queryStatistics))) {
353 result += queryStatistics.QueryResult.ProcessNodeInformation.RunningTime
354 .QuadPart *
355 100 / PR_NSEC_PER_MSEC;
359 *aResult = result;
360 return NS_OK;
363 static void UpdateANGLEConfig() {
364 if (!gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) {
365 gfxConfig::Disable(Feature::D3D11_HW_ANGLE, FeatureStatus::Disabled,
366 "D3D11 compositing is disabled",
367 "FEATURE_FAILURE_HW_ANGLE_D3D11_DISABLED"_ns);
371 void gfxWindowsPlatform::InitAcceleration() {
372 gfxPlatform::InitAcceleration();
374 DeviceManagerDx::Init();
376 // Content processes should have received content device data from parent.
377 MOZ_ASSERT_IF(XRE_IsContentProcess(), GetInitContentDeviceData());
379 InitializeConfig();
380 InitGPUProcessSupport();
381 // Ensure devices initialization. SharedSurfaceANGLE and
382 // SharedSurfaceD3D11Interop use them. The devices are lazily initialized
383 // with WebRender to reduce memory usage.
384 // Initialize them now when running non-e10s.
385 if (!BrowserTabsRemoteAutostart()) {
386 EnsureDevicesInitialized();
388 UpdateANGLEConfig();
389 UpdateRenderMode();
391 // If we have Skia and we didn't init dwrite already, do it now.
392 if (!DWriteEnabled() && GetDefaultContentBackend() == BackendType::SKIA) {
393 InitDWriteSupport();
395 // We need to listen for font setting changes even if DWrite is not used.
396 Factory::SetSystemTextQuality(gfxVars::SystemTextQuality());
397 gfxVars::SetSystemTextQualityListener(
398 gfxDWriteFont::SystemTextQualityChanged);
400 // CanUseHardwareVideoDecoding depends on DeviceManagerDx state,
401 // so update the cached value now.
402 UpdateCanUseHardwareVideoDecoding();
404 // Our ScreenHelperWin also depends on DeviceManagerDx state.
405 if (XRE_IsParentProcess() && !gfxPlatform::IsHeadless()) {
406 ScreenHelperWin::RefreshScreens();
409 RecordStartupTelemetry();
412 void gfxWindowsPlatform::InitWebRenderConfig() {
413 gfxPlatform::InitWebRenderConfig();
414 UpdateBackendPrefs();
417 bool gfxWindowsPlatform::CanUseHardwareVideoDecoding() {
418 DeviceManagerDx* dm = DeviceManagerDx::Get();
419 if (!dm) {
420 return false;
422 if (!dm->TextureSharingWorks()) {
423 return false;
425 return !dm->IsWARP() && gfxPlatform::CanUseHardwareVideoDecoding();
428 bool gfxWindowsPlatform::InitDWriteSupport() {
429 mozilla::ScopedGfxFeatureReporter reporter("DWrite");
430 if (!gfxDWriteFont::InitDWriteSupport()) {
431 return false;
434 reporter.SetSuccessful();
435 return true;
438 bool gfxWindowsPlatform::HandleDeviceReset() {
439 mozilla::gfx::DeviceResetReason resetReason =
440 mozilla::gfx::DeviceResetReason::OK;
441 if (!DidRenderingDeviceReset(&resetReason)) {
442 return false;
445 if (resetReason != mozilla::gfx::DeviceResetReason::FORCED_RESET) {
446 Telemetry::Accumulate(Telemetry::DEVICE_RESET_REASON,
447 uint32_t(resetReason));
450 // Remove devices and adapters.
451 DeviceManagerDx::Get()->ResetDevices();
453 imgLoader::NormalLoader()->ClearCache(true);
454 imgLoader::NormalLoader()->ClearCache(false);
455 imgLoader::PrivateBrowsingLoader()->ClearCache(true);
456 imgLoader::PrivateBrowsingLoader()->ClearCache(false);
457 gfxAlphaBoxBlur::ShutdownBlurCache();
459 gfxConfig::Reset(Feature::D3D11_COMPOSITING);
460 gfxConfig::Reset(Feature::D3D11_HW_ANGLE);
461 gfxConfig::Reset(Feature::DIRECT2D);
463 InitializeConfig();
464 // XXX Add InitWebRenderConfig() calling.
465 if (mInitializedDevices) {
466 InitGPUProcessSupport();
467 InitializeDevices();
469 UpdateANGLEConfig();
470 return true;
473 BackendPrefsData gfxWindowsPlatform::GetBackendPrefs() const {
474 BackendPrefsData data;
476 data.mCanvasBitmask = BackendTypeBit(BackendType::SKIA);
477 data.mContentBitmask = BackendTypeBit(BackendType::SKIA);
478 data.mCanvasDefault = BackendType::SKIA;
479 data.mContentDefault = BackendType::SKIA;
481 if (gfxConfig::IsEnabled(Feature::DIRECT2D)) {
482 data.mCanvasBitmask |= BackendTypeBit(BackendType::DIRECT2D1_1);
483 data.mCanvasDefault = BackendType::DIRECT2D1_1;
485 return data;
488 void gfxWindowsPlatform::UpdateBackendPrefs() {
489 BackendPrefsData data = GetBackendPrefs();
490 // Remove DIRECT2D1 preference if D2D1Device does not exist.
491 if (!Factory::HasD2D1Device()) {
492 data.mContentBitmask &= ~BackendTypeBit(BackendType::DIRECT2D1_1);
493 if (data.mContentDefault == BackendType::DIRECT2D1_1) {
494 data.mContentDefault = BackendType::SKIA;
497 // Don't exclude DIRECT2D1_1 if using remote canvas, because DIRECT2D1_1 and
498 // hence the device will be used in the GPU process.
499 if (!gfxPlatform::UseRemoteCanvas()) {
500 data.mCanvasBitmask &= ~BackendTypeBit(BackendType::DIRECT2D1_1);
501 if (data.mCanvasDefault == BackendType::DIRECT2D1_1) {
502 data.mCanvasDefault = BackendType::SKIA;
506 InitBackendPrefs(std::move(data));
509 bool gfxWindowsPlatform::IsDirect2DBackend() {
510 return GetDefaultContentBackend() == BackendType::DIRECT2D1_1;
513 void gfxWindowsPlatform::UpdateRenderMode() {
514 bool didReset = HandleDeviceReset();
516 UpdateBackendPrefs();
518 if (didReset) {
519 mScreenReferenceDrawTarget = CreateOffscreenContentDrawTarget(
520 IntSize(1, 1), SurfaceFormat::B8G8R8A8);
521 if (!mScreenReferenceDrawTarget) {
522 gfxCriticalNote
523 << "Failed to update reference draw target after device reset"
524 << ", D3D11 device:" << hexa(Factory::GetDirect3D11Device().get())
525 << ", D3D11 status:"
526 << FeatureStatusToString(
527 gfxConfig::GetValue(Feature::D3D11_COMPOSITING))
528 << ", D2D1 device:" << hexa(Factory::GetD2D1Device().get())
529 << ", D2D1 status:"
530 << FeatureStatusToString(gfxConfig::GetValue(Feature::DIRECT2D))
531 << ", content:" << int(GetDefaultContentBackend())
532 << ", compositor:" << int(GetCompositorBackend());
533 MOZ_CRASH(
534 "GFX: Failed to update reference draw target after device reset");
539 mozilla::gfx::BackendType gfxWindowsPlatform::GetContentBackendFor(
540 mozilla::layers::LayersBackend aLayers) {
541 mozilla::gfx::BackendType defaultBackend =
542 gfxPlatform::GetDefaultContentBackend();
543 if (aLayers == LayersBackend::LAYERS_WR &&
544 gfx::gfxVars::UseWebRenderANGLE()) {
545 return defaultBackend;
548 if (defaultBackend == BackendType::DIRECT2D1_1) {
549 // We can't have D2D without D3D11 layers, so fallback to Skia.
550 return BackendType::SKIA;
553 // Otherwise we have some non-accelerated backend and that's ok.
554 return defaultBackend;
557 mozilla::gfx::BackendType gfxWindowsPlatform::GetPreferredCanvasBackend() {
558 mozilla::gfx::BackendType backend = gfxPlatform::GetPreferredCanvasBackend();
560 if (backend == BackendType::DIRECT2D1_1) {
561 if (!gfx::gfxVars::UseWebRenderANGLE()) {
562 // We can't have D2D without ANGLE when WebRender is enabled, so fallback
563 // to Skia.
564 return BackendType::SKIA;
567 // Fall back to software when remote canvas has been deactivated.
568 if (CanvasChild::Deactivated()) {
569 return BackendType::SKIA;
572 return backend;
575 bool gfxWindowsPlatform::CreatePlatformFontList() {
576 if (DWriteEnabled()) {
577 if (gfxPlatformFontList::Initialize(new gfxDWriteFontList)) {
578 return true;
581 // DWrite font initialization failed! Don't know why this would happen,
582 // but apparently it can - see bug 594865.
583 // So we're going to fall back to GDI fonts & rendering.
584 DisableD2D(FeatureStatus::Failed, "Failed to initialize fonts",
585 "FEATURE_FAILURE_FONT_FAIL"_ns);
588 // Make sure the static variable is initialized...
589 gfxPlatform::HasVariationFontSupport();
590 // ...then force it to false, even if the Windows version was recent enough
591 // to permit it, as we're using GDI fonts.
592 sHasVariationFontSupport = false;
594 return gfxPlatformFontList::Initialize(new gfxGDIFontList);
597 // This function will permanently disable D2D for the session. It's intended to
598 // be used when, after initially chosing to use Direct2D, we encounter a
599 // scenario we can't support.
601 // This is called during gfxPlatform::Init() so at this point there should be no
602 // DrawTargetD2D/1 instances.
603 void gfxWindowsPlatform::DisableD2D(FeatureStatus aStatus, const char* aMessage,
604 const nsACString& aFailureId) {
605 gfxConfig::SetFailed(Feature::DIRECT2D, aStatus, aMessage, aFailureId);
606 Factory::SetDirect3D11Device(nullptr);
607 UpdateBackendPrefs();
610 already_AddRefed<gfxASurface> gfxWindowsPlatform::CreateOffscreenSurface(
611 const IntSize& aSize, gfxImageFormat aFormat) {
612 if (!Factory::AllowedSurfaceSize(aSize)) {
613 return nullptr;
616 RefPtr<gfxASurface> surf = nullptr;
618 #ifdef CAIRO_HAS_WIN32_SURFACE
619 if (!XRE_IsContentProcess()) {
620 if (mRenderMode == RENDER_GDI || mRenderMode == RENDER_DIRECT2D) {
621 surf = new gfxWindowsSurface(aSize, aFormat);
624 #endif
626 if (!surf || surf->CairoStatus()) {
627 surf = new gfxImageSurface(aSize, aFormat);
630 return surf.forget();
633 static const char kFontAparajita[] = "Aparajita";
634 static const char kFontArabicTypesetting[] = "Arabic Typesetting";
635 static const char kFontArial[] = "Arial";
636 static const char kFontArialUnicodeMS[] = "Arial Unicode MS";
637 static const char kFontCambria[] = "Cambria";
638 static const char kFontCambriaMath[] = "Cambria Math";
639 static const char kFontEbrima[] = "Ebrima";
640 static const char kFontEstrangeloEdessa[] = "Estrangelo Edessa";
641 static const char kFontEuphemia[] = "Euphemia";
642 static const char kFontGabriola[] = "Gabriola";
643 static const char kFontJavaneseText[] = "Javanese Text";
644 static const char kFontKhmerUI[] = "Khmer UI";
645 static const char kFontLaoUI[] = "Lao UI";
646 static const char kFontLeelawadeeUI[] = "Leelawadee UI";
647 static const char kFontLucidaSansUnicode[] = "Lucida Sans Unicode";
648 static const char kFontMVBoli[] = "MV Boli";
649 static const char kFontMalgunGothic[] = "Malgun Gothic";
650 static const char kFontMicrosoftJhengHei[] = "Microsoft JhengHei";
651 static const char kFontMicrosoftNewTaiLue[] = "Microsoft New Tai Lue";
652 static const char kFontMicrosoftPhagsPa[] = "Microsoft PhagsPa";
653 static const char kFontMicrosoftTaiLe[] = "Microsoft Tai Le";
654 static const char kFontMicrosoftUighur[] = "Microsoft Uighur";
655 static const char kFontMicrosoftYaHei[] = "Microsoft YaHei";
656 static const char kFontMicrosoftYiBaiti[] = "Microsoft Yi Baiti";
657 static const char kFontMeiryo[] = "Meiryo";
658 static const char kFontMongolianBaiti[] = "Mongolian Baiti";
659 static const char kFontMyanmarText[] = "Myanmar Text";
660 static const char kFontNirmalaUI[] = "Nirmala UI";
661 static const char kFontNyala[] = "Nyala";
662 static const char kFontPlantagenetCherokee[] = "Plantagenet Cherokee";
663 static const char kFontSegoeUI[] = "Segoe UI";
664 static const char kFontSegoeUIEmoji[] = "Segoe UI Emoji";
665 static const char kFontSegoeUISymbol[] = "Segoe UI Symbol";
666 static const char kFontSylfaen[] = "Sylfaen";
667 static const char kFontTraditionalArabic[] = "Traditional Arabic";
668 static const char kFontTwemojiMozilla[] = "Twemoji Mozilla";
669 static const char kFontUtsaah[] = "Utsaah";
670 static const char kFontYuGothic[] = "Yu Gothic";
672 void gfxWindowsPlatform::GetCommonFallbackFonts(
673 uint32_t aCh, Script aRunScript, eFontPresentation aPresentation,
674 nsTArray<const char*>& aFontList) {
675 if (PrefersColor(aPresentation)) {
676 aFontList.AppendElement(kFontSegoeUIEmoji);
677 aFontList.AppendElement(kFontTwemojiMozilla);
680 // Arial is used as the default fallback for system fallback
681 aFontList.AppendElement(kFontArial);
683 if (!IS_IN_BMP(aCh)) {
684 uint32_t p = aCh >> 16;
685 if (p == 1) { // SMP plane
686 aFontList.AppendElement(kFontSegoeUISymbol);
687 aFontList.AppendElement(kFontEbrima);
688 aFontList.AppendElement(kFontNirmalaUI);
689 aFontList.AppendElement(kFontCambriaMath);
691 } else {
692 uint32_t b = (aCh >> 8) & 0xff;
694 switch (b) {
695 case 0x05:
696 aFontList.AppendElement(kFontEstrangeloEdessa);
697 aFontList.AppendElement(kFontCambria);
698 break;
699 case 0x06:
700 aFontList.AppendElement(kFontMicrosoftUighur);
701 break;
702 case 0x07:
703 aFontList.AppendElement(kFontEstrangeloEdessa);
704 aFontList.AppendElement(kFontMVBoli);
705 aFontList.AppendElement(kFontEbrima);
706 break;
707 case 0x09:
708 aFontList.AppendElement(kFontNirmalaUI);
709 aFontList.AppendElement(kFontUtsaah);
710 aFontList.AppendElement(kFontAparajita);
711 break;
712 case 0x0a:
713 case 0x0b:
714 case 0x0c:
715 case 0x0d:
716 aFontList.AppendElement(kFontNirmalaUI);
717 break;
718 case 0x0e:
719 aFontList.AppendElement(kFontLaoUI);
720 aFontList.AppendElement(kFontLeelawadeeUI);
721 break;
722 case 0x10:
723 aFontList.AppendElement(kFontMyanmarText);
724 break;
725 case 0x11:
726 aFontList.AppendElement(kFontMalgunGothic);
727 break;
728 case 0x12:
729 case 0x13:
730 aFontList.AppendElement(kFontNyala);
731 aFontList.AppendElement(kFontPlantagenetCherokee);
732 break;
733 case 0x14:
734 case 0x15:
735 case 0x16:
736 aFontList.AppendElement(kFontEuphemia);
737 aFontList.AppendElement(kFontSegoeUISymbol);
738 break;
739 case 0x17:
740 aFontList.AppendElement(kFontKhmerUI);
741 aFontList.AppendElement(kFontLeelawadeeUI);
742 break;
743 case 0x18: // Mongolian
744 aFontList.AppendElement(kFontMongolianBaiti);
745 aFontList.AppendElement(kFontEuphemia);
746 break;
747 case 0x19:
748 aFontList.AppendElement(kFontMicrosoftTaiLe);
749 aFontList.AppendElement(kFontMicrosoftNewTaiLue);
750 aFontList.AppendElement(kFontKhmerUI);
751 aFontList.AppendElement(kFontLeelawadeeUI);
752 break;
753 case 0x1a:
754 aFontList.AppendElement(kFontLeelawadeeUI);
755 break;
756 case 0x1c:
757 aFontList.AppendElement(kFontNirmalaUI);
758 break;
759 case 0x20: // Symbol ranges
760 case 0x21:
761 case 0x22:
762 case 0x23:
763 case 0x24:
764 case 0x25:
765 case 0x26:
766 case 0x27:
767 case 0x29:
768 case 0x2a:
769 case 0x2b:
770 case 0x2c:
771 aFontList.AppendElement(kFontSegoeUI);
772 aFontList.AppendElement(kFontSegoeUISymbol);
773 aFontList.AppendElement(kFontCambria);
774 aFontList.AppendElement(kFontMeiryo);
775 aFontList.AppendElement(kFontArial);
776 aFontList.AppendElement(kFontLucidaSansUnicode);
777 aFontList.AppendElement(kFontEbrima);
778 break;
779 case 0x2d:
780 case 0x2e:
781 case 0x2f:
782 aFontList.AppendElement(kFontEbrima);
783 aFontList.AppendElement(kFontNyala);
784 aFontList.AppendElement(kFontSegoeUI);
785 aFontList.AppendElement(kFontSegoeUISymbol);
786 aFontList.AppendElement(kFontMeiryo);
787 break;
788 case 0x28: // Braille
789 aFontList.AppendElement(kFontSegoeUISymbol);
790 break;
791 case 0x30:
792 case 0x31:
793 aFontList.AppendElement(kFontMicrosoftYaHei);
794 break;
795 case 0x32:
796 aFontList.AppendElement(kFontMalgunGothic);
797 break;
798 case 0x4d:
799 aFontList.AppendElement(kFontSegoeUISymbol);
800 break;
801 case 0x9f:
802 aFontList.AppendElement(kFontMicrosoftYaHei);
803 aFontList.AppendElement(kFontYuGothic);
804 break;
805 case 0xa0: // Yi
806 case 0xa1:
807 case 0xa2:
808 case 0xa3:
809 case 0xa4:
810 aFontList.AppendElement(kFontMicrosoftYiBaiti);
811 aFontList.AppendElement(kFontSegoeUI);
812 break;
813 case 0xa5:
814 case 0xa6:
815 case 0xa7:
816 aFontList.AppendElement(kFontEbrima);
817 aFontList.AppendElement(kFontSegoeUI);
818 aFontList.AppendElement(kFontCambriaMath);
819 break;
820 case 0xa8:
821 aFontList.AppendElement(kFontMicrosoftPhagsPa);
822 aFontList.AppendElement(kFontNirmalaUI);
823 break;
824 case 0xa9:
825 aFontList.AppendElement(kFontMalgunGothic);
826 aFontList.AppendElement(kFontJavaneseText);
827 aFontList.AppendElement(kFontLeelawadeeUI);
828 break;
829 case 0xaa:
830 aFontList.AppendElement(kFontMyanmarText);
831 break;
832 case 0xab:
833 aFontList.AppendElement(kFontEbrima);
834 aFontList.AppendElement(kFontNyala);
835 break;
836 case 0xd7:
837 aFontList.AppendElement(kFontMalgunGothic);
838 break;
839 case 0xfb:
840 aFontList.AppendElement(kFontMicrosoftUighur);
841 aFontList.AppendElement(kFontGabriola);
842 aFontList.AppendElement(kFontSylfaen);
843 break;
844 case 0xfc:
845 case 0xfd:
846 aFontList.AppendElement(kFontTraditionalArabic);
847 aFontList.AppendElement(kFontArabicTypesetting);
848 break;
849 case 0xfe:
850 aFontList.AppendElement(kFontTraditionalArabic);
851 aFontList.AppendElement(kFontMicrosoftJhengHei);
852 break;
853 case 0xff:
854 aFontList.AppendElement(kFontMicrosoftJhengHei);
855 break;
856 default:
857 break;
861 // Arial Unicode MS has lots of glyphs for obscure characters,
862 // use it as a last resort
863 aFontList.AppendElement(kFontArialUnicodeMS);
865 // If we didn't begin with the color-emoji fonts, include them here
866 // so that they'll be preferred over user-installed (and possibly
867 // broken) fonts in the global fallback path.
868 if (!PrefersColor(aPresentation)) {
869 aFontList.AppendElement(kFontSegoeUIEmoji);
870 aFontList.AppendElement(kFontTwemojiMozilla);
874 bool gfxWindowsPlatform::DidRenderingDeviceReset(
875 mozilla::gfx::DeviceResetReason* aResetReason) {
876 DeviceManagerDx* dm = DeviceManagerDx::Get();
877 if (!dm) {
878 return false;
880 return dm->HasDeviceReset(aResetReason);
883 void gfxWindowsPlatform::CompositorUpdated() {
884 DeviceManagerDx::Get()->ForceDeviceReset(
885 mozilla::gfx::ForcedDeviceResetReason::COMPOSITOR_UPDATED);
886 UpdateRenderMode();
889 BOOL CALLBACK InvalidateWindowForDeviceReset(HWND aWnd, LPARAM aMsg) {
890 RedrawWindow(aWnd, nullptr, nullptr,
891 RDW_INVALIDATE | RDW_INTERNALPAINT | RDW_FRAME);
892 return TRUE;
895 void gfxWindowsPlatform::SchedulePaintIfDeviceReset() {
896 AUTO_PROFILER_LABEL("gfxWindowsPlatform::SchedulePaintIfDeviceReset", OTHER);
898 mozilla::gfx::DeviceResetReason resetReason =
899 mozilla::gfx::DeviceResetReason::OK;
900 if (!DidRenderingDeviceReset(&resetReason)) {
901 return;
904 gfxCriticalNote << "(gfxWindowsPlatform) Detected device reset: "
905 << (int)resetReason;
907 if (XRE_IsParentProcess()) {
908 // Trigger an ::OnPaint for each window.
909 ::EnumThreadWindows(GetCurrentThreadId(), InvalidateWindowForDeviceReset,
911 } else {
912 NS_DispatchToMainThread(NS_NewRunnableFunction(
913 "gfx::gfxWindowsPlatform::SchedulePaintIfDeviceReset", []() -> void {
914 gfxWindowsPlatform::GetPlatform()->CheckForContentOnlyDeviceReset();
915 }));
918 gfxCriticalNote << "(gfxWindowsPlatform) scheduled device update.";
921 void gfxWindowsPlatform::CheckForContentOnlyDeviceReset() {
922 if (!DidRenderingDeviceReset()) {
923 return;
926 bool isContentOnlyTDR;
927 D3D11DeviceStatus status;
929 DeviceManagerDx::Get()->ExportDeviceInfo(&status);
930 CompositorBridgeChild::Get()->SendCheckContentOnlyTDR(status.sequenceNumber(),
931 &isContentOnlyTDR);
933 // The parent process doesn't know about the reset yet, or the reset is
934 // local to our device.
935 if (isContentOnlyTDR) {
936 gfxCriticalNote << "A content-only TDR is detected.";
937 dom::ContentChild* cc = dom::ContentChild::GetSingleton();
938 cc->RecvReinitRenderingForDeviceReset();
942 nsTArray<uint8_t> gfxWindowsPlatform::GetPlatformCMSOutputProfileData() {
943 if (XRE_IsContentProcess()) {
944 auto& cmsOutputProfileData = GetCMSOutputProfileData();
945 // We should have set our profile data when we received our initial
946 // ContentDeviceData.
947 MOZ_ASSERT(cmsOutputProfileData.isSome(),
948 "Should have created output profile data when we received "
949 "initial content device data.");
951 // If we have data, it should not be empty.
952 MOZ_ASSERT_IF(cmsOutputProfileData.isSome(),
953 !cmsOutputProfileData->IsEmpty());
955 if (cmsOutputProfileData.isSome()) {
956 return cmsOutputProfileData.ref().Clone();
958 return nsTArray<uint8_t>();
961 return GetPlatformCMSOutputProfileData_Impl();
964 nsTArray<uint8_t> gfxWindowsPlatform::GetPlatformCMSOutputProfileData_Impl() {
965 static nsTArray<uint8_t> sCached = [&] {
966 // Check override pref first:
967 nsTArray<uint8_t> prefProfileData =
968 gfxPlatform::GetPrefCMSOutputProfileData();
969 if (!prefProfileData.IsEmpty()) {
970 return prefProfileData;
973 // -
974 // Otherwise, create a dummy DC and pull from that.
976 HDC dc = ::GetDC(nullptr);
977 if (!dc) {
978 return nsTArray<uint8_t>();
981 WCHAR profilePath[MAX_PATH];
982 DWORD profilePathLen = MAX_PATH;
984 bool getProfileResult = ::GetICMProfileW(dc, &profilePathLen, profilePath);
986 ::ReleaseDC(nullptr, dc);
988 if (!getProfileResult) {
989 return nsTArray<uint8_t>();
992 void* mem = nullptr;
993 size_t size = 0;
995 qcms_data_from_unicode_path(profilePath, &mem, &size);
996 if (!mem) {
997 return nsTArray<uint8_t>();
1000 nsTArray<uint8_t> result;
1001 result.AppendElements(static_cast<uint8_t*>(mem), size);
1003 free(mem);
1005 return result;
1006 }();
1008 return sCached.Clone();
1011 void gfxWindowsPlatform::GetDLLVersion(char16ptr_t aDLLPath,
1012 nsAString& aVersion) {
1013 DWORD versInfoSize, vers[4] = {0};
1014 // version info not available case
1015 aVersion.AssignLiteral(u"0.0.0.0");
1016 versInfoSize = GetFileVersionInfoSizeW(aDLLPath, nullptr);
1017 AutoTArray<BYTE, 512> versionInfo;
1019 if (versInfoSize == 0) {
1020 return;
1023 // XXX(Bug 1631371) Check if this should use a fallible operation as it
1024 // pretended earlier.
1025 versionInfo.AppendElements(uint32_t(versInfoSize));
1027 if (!GetFileVersionInfoW(aDLLPath, 0, versInfoSize,
1028 LPBYTE(versionInfo.Elements()))) {
1029 return;
1032 UINT len = 0;
1033 VS_FIXEDFILEINFO* fileInfo = nullptr;
1034 if (!VerQueryValue(LPBYTE(versionInfo.Elements()), TEXT("\\"),
1035 (LPVOID*)&fileInfo, &len) ||
1036 len == 0 || fileInfo == nullptr) {
1037 return;
1040 DWORD fileVersMS = fileInfo->dwFileVersionMS;
1041 DWORD fileVersLS = fileInfo->dwFileVersionLS;
1043 vers[0] = HIWORD(fileVersMS);
1044 vers[1] = LOWORD(fileVersMS);
1045 vers[2] = HIWORD(fileVersLS);
1046 vers[3] = LOWORD(fileVersLS);
1048 char buf[256];
1049 SprintfLiteral(buf, "%lu.%lu.%lu.%lu", vers[0], vers[1], vers[2], vers[3]);
1050 aVersion.Assign(NS_ConvertUTF8toUTF16(buf));
1053 static BOOL CALLBACK AppendClearTypeParams(HMONITOR aMonitor, HDC, LPRECT,
1054 LPARAM aContext) {
1055 MONITORINFOEXW monitorInfo;
1056 monitorInfo.cbSize = sizeof(MONITORINFOEXW);
1057 if (!GetMonitorInfoW(aMonitor, &monitorInfo)) {
1058 return TRUE;
1061 ClearTypeParameterInfo ctinfo;
1062 ctinfo.displayName.Assign(monitorInfo.szDevice);
1064 RefPtr<IDWriteRenderingParams> renderingParams;
1065 HRESULT hr = Factory::GetDWriteFactory()->CreateMonitorRenderingParams(
1066 aMonitor, getter_AddRefs(renderingParams));
1067 if (FAILED(hr)) {
1068 return TRUE;
1071 ctinfo.gamma = renderingParams->GetGamma() * 1000;
1072 ctinfo.pixelStructure = renderingParams->GetPixelGeometry();
1073 ctinfo.clearTypeLevel = renderingParams->GetClearTypeLevel() * 100;
1074 ctinfo.enhancedContrast = renderingParams->GetEnhancedContrast() * 100;
1076 auto* params = reinterpret_cast<nsTArray<ClearTypeParameterInfo>*>(aContext);
1077 params->AppendElement(ctinfo);
1078 return TRUE;
1081 void gfxWindowsPlatform::GetCleartypeParams(
1082 nsTArray<ClearTypeParameterInfo>& aParams) {
1083 aParams.Clear();
1084 if (!DWriteEnabled()) {
1085 return;
1087 EnumDisplayMonitors(nullptr, nullptr, AppendClearTypeParams,
1088 reinterpret_cast<LPARAM>(&aParams));
1091 void gfxWindowsPlatform::FontsPrefsChanged(const char* aPref) {
1092 bool clearTextFontCaches = true;
1094 gfxPlatform::FontsPrefsChanged(aPref);
1096 if (aPref &&
1097 !strncmp(GFX_CLEARTYPE_PARAMS, aPref, strlen(GFX_CLEARTYPE_PARAMS))) {
1098 gfxDWriteFont::UpdateClearTypeVars();
1099 } else {
1100 clearTextFontCaches = false;
1103 if (clearTextFontCaches) {
1104 gfxFontCache* fc = gfxFontCache::GetCache();
1105 if (fc) {
1106 fc->Flush();
1111 bool gfxWindowsPlatform::IsOptimus() {
1112 static int knowIsOptimus = -1;
1113 if (knowIsOptimus == -1) {
1114 // other potential optimus -- nvd3d9wrapx.dll & nvdxgiwrap.dll
1115 if (GetModuleHandleA("nvumdshim.dll") ||
1116 GetModuleHandleA("nvumdshimx.dll")) {
1117 knowIsOptimus = 1;
1118 } else {
1119 knowIsOptimus = 0;
1122 return knowIsOptimus;
1125 static void InitializeANGLEConfig() {
1126 FeatureState& d3d11ANGLE = gfxConfig::GetFeature(Feature::D3D11_HW_ANGLE);
1128 if (!gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) {
1129 d3d11ANGLE.DisableByDefault(FeatureStatus::Unavailable,
1130 "D3D11 compositing is disabled",
1131 "FEATURE_FAILURE_HW_ANGLE_D3D11_DISABLED"_ns);
1132 return;
1135 d3d11ANGLE.EnableByDefault();
1137 nsCString message;
1138 nsCString failureId;
1139 if (!gfxPlatform::IsGfxInfoStatusOkay(nsIGfxInfo::FEATURE_DIRECT3D_11_ANGLE,
1140 &message, failureId)) {
1141 d3d11ANGLE.Disable(FeatureStatus::Blocklisted, message.get(), failureId);
1145 void gfxWindowsPlatform::InitializeDirectDrawConfig() {
1146 MOZ_ASSERT(XRE_IsParentProcess());
1148 FeatureState& ddraw = gfxConfig::GetFeature(Feature::DIRECT_DRAW);
1149 ddraw.EnableByDefault();
1152 void gfxWindowsPlatform::InitializeConfig() {
1153 if (XRE_IsParentProcess()) {
1154 // The parent process first determines which features can be attempted.
1155 // This information is relayed to content processes and the GPU process.
1156 InitializeD3D11Config();
1157 InitializeANGLEConfig();
1158 InitializeD2DConfig();
1159 } else {
1160 ImportCachedContentDeviceData();
1161 InitializeANGLEConfig();
1165 void gfxWindowsPlatform::InitializeD3D11Config() {
1166 MOZ_ASSERT(XRE_IsParentProcess());
1168 FeatureState& d3d11 = gfxConfig::GetFeature(Feature::D3D11_COMPOSITING);
1170 if (!gfxConfig::IsEnabled(Feature::HW_COMPOSITING)) {
1171 d3d11.DisableByDefault(FeatureStatus::Unavailable,
1172 "Hardware compositing is disabled",
1173 "FEATURE_FAILURE_D3D11_NEED_HWCOMP"_ns);
1174 return;
1177 d3d11.EnableByDefault();
1179 // Check if the user really, really wants WARP.
1180 if (StaticPrefs::layers_d3d11_force_warp_AtStartup()) {
1181 // Force D3D11 on even if we disabled it.
1182 d3d11.UserForceEnable("User force-enabled WARP");
1185 nsCString message;
1186 nsCString failureId;
1187 if (StaticPrefs::layers_d3d11_enable_blacklist_AtStartup() &&
1188 !gfxPlatform::IsGfxInfoStatusOkay(nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS,
1189 &message, failureId)) {
1190 d3d11.Disable(FeatureStatus::Blocklisted, message.get(), failureId);
1194 /* static */
1195 void gfxWindowsPlatform::RecordContentDeviceFailure(
1196 TelemetryDeviceCode aDevice) {
1197 // If the parent process fails to acquire a device, we record this
1198 // normally as part of the environment. The exceptional case we're
1199 // looking for here is when the parent process successfully acquires
1200 // a device, but the content process fails to acquire the same device.
1201 // This would not normally be displayed in about:support.
1202 if (!XRE_IsContentProcess()) {
1203 return;
1205 Telemetry::Accumulate(Telemetry::GFX_CONTENT_FAILED_TO_ACQUIRE_DEVICE,
1206 uint32_t(aDevice));
1209 void gfxWindowsPlatform::RecordStartupTelemetry() {
1210 if (!XRE_IsParentProcess()) {
1211 return;
1214 DeviceManagerDx* dx = DeviceManagerDx::Get();
1215 nsTArray<DXGI_OUTPUT_DESC1> outputs = dx->EnumerateOutputs();
1217 uint32_t allSupportedColorSpaces = 0;
1218 for (auto& output : outputs) {
1219 uint32_t colorSpace = 1 << output.ColorSpace;
1220 allSupportedColorSpaces |= colorSpace;
1223 Telemetry::ScalarSet(
1224 Telemetry::ScalarID::GFX_HDR_WINDOWS_DISPLAY_COLORSPACE_BITFIELD,
1225 allSupportedColorSpaces);
1228 // Supports lazy device initialization on Windows, so that WebRender can avoid
1229 // initializing GPU state and allocating swap chains for most non-GPU processes.
1230 void gfxWindowsPlatform::EnsureDevicesInitialized() {
1231 MOZ_DIAGNOSTIC_ASSERT(!IsWin32kLockedDown());
1233 if (!mInitializedDevices) {
1234 mInitializedDevices = true;
1235 InitializeDevices();
1236 UpdateBackendPrefs();
1240 bool gfxWindowsPlatform::DevicesInitialized() { return mInitializedDevices; }
1242 void gfxWindowsPlatform::InitializeDevices() {
1243 MOZ_ASSERT(NS_IsMainThread());
1245 if (XRE_IsParentProcess()) {
1246 // If we're the UI process, and the GPU process is enabled, then we don't
1247 // initialize any DirectX devices. We do leave them enabled in gfxConfig
1248 // though. If the GPU process fails to create these devices it will send
1249 // a message back and we'll update their status.
1250 if (gfxConfig::IsEnabled(Feature::GPU_PROCESS)) {
1251 return;
1254 // No GPU process, continue initializing devices as normal.
1257 // If acceleration is disabled, we refuse to initialize anything.
1258 if (!gfxConfig::IsEnabled(Feature::HW_COMPOSITING)) {
1259 return;
1262 // If we previously crashed initializing devices, bail out now.
1263 D3D11LayersCrashGuard detectCrashes;
1264 if (detectCrashes.Crashed()) {
1265 gfxConfig::SetFailed(Feature::HW_COMPOSITING,
1266 FeatureStatus::CrashedOnStartup,
1267 "Crashed during startup in a previous session");
1268 gfxConfig::SetFailed(
1269 Feature::D3D11_COMPOSITING, FeatureStatus::CrashedOnStartup,
1270 "Harware acceleration crashed during startup in a previous session");
1271 gfxConfig::SetFailed(
1272 Feature::DIRECT2D, FeatureStatus::CrashedOnStartup,
1273 "Harware acceleration crashed during startup in a previous session");
1274 return;
1277 bool shouldUseD2D = gfxConfig::IsEnabled(Feature::DIRECT2D);
1279 // First, initialize D3D11. If this succeeds we attempt to use Direct2D.
1280 InitializeD3D11();
1281 InitializeD2D();
1283 if (!gfxConfig::IsEnabled(Feature::DIRECT2D) && XRE_IsContentProcess() &&
1284 shouldUseD2D) {
1285 RecordContentDeviceFailure(TelemetryDeviceCode::D2D1);
1289 void gfxWindowsPlatform::InitializeD3D11() {
1290 // This function attempts to initialize our D3D11 devices, if the hardware
1291 // is not blocklisted for D3D11 layers. This first attempt will try to create
1292 // a hardware accelerated device. If this creation fails or the hardware is
1293 // blocklisted, then this function will abort if WARP is disabled, causing us
1294 // to fallback to Basic layers. If WARP is not disabled it will use a WARP
1295 // device which should always be available on Windows 7 and higher.
1296 if (!gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) {
1297 return;
1300 DeviceManagerDx* dm = DeviceManagerDx::Get();
1301 if (XRE_IsParentProcess()) {
1302 if (!dm->CreateCompositorDevices()) {
1303 return;
1307 dm->CreateContentDevices();
1309 // Content process failed to create the d3d11 device while parent process
1310 // succeed.
1311 if (XRE_IsContentProcess() &&
1312 !gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) {
1313 gfxCriticalError()
1314 << "[D3D11] Failed to create the D3D11 device in content \
1315 process.";
1319 void gfxWindowsPlatform::InitializeD2DConfig() {
1320 FeatureState& d2d1 = gfxConfig::GetFeature(Feature::DIRECT2D);
1322 if (!gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) {
1323 d2d1.DisableByDefault(FeatureStatus::Unavailable,
1324 "Direct2D requires Direct3D 11 compositing",
1325 "FEATURE_FAILURE_D2D_D3D11_COMP"_ns);
1326 return;
1329 d2d1.SetDefaultFromPref(StaticPrefs::GetPrefName_gfx_direct2d_disabled(),
1330 false,
1331 StaticPrefs::GetPrefDefault_gfx_direct2d_disabled());
1333 nsCString message;
1334 nsCString failureId;
1335 if (!gfxPlatform::IsGfxInfoStatusOkay(nsIGfxInfo::FEATURE_DIRECT2D, &message,
1336 failureId)) {
1337 d2d1.Disable(FeatureStatus::Blocklisted, message.get(), failureId);
1340 if (!d2d1.IsEnabled() &&
1341 StaticPrefs::gfx_direct2d_force_enabled_AtStartup()) {
1342 d2d1.UserForceEnable("Force-enabled via user-preference");
1346 void gfxWindowsPlatform::InitializeD2D() {
1347 ScopedGfxFeatureReporter d2d1_1("D2D1.1");
1349 FeatureState& d2d1 = gfxConfig::GetFeature(Feature::DIRECT2D);
1351 DeviceManagerDx* dm = DeviceManagerDx::Get();
1353 // We don't know this value ahead of time, but the user can force-override
1354 // it, so we use Disable instead of SetFailed.
1355 if (dm->IsWARP()) {
1356 d2d1.Disable(FeatureStatus::Blocked,
1357 "Direct2D is not compatible with Direct3D11 WARP",
1358 "FEATURE_FAILURE_D2D_WARP_BLOCK"_ns);
1361 // If we pass all the initial checks, we can proceed to runtime decisions.
1362 if (!d2d1.IsEnabled()) {
1363 return;
1366 if (!Factory::SupportsD2D1()) {
1367 d2d1.SetFailed(FeatureStatus::Unavailable,
1368 "Failed to acquire a Direct2D 1.1 factory",
1369 "FEATURE_FAILURE_D2D_FACTORY"_ns);
1370 return;
1373 if (!dm->GetContentDevice()) {
1374 d2d1.SetFailed(FeatureStatus::Failed,
1375 "Failed to acquire a Direct3D 11 content device",
1376 "FEATURE_FAILURE_D2D_DEVICE"_ns);
1377 return;
1380 if (!dm->TextureSharingWorks()) {
1381 d2d1.SetFailed(FeatureStatus::Failed,
1382 "Direct3D11 device does not support texture sharing",
1383 "FEATURE_FAILURE_D2D_TXT_SHARING"_ns);
1384 return;
1387 // Using Direct2D depends on DWrite support.
1388 if (!DWriteEnabled() && !InitDWriteSupport()) {
1389 d2d1.SetFailed(FeatureStatus::Failed,
1390 "Failed to initialize DirectWrite support",
1391 "FEATURE_FAILURE_D2D_DWRITE"_ns);
1392 return;
1395 // Verify that Direct2D device creation succeeded.
1396 RefPtr<ID3D11Device> contentDevice = dm->GetContentDevice();
1397 if (!Factory::SetDirect3D11Device(contentDevice)) {
1398 d2d1.SetFailed(FeatureStatus::Failed, "Failed to create a Direct2D device",
1399 "FEATURE_FAILURE_D2D_CREATE_FAILED"_ns);
1400 return;
1403 MOZ_ASSERT(d2d1.IsEnabled());
1404 d2d1_1.SetSuccessful();
1407 void gfxWindowsPlatform::InitGPUProcessSupport() {
1408 FeatureState& gpuProc = gfxConfig::GetFeature(Feature::GPU_PROCESS);
1410 if (!gpuProc.IsEnabled()) {
1411 return;
1414 if (!gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) {
1415 // Don't use the GPU process if not using D3D11, unless software
1416 // compositor is allowed
1417 if (StaticPrefs::layers_gpu_process_allow_software_AtStartup()) {
1418 return;
1420 gpuProc.Disable(FeatureStatus::Unavailable,
1421 "Not using GPU Process since D3D11 is unavailable",
1422 "FEATURE_FAILURE_NO_D3D11"_ns);
1424 // If we're still enabled at this point, the user set the force-enabled pref.
1427 class D3DVsyncSource final : public VsyncSource {
1428 public:
1429 D3DVsyncSource()
1430 : mPrevVsync(TimeStamp::Now()),
1431 mVsyncEnabled(false),
1432 mWaitVBlankMonitor(NULL) {
1433 mVsyncThread = new base::Thread("WindowsVsyncThread");
1434 MOZ_RELEASE_ASSERT(mVsyncThread->Start(),
1435 "GFX: Could not start Windows vsync thread");
1436 SetVsyncRate();
1439 void SetVsyncRate() {
1440 DWM_TIMING_INFO vblankTime;
1441 // Make sure to init the cbSize, otherwise GetCompositionTiming will fail
1442 vblankTime.cbSize = sizeof(DWM_TIMING_INFO);
1443 HRESULT hr = DwmGetCompositionTimingInfo(0, &vblankTime);
1444 if (SUCCEEDED(hr)) {
1445 UNSIGNED_RATIO refreshRate = vblankTime.rateRefresh;
1446 // We get the rate in hertz / time, but we want the rate in ms.
1447 float rate =
1448 ((float)refreshRate.uiDenominator / (float)refreshRate.uiNumerator) *
1449 1000;
1450 mVsyncRate = TimeDuration::FromMilliseconds(rate);
1451 } else {
1452 mVsyncRate = TimeDuration::FromMilliseconds(1000.0 / 60.0);
1456 virtual void Shutdown() override {
1457 MOZ_ASSERT(NS_IsMainThread());
1458 DisableVsync();
1459 mVsyncThread->Stop();
1460 delete mVsyncThread;
1463 virtual void EnableVsync() override {
1464 MOZ_ASSERT(NS_IsMainThread());
1465 MOZ_ASSERT(mVsyncThread->IsRunning());
1466 { // scope lock
1467 if (mVsyncEnabled) {
1468 return;
1470 mVsyncEnabled = true;
1473 mVsyncThread->message_loop()->PostTask(NewRunnableMethod(
1474 "D3DVsyncSource::VBlankLoop", this, &D3DVsyncSource::VBlankLoop));
1477 virtual void DisableVsync() override {
1478 MOZ_ASSERT(NS_IsMainThread());
1479 MOZ_ASSERT(mVsyncThread->IsRunning());
1480 if (!mVsyncEnabled) {
1481 return;
1483 mVsyncEnabled = false;
1486 virtual bool IsVsyncEnabled() override {
1487 MOZ_ASSERT(NS_IsMainThread());
1488 return mVsyncEnabled;
1491 virtual TimeDuration GetVsyncRate() override { return mVsyncRate; }
1493 void ScheduleSoftwareVsync(TimeStamp aVsyncTimestamp) {
1494 MOZ_ASSERT(IsInVsyncThread());
1495 NS_WARNING(
1496 "DwmComposition dynamically disabled, falling back to software "
1497 "timers");
1499 TimeStamp nextVsync = aVsyncTimestamp + mVsyncRate;
1500 TimeDuration delay = nextVsync - TimeStamp::Now();
1501 if (delay.ToMilliseconds() < 0) {
1502 delay = mozilla::TimeDuration::FromMilliseconds(0);
1505 mVsyncThread->message_loop()->PostDelayedTask(
1506 NewRunnableMethod("D3DVsyncSource::VBlankLoop", this,
1507 &D3DVsyncSource::VBlankLoop),
1508 delay.ToMilliseconds());
1511 // Returns the timestamp for the just happened vsync
1512 TimeStamp GetVBlankTime() {
1513 TimeStamp vsync = TimeStamp::Now();
1514 TimeStamp now = vsync;
1516 DWM_TIMING_INFO vblankTime;
1517 // Make sure to init the cbSize, otherwise
1518 // GetCompositionTiming will fail
1519 vblankTime.cbSize = sizeof(DWM_TIMING_INFO);
1520 HRESULT hr = DwmGetCompositionTimingInfo(0, &vblankTime);
1521 if (!SUCCEEDED(hr)) {
1522 return vsync;
1525 LARGE_INTEGER frequency;
1526 QueryPerformanceFrequency(&frequency);
1528 LARGE_INTEGER qpcNow;
1529 QueryPerformanceCounter(&qpcNow);
1531 const int microseconds = 1000000;
1532 int64_t adjust = qpcNow.QuadPart - vblankTime.qpcVBlank;
1533 int64_t usAdjust = (adjust * microseconds) / frequency.QuadPart;
1534 vsync -= TimeDuration::FromMicroseconds((double)usAdjust);
1536 // On Windows 10 and on, DWMGetCompositionTimingInfo, mostly
1537 // reports the upcoming vsync time, which is in the future.
1538 // It can also sometimes report a vblank time in the past.
1539 // Since large parts of Gecko assume TimeStamps can't be in future,
1540 // use the previous vsync.
1542 // Windows 10 and Intel HD vsync timestamps are messy and
1543 // all over the place once in a while. Most of the time,
1544 // it reports the upcoming vsync. Sometimes, that upcoming
1545 // vsync is in the past. Sometimes that upcoming vsync is before
1546 // the previously seen vsync.
1547 // In these error cases, normalize to Now();
1548 if (vsync >= now) {
1549 vsync = vsync - mVsyncRate;
1552 // On Windows 7 and 8, DwmFlush wakes up AFTER qpcVBlankTime
1553 // from DWMGetCompositionTimingInfo. We can return the adjusted vsync.
1554 if (vsync >= now) {
1555 vsync = now;
1558 // Our vsync time is some time very far in the past, adjust to Now.
1559 // 4 ms is arbitrary, so feel free to pick something else if this isn't
1560 // working. See the comment above.
1561 if ((now - vsync).ToMilliseconds() > 4.0) {
1562 vsync = now;
1565 return vsync;
1568 void VBlankLoop() {
1569 MOZ_ASSERT(IsInVsyncThread());
1570 MOZ_ASSERT(sizeof(int64_t) == sizeof(QPC_TIME));
1572 TimeStamp vsync = TimeStamp::Now();
1573 mPrevVsync = TimeStamp();
1574 TimeStamp flushTime = TimeStamp::Now();
1575 TimeDuration longVBlank = mVsyncRate * 2;
1577 for (;;) {
1578 { // scope lock
1579 if (!mVsyncEnabled) return;
1582 // Large parts of gecko assume that the refresh driver timestamp
1583 // must be <= Now() and cannot be in the future.
1584 MOZ_ASSERT(vsync <= TimeStamp::Now());
1585 NotifyVsync(vsync, vsync + mVsyncRate);
1587 HRESULT hr = E_FAIL;
1588 if (!StaticPrefs::gfx_vsync_force_disable_waitforvblank()) {
1589 UpdateVBlankOutput();
1590 if (mWaitVBlankOutput) {
1591 const TimeStamp vblank_begin_wait = TimeStamp::Now();
1593 AUTO_PROFILER_THREAD_SLEEP;
1594 hr = mWaitVBlankOutput->WaitForVBlank();
1596 if (SUCCEEDED(hr)) {
1597 // vblank might return instantly when running headless,
1598 // monitor powering off, etc. Since we're on a dedicated
1599 // thread, instant-return should not happen in the normal
1600 // case, so catch any odd behavior with a time cutoff:
1601 TimeDuration vblank_wait = TimeStamp::Now() - vblank_begin_wait;
1602 if (vblank_wait.ToMilliseconds() < 1.0) {
1603 hr = E_FAIL; // fall back on old behavior
1608 if (!SUCCEEDED(hr)) {
1609 hr = DwmFlush();
1611 if (!SUCCEEDED(hr)) {
1612 // DWMFlush isn't working, fallback to software vsync.
1613 ScheduleSoftwareVsync(TimeStamp::Now());
1614 return;
1617 TimeStamp now = TimeStamp::Now();
1618 TimeDuration flushDiff = now - flushTime;
1619 flushTime = now;
1620 if ((flushDiff > longVBlank) || mPrevVsync.IsNull()) {
1621 // Our vblank took longer than 2 intervals, readjust our timestamps
1622 vsync = GetVBlankTime();
1623 mPrevVsync = vsync;
1624 } else {
1625 // Instead of giving the actual vsync time, a constant interval
1626 // between vblanks instead of the noise generated via hardware
1627 // is actually what we want. Most apps just care about the diff
1628 // between vblanks to animate, so a clean constant interval is
1629 // smoother.
1630 vsync = mPrevVsync + mVsyncRate;
1631 if (vsync > now) {
1632 // DWMFlush woke up very early, so readjust our times again
1633 vsync = GetVBlankTime();
1636 if (vsync <= mPrevVsync) {
1637 vsync = TimeStamp::Now();
1640 if ((now - vsync).ToMilliseconds() > 2.0) {
1641 // Account for time drift here where vsync never quite catches up to
1642 // Now and we'd fall ever so slightly further behind Now().
1643 vsync = GetVBlankTime();
1646 mPrevVsync = vsync;
1648 } // end for
1650 virtual ~D3DVsyncSource() { MOZ_ASSERT(NS_IsMainThread()); }
1652 private:
1653 bool IsInVsyncThread() {
1654 return mVsyncThread->thread_id() == PlatformThread::CurrentId();
1657 void UpdateVBlankOutput() {
1658 HMONITOR primary_monitor =
1659 MonitorFromWindow(nullptr, MONITOR_DEFAULTTOPRIMARY);
1660 if (primary_monitor == mWaitVBlankMonitor && mWaitVBlankOutput) {
1661 return;
1664 mWaitVBlankMonitor = primary_monitor;
1666 RefPtr<IDXGIOutput> output = nullptr;
1667 if (DeviceManagerDx* dx = DeviceManagerDx::Get()) {
1668 if (dx->GetOutputFromMonitor(mWaitVBlankMonitor, &output)) {
1669 mWaitVBlankOutput = output;
1670 return;
1674 // failed to convert a monitor to an output so keep trying
1675 mWaitVBlankOutput = nullptr;
1678 TimeStamp mPrevVsync;
1679 base::Thread* mVsyncThread;
1680 TimeDuration mVsyncRate;
1681 Atomic<bool> mVsyncEnabled;
1683 HMONITOR mWaitVBlankMonitor;
1684 RefPtr<IDXGIOutput> mWaitVBlankOutput;
1685 }; // D3DVsyncSource
1687 already_AddRefed<mozilla::gfx::VsyncSource>
1688 gfxWindowsPlatform::CreateGlobalHardwareVsyncSource() {
1689 MOZ_RELEASE_ASSERT(NS_IsMainThread(), "GFX: Not in main thread.");
1691 RefPtr<VsyncSource> d3dVsyncSource = new D3DVsyncSource();
1692 return d3dVsyncSource.forget();
1695 void gfxWindowsPlatform::ImportGPUDeviceData(
1696 const mozilla::gfx::GPUDeviceData& aData) {
1697 MOZ_ASSERT(XRE_IsParentProcess());
1699 gfxPlatform::ImportGPUDeviceData(aData);
1701 gfxConfig::ImportChange(Feature::D3D11_COMPOSITING, aData.d3d11Compositing());
1703 DeviceManagerDx* dm = DeviceManagerDx::Get();
1704 if (gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) {
1705 dm->ImportDeviceInfo(aData.gpuDevice().ref());
1706 } else {
1707 // There should be no devices, so this just takes away the device status.
1708 dm->ResetDevices();
1710 // Make sure we disable D2D if content processes might use it.
1711 FeatureState& d2d1 = gfxConfig::GetFeature(Feature::DIRECT2D);
1712 if (d2d1.IsEnabled()) {
1713 d2d1.SetFailed(FeatureStatus::Unavailable,
1714 "Direct2D requires Direct3D 11 compositing",
1715 "FEATURE_FAILURE_D2D_D3D11_COMP"_ns);
1719 // CanUseHardwareVideoDecoding depends on d3d11 state, so update
1720 // the cached value now.
1721 UpdateCanUseHardwareVideoDecoding();
1723 // For completeness (and messaging in about:support). Content recomputes this
1724 // on its own, and we won't use ANGLE in the UI process if we're using a GPU
1725 // process.
1726 UpdateANGLEConfig();
1729 void gfxWindowsPlatform::ImportContentDeviceData(
1730 const mozilla::gfx::ContentDeviceData& aData) {
1731 MOZ_ASSERT(XRE_IsContentProcess());
1733 gfxPlatform::ImportContentDeviceData(aData);
1735 const DevicePrefs& prefs = aData.prefs();
1736 gfxConfig::Inherit(Feature::D3D11_COMPOSITING, prefs.d3d11Compositing());
1737 gfxConfig::Inherit(Feature::DIRECT2D, prefs.useD2D1());
1739 if (gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) {
1740 DeviceManagerDx* dm = DeviceManagerDx::Get();
1741 dm->ImportDeviceInfo(aData.d3d11());
1745 void gfxWindowsPlatform::BuildContentDeviceData(ContentDeviceData* aOut) {
1746 // Check for device resets before giving back new graphics information.
1747 UpdateRenderMode();
1749 gfxPlatform::BuildContentDeviceData(aOut);
1751 const FeatureState& d3d11 = gfxConfig::GetFeature(Feature::D3D11_COMPOSITING);
1752 aOut->prefs().d3d11Compositing() = d3d11.GetValue();
1753 aOut->prefs().useD2D1() = gfxConfig::GetValue(Feature::DIRECT2D);
1755 if (d3d11.IsEnabled()) {
1756 DeviceManagerDx* dm = DeviceManagerDx::Get();
1757 dm->ExportDeviceInfo(&aOut->d3d11());
1760 aOut->cmsOutputProfileData() =
1761 gfxPlatform::GetPlatform()->GetPlatformCMSOutputProfileData();
1764 bool gfxWindowsPlatform::CheckVariationFontSupport() {
1765 // Variation font support is only available on Fall Creators Update or later.
1766 return IsWin10FallCreatorsUpdateOrLater();
1769 void gfxWindowsPlatform::GetPlatformDisplayInfo(
1770 mozilla::widget::InfoObject& aObj) {
1771 HwStretchingSupport stretch;
1772 DeviceManagerDx::Get()->CheckHardwareStretchingSupport(stretch);
1774 nsPrintfCString stretchValue(
1775 "both=%u window-only=%u full-screen-only=%u none=%u error=%u",
1776 stretch.mBoth, stretch.mWindowOnly, stretch.mFullScreenOnly,
1777 stretch.mNone, stretch.mError);
1778 aObj.DefineProperty("HardwareStretching", stretchValue.get());
1780 ScaledResolutionSet scaled;
1781 GetScaledResolutions(scaled);
1782 if (scaled.IsEmpty()) {
1783 return;
1786 aObj.DefineProperty("ScaledResolutionCount", scaled.Length());
1787 for (size_t i = 0; i < scaled.Length(); ++i) {
1788 auto& s = scaled[i];
1789 nsPrintfCString name("ScaledResolution%zu", i);
1790 nsPrintfCString value("source %dx%d, target %dx%d", s.first.width,
1791 s.first.height, s.second.width, s.second.height);
1792 aObj.DefineProperty(name.get(), value.get());