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