Source code

Revision control

Other Tools

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/. */
6
7
#define INITGUID // set before devguid.h
8
9
#include "gfxWindowsPlatform.h"
10
11
#include "cairo.h"
12
#include "mozilla/ArrayUtils.h"
13
#include "mozilla/layers/CompositorBridgeChild.h"
14
15
#include "gfxImageSurface.h"
16
#include "gfxWindowsSurface.h"
17
18
#include "nsUnicharUtils.h"
19
#include "nsUnicodeProperties.h"
20
21
#include "mozilla/Preferences.h"
22
#include "mozilla/Services.h"
23
#include "mozilla/Sprintf.h"
24
#include "mozilla/WindowsVersion.h"
25
#include "nsIGfxInfo.h"
26
#include "nsServiceManagerUtils.h"
27
#include "nsTArray.h"
28
#include "nsThreadUtils.h"
29
#include "mozilla/Telemetry.h"
30
#include "GeckoProfiler.h"
31
32
#include "nsIWindowsRegKey.h"
33
#include "nsIFile.h"
34
#include "plbase64.h"
35
#include "nsIXULRuntime.h"
36
#include "imgLoader.h"
37
38
#include "nsIGfxInfo.h"
39
40
#include "gfxCrashReporterUtils.h"
41
42
#include "gfxGDIFontList.h"
43
#include "gfxGDIFont.h"
44
45
#include "mozilla/layers/CompositorThread.h"
46
#include "mozilla/layers/PaintThread.h"
47
#include "mozilla/layers/ReadbackManagerD3D11.h"
48
49
#include "gfxDWriteFontList.h"
50
#include "gfxDWriteFonts.h"
51
#include "gfxDWriteCommon.h"
52
#include <dwrite.h>
53
54
#include "gfxTextRun.h"
55
#include "gfxUserFontSet.h"
56
#include "nsWindowsHelpers.h"
57
#include "gfx2DGlue.h"
58
59
#include <string>
60
61
#include <d3d10_1.h>
62
63
#include "mozilla/gfx/2D.h"
64
#include "mozilla/gfx/gfxVars.h"
65
66
#include "nsMemory.h"
67
68
#include <dwmapi.h>
69
#include <d3d11.h>
70
#include <d2d1_1.h>
71
72
#include "nsIMemoryReporter.h"
73
#include <winternl.h>
74
#include "d3dkmtQueryStatistics.h"
75
76
#include "base/thread.h"
77
#include "mozilla/StaticPrefs_gfx.h"
78
#include "mozilla/StaticPrefs_layers.h"
79
#include "gfxConfig.h"
80
#include "VsyncSource.h"
81
#include "DriverCrashGuard.h"
82
#include "mozilla/dom/ContentChild.h"
83
#include "mozilla/gfx/DeviceManagerDx.h"
84
#include "mozilla/layers/DeviceAttachmentsD3D11.h"
85
#include "D3D11Checks.h"
86
87
#include <devguid.h> // for GUID_DEVCLASS_BATTERY
88
#include <setupapi.h> // for SetupDi*
89
#include <winioctl.h> // for IOCTL_*
90
#include <batclass.h> // for BATTERY_*
91
92
using namespace mozilla;
93
using namespace mozilla::gfx;
94
using namespace mozilla::layers;
95
using namespace mozilla::widget;
96
using namespace mozilla::image;
97
using namespace mozilla::unicode;
98
99
DCForMetrics::DCForMetrics() {
100
// Get the whole screen DC:
101
mDC = GetDC(nullptr);
102
SetGraphicsMode(mDC, GM_ADVANCED);
103
}
104
105
class GfxD2DVramReporter final : public nsIMemoryReporter {
106
~GfxD2DVramReporter() {}
107
108
public:
109
NS_DECL_ISUPPORTS
110
111
NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport,
112
nsISupports* aData, bool aAnonymize) override {
113
MOZ_COLLECT_REPORT("gfx-d2d-vram-draw-target", KIND_OTHER, UNITS_BYTES,
114
Factory::GetD2DVRAMUsageDrawTarget(),
115
"Video memory used by D2D DrawTargets.");
116
117
MOZ_COLLECT_REPORT("gfx-d2d-vram-source-surface", KIND_OTHER, UNITS_BYTES,
118
Factory::GetD2DVRAMUsageSourceSurface(),
119
"Video memory used by D2D SourceSurfaces.");
120
121
return NS_OK;
122
}
123
};
124
125
NS_IMPL_ISUPPORTS(GfxD2DVramReporter, nsIMemoryReporter)
126
127
#define GFX_CLEARTYPE_PARAMS "gfx.font_rendering.cleartype_params."
128
#define GFX_CLEARTYPE_PARAMS_GAMMA "gfx.font_rendering.cleartype_params.gamma"
129
#define GFX_CLEARTYPE_PARAMS_CONTRAST \
130
"gfx.font_rendering.cleartype_params.enhanced_contrast"
131
#define GFX_CLEARTYPE_PARAMS_LEVEL \
132
"gfx.font_rendering.cleartype_params.cleartype_level"
133
#define GFX_CLEARTYPE_PARAMS_STRUCTURE \
134
"gfx.font_rendering.cleartype_params.pixel_structure"
135
#define GFX_CLEARTYPE_PARAMS_MODE \
136
"gfx.font_rendering.cleartype_params.rendering_mode"
137
138
class GPUAdapterReporter final : public nsIMemoryReporter {
139
// Callers must Release the DXGIAdapter after use or risk mem-leak
140
static bool GetDXGIAdapter(IDXGIAdapter** aDXGIAdapter) {
141
RefPtr<ID3D11Device> d3d11Device;
142
RefPtr<IDXGIDevice> dxgiDevice;
143
bool result = false;
144
145
if ((d3d11Device = mozilla::gfx::Factory::GetDirect3D11Device())) {
146
if (d3d11Device->QueryInterface(__uuidof(IDXGIDevice),
147
getter_AddRefs(dxgiDevice)) == S_OK) {
148
result = (dxgiDevice->GetAdapter(aDXGIAdapter) == S_OK);
149
}
150
}
151
152
return result;
153
}
154
155
~GPUAdapterReporter() {}
156
157
public:
158
NS_DECL_ISUPPORTS
159
160
NS_IMETHOD
161
CollectReports(nsIHandleReportCallback* aHandleReport, nsISupports* aData,
162
bool aAnonymize) override {
163
HANDLE ProcessHandle = GetCurrentProcess();
164
165
int64_t dedicatedBytesUsed = 0;
166
int64_t sharedBytesUsed = 0;
167
int64_t committedBytesUsed = 0;
168
IDXGIAdapter* DXGIAdapter;
169
170
HMODULE gdi32Handle;
171
PFND3DKMTQS queryD3DKMTStatistics = nullptr;
172
173
if ((gdi32Handle = LoadLibrary(TEXT("gdi32.dll"))))
174
queryD3DKMTStatistics =
175
(PFND3DKMTQS)GetProcAddress(gdi32Handle, "D3DKMTQueryStatistics");
176
177
if (queryD3DKMTStatistics && GetDXGIAdapter(&DXGIAdapter)) {
178
// Most of this block is understood thanks to wj32's work on Process
179
// Hacker
180
181
DXGI_ADAPTER_DESC adapterDesc;
182
D3DKMTQS queryStatistics;
183
184
DXGIAdapter->GetDesc(&adapterDesc);
185
DXGIAdapter->Release();
186
187
memset(&queryStatistics, 0, sizeof(D3DKMTQS));
188
queryStatistics.Type = D3DKMTQS_PROCESS;
189
queryStatistics.AdapterLuid = adapterDesc.AdapterLuid;
190
queryStatistics.hProcess = ProcessHandle;
191
if (NT_SUCCESS(queryD3DKMTStatistics(&queryStatistics))) {
192
committedBytesUsed =
193
queryStatistics.QueryResult.ProcessInfo.SystemMemory.BytesAllocated;
194
}
195
196
memset(&queryStatistics, 0, sizeof(D3DKMTQS));
197
queryStatistics.Type = D3DKMTQS_ADAPTER;
198
queryStatistics.AdapterLuid = adapterDesc.AdapterLuid;
199
if (NT_SUCCESS(queryD3DKMTStatistics(&queryStatistics))) {
200
ULONG i;
201
ULONG segmentCount = queryStatistics.QueryResult.AdapterInfo.NbSegments;
202
203
for (i = 0; i < segmentCount; i++) {
204
memset(&queryStatistics, 0, sizeof(D3DKMTQS));
205
queryStatistics.Type = D3DKMTQS_SEGMENT;
206
queryStatistics.AdapterLuid = adapterDesc.AdapterLuid;
207
queryStatistics.QuerySegment.SegmentId = i;
208
209
if (NT_SUCCESS(queryD3DKMTStatistics(&queryStatistics))) {
210
bool aperture;
211
212
// SegmentInformation has a different definition in Win7 than later
213
// versions
214
if (!IsWin8OrLater())
215
aperture = queryStatistics.QueryResult.SegmentInfoWin7.Aperture;
216
else
217
aperture = queryStatistics.QueryResult.SegmentInfoWin8.Aperture;
218
219
memset(&queryStatistics, 0, sizeof(D3DKMTQS));
220
queryStatistics.Type = D3DKMTQS_PROCESS_SEGMENT;
221
queryStatistics.AdapterLuid = adapterDesc.AdapterLuid;
222
queryStatistics.hProcess = ProcessHandle;
223
queryStatistics.QueryProcessSegment.SegmentId = i;
224
if (NT_SUCCESS(queryD3DKMTStatistics(&queryStatistics))) {
225
ULONGLONG bytesCommitted;
226
if (!IsWin8OrLater())
227
bytesCommitted = queryStatistics.QueryResult.ProcessSegmentInfo
228
.Win7.BytesCommitted;
229
else
230
bytesCommitted = queryStatistics.QueryResult.ProcessSegmentInfo
231
.Win8.BytesCommitted;
232
if (aperture)
233
sharedBytesUsed += bytesCommitted;
234
else
235
dedicatedBytesUsed += bytesCommitted;
236
}
237
}
238
}
239
}
240
}
241
242
FreeLibrary(gdi32Handle);
243
244
MOZ_COLLECT_REPORT("gpu-committed", KIND_OTHER, UNITS_BYTES,
245
committedBytesUsed,
246
"Memory committed by the Windows graphics system.");
247
248
MOZ_COLLECT_REPORT(
249
"gpu-dedicated", KIND_OTHER, UNITS_BYTES, dedicatedBytesUsed,
250
"Out-of-process memory allocated for this process in a physical "
251
"GPU adapter's memory.");
252
253
MOZ_COLLECT_REPORT("gpu-shared", KIND_OTHER, UNITS_BYTES, sharedBytesUsed,
254
"In-process memory that is shared with the GPU.");
255
256
return NS_OK;
257
}
258
};
259
260
NS_IMPL_ISUPPORTS(GPUAdapterReporter, nsIMemoryReporter)
261
262
Atomic<size_t> gfxWindowsPlatform::sD3D11SharedTextures;
263
Atomic<size_t> gfxWindowsPlatform::sD3D9SharedTextures;
264
265
class D3DSharedTexturesReporter final : public nsIMemoryReporter {
266
~D3DSharedTexturesReporter() {}
267
268
public:
269
NS_DECL_ISUPPORTS
270
271
NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport,
272
nsISupports* aData, bool aAnonymize) override {
273
if (gfxWindowsPlatform::sD3D11SharedTextures > 0) {
274
MOZ_COLLECT_REPORT("d3d11-shared-textures", KIND_OTHER, UNITS_BYTES,
275
gfxWindowsPlatform::sD3D11SharedTextures,
276
"D3D11 shared textures.");
277
}
278
279
if (gfxWindowsPlatform::sD3D9SharedTextures > 0) {
280
MOZ_COLLECT_REPORT("d3d9-shared-textures", KIND_OTHER, UNITS_BYTES,
281
gfxWindowsPlatform::sD3D9SharedTextures,
282
"D3D9 shared textures.");
283
}
284
285
return NS_OK;
286
}
287
};
288
289
NS_IMPL_ISUPPORTS(D3DSharedTexturesReporter, nsIMemoryReporter)
290
291
gfxWindowsPlatform::gfxWindowsPlatform() : mRenderMode(RENDER_GDI) {
292
/*
293
* Initialize COM
294
*/
295
CoInitialize(nullptr);
296
297
RegisterStrongMemoryReporter(new GfxD2DVramReporter());
298
RegisterStrongMemoryReporter(new GPUAdapterReporter());
299
RegisterStrongMemoryReporter(new D3DSharedTexturesReporter());
300
}
301
302
gfxWindowsPlatform::~gfxWindowsPlatform() {
303
mozilla::gfx::Factory::D2DCleanup();
304
305
DeviceManagerDx::Shutdown();
306
307
/*
308
* Uninitialize COM
309
*/
310
CoUninitialize();
311
}
312
313
static void UpdateANGLEConfig() {
314
if (!gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) {
315
gfxConfig::Disable(Feature::D3D11_HW_ANGLE, FeatureStatus::Disabled,
316
"D3D11 compositing is disabled");
317
}
318
}
319
320
bool gfxWindowsPlatform::HasBattery() {
321
// Helper classes to manage lifetimes of Windows structs.
322
class MOZ_STACK_CLASS HDevInfoHolder final {
323
public:
324
explicit HDevInfoHolder(HDEVINFO aHandle) : mHandle(aHandle) {}
325
326
~HDevInfoHolder() { ::SetupDiDestroyDeviceInfoList(mHandle); }
327
328
private:
329
HDEVINFO mHandle;
330
};
331
332
class MOZ_STACK_CLASS HandleHolder final {
333
public:
334
explicit HandleHolder(HANDLE aHandle) : mHandle(aHandle) {}
335
336
~HandleHolder() { ::CloseHandle(mHandle); }
337
338
private:
339
HANDLE mHandle;
340
};
341
342
HDEVINFO hdev =
343
::SetupDiGetClassDevs(&GUID_DEVCLASS_BATTERY, nullptr, nullptr,
344
DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
345
if (hdev == INVALID_HANDLE_VALUE) {
346
return true;
347
}
348
349
HDevInfoHolder hdevHolder(hdev);
350
351
DWORD i = 0;
352
SP_DEVICE_INTERFACE_DATA did = {0};
353
did.cbSize = sizeof(did);
354
355
while (::SetupDiEnumDeviceInterfaces(hdev, nullptr, &GUID_DEVCLASS_BATTERY, i,
356
&did)) {
357
DWORD bufferSize = 0;
358
::SetupDiGetDeviceInterfaceDetail(hdev, &did, nullptr, 0, &bufferSize,
359
nullptr);
360
if (::GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
361
return true;
362
}
363
364
UniquePtr<uint8_t[]> buffer(new (std::nothrow) uint8_t[bufferSize]);
365
if (!buffer) {
366
return true;
367
}
368
369
PSP_DEVICE_INTERFACE_DETAIL_DATA pdidd =
370
reinterpret_cast<PSP_DEVICE_INTERFACE_DETAIL_DATA>(buffer.get());
371
pdidd->cbSize = sizeof(*pdidd);
372
if (!::SetupDiGetDeviceInterfaceDetail(hdev, &did, pdidd, bufferSize,
373
&bufferSize, nullptr)) {
374
return true;
375
}
376
377
HANDLE hbat = ::CreateFile(pdidd->DevicePath, GENERIC_READ | GENERIC_WRITE,
378
FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr,
379
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
380
if (hbat == INVALID_HANDLE_VALUE) {
381
return true;
382
}
383
384
HandleHolder hbatHolder(hbat);
385
386
BATTERY_QUERY_INFORMATION bqi = {0};
387
DWORD dwWait = 0;
388
DWORD dwOut;
389
390
// We need the tag to query the information below.
391
if (!::DeviceIoControl(hbat, IOCTL_BATTERY_QUERY_TAG, &dwWait,
392
sizeof(dwWait), &bqi.BatteryTag,
393
sizeof(bqi.BatteryTag), &dwOut, nullptr) ||
394
!bqi.BatteryTag) {
395
return true;
396
}
397
398
BATTERY_INFORMATION bi = {0};
399
bqi.InformationLevel = BatteryInformation;
400
401
if (!::DeviceIoControl(hbat, IOCTL_BATTERY_QUERY_INFORMATION, &bqi,
402
sizeof(bqi), &bi, sizeof(bi), &dwOut, nullptr)) {
403
return true;
404
}
405
406
// If a battery intended for general use (i.e. system use) is not a UPS
407
// (i.e. short term), then we know for certain we have a battery.
408
if ((bi.Capabilities & BATTERY_SYSTEM_BATTERY) &&
409
!(bi.Capabilities & BATTERY_IS_SHORT_TERM)) {
410
return true;
411
}
412
413
// Otherwise we check the next battery.
414
++i;
415
}
416
417
// If we fail to enumerate because there are no more batteries to check, then
418
// we can safely say there are indeed no system batteries.
419
return ::GetLastError() != ERROR_NO_MORE_ITEMS;
420
}
421
422
void gfxWindowsPlatform::InitAcceleration() {
423
gfxPlatform::InitAcceleration();
424
425
DeviceManagerDx::Init();
426
427
InitializeConfig();
428
// Ensure devices initialization. SharedSurfaceANGLE and
429
// SharedSurfaceD3D11Interop use them. The devices are lazily initialized
430
// with WebRender to reduce memory usage.
431
// Initialize them now when running non-e10s.
432
if (!BrowserTabsRemoteAutostart()) {
433
EnsureDevicesInitialized();
434
}
435
UpdateANGLEConfig();
436
UpdateRenderMode();
437
438
// If we have Skia and we didn't init dwrite already, do it now.
439
if (!DWriteEnabled() && GetDefaultContentBackend() == BackendType::SKIA) {
440
InitDWriteSupport();
441
}
442
// We need to listen for font setting changes even if DWrite is not used.
443
Factory::SetSystemTextQuality(gfxVars::SystemTextQuality());
444
gfxVars::SetSystemTextQualityListener(
445
gfxDWriteFont::SystemTextQualityChanged);
446
447
// CanUseHardwareVideoDecoding depends on DeviceManagerDx state,
448
// so update the cached value now.
449
UpdateCanUseHardwareVideoDecoding();
450
451
RecordStartupTelemetry();
452
}
453
454
void gfxWindowsPlatform::InitWebRenderConfig() {
455
gfxPlatform::InitWebRenderConfig();
456
457
if (gfxVars::UseWebRender()) {
458
UpdateBackendPrefs();
459
}
460
}
461
462
bool gfxWindowsPlatform::CanUseHardwareVideoDecoding() {
463
DeviceManagerDx* dm = DeviceManagerDx::Get();
464
if (!dm) {
465
return false;
466
}
467
if (!dm->TextureSharingWorks()) {
468
return false;
469
}
470
return !dm->IsWARP() && gfxPlatform::CanUseHardwareVideoDecoding();
471
}
472
473
bool gfxWindowsPlatform::InitDWriteSupport() {
474
mozilla::ScopedGfxFeatureReporter reporter("DWrite");
475
if (!Factory::EnsureDWriteFactory()) {
476
return false;
477
}
478
479
SetupClearTypeParams();
480
reporter.SetSuccessful();
481
return true;
482
}
483
484
bool gfxWindowsPlatform::HandleDeviceReset() {
485
DeviceResetReason resetReason = DeviceResetReason::OK;
486
if (!DidRenderingDeviceReset(&resetReason)) {
487
return false;
488
}
489
490
if (resetReason != DeviceResetReason::FORCED_RESET) {
491
Telemetry::Accumulate(Telemetry::DEVICE_RESET_REASON,
492
uint32_t(resetReason));
493
}
494
495
// Remove devices and adapters.
496
DeviceManagerDx::Get()->ResetDevices();
497
498
imgLoader::NormalLoader()->ClearCache(true);
499
imgLoader::NormalLoader()->ClearCache(false);
500
imgLoader::PrivateBrowsingLoader()->ClearCache(true);
501
imgLoader::PrivateBrowsingLoader()->ClearCache(false);
502
gfxAlphaBoxBlur::ShutdownBlurCache();
503
504
gfxConfig::Reset(Feature::D3D11_COMPOSITING);
505
gfxConfig::Reset(Feature::ADVANCED_LAYERS);
506
gfxConfig::Reset(Feature::D3D11_HW_ANGLE);
507
gfxConfig::Reset(Feature::DIRECT2D);
508
509
InitializeConfig();
510
if (mInitializedDevices) {
511
InitializeDevices();
512
}
513
UpdateANGLEConfig();
514
return true;
515
}
516
517
BackendPrefsData gfxWindowsPlatform::GetBackendPrefs() const {
518
BackendPrefsData data;
519
520
data.mCanvasBitmask = BackendTypeBit(BackendType::SKIA);
521
data.mContentBitmask = BackendTypeBit(BackendType::SKIA);
522
data.mCanvasDefault = BackendType::SKIA;
523
data.mContentDefault = BackendType::SKIA;
524
525
if (gfxConfig::IsEnabled(Feature::DIRECT2D)) {
526
data.mCanvasBitmask |= BackendTypeBit(BackendType::DIRECT2D1_1);
527
data.mCanvasDefault = BackendType::DIRECT2D1_1;
528
// We do not use d2d for content when WebRender is used.
529
if (!gfxVars::UseWebRender()) {
530
data.mContentBitmask |= BackendTypeBit(BackendType::DIRECT2D1_1);
531
data.mContentDefault = BackendType::DIRECT2D1_1;
532
}
533
}
534
return data;
535
}
536
537
void gfxWindowsPlatform::UpdateBackendPrefs() {
538
BackendPrefsData data = GetBackendPrefs();
539
// Remove DIRECT2D1 preference if D2D1Device does not exist.
540
if (!Factory::HasD2D1Device()) {
541
data.mCanvasBitmask &= ~BackendTypeBit(BackendType::DIRECT2D1_1);
542
data.mContentBitmask &= ~BackendTypeBit(BackendType::DIRECT2D1_1);
543
if (data.mCanvasDefault == BackendType::DIRECT2D1_1) {
544
data.mCanvasDefault = BackendType::SKIA;
545
}
546
if (data.mContentDefault == BackendType::DIRECT2D1_1) {
547
data.mContentDefault = BackendType::SKIA;
548
}
549
}
550
InitBackendPrefs(std::move(data));
551
}
552
553
bool gfxWindowsPlatform::IsDirect2DBackend() {
554
return GetDefaultContentBackend() == BackendType::DIRECT2D1_1;
555
}
556
557
void gfxWindowsPlatform::UpdateRenderMode() {
558
bool didReset = HandleDeviceReset();
559
560
UpdateBackendPrefs();
561
562
if (PaintThread::Get()) {
563
PaintThread::Get()->UpdateRenderMode();
564
}
565
566
if (didReset) {
567
mScreenReferenceDrawTarget = CreateOffscreenContentDrawTarget(
568
IntSize(1, 1), SurfaceFormat::B8G8R8A8);
569
if (!mScreenReferenceDrawTarget) {
570
gfxCriticalNote
571
<< "Failed to update reference draw target after device reset"
572
<< ", D3D11 device:" << hexa(Factory::GetDirect3D11Device().get())
573
<< ", D3D11 status:"
574
<< FeatureStatusToString(
575
gfxConfig::GetValue(Feature::D3D11_COMPOSITING))
576
<< ", D2D1 device:" << hexa(Factory::GetD2D1Device().get())
577
<< ", D2D1 status:"
578
<< FeatureStatusToString(gfxConfig::GetValue(Feature::DIRECT2D))
579
<< ", content:" << int(GetDefaultContentBackend())
580
<< ", compositor:" << int(GetCompositorBackend());
581
MOZ_CRASH(
582
"GFX: Failed to update reference draw target after device reset");
583
}
584
}
585
}
586
587
mozilla::gfx::BackendType gfxWindowsPlatform::GetContentBackendFor(
588
mozilla::layers::LayersBackend aLayers) {
589
mozilla::gfx::BackendType defaultBackend =
590
gfxPlatform::GetDefaultContentBackend();
591
if (aLayers == LayersBackend::LAYERS_D3D11) {
592
return defaultBackend;
593
}
594
595
if (aLayers == LayersBackend::LAYERS_WR &&
596
gfx::gfxVars::UseWebRenderANGLE()) {
597
return defaultBackend;
598
}
599
600
if (defaultBackend == BackendType::DIRECT2D1_1) {
601
// We can't have D2D without D3D11 layers, so fallback to Skia.
602
return BackendType::SKIA;
603
}
604
605
// Otherwise we have some non-accelerated backend and that's ok.
606
return defaultBackend;
607
}
608
609
mozilla::gfx::BackendType gfxWindowsPlatform::GetPreferredCanvasBackend() {
610
mozilla::gfx::BackendType backend = gfxPlatform::GetPreferredCanvasBackend();
611
612
if (backend == BackendType::DIRECT2D1_1 && gfx::gfxVars::UseWebRender() &&
613
!gfx::gfxVars::UseWebRenderANGLE()) {
614
// We can't have D2D without ANGLE when WebRender is enabled, so fallback to
615
// Skia.
616
return BackendType::SKIA;
617
}
618
return backend;
619
}
620
621
gfxPlatformFontList* gfxWindowsPlatform::CreatePlatformFontList() {
622
gfxPlatformFontList* pfl;
623
624
// bug 630201 - older pre-RTM versions of Direct2D/DirectWrite cause odd
625
// crashers so blacklist them altogether
626
if (IsNotWin7PreRTM() && DWriteEnabled()) {
627
pfl = new gfxDWriteFontList();
628
if (NS_SUCCEEDED(pfl->InitFontList())) {
629
return pfl;
630
}
631
// DWrite font initialization failed! Don't know why this would happen,
632
// but apparently it can - see bug 594865.
633
// So we're going to fall back to GDI fonts & rendering.
634
gfxPlatformFontList::Shutdown();
635
DisableD2D(FeatureStatus::Failed, "Failed to initialize fonts",
636
NS_LITERAL_CSTRING("FEATURE_FAILURE_FONT_FAIL"));
637
}
638
639
// Ensure this is false, even if the Windows version was recent enough to
640
// permit it, as we're using GDI fonts.
641
mHasVariationFontSupport = false;
642
643
pfl = new gfxGDIFontList();
644
645
if (NS_SUCCEEDED(pfl->InitFontList())) {
646
return pfl;
647
}
648
649
gfxPlatformFontList::Shutdown();
650
return nullptr;
651
}
652
653
// This function will permanently disable D2D for the session. It's intended to
654
// be used when, after initially chosing to use Direct2D, we encounter a
655
// scenario we can't support.
656
//
657
// This is called during gfxPlatform::Init() so at this point there should be no
658
// DrawTargetD2D/1 instances.
659
void gfxWindowsPlatform::DisableD2D(FeatureStatus aStatus, const char* aMessage,
660
const nsACString& aFailureId) {
661
gfxConfig::SetFailed(Feature::DIRECT2D, aStatus, aMessage, aFailureId);
662
Factory::SetDirect3D11Device(nullptr);
663
UpdateBackendPrefs();
664
}
665
666
already_AddRefed<gfxASurface> gfxWindowsPlatform::CreateOffscreenSurface(
667
const IntSize& aSize, gfxImageFormat aFormat) {
668
if (!Factory::AllowedSurfaceSize(aSize)) {
669
return nullptr;
670
}
671
672
RefPtr<gfxASurface> surf = nullptr;
673
674
#ifdef CAIRO_HAS_WIN32_SURFACE
675
if (mRenderMode == RENDER_GDI || mRenderMode == RENDER_DIRECT2D)
676
surf = new gfxWindowsSurface(aSize, aFormat);
677
#endif
678
679
if (!surf || surf->CairoStatus()) {
680
surf = new gfxImageSurface(aSize, aFormat);
681
}
682
683
return surf.forget();
684
}
685
686
static const char kFontAparajita[] = "Aparajita";
687
static const char kFontArabicTypesetting[] = "Arabic Typesetting";
688
static const char kFontArial[] = "Arial";
689
static const char kFontArialUnicodeMS[] = "Arial Unicode MS";
690
static const char kFontCambria[] = "Cambria";
691
static const char kFontCambriaMath[] = "Cambria Math";
692
static const char kFontEbrima[] = "Ebrima";
693
static const char kFontEstrangeloEdessa[] = "Estrangelo Edessa";
694
static const char kFontEuphemia[] = "Euphemia";
695
static const char kFontGabriola[] = "Gabriola";
696
static const char kFontJavaneseText[] = "Javanese Text";
697
static const char kFontKhmerUI[] = "Khmer UI";
698
static const char kFontLaoUI[] = "Lao UI";
699
static const char kFontLeelawadeeUI[] = "Leelawadee UI";
700
static const char kFontLucidaSansUnicode[] = "Lucida Sans Unicode";
701
static const char kFontMVBoli[] = "MV Boli";
702
static const char kFontMalgunGothic[] = "Malgun Gothic";
703
static const char kFontMicrosoftJhengHei[] = "Microsoft JhengHei";
704
static const char kFontMicrosoftNewTaiLue[] = "Microsoft New Tai Lue";
705
static const char kFontMicrosoftPhagsPa[] = "Microsoft PhagsPa";
706
static const char kFontMicrosoftTaiLe[] = "Microsoft Tai Le";
707
static const char kFontMicrosoftUighur[] = "Microsoft Uighur";
708
static const char kFontMicrosoftYaHei[] = "Microsoft YaHei";
709
static const char kFontMicrosoftYiBaiti[] = "Microsoft Yi Baiti";
710
static const char kFontMeiryo[] = "Meiryo";
711
static const char kFontMongolianBaiti[] = "Mongolian Baiti";
712
static const char kFontMyanmarText[] = "Myanmar Text";
713
static const char kFontNirmalaUI[] = "Nirmala UI";
714
static const char kFontNyala[] = "Nyala";
715
static const char kFontPlantagenetCherokee[] = "Plantagenet Cherokee";
716
static const char kFontSegoeUI[] = "Segoe UI";
717
static const char kFontSegoeUIEmoji[] = "Segoe UI Emoji";
718
static const char kFontSegoeUISymbol[] = "Segoe UI Symbol";
719
static const char kFontSylfaen[] = "Sylfaen";
720
static const char kFontTraditionalArabic[] = "Traditional Arabic";
721
static const char kFontTwemojiMozilla[] = "Twemoji Mozilla";
722
static const char kFontUtsaah[] = "Utsaah";
723
static const char kFontYuGothic[] = "Yu Gothic";
724
725
void gfxWindowsPlatform::GetCommonFallbackFonts(
726
uint32_t aCh, uint32_t aNextCh, Script aRunScript,
727
nsTArray<const char*>& aFontList) {
728
EmojiPresentation emoji = GetEmojiPresentation(aCh);
729
if (emoji != EmojiPresentation::TextOnly) {
730
if (aNextCh == kVariationSelector16 ||
731
(aNextCh != kVariationSelector15 &&
732
emoji == EmojiPresentation::EmojiDefault)) {
733
// if char is followed by VS16, try for a color emoji glyph
734
aFontList.AppendElement(kFontSegoeUIEmoji);
735
aFontList.AppendElement(kFontTwemojiMozilla);
736
}
737
}
738
739
// Arial is used as the default fallback for system fallback
740
aFontList.AppendElement(kFontArial);
741
742
if (!IS_IN_BMP(aCh)) {
743
uint32_t p = aCh >> 16;
744
if (p == 1) { // SMP plane
745
aFontList.AppendElement(kFontSegoeUISymbol);
746
aFontList.AppendElement(kFontEbrima);
747
aFontList.AppendElement(kFontNirmalaUI);
748
aFontList.AppendElement(kFontCambriaMath);
749
}
750
} else {
751
uint32_t b = (aCh >> 8) & 0xff;
752
753
switch (b) {
754
case 0x05:
755
aFontList.AppendElement(kFontEstrangeloEdessa);
756
aFontList.AppendElement(kFontCambria);
757
break;
758
case 0x06:
759
aFontList.AppendElement(kFontMicrosoftUighur);
760
break;
761
case 0x07:
762
aFontList.AppendElement(kFontEstrangeloEdessa);
763
aFontList.AppendElement(kFontMVBoli);
764
aFontList.AppendElement(kFontEbrima);
765
break;
766
case 0x09:
767
aFontList.AppendElement(kFontNirmalaUI);
768
aFontList.AppendElement(kFontUtsaah);
769
aFontList.AppendElement(kFontAparajita);
770
break;
771
case 0x0a:
772
case 0x0b:
773
case 0x0c:
774
case 0x0d:
775
aFontList.AppendElement(kFontNirmalaUI);
776
break;
777
case 0x0e:
778
aFontList.AppendElement(kFontLaoUI);
779
aFontList.AppendElement(kFontLeelawadeeUI);
780
break;
781
case 0x10:
782
aFontList.AppendElement(kFontMyanmarText);
783
break;
784
case 0x11:
785
aFontList.AppendElement(kFontMalgunGothic);
786
break;
787
case 0x12:
788
case 0x13:
789
aFontList.AppendElement(kFontNyala);
790
aFontList.AppendElement(kFontPlantagenetCherokee);
791
break;
792
case 0x14:
793
case 0x15:
794
case 0x16:
795
aFontList.AppendElement(kFontEuphemia);
796
aFontList.AppendElement(kFontSegoeUISymbol);
797
break;
798
case 0x17:
799
aFontList.AppendElement(kFontKhmerUI);
800
aFontList.AppendElement(kFontLeelawadeeUI);
801
break;
802
case 0x18: // Mongolian
803
aFontList.AppendElement(kFontMongolianBaiti);
804
aFontList.AppendElement(kFontEuphemia);
805
break;
806
case 0x19:
807
aFontList.AppendElement(kFontMicrosoftTaiLe);
808
aFontList.AppendElement(kFontMicrosoftNewTaiLue);
809
aFontList.AppendElement(kFontKhmerUI);
810
aFontList.AppendElement(kFontLeelawadeeUI);
811
break;
812
case 0x1a:
813
aFontList.AppendElement(kFontLeelawadeeUI);
814
break;
815
case 0x1c:
816
aFontList.AppendElement(kFontNirmalaUI);
817
break;
818
case 0x20: // Symbol ranges
819
case 0x21:
820
case 0x22:
821
case 0x23:
822
case 0x24:
823
case 0x25:
824
case 0x26:
825
case 0x27:
826
case 0x29:
827
case 0x2a:
828
case 0x2b:
829
case 0x2c:
830
aFontList.AppendElement(kFontSegoeUI);
831
aFontList.AppendElement(kFontSegoeUISymbol);
832
aFontList.AppendElement(kFontCambria);
833
aFontList.AppendElement(kFontMeiryo);
834
aFontList.AppendElement(kFontArial);
835
aFontList.AppendElement(kFontLucidaSansUnicode);
836
aFontList.AppendElement(kFontEbrima);
837
break;
838
case 0x2d:
839
case 0x2e:
840
case 0x2f:
841
aFontList.AppendElement(kFontEbrima);
842
aFontList.AppendElement(kFontNyala);
843
aFontList.AppendElement(kFontSegoeUI);
844
aFontList.AppendElement(kFontSegoeUISymbol);
845
aFontList.AppendElement(kFontMeiryo);
846
break;
847
case 0x28: // Braille
848
aFontList.AppendElement(kFontSegoeUISymbol);
849
break;
850
case 0x30:
851
case 0x31:
852
aFontList.AppendElement(kFontMicrosoftYaHei);
853
break;
854
case 0x32:
855
aFontList.AppendElement(kFontMalgunGothic);
856
break;
857
case 0x4d:
858
aFontList.AppendElement(kFontSegoeUISymbol);
859
break;
860
case 0x9f:
861
aFontList.AppendElement(kFontMicrosoftYaHei);
862
aFontList.AppendElement(kFontYuGothic);
863
break;
864
case 0xa0: // Yi
865
case 0xa1:
866
case 0xa2:
867
case 0xa3:
868
case 0xa4:
869
aFontList.AppendElement(kFontMicrosoftYiBaiti);
870
aFontList.AppendElement(kFontSegoeUI);
871
break;
872
case 0xa5:
873
case 0xa6:
874
case 0xa7:
875
aFontList.AppendElement(kFontEbrima);
876
aFontList.AppendElement(kFontSegoeUI);
877
aFontList.AppendElement(kFontCambriaMath);
878
break;
879
case 0xa8:
880
aFontList.AppendElement(kFontMicrosoftPhagsPa);
881
aFontList.AppendElement(kFontNirmalaUI);
882
break;
883
case 0xa9:
884
aFontList.AppendElement(kFontMalgunGothic);
885
aFontList.AppendElement(kFontJavaneseText);
886
aFontList.AppendElement(kFontLeelawadeeUI);
887
break;
888
case 0xaa:
889
aFontList.AppendElement(kFontMyanmarText);
890
break;
891
case 0xab:
892
aFontList.AppendElement(kFontEbrima);
893
aFontList.AppendElement(kFontNyala);
894
break;
895
case 0xd7:
896
aFontList.AppendElement(kFontMalgunGothic);
897
break;
898
case 0xfb:
899
aFontList.AppendElement(kFontMicrosoftUighur);
900
aFontList.AppendElement(kFontGabriola);
901
aFontList.AppendElement(kFontSylfaen);
902
break;
903
case 0xfc:
904
case 0xfd:
905
aFontList.AppendElement(kFontTraditionalArabic);
906
aFontList.AppendElement(kFontArabicTypesetting);
907
break;
908
case 0xfe:
909
aFontList.AppendElement(kFontTraditionalArabic);
910
aFontList.AppendElement(kFontMicrosoftJhengHei);
911
break;
912
case 0xff:
913
aFontList.AppendElement(kFontMicrosoftJhengHei);
914
break;
915
default:
916
break;
917
}
918
}
919
920
// Arial Unicode MS has lots of glyphs for obscure characters,
921
// use it as a last resort
922
aFontList.AppendElement(kFontArialUnicodeMS);
923
}
924
925
gfxFontGroup* gfxWindowsPlatform::CreateFontGroup(
926
const FontFamilyList& aFontFamilyList, const gfxFontStyle* aStyle,
927
gfxTextPerfMetrics* aTextPerf, gfxUserFontSet* aUserFontSet,
928
gfxFloat aDevToCssSize) {
929
return new gfxFontGroup(aFontFamilyList, aStyle, aTextPerf, aUserFontSet,
930
aDevToCssSize);
931
}
932
933
bool gfxWindowsPlatform::DidRenderingDeviceReset(
934
DeviceResetReason* aResetReason) {
935
DeviceManagerDx* dm = DeviceManagerDx::Get();
936
if (!dm) {
937
return false;
938
}
939
return dm->HasDeviceReset(aResetReason);
940
}
941
942
void gfxWindowsPlatform::CompositorUpdated() {
943
DeviceManagerDx::Get()->ForceDeviceReset(
944
ForcedDeviceResetReason::COMPOSITOR_UPDATED);
945
UpdateRenderMode();
946
}
947
948
BOOL CALLBACK InvalidateWindowForDeviceReset(HWND aWnd, LPARAM aMsg) {
949
RedrawWindow(aWnd, nullptr, nullptr,
950
RDW_INVALIDATE | RDW_INTERNALPAINT | RDW_FRAME);
951
return TRUE;
952
}
953
954
void gfxWindowsPlatform::SchedulePaintIfDeviceReset() {
955
AUTO_PROFILER_LABEL("gfxWindowsPlatform::SchedulePaintIfDeviceReset", OTHER);
956
957
DeviceResetReason resetReason = DeviceResetReason::OK;
958
if (!DidRenderingDeviceReset(&resetReason)) {
959
return;
960
}
961
962
gfxCriticalNote << "(gfxWindowsPlatform) Detected device reset: "
963
<< (int)resetReason;
964
965
if (XRE_IsParentProcess()) {
966
// Trigger an ::OnPaint for each window.
967
::EnumThreadWindows(GetCurrentThreadId(), InvalidateWindowForDeviceReset,
968
0);
969
} else {
970
NS_DispatchToMainThread(NS_NewRunnableFunction(
971
"gfx::gfxWindowsPlatform::SchedulePaintIfDeviceReset", []() -> void {
972
gfxWindowsPlatform::GetPlatform()->CheckForContentOnlyDeviceReset();
973
}));
974
}
975
976
gfxCriticalNote << "(gfxWindowsPlatform) scheduled device update.";
977
}
978
979
void gfxWindowsPlatform::CheckForContentOnlyDeviceReset() {
980
if (!DidRenderingDeviceReset()) {
981
return;
982
}
983
984
bool isContentOnlyTDR;
985
D3D11DeviceStatus status;
986
987
DeviceManagerDx::Get()->ExportDeviceInfo(&status);
988
CompositorBridgeChild::Get()->SendCheckContentOnlyTDR(status.sequenceNumber(),
989
&isContentOnlyTDR);
990
991
// The parent process doesn't know about the reset yet, or the reset is
992
// local to our device.
993
if (isContentOnlyTDR) {
994
gfxCriticalNote << "A content-only TDR is detected.";
995
dom::ContentChild* cc = dom::ContentChild::GetSingleton();
996
cc->RecvReinitRenderingForDeviceReset();
997
}
998
}
999
1000
void gfxWindowsPlatform::GetPlatformCMSOutputProfile(void*& mem,
1001
size_t& mem_size) {
1002
WCHAR str[MAX_PATH];
1003
DWORD size = MAX_PATH;
1004
BOOL res;
1005
1006
mem = nullptr;
1007
mem_size = 0;
1008
1009
HDC dc = GetDC(nullptr);
1010
if (!dc) return;
1011
1012
MOZ_SEH_TRY { res = GetICMProfileW(dc, &size, (LPWSTR)&str); }
1013
MOZ_SEH_EXCEPT(GetExceptionCode() == EXCEPTION_ILLEGAL_INSTRUCTION) {
1014
res = FALSE;
1015
}
1016
1017
ReleaseDC(nullptr, dc);
1018
if (!res) return;
1019
1020
#ifdef _WIN32
1021
qcms_data_from_unicode_path(str, &mem, &mem_size);
1022
1023
# ifdef DEBUG_tor
1024
if (mem_size > 0)
1025
fprintf(stderr, "ICM profile read from %s successfully\n",
1026
NS_ConvertUTF16toUTF8(str).get());
1027
# endif // DEBUG_tor
1028
#endif // _WIN32
1029
}
1030
1031
void gfxWindowsPlatform::GetDLLVersion(char16ptr_t aDLLPath,
1032
nsAString& aVersion) {
1033
DWORD versInfoSize, vers[4] = {0};
1034
// version info not available case
1035
aVersion.AssignLiteral(u"0.0.0.0");
1036
versInfoSize = GetFileVersionInfoSizeW(aDLLPath, nullptr);
1037
AutoTArray<BYTE, 512> versionInfo;
1038
1039
if (versInfoSize == 0 ||
1040
!versionInfo.AppendElements(uint32_t(versInfoSize))) {
1041
return;
1042
}
1043
1044
if (!GetFileVersionInfoW(aDLLPath, 0, versInfoSize,
1045
LPBYTE(versionInfo.Elements()))) {
1046
return;
1047
}
1048
1049
UINT len = 0;
1050
VS_FIXEDFILEINFO* fileInfo = nullptr;
1051
if (!VerQueryValue(LPBYTE(versionInfo.Elements()), TEXT("\\"),
1052
(LPVOID*)&fileInfo, &len) ||
1053
len == 0 || fileInfo == nullptr) {
1054
return;
1055
}
1056
1057
DWORD fileVersMS = fileInfo->dwFileVersionMS;
1058
DWORD fileVersLS = fileInfo->dwFileVersionLS;
1059
1060
vers[0] = HIWORD(fileVersMS);
1061
vers[1] = LOWORD(fileVersMS);
1062
vers[2] = HIWORD(fileVersLS);
1063
vers[3] = LOWORD(fileVersLS);
1064
1065
char buf[256];
1066
SprintfLiteral(buf, "%u.%u.%u.%u", vers[0], vers[1], vers[2], vers[3]);
1067
aVersion.Assign(NS_ConvertUTF8toUTF16(buf));
1068
}
1069
1070
static BOOL CALLBACK AppendClearTypeParams(HMONITOR aMonitor, HDC, LPRECT,
1071
LPARAM aContext) {
1072
MONITORINFOEXW monitorInfo;
1073
monitorInfo.cbSize = sizeof(MONITORINFOEXW);
1074
if (!GetMonitorInfoW(aMonitor, &monitorInfo)) {
1075
return TRUE;
1076
}
1077
1078
ClearTypeParameterInfo ctinfo;
1079
ctinfo.displayName.Assign(monitorInfo.szDevice);
1080
1081
RefPtr<IDWriteRenderingParams> renderingParams;
1082
HRESULT hr = Factory::GetDWriteFactory()->CreateMonitorRenderingParams(
1083
aMonitor, getter_AddRefs(renderingParams));
1084
if (FAILED(hr)) {
1085
return TRUE;
1086
}
1087
1088
ctinfo.gamma = renderingParams->GetGamma() * 1000;
1089
ctinfo.pixelStructure = renderingParams->GetPixelGeometry();
1090
ctinfo.clearTypeLevel = renderingParams->GetClearTypeLevel() * 100;
1091
ctinfo.enhancedContrast = renderingParams->GetEnhancedContrast() * 100;
1092
1093
auto* params = reinterpret_cast<nsTArray<ClearTypeParameterInfo>*>(aContext);
1094
params->AppendElement(ctinfo);
1095
return TRUE;
1096
}
1097
1098
void gfxWindowsPlatform::GetCleartypeParams(
1099
nsTArray<ClearTypeParameterInfo>& aParams) {
1100
aParams.Clear();
1101
if (!DWriteEnabled()) {
1102
return;
1103
}
1104
EnumDisplayMonitors(nullptr, nullptr, AppendClearTypeParams,
1105
reinterpret_cast<LPARAM>(&aParams));
1106
}
1107
1108
void gfxWindowsPlatform::FontsPrefsChanged(const char* aPref) {
1109
bool clearTextFontCaches = true;
1110
1111
gfxPlatform::FontsPrefsChanged(aPref);
1112
1113
if (aPref &&
1114
!strncmp(GFX_CLEARTYPE_PARAMS, aPref, strlen(GFX_CLEARTYPE_PARAMS))) {
1115
SetupClearTypeParams();
1116
} else {
1117
clearTextFontCaches = false;
1118
}
1119
1120
if (clearTextFontCaches) {
1121
gfxFontCache* fc = gfxFontCache::GetCache();
1122
if (fc) {
1123
fc->Flush();
1124
}
1125
}
1126
}
1127
1128
#define DISPLAY1_REGISTRY_KEY \
1129
HKEY_CURRENT_USER, L"Software\\Microsoft\\Avalon.Graphics\\DISPLAY1"
1130
1131
#define ENHANCED_CONTRAST_VALUE_NAME L"EnhancedContrastLevel"
1132
1133
void gfxWindowsPlatform::SetupClearTypeParams() {
1134
if (DWriteEnabled()) {
1135
// any missing prefs will default to invalid (-1) and be ignored;
1136
// out-of-range values will also be ignored
1137
FLOAT gamma = -1.0;
1138
FLOAT contrast = -1.0;
1139
FLOAT level = -1.0;
1140
int geometry = -1;
1141
int mode = -1;
1142
int32_t value;
1143
if (NS_SUCCEEDED(Preferences::GetInt(GFX_CLEARTYPE_PARAMS_GAMMA, &value))) {
1144
if (value >= 1000 && value <= 2200) {
1145
gamma = FLOAT(value / 1000.0);
1146
}
1147
}
1148
1149
if (NS_SUCCEEDED(
1150
Preferences::GetInt(GFX_CLEARTYPE_PARAMS_CONTRAST, &value))) {
1151
if (value >= 0 && value <= 1000) {
1152
contrast = FLOAT(value / 100.0);
1153
}
1154
}
1155
1156
if (NS_SUCCEEDED(Preferences::GetInt(GFX_CLEARTYPE_PARAMS_LEVEL, &value))) {
1157
if (value >= 0 && value <= 100) {
1158
level = FLOAT(value / 100.0);
1159
}
1160
}
1161
1162
if (NS_SUCCEEDED(
1163
Preferences::GetInt(GFX_CLEARTYPE_PARAMS_STRUCTURE, &value))) {
1164
if (value >= 0 && value <= 2) {
1165
geometry = value;
1166
}
1167
}
1168
1169
if (NS_SUCCEEDED(Preferences::GetInt(GFX_CLEARTYPE_PARAMS_MODE, &value))) {
1170
if (value >= 0 && value <= 5) {
1171
mode = value;
1172
}
1173
}
1174
1175
cairo_dwrite_set_cleartype_params(gamma, contrast, level, geometry, mode);
1176
1177
switch (mode) {
1178
case DWRITE_RENDERING_MODE_ALIASED:
1179
case DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC:
1180
mMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC;
1181
break;
1182
case DWRITE_RENDERING_MODE_CLEARTYPE_GDI_NATURAL:
1183
mMeasuringMode = DWRITE_MEASURING_MODE_GDI_NATURAL;
1184
break;
1185
default:
1186
mMeasuringMode = DWRITE_MEASURING_MODE_NATURAL;
1187
break;
1188
}
1189
1190
RefPtr<IDWriteRenderingParams> defaultRenderingParams;
1191
Factory::GetDWriteFactory()->CreateRenderingParams(
1192
getter_AddRefs(defaultRenderingParams));
1193
// For EnhancedContrast, we override the default if the user has not set it
1194
// in the registry (by using the ClearType Tuner).
1195
if (contrast < 0.0 || contrast > 10.0) {
1196
HKEY hKey;
1197
LONG res = RegOpenKeyExW(DISPLAY1_REGISTRY_KEY, 0, KEY_READ, &hKey);
1198
if (res == ERROR_SUCCESS) {
1199
res = RegQueryValueExW(hKey, ENHANCED_CONTRAST_VALUE_NAME, nullptr,
1200
nullptr, nullptr, nullptr);
1201
if (res == ERROR_SUCCESS) {
1202
contrast = defaultRenderingParams->GetEnhancedContrast();
1203
}
1204
RegCloseKey(hKey);
1205
}
1206
1207
if (contrast < 0.0 || contrast > 10.0) {
1208
contrast = 1.0;
1209
}
1210
}
1211
1212
// For parameters that have not been explicitly set,
1213
// we copy values from default params (or our overridden value for contrast)
1214
if (gamma < 1.0 || gamma > 2.2) {
1215
gamma = defaultRenderingParams->GetGamma();
1216
}
1217
1218
if (level < 0.0 || level > 1.0) {
1219
level = defaultRenderingParams->GetClearTypeLevel();
1220
}
1221
1222
DWRITE_PIXEL_GEOMETRY dwriteGeometry =
1223
static_cast<DWRITE_PIXEL_GEOMETRY>(geometry);
1224
DWRITE_RENDERING_MODE renderMode = static_cast<DWRITE_RENDERING_MODE>(mode);
1225
1226
if (dwriteGeometry < DWRITE_PIXEL_GEOMETRY_FLAT ||
1227
dwriteGeometry > DWRITE_PIXEL_GEOMETRY_BGR) {
1228
dwriteGeometry = defaultRenderingParams->GetPixelGeometry();
1229
}
1230
1231
Factory::SetBGRSubpixelOrder(dwriteGeometry == DWRITE_PIXEL_GEOMETRY_BGR);
1232
1233
if (renderMode < DWRITE_RENDERING_MODE_DEFAULT ||
1234
renderMode > DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC) {
1235
renderMode = defaultRenderingParams->GetRenderingMode();
1236
}
1237
1238
mRenderingParams[TEXT_RENDERING_NO_CLEARTYPE] = defaultRenderingParams;
1239
1240
HRESULT hr = Factory::GetDWriteFactory()->CreateCustomRenderingParams(
1241
gamma, contrast, level, dwriteGeometry, renderMode,
1242
getter_AddRefs(mRenderingParams[TEXT_RENDERING_NORMAL]));
1243
if (FAILED(hr) || !mRenderingParams[TEXT_RENDERING_NORMAL]) {
1244
mRenderingParams[TEXT_RENDERING_NORMAL] = defaultRenderingParams;
1245
}
1246
1247
hr = Factory::GetDWriteFactory()->CreateCustomRenderingParams(
1248
gamma, contrast, level, dwriteGeometry,
1249
DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC,
1250
getter_AddRefs(mRenderingParams[TEXT_RENDERING_GDI_CLASSIC]));
1251
if (FAILED(hr) || !mRenderingParams[TEXT_RENDERING_GDI_CLASSIC]) {
1252
mRenderingParams[TEXT_RENDERING_GDI_CLASSIC] = defaultRenderingParams;
1253
}
1254
}
1255
}
1256
1257
ReadbackManagerD3D11* gfxWindowsPlatform::GetReadbackManager() {
1258
if (!mD3D11ReadbackManager) {
1259
mD3D11ReadbackManager = new ReadbackManagerD3D11();
1260
}
1261
1262
return mD3D11ReadbackManager;
1263
}
1264
1265
bool gfxWindowsPlatform::IsOptimus() {
1266
static int knowIsOptimus = -1;
1267
if (knowIsOptimus == -1) {
1268
// other potential optimus -- nvd3d9wrapx.dll & nvdxgiwrap.dll
1269
if (GetModuleHandleA("nvumdshim.dll") ||
1270
GetModuleHandleA("nvumdshimx.dll")) {
1271
knowIsOptimus = 1;
1272
} else {
1273
knowIsOptimus = 0;
1274
}
1275
}
1276
return knowIsOptimus;
1277
}
1278
/*
1279
static inline bool
1280
IsWARPStable()
1281
{
1282
// It seems like nvdxgiwrap makes a mess of WARP. See bug 1154703.
1283
if (!IsWin8OrLater() || GetModuleHandleA("nvdxgiwrap.dll")) {
1284
return false;
1285
}
1286
return true;
1287
}
1288
*/
1289
static void InitializeANGLEConfig() {
1290
FeatureState& d3d11ANGLE = gfxConfig::GetFeature(Feature::D3D11_HW_ANGLE);
1291
1292
if (!gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) {
1293
d3d11ANGLE.DisableByDefault(
1294
FeatureStatus::Unavailable, "D3D11 compositing is disabled",
1295
NS_LITERAL_CSTRING("FEATURE_FAILURE_D3D11_DISABLED"));
1296
return;
1297
}
1298
1299
d3d11ANGLE.EnableByDefault();
1300
1301
nsCString message;
1302
nsCString failureId;
1303
if (!gfxPlatform::IsGfxInfoStatusOkay(nsIGfxInfo::FEATURE_DIRECT3D_11_ANGLE,
1304
&message, failureId)) {
1305
d3d11ANGLE.Disable(FeatureStatus::Blacklisted, message.get(), failureId);
1306
}
1307
}
1308
1309
void gfxWindowsPlatform::InitializeDirectDrawConfig() {
1310
MOZ_ASSERT(XRE_IsParentProcess());
1311
1312
FeatureState& ddraw = gfxConfig::GetFeature(Feature::DIRECT_DRAW);
1313
ddraw.EnableByDefault();
1314
}
1315
1316
void gfxWindowsPlatform::InitializeConfig() {
1317
if (XRE_IsParentProcess()) {
1318
// The parent process first determines which features can be attempted.
1319
// This information is relayed to content processes and the GPU process.
1320
InitializeD3D11Config();
1321
InitializeANGLEConfig();
1322
InitializeD2DConfig();
1323
} else {
1324
FetchAndImportContentDeviceData();
1325
InitializeANGLEConfig();
1326
}
1327
}
1328
1329
void gfxWindowsPlatform::InitializeD3D11Config() {
1330
MOZ_ASSERT(XRE_IsParentProcess());
1331
1332
FeatureState& d3d11 = gfxConfig::GetFeature(Feature::D3D11_COMPOSITING);
1333
1334
if (!gfxConfig::IsEnabled(Feature::HW_COMPOSITING)) {
1335
d3d11.DisableByDefault(
1336
FeatureStatus::Unavailable, "Hardware compositing is disabled",
1337
NS_LITERAL_CSTRING("FEATURE_FAILURE_D3D11_NEED_HWCOMP"));
1338
return;
1339
}
1340
1341
d3d11.EnableByDefault();
1342
1343
// Check if the user really, really wants WARP.
1344
if (StaticPrefs::layers_d3d11_force_warp_AtStartup()) {
1345
// Force D3D11 on even if we disabled it.
1346
d3d11.UserForceEnable("User force-enabled WARP");
1347
}
1348
1349
if (!IsWin8OrLater() &&
1350
!DeviceManagerDx::Get()->CheckRemotePresentSupport()) {
1351
nsCOMPtr<nsIGfxInfo> gfxInfo;
1352
gfxInfo = services::GetGfxInfo();
1353
nsAutoString adaptorId;
1354
gfxInfo->GetAdapterDeviceID(adaptorId);
1355
// Blacklist Intel HD Graphics 510/520/530 on Windows 7 without platform
1356
// update due to the crashes in Bug 1351349.
1357
if (adaptorId.EqualsLiteral("0x1912") ||
1358
adaptorId.EqualsLiteral("0x1916") ||
1359
adaptorId.EqualsLiteral("0x1902")) {
1360
#ifdef RELEASE_OR_BETA
1361
d3d11.Disable(FeatureStatus::Blacklisted, "Blacklisted, see bug 1351349",
1362
NS_LITERAL_CSTRING("FEATURE_FAILURE_BUG_1351349"));
1363
#else
1364
Preferences::SetBool("gfx.compositor.clearstate", true);
1365
#endif
1366
}
1367
}
1368
1369
nsCString message;
1370
nsCString failureId;
1371
if (StaticPrefs::layers_d3d11_enable_blacklist_AtStartup() &&
1372
!gfxPlatform::IsGfxInfoStatusOkay(nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS,
1373
&message, failureId)) {
1374
d3d11.Disable(FeatureStatus::Blacklisted, message.get(), failureId);
1375
}
1376
1377
InitializeAdvancedLayersConfig();
1378
}
1379
1380
/* static */
1381
void gfxWindowsPlatform::InitializeAdvancedLayersConfig() {
1382
// Only enable Advanced Layers if D3D11 succeeded.
1383
if (!gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) {
1384
return;
1385
}
1386
1387
FeatureState& al = gfxConfig::GetFeature(Feature::ADVANCED_LAYERS);
1388
al.SetDefaultFromPref(StaticPrefs::GetPrefName_layers_mlgpu_enabled(),
1389
true /* aIsEnablePref */,
1390
StaticPrefs::GetPrefDefault_layers_mlgpu_enabled());
1391
1392
// Windows 7 has an extra pref since it uses totally different buffer paths
1393
// that haven't been performance tested yet.
1394
if (al.IsEnabled() && !IsWin8OrLater()) {
1395
if (StaticPrefs::layers_mlgpu_enable_on_windows7_AtStartup()) {
1396
al.UserEnable("Enabled for Windows 7 via user-preference");
1397
} else {
1398
al.Disable(FeatureStatus::Disabled,
1399
"Advanced Layers is disabled on Windows 7 by default",
1400
NS_LITERAL_CSTRING("FEATURE_FAILURE_DISABLED_ON_WIN7"));
1401
}
1402
}
1403
1404
nsCString message, failureId;
1405
if (!IsGfxInfoStatusOkay(nsIGfxInfo::FEATURE_ADVANCED_LAYERS, &message,
1406
failureId)) {
1407
al.Disable(FeatureStatus::Blacklisted, message.get(), failureId);
1408
} else if (Preferences::GetBool("layers.mlgpu.sanity-test-failed", false)) {
1409
al.Disable(FeatureStatus::Broken, "Failed to render sanity test",
1410
NS_LITERAL_CSTRING("FEATURE_FAILURE_FAILED_TO_RENDER"));
1411
}
1412
}
1413
1414
/* static */
1415
void gfxWindowsPlatform::RecordContentDeviceFailure(
1416
TelemetryDeviceCode aDevice) {
1417
// If the parent process fails to acquire a device, we record this
1418
// normally as part of the environment. The exceptional case we're
1419
// looking for here is when the parent process successfully acquires
1420
// a device, but the content process fails to acquire the same device.
1421
// This would not normally be displayed in about:support.
1422
if (!XRE_IsContentProcess()) {
1423
return;
1424
}
1425
Telemetry::Accumulate(Telemetry::GFX_CONTENT_FAILED_TO_ACQUIRE_DEVICE,
1426
uint32_t(aDevice));
1427
}
1428
1429
void gfxWindowsPlatform::RecordStartupTelemetry() {
1430
if (!XRE_IsParentProcess()) {
1431
return;
1432
}
1433
1434
DeviceManagerDx* dx = DeviceManagerDx::Get();
1435
nsTArray<DXGI_OUTPUT_DESC1> outputs = dx->EnumerateOutputs();
1436
1437
uint32_t allSupportedColorSpaces = 0;
1438
for (auto& output : outputs) {
1439
uint32_t colorSpace = 1 << output.ColorSpace;
1440
allSupportedColorSpaces |= colorSpace;
1441
}
1442
1443
Telemetry::ScalarSet(
1444
Telemetry::ScalarID::GFX_HDR_WINDOWS_DISPLAY_COLORSPACE_BITFIELD,
1445
allSupportedColorSpaces);
1446
}
1447
1448
// Supports lazy device initialization on Windows, so that WebRender can avoid
1449
// initializing GPU state and allocating swap chains for most non-GPU processes.
1450
void gfxWindowsPlatform::EnsureDevicesInitialized() {
1451
if (!mInitializedDevices) {
1452
mInitializedDevices = true;
1453
InitializeDevices();
1454
UpdateBackendPrefs();
1455
}
1456
}
1457
1458
bool gfxWindowsPlatform::DevicesInitialized() { return mInitializedDevices; }
1459
1460
void gfxWindowsPlatform::InitializeDevices() {
1461
MOZ_ASSERT(NS_IsMainThread());
1462
1463
if (XRE_IsParentProcess()) {
1464
// If we're the UI process, and the GPU process is enabled, then we don't
1465
// initialize any DirectX devices. We do leave them enabled in gfxConfig
1466
// though. If the GPU process fails to create these devices it will send
1467
// a message back and we'll update their status.
1468
if (InitGPUProcessSupport()) {
1469
return;
1470
}
1471
1472
// No GPU process, continue initializing devices as normal.
1473
}
1474
1475
// If acceleration is disabled, we refuse to initialize anything.
1476
if (!gfxConfig::IsEnabled(Feature::HW_COMPOSITING)) {
1477
return;
1478
}
1479
1480
// If we previously crashed initializing devices, bail out now.
1481
D3D11LayersCrashGuard detectCrashes;
1482
if (detectCrashes.Crashed()) {
1483
gfxConfig::SetFailed(Feature::HW_COMPOSITING,
1484
FeatureStatus::CrashedOnStartup,
1485
"Crashed during startup in a previous session");
1486
gfxConfig::SetFailed(
1487
Feature::D3D11_COMPOSITING, FeatureStatus::CrashedOnStartup,
1488
"Harware acceleration crashed during startup in a previous session");
1489
gfxConfig::SetFailed(
1490
Feature::DIRECT2D, FeatureStatus::CrashedOnStartup,
1491
"Harware acceleration crashed during startup in a previous session");
1492
return;
1493
}
1494
1495
bool shouldUseD2D = gfxConfig::IsEnabled(Feature::DIRECT2D);
1496
1497
// First, initialize D3D11. If this succeeds we attempt to use Direct2D.
1498
InitializeD3D11();
1499
InitializeD2D();
1500
1501
if (!gfxConfig::IsEnabled(Feature::DIRECT2D) && XRE_IsContentProcess() &&
1502
shouldUseD2D) {
1503
RecordContentDeviceFailure(TelemetryDeviceCode::D2D1);
1504
}
1505
}
1506
1507
void gfxWindowsPlatform::InitializeD3D11() {
1508
// This function attempts to initialize our D3D11 devices, if the hardware
1509
// is not blacklisted for D3D11 layers. This first attempt will try to create
1510
// a hardware accelerated device. If this creation fails or the hardware is
1511
// blacklisted, then this function will abort if WARP is disabled, causing us
1512
// to fallback to Basic layers. If WARP is not disabled it will use a WARP
1513
// device which should always be available on Windows 7 and higher.
1514
if (!gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) {
1515
return;
1516
}
1517
1518
DeviceManagerDx* dm = DeviceManagerDx::Get();
1519
if (XRE_IsParentProcess()) {
1520
if (!dm->CreateCompositorDevices()) {
1521
return;
1522
}
1523
}
1524
1525
dm->CreateContentDevices();
1526
1527
// Content process failed to create the d3d11 device while parent process
1528
// succeed.
1529
if (XRE_IsContentProcess() &&
1530
!gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) {
1531
gfxCriticalError()
1532
<< "[D3D11] Failed to create the D3D11 device in content \
1533
process.";
1534
}
1535
}
1536
1537
void gfxWindowsPlatform::InitializeD2DConfig() {
1538
FeatureState& d2d1 = gfxConfig::GetFeature(Feature::DIRECT2D);
1539
1540
if (!gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) {
1541
d2d1.DisableByDefault(FeatureStatus::Unavailable,
1542
"Direct2D requires Direct3D 11 compositing",
1543
NS_LITERAL_CSTRING("FEATURE_FAILURE_D2D_D3D11_COMP"));
1544
return;
1545
}
1546
1547
d2d1.SetDefaultFromPref(StaticPrefs::GetPrefName_gfx_direct2d_disabled(),
1548
false,
1549
StaticPrefs::GetPrefDefault_gfx_direct2d_disabled());
1550
1551
nsCString message;
1552
nsCString failureId;
1553
if (!gfxPlatform::IsGfxInfoStatusOkay(nsIGfxInfo::FEATURE_DIRECT2D, &message,
1554
failureId)) {
1555
d2d1.Disable(FeatureStatus::Blacklisted, message.get(), failureId);
1556
}
1557
1558
if (!d2d1.IsEnabled() &&
1559
StaticPrefs::gfx_direct2d_force_enabled_AtStartup()) {
1560
d2d1.UserForceEnable("Force-enabled via user-preference");
1561
}
1562
}
1563
1564
void gfxWindowsPlatform::InitializeD2D() {
1565
ScopedGfxFeatureReporter d2d1_1("D2D1.1");
1566
1567
FeatureState& d2d1 = gfxConfig::GetFeature(Feature::DIRECT2D);
1568
1569
DeviceManagerDx* dm = DeviceManagerDx::Get();
1570
1571
// We don't know this value ahead of time, but the user can force-override
1572
// it, so we use Disable instead of SetFailed.
1573
if (dm->IsWARP()) {
1574
d2d1.Disable(FeatureStatus::Blocked,
1575
"Direct2D is not compatible with Direct3D11 WARP",
1576
NS_LITERAL_CSTRING("FEATURE_FAILURE_D2D_WARP_BLOCK"));
1577
}
1578
1579
// If we pass all the initial checks, we can proceed to runtime decisions.
1580
if (!d2d1.IsEnabled()) {
1581
return;
1582
}
1583
1584
if (!Factory::SupportsD2D1()) {
1585
d2d1.SetFailed(FeatureStatus::Unavailable,
1586
"Failed to acquire a Direct2D 1.1 factory",
1587
NS_LITERAL_CSTRING("FEATURE_FAILURE_D2D_FACTORY"));
1588
return;
1589
}
1590
1591
if (!dm->GetContentDevice()) {
1592
d2d1.SetFailed(FeatureStatus::Failed,
1593
"Failed to acquire a Direct3D 11 content device",
1594
NS_LITERAL_CSTRING("FEATURE_FAILURE_D2D_DEVICE"));
1595
return;
1596
}
1597
1598
if (!dm->TextureSharingWorks()) {
1599
d2d1.SetFailed(FeatureStatus::Failed,
1600
"Direct3D11 device does not support texture sharing",
1601
NS_LITERAL_CSTRING("FEATURE_FAILURE_D2D_TXT_SHARING"));
1602
return;
1603
}
1604
1605
// Using Direct2D depends on DWrite support.
1606
if (!DWriteEnabled() && !InitDWriteSupport()) {
1607
d2d1.SetFailed(FeatureStatus::Failed,
1608
"Failed to initialize DirectWrite support",
1609
NS_LITERAL_CSTRING("FEATURE_FAILURE_D2D_DWRITE"));
1610
return;
1611
}
1612
1613
// Verify that Direct2D device creation succeeded.
1614
RefPtr<ID3D11Device> contentDevice = dm->GetContentDevice();
1615
if (!Factory::SetDirect3D11Device(contentDevice)) {
1616
d2d1.SetFailed(FeatureStatus::Failed, "Failed to create a Direct2D device",
1617
NS_LITERAL_CSTRING("FEATURE_FAILURE_D2D_CREATE_FAILED"));
1618
return;
1619
}
1620
1621
MOZ_ASSERT(d2d1.IsEnabled());
1622
d2d1_1.SetSuccessful();
1623
}
1624
1625
bool gfxWindowsPlatform::InitGPUProcessSupport() {
1626
FeatureState& gpuProc = gfxConfig::GetFeature(Feature::GPU_PROCESS);
1627
1628
if (!gpuProc.IsEnabled()) {
1629
return false;
1630
}
1631
1632
nsCString message;
1633
nsCString failureId;
1634
if (!gfxPlatform::IsGfxInfoStatusOkay(nsIGfxInfo::FEATURE_GPU_PROCESS,
1635
&message, failureId)) {
1636
gpuProc.Disable(FeatureStatus::Blacklisted, message.get(), failureId);
1637
return false;
1638
}
1639
1640
if (!gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) {
1641
// Don't use the GPU process if not using D3D11, unless software
1642
// compositor is allowed
1643
if (StaticPrefs::layers_gpu_process_allow_software_AtStartup()) {
1644
return gpuProc.IsEnabled();
1645
}
1646
gpuProc.Disable(FeatureStatus::Unavailable,
1647
"Not using GPU Process since D3D11 is unavailable",
1648
NS_LITERAL_CSTRING("FEATURE_FAILURE_NO_D3D11"));
1649
} else if (!IsWin7SP1OrLater()) {
1650
// On Windows 7 Pre-SP1, DXGI 1.2 is not available and remote presentation
1651
// for D3D11 will not work. Rather than take a regression we revert back
1652
// to in-process rendering.
1653
gpuProc.Disable(FeatureStatus::Unavailable,
1654
"Windows 7 Pre-SP1 cannot use the GPU process",
1655
NS_LITERAL_CSTRING("FEATURE_FAILURE_OLD_WINDOWS"));
1656
} else if (!IsWin8OrLater()) {
1657
// Windows 7 SP1 can have DXGI 1.2 only via the Platform Update, so we
1658
// explicitly check for that here.
1659
if (!DeviceManagerDx::Get()->CheckRemotePresentSupport()) {
1660
gpuProc.Disable(FeatureStatus::Unavailable,
1661
"GPU Process requires the Windows 7 Platform Update",
1662
NS_LITERAL_CSTRING("FEATURE_FAILURE_PLATFORM_UPDATE"));
1663
} else {
1664
// Clear anything cached by the above call since we don't need it.
1665
DeviceManagerDx::Get()->ResetDevices();
1666
}
1667
}
1668
1669
// If we're still enabled at this point, the user set the force-enabled pref.
1670
return gpuProc.IsEnabled();
1671
}
1672
1673
bool gfxWindowsPlatform::DwmCompositionEnabled() {
1674
BOOL dwmEnabled = false;
1675
1676
if (FAILED(DwmIsCompositionEnabled(&dwmEnabled))) {
1677
return false;
1678
}
1679
1680
return dwmEnabled;
1681
}
1682
1683
class D3DVsyncSource final : public VsyncSource {
1684
public:
1685
class D3DVsyncDisplay final : public VsyncSource::Display {
1686
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(D3DVsyncDisplay)
1687
public:
1688
D3DVsyncDisplay()
1689
: mPrevVsync(TimeStamp::Now()),
1690
mVsyncEnabledLock("D3DVsyncEnabledLock"),
1691
mVsyncEnabled(false) {
1692
mVsyncThread = new base::Thread("WindowsVsyncThread");
1693
MOZ_RELEASE_ASSERT(mVsyncThread->Start(),
1694
"GFX: Could not start Windows vsync thread");
1695
SetVsyncRate();
1696
}
1697
1698
void SetVsyncRate() {
1699
if (!gfxWindowsPlatform::GetPlatform()->DwmCompositionEnabled()) {
1700
mVsyncRate = TimeDuration::FromMilliseconds(1000.0 / 60.0);
1701
return;
1702
}
1703
1704
DWM_TIMING_INFO vblankTime;
1705
// Make sure to init the cbSize, otherwise GetCompositionTiming will fail
1706
vblankTime.cbSize = sizeof(DWM_TIMING_INFO);
1707
HRESULT hr = DwmGetCompositionTimingInfo(0, &vblankTime);
1708
if (SUCCEEDED(hr)) {
1709
UNSIGNED_RATIO refreshRate = vblankTime.rateRefresh;
1710
// We get the rate in hertz / time, but we want the rate in ms.
1711
float rate = ((float)refreshRate.uiDenominator /
1712
(float)refreshRate.uiNumerator) *
1713
1000;
1714
mVsyncRate = TimeDuration::FromMilliseconds(rate);
1715
} else {
1716
mVsyncRate = TimeDuration::FromMilliseconds(1000.0 / 60.0);
1717
}
1718
}
1719
1720
virtual void Shutdown() override {
1721
MOZ_ASSERT(NS_IsMainThread());
1722
DisableVsync();
1723
mVsyncThread->Stop();
1724
delete mVsyncThread;
1725
}
1726
1727
virtual void EnableVsync() override {
1728
MOZ_ASSERT(NS_IsMainThread());
1729
MOZ_ASSERT(mVsyncThread->IsRunning());
1730
{ // scope lock
1731
MonitorAutoLock lock(mVsyncEnabledLock);
1732
if (mVsyncEnabled) {
1733
return;
1734
}
1735
mVsyncEnabled = true;
1736
}
1737
1738
mVsyncThread->message_loop()->PostTask(NewRunnableMethod(
1739
"D3DVsyncDisplay::VBlankLoop", this, &D3DVsyncDisplay::VBlankLoop));
1740
}
1741
1742
virtual void DisableVsync() override {
1743
MOZ_ASSERT(NS_IsMainThread());
1744
MOZ_ASSERT(mVsyncThread->IsRunning());
1745
MonitorAutoLock lock(mVsyncEnabledLock);
1746
if (!mVsyncEnabled) {
1747
return;
1748
}
1749
mVsyncEnabled = false;
1750
}
1751
1752
virtual bool IsVsyncEnabled() override {
1753
MOZ_ASSERT(NS_IsMainThread());
1754
MonitorAutoLock lock(mVsyncEnabledLock);
1755
return mVsyncEnabled;
1756
}
1757
1758
virtual TimeDuration GetVsyncRate() override { return mVsyncRate; }
1759
1760
void ScheduleSoftwareVsync(TimeStamp aVsyncTimestamp) {
1761
MOZ_ASSERT(IsInVsyncThread());
1762
NS_WARNING(
1763
"DwmComposition dynamically disabled, falling back to software "
1764
"timers");
1765
1766
TimeStamp nextVsync = aVsyncTimestamp + mVsyncRate;
1767
TimeDuration delay = nextVsync - TimeStamp::Now();
1768
if (delay.ToMilliseconds() < 0) {
1769
delay = mozilla::TimeDuration::FromMilliseconds(0);
1770
}
1771
1772
mVsyncThread->message_loop()->PostDelayedTask(
1773
NewRunnableMethod("D3DVsyncDisplay::VBlankLoop", this,
1774
&D3DVsyncDisplay::VBlankLoop),
1775
delay.ToMilliseconds());
1776
}
1777
1778
// Returns the timestamp for the just happened vsync
1779
TimeStamp GetVBlankTime() {
1780
TimeStamp vsync = TimeStamp::Now();
1781
TimeStamp now = vsync;
1782
1783
DWM_TIMING_INFO vblankTime;
1784
// Make sure to init the cbSize, otherwise
1785
// GetCompositionTiming will fail
1786
vblankTime.cbSize = sizeof(DWM_TIMING_INFO);
1787
HRESULT hr = DwmGetCompositionTimingInfo(0, &vblankTime);
1788
if (!SUCCEEDED(hr)) {
1789
return vsync;
1790
}
1791
1792
LARGE_INTEGER frequency;
1793
QueryPerformanceFrequency(&frequency);
1794
1795
LARGE_INTEGER qpcNow;
1796
QueryPerformanceCounter(&qpcNow);
1797
1798
const int microseconds = 1000000;
1799
int64_t adjust = qpcNow.QuadPart - vblankTime.qpcVBlank;
1800
int64_t usAdjust = (adjust * microseconds) / frequency.QuadPart;
1801
vsync -= TimeDuration::FromMicroseconds((double)usAdjust);
1802
1803
if (IsWin10OrLater()) {
1804
// On Windows 10 and on, DWMGetCompositionTimingInfo, mostly
1805
// reports the upcoming vsync time, which is in the future.
1806
// It can also sometimes report a vblank time in the past.
1807
// Since large parts of Gecko assume TimeStamps can't be in future,
1808
// use the previous vsync.
1809
1810
// Windows 10 and Intel HD vsync timestamps are messy and
1811
// all over the place once in a while. Most of the time,
1812
// it reports the upcoming vsync. Sometimes, that upcoming
1813
// vsync is in the past. Sometimes that upcoming vsync is before
1814
// the previously seen vsync.
1815
// In these error cases, normalize to Now();
1816
if (vsync >= now) {
1817
vsync = vsync - mVsyncRate;
1818
}
1819
}
1820
1821
// On Windows 7 and 8, DwmFlush wakes up AFTER qpcVBlankTime
1822
// from DWMGetCompositionTimingInfo. We can return the adjusted vsync.
1823
if (vsync >= now) {
1824
vsync = now;
1825
}
1826
1827
// Our vsync time is some time very far in the past, adjust to Now.
1828
// 4 ms is arbitrary, so feel free to pick something else if this isn't
1829
// working. See the comment above within IsWin10OrLater().
1830
if ((now - vsync).ToMilliseconds() > 4.0) {
1831
vsync = now;
1832
}
1833
1834
return vsync;
1835
}
1836
1837
void VBlankLoop() {
1838
MOZ_ASSERT(IsInVsyncThread());
1839
MOZ_ASSERT(sizeof(int64_t) == sizeof(QPC_TIME));
1840
1841
TimeStamp vsync = TimeStamp::Now();
1842
mPrevVsync = TimeStamp();
1843
TimeStamp flushTime = TimeStamp::Now();
1844
TimeDuration longVBlank = mVsyncRate * 2;
1845
1846
for (;;) {
1847
{ // scope lock
1848
MonitorAutoLock lock(mVsyncEnabledLock);
1849
if (!mVsyncEnabled) return;
1850
}
1851
1852
// Large parts of gecko assume that the refresh driver timestamp
1853
// must be <= Now() and cannot be in the future.
1854
MOZ_ASSERT(vsync <= TimeStamp::Now());
1855
Display::NotifyVsync(vsync);
1856
1857
// DwmComposition can be dynamically enabled/disabled
1858
// so we have to check every time that it's available.
1859
// When it is unavailable, we fallback to software but will try
1860
// to get back to dwm rendering once it's re-enabled
1861
if (!gfxWindowsPlatform::GetPlatform()->DwmCompositionEnabled()) {
1862
ScheduleSoftwareVsync(vsync);
1863
return;
1864
}
1865
1866
// Using WaitForVBlank, the whole system dies because WaitForVBlank
1867
// only works if it's run on the same thread as the Present();
1868
HRESULT hr = DwmFlush();
1869
if (!SUCCEEDED(hr)) {
1870
// DWMFlush isn't working, fallback to software vsync.
1871
ScheduleSoftwareVsync(TimeStamp::Now());
1872
return;
1873
}
1874
1875
TimeStamp now = TimeStamp::Now();
1876
TimeDuration flushDiff = now - flushTime;
1877
flushTime = now;
1878
if ((flushDiff > longVBlank) || mPrevVsync.IsNull()) {
1879
// Our vblank took longer than 2 intervals, readjust our timestamps
1880
vsync = GetVBlankTime();
1881
mPrevVsync = vsync;
1882
} else {
1883
// Instead of giving the actual vsync time, a constant interval
1884
// between vblanks instead of the noise generated via hardware
1885
// is actually what we want. Most apps just care about the diff
1886
// between vblanks to animate, so a clean constant interval is
1887
// smoother.
1888
vsync = mPrevVsync + mVsyncRate;
1889
if (vsync > now) {
1890
// DWMFlush woke up very early, so readjust our times again
1891
vsync = GetVBlankTime();
1892
}
1893
1894
if (vsync <= mPrevVsync) {
1895
vsync = TimeStamp::Now();
1896
}
1897