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