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"
12 #include "mozilla/ArrayUtils.h"
13 #include "mozilla/layers/CompositorBridgeChild.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"
31 #include "nsThreadUtils.h"
32 #include "mozilla/Telemetry.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"
53 #include "gfxTextRun.h"
54 #include "gfxUserFontSet.h"
55 #include "nsWindowsHelpers.h"
56 #include "gfx2DGlue.h"
62 #include "mozilla/gfx/2D.h"
63 #include "mozilla/gfx/gfxVars.h"
69 #include "nsIMemoryReporter.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:
97 SetGraphicsMode(mDC
, GM_ADVANCED
);
100 class GfxD2DVramReporter final
: public nsIMemoryReporter
{
101 ~GfxD2DVramReporter() {}
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.");
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
;
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
);
139 ~GPUAdapterReporter() {}
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
;
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
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
))) {
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
))) {
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
;
204 sharedBytesUsed
+= bytesCommitted
;
206 dedicatedBytesUsed
+= bytesCommitted
;
213 FreeLibrary(gdi32Handle
);
215 MOZ_COLLECT_REPORT("gpu-committed", KIND_OTHER
, UNITS_BYTES
,
217 "Memory committed by the Windows graphics system.");
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.");
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() {}
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.");
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()) {
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()) {
292 void gfxWindowsPlatform::InitMemoryReportersForGPUProcess() {
293 MOZ_RELEASE_ASSERT(XRE_IsGPUProcess());
295 RegisterStrongMemoryReporter(new GfxD2DVramReporter());
296 RegisterStrongMemoryReporter(new GPUAdapterReporter());
297 RegisterStrongMemoryReporter(new D3DSharedTexturesReporter());
301 nsresult
gfxWindowsPlatform::GetGpuTimeSinceProcessStartInMs(
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()) {
310 nsModuleHandle
module(LoadLibrary(L
"gdi32.dll"));
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();
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.
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
;
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
355 100 / PR_NSEC_PER_MSEC
;
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());
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();
391 // If we have Skia and we didn't init dwrite already, do it now.
392 if (!DWriteEnabled() && GetDefaultContentBackend() == BackendType::SKIA
) {
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();
422 if (!dm
->TextureSharingWorks()) {
425 return !dm
->IsWARP() && gfxPlatform::CanUseHardwareVideoDecoding();
428 bool gfxWindowsPlatform::InitDWriteSupport() {
429 mozilla::ScopedGfxFeatureReporter
reporter("DWrite");
430 if (!gfxDWriteFont::InitDWriteSupport()) {
434 reporter
.SetSuccessful();
438 bool gfxWindowsPlatform::HandleDeviceReset() {
439 DeviceResetReason resetReason
= DeviceResetReason::OK
;
440 if (!DidRenderingDeviceReset(&resetReason
)) {
444 if (resetReason
!= DeviceResetReason::FORCED_RESET
) {
445 Telemetry::Accumulate(Telemetry::DEVICE_RESET_REASON
,
446 uint32_t(resetReason
));
449 // Remove devices and adapters.
450 DeviceManagerDx::Get()->ResetDevices();
452 imgLoader::NormalLoader()->ClearCache(true);
453 imgLoader::NormalLoader()->ClearCache(false);
454 imgLoader::PrivateBrowsingLoader()->ClearCache(true);
455 imgLoader::PrivateBrowsingLoader()->ClearCache(false);
456 gfxAlphaBoxBlur::ShutdownBlurCache();
458 gfxConfig::Reset(Feature::D3D11_COMPOSITING
);
459 gfxConfig::Reset(Feature::D3D11_HW_ANGLE
);
460 gfxConfig::Reset(Feature::DIRECT2D
);
463 // XXX Add InitWebRenderConfig() calling.
464 if (mInitializedDevices
) {
465 InitGPUProcessSupport();
472 BackendPrefsData
gfxWindowsPlatform::GetBackendPrefs() const {
473 BackendPrefsData data
;
475 data
.mCanvasBitmask
= BackendTypeBit(BackendType::SKIA
);
476 data
.mContentBitmask
= BackendTypeBit(BackendType::SKIA
);
477 data
.mCanvasDefault
= BackendType::SKIA
;
478 data
.mContentDefault
= BackendType::SKIA
;
480 if (gfxConfig::IsEnabled(Feature::DIRECT2D
)) {
481 data
.mCanvasBitmask
|= BackendTypeBit(BackendType::DIRECT2D1_1
);
482 data
.mCanvasDefault
= BackendType::DIRECT2D1_1
;
487 void gfxWindowsPlatform::UpdateBackendPrefs() {
488 BackendPrefsData data
= GetBackendPrefs();
489 // Remove DIRECT2D1 preference if D2D1Device does not exist.
490 if (!Factory::HasD2D1Device()) {
491 data
.mContentBitmask
&= ~BackendTypeBit(BackendType::DIRECT2D1_1
);
492 if (data
.mContentDefault
== BackendType::DIRECT2D1_1
) {
493 data
.mContentDefault
= BackendType::SKIA
;
496 // Don't exclude DIRECT2D1_1 if using remote canvas, because DIRECT2D1_1 and
497 // hence the device will be used in the GPU process.
498 if (!gfxPlatform::UseRemoteCanvas()) {
499 data
.mCanvasBitmask
&= ~BackendTypeBit(BackendType::DIRECT2D1_1
);
500 if (data
.mCanvasDefault
== BackendType::DIRECT2D1_1
) {
501 data
.mCanvasDefault
= BackendType::SKIA
;
505 InitBackendPrefs(std::move(data
));
508 bool gfxWindowsPlatform::IsDirect2DBackend() {
509 return GetDefaultContentBackend() == BackendType::DIRECT2D1_1
;
512 void gfxWindowsPlatform::UpdateRenderMode() {
513 bool didReset
= HandleDeviceReset();
515 UpdateBackendPrefs();
518 mScreenReferenceDrawTarget
= CreateOffscreenContentDrawTarget(
519 IntSize(1, 1), SurfaceFormat::B8G8R8A8
);
520 if (!mScreenReferenceDrawTarget
) {
522 << "Failed to update reference draw target after device reset"
523 << ", D3D11 device:" << hexa(Factory::GetDirect3D11Device().get())
525 << FeatureStatusToString(
526 gfxConfig::GetValue(Feature::D3D11_COMPOSITING
))
527 << ", D2D1 device:" << hexa(Factory::GetD2D1Device().get())
529 << FeatureStatusToString(gfxConfig::GetValue(Feature::DIRECT2D
))
530 << ", content:" << int(GetDefaultContentBackend())
531 << ", compositor:" << int(GetCompositorBackend());
533 "GFX: Failed to update reference draw target after device reset");
538 mozilla::gfx::BackendType
gfxWindowsPlatform::GetContentBackendFor(
539 mozilla::layers::LayersBackend aLayers
) {
540 mozilla::gfx::BackendType defaultBackend
=
541 gfxPlatform::GetDefaultContentBackend();
542 if (aLayers
== LayersBackend::LAYERS_WR
&&
543 gfx::gfxVars::UseWebRenderANGLE()) {
544 return defaultBackend
;
547 if (defaultBackend
== BackendType::DIRECT2D1_1
) {
548 // We can't have D2D without D3D11 layers, so fallback to Skia.
549 return BackendType::SKIA
;
552 // Otherwise we have some non-accelerated backend and that's ok.
553 return defaultBackend
;
556 mozilla::gfx::BackendType
gfxWindowsPlatform::GetPreferredCanvasBackend() {
557 mozilla::gfx::BackendType backend
= gfxPlatform::GetPreferredCanvasBackend();
559 if (backend
== BackendType::DIRECT2D1_1
) {
560 if (!gfx::gfxVars::UseWebRenderANGLE()) {
561 // We can't have D2D without ANGLE when WebRender is enabled, so fallback
563 return BackendType::SKIA
;
566 // Fall back to software when remote canvas has been deactivated.
567 if (CanvasChild::Deactivated()) {
568 return BackendType::SKIA
;
574 bool gfxWindowsPlatform::CreatePlatformFontList() {
575 if (DWriteEnabled()) {
576 if (gfxPlatformFontList::Initialize(new gfxDWriteFontList
)) {
580 // DWrite font initialization failed! Don't know why this would happen,
581 // but apparently it can - see bug 594865.
582 // So we're going to fall back to GDI fonts & rendering.
583 DisableD2D(FeatureStatus::Failed
, "Failed to initialize fonts",
584 "FEATURE_FAILURE_FONT_FAIL"_ns
);
587 // Make sure the static variable is initialized...
588 gfxPlatform::HasVariationFontSupport();
589 // ...then force it to false, even if the Windows version was recent enough
590 // to permit it, as we're using GDI fonts.
591 sHasVariationFontSupport
= false;
593 return gfxPlatformFontList::Initialize(new gfxGDIFontList
);
596 // This function will permanently disable D2D for the session. It's intended to
597 // be used when, after initially chosing to use Direct2D, we encounter a
598 // scenario we can't support.
600 // This is called during gfxPlatform::Init() so at this point there should be no
601 // DrawTargetD2D/1 instances.
602 void gfxWindowsPlatform::DisableD2D(FeatureStatus aStatus
, const char* aMessage
,
603 const nsACString
& aFailureId
) {
604 gfxConfig::SetFailed(Feature::DIRECT2D
, aStatus
, aMessage
, aFailureId
);
605 Factory::SetDirect3D11Device(nullptr);
606 UpdateBackendPrefs();
609 already_AddRefed
<gfxASurface
> gfxWindowsPlatform::CreateOffscreenSurface(
610 const IntSize
& aSize
, gfxImageFormat aFormat
) {
611 if (!Factory::AllowedSurfaceSize(aSize
)) {
615 RefPtr
<gfxASurface
> surf
= nullptr;
617 #ifdef CAIRO_HAS_WIN32_SURFACE
618 if (!XRE_IsContentProcess()) {
619 if (mRenderMode
== RENDER_GDI
|| mRenderMode
== RENDER_DIRECT2D
) {
620 surf
= new gfxWindowsSurface(aSize
, aFormat
);
625 if (!surf
|| surf
->CairoStatus()) {
626 surf
= new gfxImageSurface(aSize
, aFormat
);
629 return surf
.forget();
632 static const char kFontAparajita
[] = "Aparajita";
633 static const char kFontArabicTypesetting
[] = "Arabic Typesetting";
634 static const char kFontArial
[] = "Arial";
635 static const char kFontArialUnicodeMS
[] = "Arial Unicode MS";
636 static const char kFontCambria
[] = "Cambria";
637 static const char kFontCambriaMath
[] = "Cambria Math";
638 static const char kFontEbrima
[] = "Ebrima";
639 static const char kFontEstrangeloEdessa
[] = "Estrangelo Edessa";
640 static const char kFontEuphemia
[] = "Euphemia";
641 static const char kFontGabriola
[] = "Gabriola";
642 static const char kFontJavaneseText
[] = "Javanese Text";
643 static const char kFontKhmerUI
[] = "Khmer UI";
644 static const char kFontLaoUI
[] = "Lao UI";
645 static const char kFontLeelawadeeUI
[] = "Leelawadee UI";
646 static const char kFontLucidaSansUnicode
[] = "Lucida Sans Unicode";
647 static const char kFontMVBoli
[] = "MV Boli";
648 static const char kFontMalgunGothic
[] = "Malgun Gothic";
649 static const char kFontMicrosoftJhengHei
[] = "Microsoft JhengHei";
650 static const char kFontMicrosoftNewTaiLue
[] = "Microsoft New Tai Lue";
651 static const char kFontMicrosoftPhagsPa
[] = "Microsoft PhagsPa";
652 static const char kFontMicrosoftTaiLe
[] = "Microsoft Tai Le";
653 static const char kFontMicrosoftUighur
[] = "Microsoft Uighur";
654 static const char kFontMicrosoftYaHei
[] = "Microsoft YaHei";
655 static const char kFontMicrosoftYiBaiti
[] = "Microsoft Yi Baiti";
656 static const char kFontMeiryo
[] = "Meiryo";
657 static const char kFontMongolianBaiti
[] = "Mongolian Baiti";
658 static const char kFontMyanmarText
[] = "Myanmar Text";
659 static const char kFontNirmalaUI
[] = "Nirmala UI";
660 static const char kFontNyala
[] = "Nyala";
661 static const char kFontPlantagenetCherokee
[] = "Plantagenet Cherokee";
662 static const char kFontSegoeUI
[] = "Segoe UI";
663 static const char kFontSegoeUIEmoji
[] = "Segoe UI Emoji";
664 static const char kFontSegoeUISymbol
[] = "Segoe UI Symbol";
665 static const char kFontSylfaen
[] = "Sylfaen";
666 static const char kFontTraditionalArabic
[] = "Traditional Arabic";
667 static const char kFontTwemojiMozilla
[] = "Twemoji Mozilla";
668 static const char kFontUtsaah
[] = "Utsaah";
669 static const char kFontYuGothic
[] = "Yu Gothic";
671 void gfxWindowsPlatform::GetCommonFallbackFonts(
672 uint32_t aCh
, Script aRunScript
, eFontPresentation aPresentation
,
673 nsTArray
<const char*>& aFontList
) {
674 if (PrefersColor(aPresentation
)) {
675 aFontList
.AppendElement(kFontSegoeUIEmoji
);
676 aFontList
.AppendElement(kFontTwemojiMozilla
);
679 // Arial is used as the default fallback for system fallback
680 aFontList
.AppendElement(kFontArial
);
682 if (!IS_IN_BMP(aCh
)) {
683 uint32_t p
= aCh
>> 16;
684 if (p
== 1) { // SMP plane
685 aFontList
.AppendElement(kFontSegoeUISymbol
);
686 aFontList
.AppendElement(kFontEbrima
);
687 aFontList
.AppendElement(kFontNirmalaUI
);
688 aFontList
.AppendElement(kFontCambriaMath
);
691 uint32_t b
= (aCh
>> 8) & 0xff;
695 aFontList
.AppendElement(kFontEstrangeloEdessa
);
696 aFontList
.AppendElement(kFontCambria
);
699 aFontList
.AppendElement(kFontMicrosoftUighur
);
702 aFontList
.AppendElement(kFontEstrangeloEdessa
);
703 aFontList
.AppendElement(kFontMVBoli
);
704 aFontList
.AppendElement(kFontEbrima
);
707 aFontList
.AppendElement(kFontNirmalaUI
);
708 aFontList
.AppendElement(kFontUtsaah
);
709 aFontList
.AppendElement(kFontAparajita
);
715 aFontList
.AppendElement(kFontNirmalaUI
);
718 aFontList
.AppendElement(kFontLaoUI
);
719 aFontList
.AppendElement(kFontLeelawadeeUI
);
722 aFontList
.AppendElement(kFontMyanmarText
);
725 aFontList
.AppendElement(kFontMalgunGothic
);
729 aFontList
.AppendElement(kFontNyala
);
730 aFontList
.AppendElement(kFontPlantagenetCherokee
);
735 aFontList
.AppendElement(kFontEuphemia
);
736 aFontList
.AppendElement(kFontSegoeUISymbol
);
739 aFontList
.AppendElement(kFontKhmerUI
);
740 aFontList
.AppendElement(kFontLeelawadeeUI
);
742 case 0x18: // Mongolian
743 aFontList
.AppendElement(kFontMongolianBaiti
);
744 aFontList
.AppendElement(kFontEuphemia
);
747 aFontList
.AppendElement(kFontMicrosoftTaiLe
);
748 aFontList
.AppendElement(kFontMicrosoftNewTaiLue
);
749 aFontList
.AppendElement(kFontKhmerUI
);
750 aFontList
.AppendElement(kFontLeelawadeeUI
);
753 aFontList
.AppendElement(kFontLeelawadeeUI
);
756 aFontList
.AppendElement(kFontNirmalaUI
);
758 case 0x20: // Symbol ranges
770 aFontList
.AppendElement(kFontSegoeUI
);
771 aFontList
.AppendElement(kFontSegoeUISymbol
);
772 aFontList
.AppendElement(kFontCambria
);
773 aFontList
.AppendElement(kFontMeiryo
);
774 aFontList
.AppendElement(kFontArial
);
775 aFontList
.AppendElement(kFontLucidaSansUnicode
);
776 aFontList
.AppendElement(kFontEbrima
);
781 aFontList
.AppendElement(kFontEbrima
);
782 aFontList
.AppendElement(kFontNyala
);
783 aFontList
.AppendElement(kFontSegoeUI
);
784 aFontList
.AppendElement(kFontSegoeUISymbol
);
785 aFontList
.AppendElement(kFontMeiryo
);
787 case 0x28: // Braille
788 aFontList
.AppendElement(kFontSegoeUISymbol
);
792 aFontList
.AppendElement(kFontMicrosoftYaHei
);
795 aFontList
.AppendElement(kFontMalgunGothic
);
798 aFontList
.AppendElement(kFontSegoeUISymbol
);
801 aFontList
.AppendElement(kFontMicrosoftYaHei
);
802 aFontList
.AppendElement(kFontYuGothic
);
809 aFontList
.AppendElement(kFontMicrosoftYiBaiti
);
810 aFontList
.AppendElement(kFontSegoeUI
);
815 aFontList
.AppendElement(kFontEbrima
);
816 aFontList
.AppendElement(kFontSegoeUI
);
817 aFontList
.AppendElement(kFontCambriaMath
);
820 aFontList
.AppendElement(kFontMicrosoftPhagsPa
);
821 aFontList
.AppendElement(kFontNirmalaUI
);
824 aFontList
.AppendElement(kFontMalgunGothic
);
825 aFontList
.AppendElement(kFontJavaneseText
);
826 aFontList
.AppendElement(kFontLeelawadeeUI
);
829 aFontList
.AppendElement(kFontMyanmarText
);
832 aFontList
.AppendElement(kFontEbrima
);
833 aFontList
.AppendElement(kFontNyala
);
836 aFontList
.AppendElement(kFontMalgunGothic
);
839 aFontList
.AppendElement(kFontMicrosoftUighur
);
840 aFontList
.AppendElement(kFontGabriola
);
841 aFontList
.AppendElement(kFontSylfaen
);
845 aFontList
.AppendElement(kFontTraditionalArabic
);
846 aFontList
.AppendElement(kFontArabicTypesetting
);
849 aFontList
.AppendElement(kFontTraditionalArabic
);
850 aFontList
.AppendElement(kFontMicrosoftJhengHei
);
853 aFontList
.AppendElement(kFontMicrosoftJhengHei
);
860 // Arial Unicode MS has lots of glyphs for obscure characters,
861 // use it as a last resort
862 aFontList
.AppendElement(kFontArialUnicodeMS
);
864 // If we didn't begin with the color-emoji fonts, include them here
865 // so that they'll be preferred over user-installed (and possibly
866 // broken) fonts in the global fallback path.
867 if (!PrefersColor(aPresentation
)) {
868 aFontList
.AppendElement(kFontSegoeUIEmoji
);
869 aFontList
.AppendElement(kFontTwemojiMozilla
);
873 bool gfxWindowsPlatform::DidRenderingDeviceReset(
874 DeviceResetReason
* aResetReason
) {
875 DeviceManagerDx
* dm
= DeviceManagerDx::Get();
879 return dm
->HasDeviceReset(aResetReason
);
882 void gfxWindowsPlatform::CompositorUpdated() {
883 DeviceManagerDx::Get()->ForceDeviceReset(
884 ForcedDeviceResetReason::COMPOSITOR_UPDATED
);
888 BOOL CALLBACK
InvalidateWindowForDeviceReset(HWND aWnd
, LPARAM aMsg
) {
889 RedrawWindow(aWnd
, nullptr, nullptr,
890 RDW_INVALIDATE
| RDW_INTERNALPAINT
| RDW_FRAME
);
894 void gfxWindowsPlatform::SchedulePaintIfDeviceReset() {
895 AUTO_PROFILER_LABEL("gfxWindowsPlatform::SchedulePaintIfDeviceReset", OTHER
);
897 DeviceResetReason resetReason
= DeviceResetReason::OK
;
898 if (!DidRenderingDeviceReset(&resetReason
)) {
902 gfxCriticalNote
<< "(gfxWindowsPlatform) Detected device reset: "
905 if (XRE_IsParentProcess()) {
906 // Trigger an ::OnPaint for each window.
907 ::EnumThreadWindows(GetCurrentThreadId(), InvalidateWindowForDeviceReset
,
910 NS_DispatchToMainThread(NS_NewRunnableFunction(
911 "gfx::gfxWindowsPlatform::SchedulePaintIfDeviceReset", []() -> void {
912 gfxWindowsPlatform::GetPlatform()->CheckForContentOnlyDeviceReset();
916 gfxCriticalNote
<< "(gfxWindowsPlatform) scheduled device update.";
919 void gfxWindowsPlatform::CheckForContentOnlyDeviceReset() {
920 if (!DidRenderingDeviceReset()) {
924 bool isContentOnlyTDR
;
925 D3D11DeviceStatus status
;
927 DeviceManagerDx::Get()->ExportDeviceInfo(&status
);
928 CompositorBridgeChild::Get()->SendCheckContentOnlyTDR(status
.sequenceNumber(),
931 // The parent process doesn't know about the reset yet, or the reset is
932 // local to our device.
933 if (isContentOnlyTDR
) {
934 gfxCriticalNote
<< "A content-only TDR is detected.";
935 dom::ContentChild
* cc
= dom::ContentChild::GetSingleton();
936 cc
->RecvReinitRenderingForDeviceReset();
940 nsTArray
<uint8_t> gfxWindowsPlatform::GetPlatformCMSOutputProfileData() {
941 if (XRE_IsContentProcess()) {
942 auto& cmsOutputProfileData
= GetCMSOutputProfileData();
943 // We should have set our profile data when we received our initial
944 // ContentDeviceData.
945 MOZ_ASSERT(cmsOutputProfileData
.isSome(),
946 "Should have created output profile data when we received "
947 "initial content device data.");
949 // If we have data, it should not be empty.
950 MOZ_ASSERT_IF(cmsOutputProfileData
.isSome(),
951 !cmsOutputProfileData
->IsEmpty());
953 if (cmsOutputProfileData
.isSome()) {
954 return cmsOutputProfileData
.ref().Clone();
956 return nsTArray
<uint8_t>();
959 return GetPlatformCMSOutputProfileData_Impl();
962 nsTArray
<uint8_t> gfxWindowsPlatform::GetPlatformCMSOutputProfileData_Impl() {
963 static nsTArray
<uint8_t> sCached
= [&] {
964 // Check override pref first:
965 nsTArray
<uint8_t> prefProfileData
=
966 gfxPlatform::GetPrefCMSOutputProfileData();
967 if (!prefProfileData
.IsEmpty()) {
968 return prefProfileData
;
972 // Otherwise, create a dummy DC and pull from that.
974 HDC dc
= ::GetDC(nullptr);
976 return nsTArray
<uint8_t>();
979 WCHAR profilePath
[MAX_PATH
];
980 DWORD profilePathLen
= MAX_PATH
;
982 bool getProfileResult
= ::GetICMProfileW(dc
, &profilePathLen
, profilePath
);
984 ::ReleaseDC(nullptr, dc
);
986 if (!getProfileResult
) {
987 return nsTArray
<uint8_t>();
993 qcms_data_from_unicode_path(profilePath
, &mem
, &size
);
995 return nsTArray
<uint8_t>();
998 nsTArray
<uint8_t> result
;
999 result
.AppendElements(static_cast<uint8_t*>(mem
), size
);
1006 return sCached
.Clone();
1009 void gfxWindowsPlatform::GetDLLVersion(char16ptr_t aDLLPath
,
1010 nsAString
& aVersion
) {
1011 DWORD versInfoSize
, vers
[4] = {0};
1012 // version info not available case
1013 aVersion
.AssignLiteral(u
"0.0.0.0");
1014 versInfoSize
= GetFileVersionInfoSizeW(aDLLPath
, nullptr);
1015 AutoTArray
<BYTE
, 512> versionInfo
;
1017 if (versInfoSize
== 0) {
1021 // XXX(Bug 1631371) Check if this should use a fallible operation as it
1022 // pretended earlier.
1023 versionInfo
.AppendElements(uint32_t(versInfoSize
));
1025 if (!GetFileVersionInfoW(aDLLPath
, 0, versInfoSize
,
1026 LPBYTE(versionInfo
.Elements()))) {
1031 VS_FIXEDFILEINFO
* fileInfo
= nullptr;
1032 if (!VerQueryValue(LPBYTE(versionInfo
.Elements()), TEXT("\\"),
1033 (LPVOID
*)&fileInfo
, &len
) ||
1034 len
== 0 || fileInfo
== nullptr) {
1038 DWORD fileVersMS
= fileInfo
->dwFileVersionMS
;
1039 DWORD fileVersLS
= fileInfo
->dwFileVersionLS
;
1041 vers
[0] = HIWORD(fileVersMS
);
1042 vers
[1] = LOWORD(fileVersMS
);
1043 vers
[2] = HIWORD(fileVersLS
);
1044 vers
[3] = LOWORD(fileVersLS
);
1047 SprintfLiteral(buf
, "%lu.%lu.%lu.%lu", vers
[0], vers
[1], vers
[2], vers
[3]);
1048 aVersion
.Assign(NS_ConvertUTF8toUTF16(buf
));
1051 static BOOL CALLBACK
AppendClearTypeParams(HMONITOR aMonitor
, HDC
, LPRECT
,
1053 MONITORINFOEXW monitorInfo
;
1054 monitorInfo
.cbSize
= sizeof(MONITORINFOEXW
);
1055 if (!GetMonitorInfoW(aMonitor
, &monitorInfo
)) {
1059 ClearTypeParameterInfo ctinfo
;
1060 ctinfo
.displayName
.Assign(monitorInfo
.szDevice
);
1062 RefPtr
<IDWriteRenderingParams
> renderingParams
;
1063 HRESULT hr
= Factory::GetDWriteFactory()->CreateMonitorRenderingParams(
1064 aMonitor
, getter_AddRefs(renderingParams
));
1069 ctinfo
.gamma
= renderingParams
->GetGamma() * 1000;
1070 ctinfo
.pixelStructure
= renderingParams
->GetPixelGeometry();
1071 ctinfo
.clearTypeLevel
= renderingParams
->GetClearTypeLevel() * 100;
1072 ctinfo
.enhancedContrast
= renderingParams
->GetEnhancedContrast() * 100;
1074 auto* params
= reinterpret_cast<nsTArray
<ClearTypeParameterInfo
>*>(aContext
);
1075 params
->AppendElement(ctinfo
);
1079 void gfxWindowsPlatform::GetCleartypeParams(
1080 nsTArray
<ClearTypeParameterInfo
>& aParams
) {
1082 if (!DWriteEnabled()) {
1085 EnumDisplayMonitors(nullptr, nullptr, AppendClearTypeParams
,
1086 reinterpret_cast<LPARAM
>(&aParams
));
1089 void gfxWindowsPlatform::FontsPrefsChanged(const char* aPref
) {
1090 bool clearTextFontCaches
= true;
1092 gfxPlatform::FontsPrefsChanged(aPref
);
1095 !strncmp(GFX_CLEARTYPE_PARAMS
, aPref
, strlen(GFX_CLEARTYPE_PARAMS
))) {
1096 gfxDWriteFont::UpdateClearTypeVars();
1098 clearTextFontCaches
= false;
1101 if (clearTextFontCaches
) {
1102 gfxFontCache
* fc
= gfxFontCache::GetCache();
1109 bool gfxWindowsPlatform::IsOptimus() {
1110 static int knowIsOptimus
= -1;
1111 if (knowIsOptimus
== -1) {
1112 // other potential optimus -- nvd3d9wrapx.dll & nvdxgiwrap.dll
1113 if (GetModuleHandleA("nvumdshim.dll") ||
1114 GetModuleHandleA("nvumdshimx.dll")) {
1120 return knowIsOptimus
;
1123 static void InitializeANGLEConfig() {
1124 FeatureState
& d3d11ANGLE
= gfxConfig::GetFeature(Feature::D3D11_HW_ANGLE
);
1126 if (!gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING
)) {
1127 d3d11ANGLE
.DisableByDefault(FeatureStatus::Unavailable
,
1128 "D3D11 compositing is disabled",
1129 "FEATURE_FAILURE_HW_ANGLE_D3D11_DISABLED"_ns
);
1133 d3d11ANGLE
.EnableByDefault();
1136 nsCString failureId
;
1137 if (!gfxPlatform::IsGfxInfoStatusOkay(nsIGfxInfo::FEATURE_DIRECT3D_11_ANGLE
,
1138 &message
, failureId
)) {
1139 d3d11ANGLE
.Disable(FeatureStatus::Blocklisted
, message
.get(), failureId
);
1143 void gfxWindowsPlatform::InitializeDirectDrawConfig() {
1144 MOZ_ASSERT(XRE_IsParentProcess());
1146 FeatureState
& ddraw
= gfxConfig::GetFeature(Feature::DIRECT_DRAW
);
1147 ddraw
.EnableByDefault();
1150 void gfxWindowsPlatform::InitializeConfig() {
1151 if (XRE_IsParentProcess()) {
1152 // The parent process first determines which features can be attempted.
1153 // This information is relayed to content processes and the GPU process.
1154 InitializeD3D11Config();
1155 InitializeANGLEConfig();
1156 InitializeD2DConfig();
1158 ImportCachedContentDeviceData();
1159 InitializeANGLEConfig();
1163 void gfxWindowsPlatform::InitializeD3D11Config() {
1164 MOZ_ASSERT(XRE_IsParentProcess());
1166 FeatureState
& d3d11
= gfxConfig::GetFeature(Feature::D3D11_COMPOSITING
);
1168 if (!gfxConfig::IsEnabled(Feature::HW_COMPOSITING
)) {
1169 d3d11
.DisableByDefault(FeatureStatus::Unavailable
,
1170 "Hardware compositing is disabled",
1171 "FEATURE_FAILURE_D3D11_NEED_HWCOMP"_ns
);
1175 d3d11
.EnableByDefault();
1177 // Check if the user really, really wants WARP.
1178 if (StaticPrefs::layers_d3d11_force_warp_AtStartup()) {
1179 // Force D3D11 on even if we disabled it.
1180 d3d11
.UserForceEnable("User force-enabled WARP");
1184 nsCString failureId
;
1185 if (StaticPrefs::layers_d3d11_enable_blacklist_AtStartup() &&
1186 !gfxPlatform::IsGfxInfoStatusOkay(nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS
,
1187 &message
, failureId
)) {
1188 d3d11
.Disable(FeatureStatus::Blocklisted
, message
.get(), failureId
);
1193 void gfxWindowsPlatform::RecordContentDeviceFailure(
1194 TelemetryDeviceCode aDevice
) {
1195 // If the parent process fails to acquire a device, we record this
1196 // normally as part of the environment. The exceptional case we're
1197 // looking for here is when the parent process successfully acquires
1198 // a device, but the content process fails to acquire the same device.
1199 // This would not normally be displayed in about:support.
1200 if (!XRE_IsContentProcess()) {
1203 Telemetry::Accumulate(Telemetry::GFX_CONTENT_FAILED_TO_ACQUIRE_DEVICE
,
1207 void gfxWindowsPlatform::RecordStartupTelemetry() {
1208 if (!XRE_IsParentProcess()) {
1212 DeviceManagerDx
* dx
= DeviceManagerDx::Get();
1213 nsTArray
<DXGI_OUTPUT_DESC1
> outputs
= dx
->EnumerateOutputs();
1215 uint32_t allSupportedColorSpaces
= 0;
1216 for (auto& output
: outputs
) {
1217 uint32_t colorSpace
= 1 << output
.ColorSpace
;
1218 allSupportedColorSpaces
|= colorSpace
;
1221 Telemetry::ScalarSet(
1222 Telemetry::ScalarID::GFX_HDR_WINDOWS_DISPLAY_COLORSPACE_BITFIELD
,
1223 allSupportedColorSpaces
);
1226 // Supports lazy device initialization on Windows, so that WebRender can avoid
1227 // initializing GPU state and allocating swap chains for most non-GPU processes.
1228 void gfxWindowsPlatform::EnsureDevicesInitialized() {
1229 MOZ_DIAGNOSTIC_ASSERT(!IsWin32kLockedDown());
1231 if (!mInitializedDevices
) {
1232 mInitializedDevices
= true;
1233 InitializeDevices();
1234 UpdateBackendPrefs();
1238 bool gfxWindowsPlatform::DevicesInitialized() { return mInitializedDevices
; }
1240 void gfxWindowsPlatform::InitializeDevices() {
1241 MOZ_ASSERT(NS_IsMainThread());
1243 if (XRE_IsParentProcess()) {
1244 // If we're the UI process, and the GPU process is enabled, then we don't
1245 // initialize any DirectX devices. We do leave them enabled in gfxConfig
1246 // though. If the GPU process fails to create these devices it will send
1247 // a message back and we'll update their status.
1248 if (gfxConfig::IsEnabled(Feature::GPU_PROCESS
)) {
1252 // No GPU process, continue initializing devices as normal.
1255 // If acceleration is disabled, we refuse to initialize anything.
1256 if (!gfxConfig::IsEnabled(Feature::HW_COMPOSITING
)) {
1260 // If we previously crashed initializing devices, bail out now.
1261 D3D11LayersCrashGuard detectCrashes
;
1262 if (detectCrashes
.Crashed()) {
1263 gfxConfig::SetFailed(Feature::HW_COMPOSITING
,
1264 FeatureStatus::CrashedOnStartup
,
1265 "Crashed during startup in a previous session");
1266 gfxConfig::SetFailed(
1267 Feature::D3D11_COMPOSITING
, FeatureStatus::CrashedOnStartup
,
1268 "Harware acceleration crashed during startup in a previous session");
1269 gfxConfig::SetFailed(
1270 Feature::DIRECT2D
, FeatureStatus::CrashedOnStartup
,
1271 "Harware acceleration crashed during startup in a previous session");
1275 bool shouldUseD2D
= gfxConfig::IsEnabled(Feature::DIRECT2D
);
1277 // First, initialize D3D11. If this succeeds we attempt to use Direct2D.
1281 if (!gfxConfig::IsEnabled(Feature::DIRECT2D
) && XRE_IsContentProcess() &&
1283 RecordContentDeviceFailure(TelemetryDeviceCode::D2D1
);
1287 void gfxWindowsPlatform::InitializeD3D11() {
1288 // This function attempts to initialize our D3D11 devices, if the hardware
1289 // is not blocklisted for D3D11 layers. This first attempt will try to create
1290 // a hardware accelerated device. If this creation fails or the hardware is
1291 // blocklisted, then this function will abort if WARP is disabled, causing us
1292 // to fallback to Basic layers. If WARP is not disabled it will use a WARP
1293 // device which should always be available on Windows 7 and higher.
1294 if (!gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING
)) {
1298 DeviceManagerDx
* dm
= DeviceManagerDx::Get();
1299 if (XRE_IsParentProcess()) {
1300 if (!dm
->CreateCompositorDevices()) {
1305 dm
->CreateContentDevices();
1307 // Content process failed to create the d3d11 device while parent process
1309 if (XRE_IsContentProcess() &&
1310 !gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING
)) {
1312 << "[D3D11] Failed to create the D3D11 device in content \
1317 void gfxWindowsPlatform::InitializeD2DConfig() {
1318 FeatureState
& d2d1
= gfxConfig::GetFeature(Feature::DIRECT2D
);
1320 if (!gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING
)) {
1321 d2d1
.DisableByDefault(FeatureStatus::Unavailable
,
1322 "Direct2D requires Direct3D 11 compositing",
1323 "FEATURE_FAILURE_D2D_D3D11_COMP"_ns
);
1327 d2d1
.SetDefaultFromPref(StaticPrefs::GetPrefName_gfx_direct2d_disabled(),
1329 StaticPrefs::GetPrefDefault_gfx_direct2d_disabled());
1332 nsCString failureId
;
1333 if (!gfxPlatform::IsGfxInfoStatusOkay(nsIGfxInfo::FEATURE_DIRECT2D
, &message
,
1335 d2d1
.Disable(FeatureStatus::Blocklisted
, message
.get(), failureId
);
1338 if (!d2d1
.IsEnabled() &&
1339 StaticPrefs::gfx_direct2d_force_enabled_AtStartup()) {
1340 d2d1
.UserForceEnable("Force-enabled via user-preference");
1344 void gfxWindowsPlatform::InitializeD2D() {
1345 ScopedGfxFeatureReporter
d2d1_1("D2D1.1");
1347 FeatureState
& d2d1
= gfxConfig::GetFeature(Feature::DIRECT2D
);
1349 DeviceManagerDx
* dm
= DeviceManagerDx::Get();
1351 // We don't know this value ahead of time, but the user can force-override
1352 // it, so we use Disable instead of SetFailed.
1354 d2d1
.Disable(FeatureStatus::Blocked
,
1355 "Direct2D is not compatible with Direct3D11 WARP",
1356 "FEATURE_FAILURE_D2D_WARP_BLOCK"_ns
);
1359 // If we pass all the initial checks, we can proceed to runtime decisions.
1360 if (!d2d1
.IsEnabled()) {
1364 if (!Factory::SupportsD2D1()) {
1365 d2d1
.SetFailed(FeatureStatus::Unavailable
,
1366 "Failed to acquire a Direct2D 1.1 factory",
1367 "FEATURE_FAILURE_D2D_FACTORY"_ns
);
1371 if (!dm
->GetContentDevice()) {
1372 d2d1
.SetFailed(FeatureStatus::Failed
,
1373 "Failed to acquire a Direct3D 11 content device",
1374 "FEATURE_FAILURE_D2D_DEVICE"_ns
);
1378 if (!dm
->TextureSharingWorks()) {
1379 d2d1
.SetFailed(FeatureStatus::Failed
,
1380 "Direct3D11 device does not support texture sharing",
1381 "FEATURE_FAILURE_D2D_TXT_SHARING"_ns
);
1385 // Using Direct2D depends on DWrite support.
1386 if (!DWriteEnabled() && !InitDWriteSupport()) {
1387 d2d1
.SetFailed(FeatureStatus::Failed
,
1388 "Failed to initialize DirectWrite support",
1389 "FEATURE_FAILURE_D2D_DWRITE"_ns
);
1393 // Verify that Direct2D device creation succeeded.
1394 RefPtr
<ID3D11Device
> contentDevice
= dm
->GetContentDevice();
1395 if (!Factory::SetDirect3D11Device(contentDevice
)) {
1396 d2d1
.SetFailed(FeatureStatus::Failed
, "Failed to create a Direct2D device",
1397 "FEATURE_FAILURE_D2D_CREATE_FAILED"_ns
);
1401 MOZ_ASSERT(d2d1
.IsEnabled());
1402 d2d1_1
.SetSuccessful();
1405 void gfxWindowsPlatform::InitGPUProcessSupport() {
1406 FeatureState
& gpuProc
= gfxConfig::GetFeature(Feature::GPU_PROCESS
);
1408 if (!gpuProc
.IsEnabled()) {
1412 if (!gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING
)) {
1413 // Don't use the GPU process if not using D3D11, unless software
1414 // compositor is allowed
1415 if (StaticPrefs::layers_gpu_process_allow_software_AtStartup()) {
1418 gpuProc
.Disable(FeatureStatus::Unavailable
,
1419 "Not using GPU Process since D3D11 is unavailable",
1420 "FEATURE_FAILURE_NO_D3D11"_ns
);
1422 // If we're still enabled at this point, the user set the force-enabled pref.
1425 class D3DVsyncSource final
: public VsyncSource
{
1428 : mPrevVsync(TimeStamp::Now()),
1429 mVsyncEnabled(false),
1430 mWaitVBlankMonitor(NULL
) {
1431 mVsyncThread
= new base::Thread("WindowsVsyncThread");
1432 MOZ_RELEASE_ASSERT(mVsyncThread
->Start(),
1433 "GFX: Could not start Windows vsync thread");
1437 void SetVsyncRate() {
1438 DWM_TIMING_INFO vblankTime
;
1439 // Make sure to init the cbSize, otherwise GetCompositionTiming will fail
1440 vblankTime
.cbSize
= sizeof(DWM_TIMING_INFO
);
1441 HRESULT hr
= DwmGetCompositionTimingInfo(0, &vblankTime
);
1442 if (SUCCEEDED(hr
)) {
1443 UNSIGNED_RATIO refreshRate
= vblankTime
.rateRefresh
;
1444 // We get the rate in hertz / time, but we want the rate in ms.
1446 ((float)refreshRate
.uiDenominator
/ (float)refreshRate
.uiNumerator
) *
1448 mVsyncRate
= TimeDuration::FromMilliseconds(rate
);
1450 mVsyncRate
= TimeDuration::FromMilliseconds(1000.0 / 60.0);
1454 virtual void Shutdown() override
{
1455 MOZ_ASSERT(NS_IsMainThread());
1457 mVsyncThread
->Stop();
1458 delete mVsyncThread
;
1461 virtual void EnableVsync() override
{
1462 MOZ_ASSERT(NS_IsMainThread());
1463 MOZ_ASSERT(mVsyncThread
->IsRunning());
1465 if (mVsyncEnabled
) {
1468 mVsyncEnabled
= true;
1471 mVsyncThread
->message_loop()->PostTask(NewRunnableMethod(
1472 "D3DVsyncSource::VBlankLoop", this, &D3DVsyncSource::VBlankLoop
));
1475 virtual void DisableVsync() override
{
1476 MOZ_ASSERT(NS_IsMainThread());
1477 MOZ_ASSERT(mVsyncThread
->IsRunning());
1478 if (!mVsyncEnabled
) {
1481 mVsyncEnabled
= false;
1484 virtual bool IsVsyncEnabled() override
{
1485 MOZ_ASSERT(NS_IsMainThread());
1486 return mVsyncEnabled
;
1489 virtual TimeDuration
GetVsyncRate() override
{ return mVsyncRate
; }
1491 void ScheduleSoftwareVsync(TimeStamp aVsyncTimestamp
) {
1492 MOZ_ASSERT(IsInVsyncThread());
1494 "DwmComposition dynamically disabled, falling back to software "
1497 TimeStamp nextVsync
= aVsyncTimestamp
+ mVsyncRate
;
1498 TimeDuration delay
= nextVsync
- TimeStamp::Now();
1499 if (delay
.ToMilliseconds() < 0) {
1500 delay
= mozilla::TimeDuration::FromMilliseconds(0);
1503 mVsyncThread
->message_loop()->PostDelayedTask(
1504 NewRunnableMethod("D3DVsyncSource::VBlankLoop", this,
1505 &D3DVsyncSource::VBlankLoop
),
1506 delay
.ToMilliseconds());
1509 // Returns the timestamp for the just happened vsync
1510 TimeStamp
GetVBlankTime() {
1511 TimeStamp vsync
= TimeStamp::Now();
1512 TimeStamp now
= vsync
;
1514 DWM_TIMING_INFO vblankTime
;
1515 // Make sure to init the cbSize, otherwise
1516 // GetCompositionTiming will fail
1517 vblankTime
.cbSize
= sizeof(DWM_TIMING_INFO
);
1518 HRESULT hr
= DwmGetCompositionTimingInfo(0, &vblankTime
);
1519 if (!SUCCEEDED(hr
)) {
1523 LARGE_INTEGER frequency
;
1524 QueryPerformanceFrequency(&frequency
);
1526 LARGE_INTEGER qpcNow
;
1527 QueryPerformanceCounter(&qpcNow
);
1529 const int microseconds
= 1000000;
1530 int64_t adjust
= qpcNow
.QuadPart
- vblankTime
.qpcVBlank
;
1531 int64_t usAdjust
= (adjust
* microseconds
) / frequency
.QuadPart
;
1532 vsync
-= TimeDuration::FromMicroseconds((double)usAdjust
);
1534 // On Windows 10 and on, DWMGetCompositionTimingInfo, mostly
1535 // reports the upcoming vsync time, which is in the future.
1536 // It can also sometimes report a vblank time in the past.
1537 // Since large parts of Gecko assume TimeStamps can't be in future,
1538 // use the previous vsync.
1540 // Windows 10 and Intel HD vsync timestamps are messy and
1541 // all over the place once in a while. Most of the time,
1542 // it reports the upcoming vsync. Sometimes, that upcoming
1543 // vsync is in the past. Sometimes that upcoming vsync is before
1544 // the previously seen vsync.
1545 // In these error cases, normalize to Now();
1547 vsync
= vsync
- mVsyncRate
;
1550 // On Windows 7 and 8, DwmFlush wakes up AFTER qpcVBlankTime
1551 // from DWMGetCompositionTimingInfo. We can return the adjusted vsync.
1556 // Our vsync time is some time very far in the past, adjust to Now.
1557 // 4 ms is arbitrary, so feel free to pick something else if this isn't
1558 // working. See the comment above.
1559 if ((now
- vsync
).ToMilliseconds() > 4.0) {
1567 MOZ_ASSERT(IsInVsyncThread());
1568 MOZ_ASSERT(sizeof(int64_t) == sizeof(QPC_TIME
));
1570 TimeStamp vsync
= TimeStamp::Now();
1571 mPrevVsync
= TimeStamp();
1572 TimeStamp flushTime
= TimeStamp::Now();
1573 TimeDuration longVBlank
= mVsyncRate
* 2;
1577 if (!mVsyncEnabled
) return;
1580 // Large parts of gecko assume that the refresh driver timestamp
1581 // must be <= Now() and cannot be in the future.
1582 MOZ_ASSERT(vsync
<= TimeStamp::Now());
1583 NotifyVsync(vsync
, vsync
+ mVsyncRate
);
1585 HRESULT hr
= E_FAIL
;
1586 if (!StaticPrefs::gfx_vsync_force_disable_waitforvblank()) {
1587 UpdateVBlankOutput();
1588 if (mWaitVBlankOutput
) {
1589 const TimeStamp vblank_begin_wait
= TimeStamp::Now();
1591 AUTO_PROFILER_THREAD_SLEEP
;
1592 hr
= mWaitVBlankOutput
->WaitForVBlank();
1594 if (SUCCEEDED(hr
)) {
1595 // vblank might return instantly when running headless,
1596 // monitor powering off, etc. Since we're on a dedicated
1597 // thread, instant-return should not happen in the normal
1598 // case, so catch any odd behavior with a time cutoff:
1599 TimeDuration vblank_wait
= TimeStamp::Now() - vblank_begin_wait
;
1600 if (vblank_wait
.ToMilliseconds() < 1.0) {
1601 hr
= E_FAIL
; // fall back on old behavior
1606 if (!SUCCEEDED(hr
)) {
1609 if (!SUCCEEDED(hr
)) {
1610 // DWMFlush isn't working, fallback to software vsync.
1611 ScheduleSoftwareVsync(TimeStamp::Now());
1615 TimeStamp now
= TimeStamp::Now();
1616 TimeDuration flushDiff
= now
- flushTime
;
1618 if ((flushDiff
> longVBlank
) || mPrevVsync
.IsNull()) {
1619 // Our vblank took longer than 2 intervals, readjust our timestamps
1620 vsync
= GetVBlankTime();
1623 // Instead of giving the actual vsync time, a constant interval
1624 // between vblanks instead of the noise generated via hardware
1625 // is actually what we want. Most apps just care about the diff
1626 // between vblanks to animate, so a clean constant interval is
1628 vsync
= mPrevVsync
+ mVsyncRate
;
1630 // DWMFlush woke up very early, so readjust our times again
1631 vsync
= GetVBlankTime();
1634 if (vsync
<= mPrevVsync
) {
1635 vsync
= TimeStamp::Now();
1638 if ((now
- vsync
).ToMilliseconds() > 2.0) {
1639 // Account for time drift here where vsync never quite catches up to
1640 // Now and we'd fall ever so slightly further behind Now().
1641 vsync
= GetVBlankTime();
1648 virtual ~D3DVsyncSource() { MOZ_ASSERT(NS_IsMainThread()); }
1651 bool IsInVsyncThread() {
1652 return mVsyncThread
->thread_id() == PlatformThread::CurrentId();
1655 void UpdateVBlankOutput() {
1656 HMONITOR primary_monitor
=
1657 MonitorFromWindow(nullptr, MONITOR_DEFAULTTOPRIMARY
);
1658 if (primary_monitor
== mWaitVBlankMonitor
&& mWaitVBlankOutput
) {
1662 mWaitVBlankMonitor
= primary_monitor
;
1664 RefPtr
<IDXGIOutput
> output
= nullptr;
1665 if (DeviceManagerDx
* dx
= DeviceManagerDx::Get()) {
1666 if (dx
->GetOutputFromMonitor(mWaitVBlankMonitor
, &output
)) {
1667 mWaitVBlankOutput
= output
;
1672 // failed to convert a monitor to an output so keep trying
1673 mWaitVBlankOutput
= nullptr;
1676 TimeStamp mPrevVsync
;
1677 base::Thread
* mVsyncThread
;
1678 TimeDuration mVsyncRate
;
1679 Atomic
<bool> mVsyncEnabled
;
1681 HMONITOR mWaitVBlankMonitor
;
1682 RefPtr
<IDXGIOutput
> mWaitVBlankOutput
;
1683 }; // D3DVsyncSource
1685 already_AddRefed
<mozilla::gfx::VsyncSource
>
1686 gfxWindowsPlatform::CreateGlobalHardwareVsyncSource() {
1687 MOZ_RELEASE_ASSERT(NS_IsMainThread(), "GFX: Not in main thread.");
1689 RefPtr
<VsyncSource
> d3dVsyncSource
= new D3DVsyncSource();
1690 return d3dVsyncSource
.forget();
1693 void gfxWindowsPlatform::ImportGPUDeviceData(
1694 const mozilla::gfx::GPUDeviceData
& aData
) {
1695 MOZ_ASSERT(XRE_IsParentProcess());
1697 gfxPlatform::ImportGPUDeviceData(aData
);
1699 gfxConfig::ImportChange(Feature::D3D11_COMPOSITING
, aData
.d3d11Compositing());
1701 DeviceManagerDx
* dm
= DeviceManagerDx::Get();
1702 if (gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING
)) {
1703 dm
->ImportDeviceInfo(aData
.gpuDevice().ref());
1705 // There should be no devices, so this just takes away the device status.
1708 // Make sure we disable D2D if content processes might use it.
1709 FeatureState
& d2d1
= gfxConfig::GetFeature(Feature::DIRECT2D
);
1710 if (d2d1
.IsEnabled()) {
1711 d2d1
.SetFailed(FeatureStatus::Unavailable
,
1712 "Direct2D requires Direct3D 11 compositing",
1713 "FEATURE_FAILURE_D2D_D3D11_COMP"_ns
);
1717 // CanUseHardwareVideoDecoding depends on d3d11 state, so update
1718 // the cached value now.
1719 UpdateCanUseHardwareVideoDecoding();
1721 // For completeness (and messaging in about:support). Content recomputes this
1722 // on its own, and we won't use ANGLE in the UI process if we're using a GPU
1724 UpdateANGLEConfig();
1727 void gfxWindowsPlatform::ImportContentDeviceData(
1728 const mozilla::gfx::ContentDeviceData
& aData
) {
1729 MOZ_ASSERT(XRE_IsContentProcess());
1731 gfxPlatform::ImportContentDeviceData(aData
);
1733 const DevicePrefs
& prefs
= aData
.prefs();
1734 gfxConfig::Inherit(Feature::D3D11_COMPOSITING
, prefs
.d3d11Compositing());
1735 gfxConfig::Inherit(Feature::DIRECT2D
, prefs
.useD2D1());
1737 if (gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING
)) {
1738 DeviceManagerDx
* dm
= DeviceManagerDx::Get();
1739 dm
->ImportDeviceInfo(aData
.d3d11());
1743 void gfxWindowsPlatform::BuildContentDeviceData(ContentDeviceData
* aOut
) {
1744 // Check for device resets before giving back new graphics information.
1747 gfxPlatform::BuildContentDeviceData(aOut
);
1749 const FeatureState
& d3d11
= gfxConfig::GetFeature(Feature::D3D11_COMPOSITING
);
1750 aOut
->prefs().d3d11Compositing() = d3d11
.GetValue();
1751 aOut
->prefs().useD2D1() = gfxConfig::GetValue(Feature::DIRECT2D
);
1753 if (d3d11
.IsEnabled()) {
1754 DeviceManagerDx
* dm
= DeviceManagerDx::Get();
1755 dm
->ExportDeviceInfo(&aOut
->d3d11());
1758 aOut
->cmsOutputProfileData() =
1759 gfxPlatform::GetPlatform()->GetPlatformCMSOutputProfileData();
1762 bool gfxWindowsPlatform::CheckVariationFontSupport() {
1763 // Variation font support is only available on Fall Creators Update or later.
1764 return IsWin10FallCreatorsUpdateOrLater();
1767 void gfxWindowsPlatform::GetPlatformDisplayInfo(
1768 mozilla::widget::InfoObject
& aObj
) {
1769 HwStretchingSupport stretch
;
1770 DeviceManagerDx::Get()->CheckHardwareStretchingSupport(stretch
);
1772 nsPrintfCString
stretchValue(
1773 "both=%u window-only=%u full-screen-only=%u none=%u error=%u",
1774 stretch
.mBoth
, stretch
.mWindowOnly
, stretch
.mFullScreenOnly
,
1775 stretch
.mNone
, stretch
.mError
);
1776 aObj
.DefineProperty("HardwareStretching", stretchValue
.get());
1778 ScaledResolutionSet scaled
;
1779 GetScaledResolutions(scaled
);
1780 if (scaled
.IsEmpty()) {
1784 aObj
.DefineProperty("ScaledResolutionCount", scaled
.Length());
1785 for (size_t i
= 0; i
< scaled
.Length(); ++i
) {
1786 auto& s
= scaled
[i
];
1787 nsPrintfCString
name("ScaledResolution%zu", i
);
1788 nsPrintfCString
value("source %dx%d, target %dx%d", s
.first
.width
,
1789 s
.first
.height
, s
.second
.width
, s
.second
.height
);
1790 aObj
.DefineProperty(name
.get(), value
.get());