1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 #include "DeviceManagerDx.h"
7 #include "D3D11Checks.h"
8 #include "gfxConfig.h"
9 #include "GfxDriverInfo.h"
10 #include "gfxWindowsPlatform.h"
11 #include "mozilla/D3DMessageUtils.h"
12 #include "mozilla/StaticPrefs_gfx.h"
13 #include "mozilla/StaticPrefs_layers.h"
14 #include "mozilla/Telemetry.h"
15 #include "mozilla/WindowsVersion.h"
16 #include "mozilla/gfx/GPUParent.h"
17 #include "mozilla/gfx/GPUProcessManager.h"
18 #include "mozilla/gfx/GraphicsMessages.h"
19 #include "mozilla/gfx/Logging.h"
20 #include "mozilla/gfx/gfxVars.h"
21 #include "mozilla/layers/CompositorBridgeChild.h"
22 #include "mozilla/layers/CompositorThread.h"
23 #include "mozilla/layers/DeviceAttachmentsD3D11.h"
24 #include "mozilla/Preferences.h"
25 #include "nsPrintfCString.h"
26 #include "nsString.h"
27
28 #undef _WIN32_WINNT
29 #define _WIN32_WINNT _WIN32_WINNT_WINBLUE
30 #undef NTDDI_VERSION
31 #define NTDDI_VERSION NTDDI_WINBLUE
32
33 #include <d3d11.h>
34 #include <dcomp.h>
35 #include <ddraw.h>
36
37 namespace mozilla {
38 namespace gfx {
39
40 using namespace mozilla::widget;
41 using namespace mozilla::layers;
42
43 StaticAutoPtr<DeviceManagerDx> DeviceManagerDx::sInstance;
44
45 // We don't have access to the D3D11CreateDevice type in gfxWindowsPlatform.h,
46 // since it doesn't include d3d11.h, so we use a static here. It should only
47 // be used within InitializeD3D11.
48 decltype(D3D11CreateDevice)* sD3D11CreateDeviceFn = nullptr;
49
50 // It should only be used within CreateDirectCompositionDevice.
51 decltype(DCompositionCreateDevice2)* sDcompCreateDevice2Fn = nullptr;
52
53 // It should only be used within CreateDCompSurfaceHandle
54 decltype(DCompositionCreateSurfaceHandle)* sDcompCreateSurfaceHandleFn =
55 nullptr;
56
57 // We don't have access to the DirectDrawCreateEx type in gfxWindowsPlatform.h,
58 // since it doesn't include ddraw.h, so we use a static here. It should only
59 // be used within InitializeDirectDrawConfig.
60 decltype(DirectDrawCreateEx)* sDirectDrawCreateExFn = nullptr;
61
62 /* static */
Init()63 void DeviceManagerDx::Init() { sInstance = new DeviceManagerDx(); }
64
65 /* static */
Shutdown()66 void DeviceManagerDx::Shutdown() { sInstance = nullptr; }
67
DeviceManagerDx()68 DeviceManagerDx::DeviceManagerDx()
69 : mDeviceLock("gfxWindowsPlatform.mDeviceLock"),
70 mCompositorDeviceSupportsVideo(false) {
71 // Set up the D3D11 feature levels we can ask for.
72 if (IsWin8OrLater()) {
73 mFeatureLevels.AppendElement(D3D_FEATURE_LEVEL_11_1);
74 }
75 mFeatureLevels.AppendElement(D3D_FEATURE_LEVEL_11_0);
76 mFeatureLevels.AppendElement(D3D_FEATURE_LEVEL_10_1);
77 mFeatureLevels.AppendElement(D3D_FEATURE_LEVEL_10_0);
78 }
79
LoadD3D11()80 bool DeviceManagerDx::LoadD3D11() {
81 FeatureState& d3d11 = gfxConfig::GetFeature(Feature::D3D11_COMPOSITING);
82 MOZ_ASSERT(d3d11.IsEnabled());
83
84 if (sD3D11CreateDeviceFn) {
85 return true;
86 }
87
88 nsModuleHandle module(LoadLibrarySystem32(L"d3d11.dll"));
89 if (!module) {
90 d3d11.SetFailed(FeatureStatus::Unavailable,
91 "Direct3D11 not available on this computer",
92 "FEATURE_FAILURE_D3D11_LIB"_ns);
93 return false;
94 }
95
96 sD3D11CreateDeviceFn =
97 (decltype(D3D11CreateDevice)*)GetProcAddress(module, "D3D11CreateDevice");
98 if (!sD3D11CreateDeviceFn) {
99 // We should just be on Windows Vista or XP in this case.
100 d3d11.SetFailed(FeatureStatus::Unavailable,
101 "Direct3D11 not available on this computer",
102 "FEATURE_FAILURE_D3D11_FUNCPTR"_ns);
103 return false;
104 }
105
106 mD3D11Module.steal(module);
107 return true;
108 }
109
LoadDcomp()110 bool DeviceManagerDx::LoadDcomp() {
111 MOZ_ASSERT(gfxConfig::GetFeature(Feature::D3D11_COMPOSITING).IsEnabled());
112 MOZ_ASSERT(gfxVars::UseWebRender());
113 MOZ_ASSERT(gfxVars::UseWebRenderANGLE());
114 MOZ_ASSERT(gfxVars::UseWebRenderDCompWin());
115
116 if (sDcompCreateDevice2Fn) {
117 return true;
118 }
119
120 nsModuleHandle module(LoadLibrarySystem32(L"dcomp.dll"));
121 if (!module) {
122 return false;
123 }
124
125 sDcompCreateDevice2Fn = (decltype(DCompositionCreateDevice2)*)GetProcAddress(
126 module, "DCompositionCreateDevice2");
127 if (!sDcompCreateDevice2Fn) {
128 return false;
129 }
130
131 // Load optional API for external compositing
132 sDcompCreateSurfaceHandleFn =
133 (decltype(DCompositionCreateSurfaceHandle)*)::GetProcAddress(
134 module, "DCompositionCreateSurfaceHandle");
135 if (!sDcompCreateDevice2Fn) {
136 return false;
137 }
138
139 mDcompModule.steal(module);
140 return true;
141 }
142
ReleaseD3D11()143 void DeviceManagerDx::ReleaseD3D11() {
144 MOZ_ASSERT(!mCompositorDevice);
145 MOZ_ASSERT(!mContentDevice);
146 MOZ_ASSERT(!mVRDevice);
147 MOZ_ASSERT(!mDecoderDevice);
148
149 mD3D11Module.reset();
150 sD3D11CreateDeviceFn = nullptr;
151 }
152
EnumerateOutputs()153 nsTArray<DXGI_OUTPUT_DESC1> DeviceManagerDx::EnumerateOutputs() {
154 RefPtr<IDXGIAdapter> adapter = GetDXGIAdapter();
155
156 if (!adapter) {
157 NS_WARNING("Failed to acquire a DXGI adapter for enumerating outputs.");
158 return nsTArray<DXGI_OUTPUT_DESC1>();
159 }
160
161 nsTArray<DXGI_OUTPUT_DESC1> outputs;
162 for (UINT i = 0;; ++i) {
163 RefPtr<IDXGIOutput> output = nullptr;
164 if (FAILED(adapter->EnumOutputs(i, getter_AddRefs(output)))) {
165 break;
166 }
167
168 RefPtr<IDXGIOutput6> output6 = nullptr;
169 if (FAILED(output->QueryInterface(__uuidof(IDXGIOutput6),
170 getter_AddRefs(output6)))) {
171 break;
172 }
173
174 DXGI_OUTPUT_DESC1 desc;
175 if (FAILED(output6->GetDesc1(&desc))) {
176 break;
177 }
178
179 outputs.AppendElement(desc);
180 }
181 return outputs;
182 }
183
GetOutputFromMonitor(HMONITOR monitor,RefPtr<IDXGIOutput> * aOutOutput)184 bool DeviceManagerDx::GetOutputFromMonitor(HMONITOR monitor,
185 RefPtr<IDXGIOutput>* aOutOutput) {
186 RefPtr<IDXGIAdapter> adapter = GetDXGIAdapter();
187
188 if (!adapter) {
189 NS_WARNING("Failed to acquire a DXGI adapter for GetOutputFromMonitor.");
190 return false;
191 }
192
193 for (UINT i = 0;; ++i) {
194 RefPtr<IDXGIOutput> output = nullptr;
195 if (FAILED(adapter->EnumOutputs(i, getter_AddRefs(output)))) {
196 break;
197 }
198
199 DXGI_OUTPUT_DESC desc;
200 if (FAILED(output->GetDesc(&desc))) {
201 continue;
202 }
203
204 if (desc.Monitor == monitor) {
205 *aOutOutput = output;
206 return true;
207 }
208 }
209 return false;
210 }
211
CheckHardwareStretchingSupport(HwStretchingSupport & aRv)212 void DeviceManagerDx::CheckHardwareStretchingSupport(HwStretchingSupport& aRv) {
213 RefPtr<IDXGIAdapter> adapter = GetDXGIAdapter();
214
215 if (!adapter) {
216 NS_WARNING(
217 "Failed to acquire a DXGI adapter for checking hardware stretching "
218 "support.");
219 ++aRv.mError;
220 return;
221 }
222
223 for (UINT i = 0;; ++i) {
224 RefPtr<IDXGIOutput> output = nullptr;
225 HRESULT result = adapter->EnumOutputs(i, getter_AddRefs(output));
226 if (result == DXGI_ERROR_NOT_FOUND) {
227 // No more outputs to check.
228 break;
229 }
230
231 if (FAILED(result)) {
232 ++aRv.mError;
233 break;
234 }
235
236 RefPtr<IDXGIOutput6> output6 = nullptr;
237 if (FAILED(output->QueryInterface(__uuidof(IDXGIOutput6),
238 getter_AddRefs(output6)))) {
239 ++aRv.mError;
240 continue;
241 }
242
243 UINT flags = 0;
244 if (FAILED(output6->CheckHardwareCompositionSupport(&flags))) {
245 ++aRv.mError;
246 continue;
247 }
248
249 bool fullScreen = flags & DXGI_HARDWARE_COMPOSITION_SUPPORT_FLAG_FULLSCREEN;
250 bool window = flags & DXGI_HARDWARE_COMPOSITION_SUPPORT_FLAG_WINDOWED;
251 if (fullScreen && window) {
252 ++aRv.mBoth;
253 } else if (fullScreen) {
254 ++aRv.mFullScreenOnly;
255 } else if (window) {
256 ++aRv.mWindowOnly;
257 } else {
258 ++aRv.mNone;
259 }
260 }
261 }
262
263 #ifdef DEBUG
ProcessOwnsCompositor()264 static inline bool ProcessOwnsCompositor() {
265 return XRE_GetProcessType() == GeckoProcessType_GPU ||
266 XRE_GetProcessType() == GeckoProcessType_VR ||
267 (XRE_IsParentProcess() && !gfxConfig::IsEnabled(Feature::GPU_PROCESS));
268 }
269 #endif
270
CreateCompositorDevices()271 bool DeviceManagerDx::CreateCompositorDevices() {
272 MOZ_ASSERT(ProcessOwnsCompositor());
273
274 FeatureState& d3d11 = gfxConfig::GetFeature(Feature::D3D11_COMPOSITING);
275 MOZ_ASSERT(d3d11.IsEnabled());
276
277 if (int32_t sleepSec =
278 StaticPrefs::gfx_direct3d11_sleep_on_create_device_AtStartup()) {
279 printf_stderr("Attach to PID: %d\n", GetCurrentProcessId());
280 Sleep(sleepSec * 1000);
281 }
282
283 if (!LoadD3D11()) {
284 return false;
285 }
286
287 CreateCompositorDevice(d3d11);
288
289 if (!d3d11.IsEnabled()) {
290 MOZ_ASSERT(!mCompositorDevice);
291 ReleaseD3D11();
292
293 return false;
294 }
295
296 // We leak these everywhere and we need them our entire runtime anyway, let's
297 // leak it here as well. We keep the pointer to sD3D11CreateDeviceFn around
298 // as well for D2D1 and device resets.
299 mD3D11Module.disown();
300
301 MOZ_ASSERT(mCompositorDevice);
302 if (!d3d11.IsEnabled()) {
303 return false;
304 }
305
306 // When WR is used, do not preload attachments for D3D11 Non-WR compositor.
307 //
308 // Fallback from WR to D3D11 Non-WR compositor without re-creating gpu process
309 // could happen when WR causes error. In this case, the attachments are loaded
310 // synchronously.
311 if (!gfx::gfxVars::UseWebRender() || gfx::gfxVars::UseSoftwareWebRender()) {
312 PreloadAttachmentsOnCompositorThread();
313 }
314
315 return true;
316 }
317
CreateVRDevice()318 bool DeviceManagerDx::CreateVRDevice() {
319 MOZ_ASSERT(ProcessOwnsCompositor());
320
321 if (mVRDevice) {
322 return true;
323 }
324
325 if (!gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) {
326 NS_WARNING("Direct3D11 Compositing required for VR");
327 return false;
328 }
329
330 if (!LoadD3D11()) {
331 return false;
332 }
333
334 RefPtr<IDXGIAdapter1> adapter = GetDXGIAdapter();
335 if (!adapter) {
336 NS_WARNING("Failed to acquire a DXGI adapter for VR");
337 return false;
338 }
339
340 UINT flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
341
342 HRESULT hr;
343 if (!CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, flags, hr, mVRDevice)) {
344 gfxCriticalError() << "Crash during D3D11 device creation for VR";
345 return false;
346 }
347
348 if (FAILED(hr) || !mVRDevice) {
349 NS_WARNING("Failed to acquire a D3D11 device for VR");
350 return false;
351 }
352
353 return true;
354 }
355
CreateCanvasDevice()356 bool DeviceManagerDx::CreateCanvasDevice() {
357 MOZ_ASSERT(ProcessOwnsCompositor());
358
359 if (mCanvasDevice) {
360 return true;
361 }
362
363 if (!LoadD3D11()) {
364 return false;
365 }
366
367 RefPtr<IDXGIAdapter1> adapter = GetDXGIAdapter();
368 if (!adapter) {
369 NS_WARNING("Failed to acquire a DXGI adapter for Canvas");
370 return false;
371 }
372
373 UINT flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
374
375 HRESULT hr;
376 if (!CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, flags, hr,
377 mCanvasDevice)) {
378 gfxCriticalError() << "Crash during D3D11 device creation for Canvas";
379 return false;
380 }
381
382 if (FAILED(hr) || !mCanvasDevice) {
383 NS_WARNING("Failed to acquire a D3D11 device for Canvas");
384 return false;
385 }
386
387 if (!D3D11Checks::DoesTextureSharingWork(mCanvasDevice)) {
388 mCanvasDevice = nullptr;
389 return false;
390 }
391
392 if (XRE_IsGPUProcess()) {
393 Factory::SetDirect3D11Device(mCanvasDevice);
394 }
395
396 return true;
397 }
398
CreateDirectCompositionDevice()399 void DeviceManagerDx::CreateDirectCompositionDevice() {
400 if (!gfxVars::UseWebRenderDCompWin()) {
401 return;
402 }
403
404 if (!mCompositorDevice) {
405 return;
406 }
407
408 if (!LoadDcomp()) {
409 return;
410 }
411
412 RefPtr<IDXGIDevice> dxgiDevice;
413 if (mCompositorDevice->QueryInterface(
414 IID_PPV_ARGS((IDXGIDevice**)getter_AddRefs(dxgiDevice))) != S_OK) {
415 return;
416 }
417
418 HRESULT hr;
419 RefPtr<IDCompositionDesktopDevice> desktopDevice;
420 MOZ_SEH_TRY {
421 hr = sDcompCreateDevice2Fn(
422 dxgiDevice.get(),
423 IID_PPV_ARGS(
424 (IDCompositionDesktopDevice**)getter_AddRefs(desktopDevice)));
425 }
426 MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { return; }
427
428 if (!SUCCEEDED(hr)) {
429 return;
430 }
431
432 RefPtr<IDCompositionDevice2> compositionDevice;
433 if (desktopDevice->QueryInterface(IID_PPV_ARGS(
434 (IDCompositionDevice2**)getter_AddRefs(compositionDevice))) != S_OK) {
435 return;
436 }
437
438 mDirectCompositionDevice = compositionDevice;
439 }
440
441 /* static */
CreateDCompSurfaceHandle()442 HANDLE DeviceManagerDx::CreateDCompSurfaceHandle() {
443 if (!sDcompCreateSurfaceHandleFn) {
444 return 0;
445 }
446
447 HANDLE handle = 0;
448 HRESULT hr = sDcompCreateSurfaceHandleFn(COMPOSITIONOBJECT_ALL_ACCESS,
449 nullptr, &handle);
450 if (FAILED(hr)) {
451 return 0;
452 }
453
454 return handle;
455 }
456
ImportDeviceInfo(const D3D11DeviceStatus & aDeviceStatus)457 void DeviceManagerDx::ImportDeviceInfo(const D3D11DeviceStatus& aDeviceStatus) {
458 MOZ_ASSERT(!ProcessOwnsCompositor());
459
460 mDeviceStatus = Some(aDeviceStatus);
461 }
462
ExportDeviceInfo(D3D11DeviceStatus * aOut)463 bool DeviceManagerDx::ExportDeviceInfo(D3D11DeviceStatus* aOut) {
464 if (mDeviceStatus) {
465 *aOut = mDeviceStatus.value();
466 return true;
467 }
468
469 return false;
470 }
471
CreateContentDevices()472 void DeviceManagerDx::CreateContentDevices() {
473 MOZ_ASSERT(gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING));
474
475 if (!LoadD3D11()) {
476 return;
477 }
478
479 // We should have been assigned a DeviceStatus from the parent process,
480 // GPU process, or the same process if using in-process compositing.
481 MOZ_ASSERT(mDeviceStatus);
482
483 if (CreateContentDevice() == FeatureStatus::CrashedInHandler) {
484 DisableD3D11AfterCrash();
485 }
486 }
487
GetDXGIAdapter()488 IDXGIAdapter1* DeviceManagerDx::GetDXGIAdapter() {
489 if (mAdapter) {
490 return mAdapter;
491 }
492
493 nsModuleHandle dxgiModule(LoadLibrarySystem32(L"dxgi.dll"));
494 decltype(CreateDXGIFactory1)* createDXGIFactory1 =
495 (decltype(CreateDXGIFactory1)*)GetProcAddress(dxgiModule,
496 "CreateDXGIFactory1");
497
498 if (!createDXGIFactory1) {
499 return nullptr;
500 }
501
502 // Try to use a DXGI 1.1 adapter in order to share resources
503 // across processes.
504 RefPtr<IDXGIFactory1> factory1;
505 HRESULT hr =
506 createDXGIFactory1(__uuidof(IDXGIFactory1), getter_AddRefs(factory1));
507 if (FAILED(hr) || !factory1) {
508 // This seems to happen with some people running the iZ3D driver.
509 // They won't get acceleration.
510 return nullptr;
511 }
512
513 if (!mDeviceStatus) {
514 // If we haven't created a device yet, and have no existing device status,
515 // then this must be the compositor device. Pick the first adapter we can.
516 if (FAILED(factory1->EnumAdapters1(0, getter_AddRefs(mAdapter)))) {
517 return nullptr;
518 }
519 } else {
520 // In the UI and GPU process, we clear mDeviceStatus on device reset, so we
521 // should never reach here. Furthermore, the UI process does not create
522 // devices when using a GPU process.
523 //
524 // So, this should only ever get called on the content process or RDD
525 // process
526 MOZ_ASSERT(XRE_IsContentProcess() || XRE_IsRDDProcess());
527
528 // In the child process, we search for the adapter that matches the parent
529 // process. The first adapter can be mismatched on dual-GPU systems.
530 for (UINT index = 0;; index++) {
531 RefPtr<IDXGIAdapter1> adapter;
532 if (FAILED(factory1->EnumAdapters1(index, getter_AddRefs(adapter)))) {
533 break;
534 }
535
536 const DxgiAdapterDesc& preferred = mDeviceStatus->adapter();
537
538 DXGI_ADAPTER_DESC desc;
539 if (SUCCEEDED(adapter->GetDesc(&desc)) &&
540 desc.AdapterLuid.HighPart == preferred.AdapterLuid.HighPart &&
541 desc.AdapterLuid.LowPart == preferred.AdapterLuid.LowPart &&
542 desc.VendorId == preferred.VendorId &&
543 desc.DeviceId == preferred.DeviceId) {
544 mAdapter = adapter.forget();
545 break;
546 }
547 }
548 }
549
550 if (!mAdapter) {
551 return nullptr;
552 }
553
554 // We leak this module everywhere, we might as well do so here as well.
555 dxgiModule.disown();
556 return mAdapter;
557 }
558
CreateCompositorDeviceHelper(FeatureState & aD3d11,IDXGIAdapter1 * aAdapter,bool aAttemptVideoSupport,RefPtr<ID3D11Device> & aOutDevice)559 bool DeviceManagerDx::CreateCompositorDeviceHelper(
560 FeatureState& aD3d11, IDXGIAdapter1* aAdapter, bool aAttemptVideoSupport,
561 RefPtr<ID3D11Device>& aOutDevice) {
562 // Check if a failure was injected for testing.
563 if (StaticPrefs::gfx_testing_device_fail()) {
564 aD3d11.SetFailed(FeatureStatus::Failed,
565 "Direct3D11 device failure simulated by preference",
566 "FEATURE_FAILURE_D3D11_SIM"_ns);
567 return false;
568 }
569
570 UINT flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
571
572 DXGI_ADAPTER_DESC desc;
573 aAdapter->GetDesc(&desc);
574 if (desc.VendorId != 0x1414) {
575 // 0x1414 is Microsoft (e.g. WARP)
576 // When not using WARP, use
577 // D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS to prevent
578 // bug 1092260. IE 11 also uses this flag.
579 flags |= D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS;
580 }
581
582 if (aAttemptVideoSupport) {
583 flags |= D3D11_CREATE_DEVICE_VIDEO_SUPPORT;
584 }
585
586 HRESULT hr;
587 RefPtr<ID3D11Device> device;
588 if (!CreateDevice(aAdapter, D3D_DRIVER_TYPE_UNKNOWN, flags, hr, device)) {
589 if (!aAttemptVideoSupport) {
590 gfxCriticalError() << "Crash during D3D11 device creation";
591 aD3d11.SetFailed(FeatureStatus::CrashedInHandler,
592 "Crashed trying to acquire a D3D11 device",
593 "FEATURE_FAILURE_D3D11_DEVICE1"_ns);
594 }
595 return false;
596 }
597
598 if (FAILED(hr) || !device) {
599 if (!aAttemptVideoSupport) {
600 aD3d11.SetFailed(FeatureStatus::Failed,
601 "Failed to acquire a D3D11 device",
602 "FEATURE_FAILURE_D3D11_DEVICE2"_ns);
603 }
604 return false;
605 }
606 if (!D3D11Checks::DoesDeviceWork()) {
607 if (!aAttemptVideoSupport) {
608 aD3d11.SetFailed(FeatureStatus::Broken,
609 "Direct3D11 device was determined to be broken",
610 "FEATURE_FAILURE_D3D11_BROKEN"_ns);
611 }
612 return false;
613 }
614
615 aOutDevice = device;
616 return true;
617 }
618
619 // Note that it's enough for us to just use a counter for a unique ID,
620 // even though the counter isn't synchronized between processes. If we
621 // start in the GPU process and wind up in the parent process, the
622 // whole graphics stack is blown away anyway. But just in case, we
623 // make gpu process IDs negative and parent process IDs positive.
GetNextDeviceCounter()624 static inline int32_t GetNextDeviceCounter() {
625 static int32_t sDeviceCounter = 0;
626 return XRE_IsGPUProcess() ? --sDeviceCounter : ++sDeviceCounter;
627 }
628
CreateCompositorDevice(FeatureState & d3d11)629 void DeviceManagerDx::CreateCompositorDevice(FeatureState& d3d11) {
630 if (StaticPrefs::layers_d3d11_force_warp_AtStartup()) {
631 CreateWARPCompositorDevice();
632 return;
633 }
634
635 RefPtr<IDXGIAdapter1> adapter = GetDXGIAdapter();
636 if (!adapter) {
637 d3d11.SetFailed(FeatureStatus::Unavailable,
638 "Failed to acquire a DXGI adapter",
639 "FEATURE_FAILURE_D3D11_DXGI"_ns);
640 return;
641 }
642
643 if (XRE_IsGPUProcess() && !D3D11Checks::DoesRemotePresentWork(adapter)) {
644 d3d11.SetFailed(FeatureStatus::Unavailable,
645 "DXGI does not support out-of-process presentation",
646 "FEATURE_FAILURE_D3D11_REMOTE_PRESENT"_ns);
647 return;
648 }
649
650 RefPtr<ID3D11Device> device;
651 if (!CreateCompositorDeviceHelper(d3d11, adapter, true, device)) {
652 // Try again without video support and record that it failed.
653 mCompositorDeviceSupportsVideo = false;
654 if (!CreateCompositorDeviceHelper(d3d11, adapter, false, device)) {
655 return;
656 }
657 } else {
658 mCompositorDeviceSupportsVideo = true;
659 }
660
661 // Only test this when not using WARP since it can fail and cause
662 // GetDeviceRemovedReason to return weird values.
663 bool textureSharingWorks = D3D11Checks::DoesTextureSharingWork(device);
664
665 DXGI_ADAPTER_DESC desc;
666 PodZero(&desc);
667 adapter->GetDesc(&desc);
668
669 if (!textureSharingWorks) {
670 gfxConfig::SetFailed(Feature::D3D11_HW_ANGLE, FeatureStatus::Broken,
671 "Texture sharing doesn't work",
672 "FEATURE_FAILURE_HW_ANGLE_NEEDS_TEXTURE_SHARING"_ns);
673 }
674 if (D3D11Checks::DoesRenderTargetViewNeedRecreating(device)) {
675 gfxConfig::SetFailed(Feature::D3D11_HW_ANGLE, FeatureStatus::Broken,
676 "RenderTargetViews need recreating",
677 "FEATURE_FAILURE_HW_ANGLE_NEEDS_RTV_RECREATION"_ns);
678 }
679 if (XRE_IsParentProcess()) {
680 // It seems like this may only happen when we're using the NVIDIA gpu
681 D3D11Checks::WarnOnAdapterMismatch(device);
682 }
683
684 uint32_t featureLevel = device->GetFeatureLevel();
685 auto formatOptions = D3D11Checks::FormatOptions(device);
686 {
687 MutexAutoLock lock(mDeviceLock);
688 mCompositorDevice = device;
689
690 int32_t sequenceNumber = GetNextDeviceCounter();
691 mDeviceStatus = Some(D3D11DeviceStatus(
692 false, textureSharingWorks, featureLevel, DxgiAdapterDesc::From(desc),
693 sequenceNumber, formatOptions));
694 }
695 mCompositorDevice->SetExceptionMode(0);
696 }
697
CreateDevice(IDXGIAdapter * aAdapter,D3D_DRIVER_TYPE aDriverType,UINT aFlags,HRESULT & aResOut,RefPtr<ID3D11Device> & aOutDevice)698 bool DeviceManagerDx::CreateDevice(IDXGIAdapter* aAdapter,
699 D3D_DRIVER_TYPE aDriverType, UINT aFlags,
700 HRESULT& aResOut,
701 RefPtr<ID3D11Device>& aOutDevice) {
702 if (StaticPrefs::gfx_direct3d11_enable_debug_layer_AtStartup() ||
703 StaticPrefs::gfx_direct3d11_break_on_error_AtStartup()) {
704 aFlags |= D3D11_CREATE_DEVICE_DEBUG;
705 }
706
707 MOZ_SEH_TRY {
708 aResOut = sD3D11CreateDeviceFn(
709 aAdapter, aDriverType, nullptr, aFlags, mFeatureLevels.Elements(),
710 mFeatureLevels.Length(), D3D11_SDK_VERSION, getter_AddRefs(aOutDevice),
711 nullptr, nullptr);
712 }
713 MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { return false; }
714
715 if (StaticPrefs::gfx_direct3d11_break_on_error_AtStartup()) {
716 do {
717 if (!aOutDevice) break;
718
719 RefPtr<ID3D11Debug> debug;
720 if (!SUCCEEDED(aOutDevice->QueryInterface(__uuidof(ID3D11Debug),
721 getter_AddRefs(debug))))
722 break;
723
724 RefPtr<ID3D11InfoQueue> infoQueue;
725 if (!SUCCEEDED(debug->QueryInterface(__uuidof(ID3D11InfoQueue),
726 getter_AddRefs(infoQueue))))
727 break;
728
729 D3D11_INFO_QUEUE_FILTER filter;
730 PodZero(&filter);
731
732 // Disable warnings caused by Advanced Layers that are known and not
733 // problematic.
734 D3D11_MESSAGE_ID blockIDs[] = {
735 D3D11_MESSAGE_ID_DEVICE_DRAW_CONSTANT_BUFFER_TOO_SMALL};
736 filter.DenyList.NumIDs = MOZ_ARRAY_LENGTH(blockIDs);
737 filter.DenyList.pIDList = blockIDs;
738 infoQueue->PushStorageFilter(&filter);
739
740 infoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_CORRUPTION, true);
741 infoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_ERROR, true);
742 infoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_WARNING, true);
743 } while (false);
744 }
745
746 return true;
747 }
748
CreateWARPCompositorDevice()749 void DeviceManagerDx::CreateWARPCompositorDevice() {
750 ScopedGfxFeatureReporter reporterWARP(
751 "D3D11-WARP", StaticPrefs::layers_d3d11_force_warp_AtStartup());
752 FeatureState& d3d11 = gfxConfig::GetFeature(Feature::D3D11_COMPOSITING);
753
754 HRESULT hr;
755 RefPtr<ID3D11Device> device;
756
757 // Use D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS
758 // to prevent bug 1092260. IE 11 also uses this flag.
759 UINT flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
760 if (!CreateDevice(nullptr, D3D_DRIVER_TYPE_WARP, flags, hr, device)) {
761 gfxCriticalError() << "Exception occurred initializing WARP D3D11 device!";
762 d3d11.SetFailed(FeatureStatus::CrashedInHandler,
763 "Crashed creating a D3D11 WARP device",
764 "FEATURE_FAILURE_D3D11_WARP_DEVICE"_ns);
765 }
766
767 if (FAILED(hr) || !device) {
768 // This should always succeed... in theory.
769 gfxCriticalError() << "Failed to initialize WARP D3D11 device! "
770 << hexa(hr);
771 d3d11.SetFailed(FeatureStatus::Failed,
772 "Failed to create a D3D11 WARP device",
773 "FEATURE_FAILURE_D3D11_WARP_DEVICE2"_ns);
774 return;
775 }
776
777 // Only test for texture sharing on Windows 8 since it puts the device into
778 // an unusable state if used on Windows 7
779 bool textureSharingWorks = false;
780 if (IsWin8OrLater()) {
781 textureSharingWorks = D3D11Checks::DoesTextureSharingWork(device);
782 }
783
784 DXGI_ADAPTER_DESC desc;
785 D3D11Checks::GetDxgiDesc(device, &desc);
786
787 int featureLevel = device->GetFeatureLevel();
788
789 auto formatOptions = D3D11Checks::FormatOptions(device);
790 {
791 MutexAutoLock lock(mDeviceLock);
792 mCompositorDevice = device;
793
794 int32_t sequenceNumber = GetNextDeviceCounter();
795 mDeviceStatus = Some(D3D11DeviceStatus(
796 true, textureSharingWorks, featureLevel, DxgiAdapterDesc::From(desc),
797 sequenceNumber, formatOptions));
798 }
799 mCompositorDevice->SetExceptionMode(0);
800
801 reporterWARP.SetSuccessful();
802 }
803
CreateContentDevice()804 FeatureStatus DeviceManagerDx::CreateContentDevice() {
805 RefPtr<IDXGIAdapter1> adapter;
806 if (!mDeviceStatus->isWARP()) {
807 adapter = GetDXGIAdapter();
808 if (!adapter) {
809 gfxCriticalNote << "Could not get a DXGI adapter";
810 return FeatureStatus::Unavailable;
811 }
812 }
813
814 HRESULT hr;
815 RefPtr<ID3D11Device> device;
816
817 UINT flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
818 D3D_DRIVER_TYPE type =
819 mDeviceStatus->isWARP() ? D3D_DRIVER_TYPE_WARP : D3D_DRIVER_TYPE_UNKNOWN;
820 if (!CreateDevice(adapter, type, flags, hr, device)) {
821 gfxCriticalNote
822 << "Recovered from crash while creating a D3D11 content device";
823 gfxWindowsPlatform::RecordContentDeviceFailure(
824 TelemetryDeviceCode::Content);
825 return FeatureStatus::CrashedInHandler;
826 }
827
828 if (FAILED(hr) || !device) {
829 gfxCriticalNote << "Failed to create a D3D11 content device: " << hexa(hr);
830 gfxWindowsPlatform::RecordContentDeviceFailure(
831 TelemetryDeviceCode::Content);
832 return FeatureStatus::Failed;
833 }
834
835 // InitializeD2D() will abort early if the compositor device did not support
836 // texture sharing. If we're in the content process, we can't rely on the
837 // parent device alone: some systems have dual GPUs that are capable of
838 // binding the parent and child processes to different GPUs. As a safety net,
839 // we re-check texture sharing against the newly created D3D11 content device.
840 // If it fails, we won't use Direct2D.
841 if (XRE_IsContentProcess()) {
842 if (!D3D11Checks::DoesTextureSharingWork(device)) {
843 return FeatureStatus::Failed;
844 }
845
846 DebugOnly<bool> ok = ContentAdapterIsParentAdapter(device);
847 MOZ_ASSERT(ok);
848 }
849
850 {
851 MutexAutoLock lock(mDeviceLock);
852 mContentDevice = device;
853 }
854 mContentDevice->SetExceptionMode(0);
855
856 RefPtr<ID3D10Multithread> multi;
857 hr = mContentDevice->QueryInterface(__uuidof(ID3D10Multithread),
858 getter_AddRefs(multi));
859 if (SUCCEEDED(hr) && multi) {
860 multi->SetMultithreadProtected(TRUE);
861 }
862 return FeatureStatus::Available;
863 }
864
CreateDecoderDevice()865 RefPtr<ID3D11Device> DeviceManagerDx::CreateDecoderDevice() {
866 bool isAMD = false;
867 {
868 MutexAutoLock lock(mDeviceLock);
869 if (!mDeviceStatus) {
870 return nullptr;
871 }
872 isAMD = mDeviceStatus->adapter().VendorId == 0x1002;
873 }
874
875 bool reuseDevice = false;
876 if (StaticPrefs::gfx_direct3d11_reuse_decoder_device() < 0) {
877 // Use the default logic, which is to allow reuse of devices on AMD, but
878 // create separate devices everywhere else.
879 if (isAMD) {
880 reuseDevice = true;
881 }
882 } else if (StaticPrefs::gfx_direct3d11_reuse_decoder_device() > 0) {
883 reuseDevice = true;
884 }
885
886 if (reuseDevice) {
887 if (mCompositorDevice && mCompositorDeviceSupportsVideo &&
888 !mDecoderDevice) {
889 mDecoderDevice = mCompositorDevice;
890
891 RefPtr<ID3D10Multithread> multi;
892 mDecoderDevice->QueryInterface(__uuidof(ID3D10Multithread),
893 getter_AddRefs(multi));
894 if (multi) {
895 multi->SetMultithreadProtected(TRUE);
896 }
897 }
898
899 if (mDecoderDevice) {
900 RefPtr<ID3D11Device> dev = mDecoderDevice;
901 return dev.forget();
902 }
903 }
904
905 if (!sD3D11CreateDeviceFn) {
906 // We should just be on Windows Vista or XP in this case.
907 return nullptr;
908 }
909
910 RefPtr<IDXGIAdapter1> adapter = GetDXGIAdapter();
911 if (!adapter) {
912 return nullptr;
913 }
914
915 HRESULT hr;
916 RefPtr<ID3D11Device> device;
917
918 UINT flags = D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS |
919 D3D11_CREATE_DEVICE_VIDEO_SUPPORT;
920 if (!CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, flags, hr, device)) {
921 return nullptr;
922 }
923 if (FAILED(hr) || !device || !D3D11Checks::DoesDeviceWork()) {
924 return nullptr;
925 }
926
927 RefPtr<ID3D10Multithread> multi;
928 device->QueryInterface(__uuidof(ID3D10Multithread), getter_AddRefs(multi));
929 if (multi) {
930 multi->SetMultithreadProtected(TRUE);
931 }
932 if (reuseDevice) {
933 mDecoderDevice = device;
934 }
935 return device;
936 }
937
ResetDevices()938 void DeviceManagerDx::ResetDevices() {
939 MutexAutoLock lock(mDeviceLock);
940
941 mAdapter = nullptr;
942 mCompositorAttachments = nullptr;
943 mCompositorDevice = nullptr;
944 mContentDevice = nullptr;
945 mCanvasDevice = nullptr;
946 mImageDevice = nullptr;
947 mDirectCompositionDevice = nullptr;
948 mDeviceStatus = Nothing();
949 mDeviceResetReason = Nothing();
950 Factory::SetDirect3D11Device(nullptr);
951 }
952
MaybeResetAndReacquireDevices()953 bool DeviceManagerDx::MaybeResetAndReacquireDevices() {
954 DeviceResetReason resetReason;
955 if (!HasDeviceReset(&resetReason)) {
956 return false;
957 }
958
959 GPUProcessManager::RecordDeviceReset(resetReason);
960
961 bool createCompositorDevice = !!mCompositorDevice;
962 bool createContentDevice = !!mContentDevice;
963 bool createCanvasDevice = !!mCanvasDevice;
964 bool createDirectCompositionDevice = !!mDirectCompositionDevice;
965
966 ResetDevices();
967
968 if (createCompositorDevice && !CreateCompositorDevices()) {
969 // Just stop, don't try anything more
970 return true;
971 }
972 if (createContentDevice) {
973 CreateContentDevices();
974 }
975 if (createCanvasDevice) {
976 CreateCanvasDevice();
977 }
978 if (createDirectCompositionDevice) {
979 CreateDirectCompositionDevice();
980 }
981
982 return true;
983 }
984
ContentAdapterIsParentAdapter(ID3D11Device * device)985 bool DeviceManagerDx::ContentAdapterIsParentAdapter(ID3D11Device* device) {
986 DXGI_ADAPTER_DESC desc;
987 if (!D3D11Checks::GetDxgiDesc(device, &desc)) {
988 gfxCriticalNote << "Could not query device DXGI adapter info";
989 return false;
990 }
991
992 const DxgiAdapterDesc& preferred = mDeviceStatus->adapter();
993
994 if (desc.VendorId != preferred.VendorId ||
995 desc.DeviceId != preferred.DeviceId ||
996 desc.SubSysId != preferred.SubSysId ||
997 desc.AdapterLuid.HighPart != preferred.AdapterLuid.HighPart ||
998 desc.AdapterLuid.LowPart != preferred.AdapterLuid.LowPart) {
999 gfxCriticalNote << "VendorIDMismatch P " << hexa(preferred.VendorId) << " "
1000 << hexa(desc.VendorId);
1001 return false;
1002 }
1003
1004 return true;
1005 }
1006
HResultToResetReason(HRESULT hr)1007 static DeviceResetReason HResultToResetReason(HRESULT hr) {
1008 switch (hr) {
1009 case DXGI_ERROR_DEVICE_HUNG:
1010 return DeviceResetReason::HUNG;
1011 case DXGI_ERROR_DEVICE_REMOVED:
1012 return DeviceResetReason::REMOVED;
1013 case DXGI_ERROR_DEVICE_RESET:
1014 return DeviceResetReason::RESET;
1015 case DXGI_ERROR_DRIVER_INTERNAL_ERROR:
1016 return DeviceResetReason::DRIVER_ERROR;
1017 case DXGI_ERROR_INVALID_CALL:
1018 return DeviceResetReason::INVALID_CALL;
1019 case E_OUTOFMEMORY:
1020 return DeviceResetReason::OUT_OF_MEMORY;
1021 default:
1022 MOZ_ASSERT(false);
1023 }
1024 return DeviceResetReason::OTHER;
1025 }
1026
HasDeviceReset(DeviceResetReason * aOutReason)1027 bool DeviceManagerDx::HasDeviceReset(DeviceResetReason* aOutReason) {
1028 MutexAutoLock lock(mDeviceLock);
1029
1030 if (mDeviceResetReason) {
1031 if (aOutReason) {
1032 *aOutReason = mDeviceResetReason.value();
1033 }
1034 return true;
1035 }
1036
1037 DeviceResetReason reason;
1038 if (GetAnyDeviceRemovedReason(&reason)) {
1039 mDeviceResetReason = Some(reason);
1040 if (aOutReason) {
1041 *aOutReason = reason;
1042 }
1043 return true;
1044 }
1045
1046 return false;
1047 }
1048
DidDeviceReset(const RefPtr<ID3D11Device> & aDevice,DeviceResetReason * aOutReason)1049 static inline bool DidDeviceReset(const RefPtr<ID3D11Device>& aDevice,
1050 DeviceResetReason* aOutReason) {
1051 if (!aDevice) {
1052 return false;
1053 }
1054 HRESULT hr = aDevice->GetDeviceRemovedReason();
1055 if (hr == S_OK) {
1056 return false;
1057 }
1058
1059 *aOutReason = HResultToResetReason(hr);
1060 return true;
1061 }
1062
GetAnyDeviceRemovedReason(DeviceResetReason * aOutReason)1063 bool DeviceManagerDx::GetAnyDeviceRemovedReason(DeviceResetReason* aOutReason) {
1064 // Caller must own the lock, since we access devices directly, and can be
1065 // called from any thread.
1066 mDeviceLock.AssertCurrentThreadOwns();
1067
1068 if (DidDeviceReset(mCompositorDevice, aOutReason) ||
1069 DidDeviceReset(mContentDevice, aOutReason) ||
1070 DidDeviceReset(mCanvasDevice, aOutReason)) {
1071 return true;
1072 }
1073
1074 if (XRE_IsParentProcess() && NS_IsMainThread() &&
1075 StaticPrefs::gfx_testing_device_reset()) {
1076 Preferences::SetInt("gfx.testing.device-reset", 0);
1077 *aOutReason = DeviceResetReason::FORCED_RESET;
1078 return true;
1079 }
1080
1081 return false;
1082 }
1083
ForceDeviceReset(ForcedDeviceResetReason aReason)1084 void DeviceManagerDx::ForceDeviceReset(ForcedDeviceResetReason aReason) {
1085 Telemetry::Accumulate(Telemetry::FORCED_DEVICE_RESET_REASON,
1086 uint32_t(aReason));
1087 {
1088 MutexAutoLock lock(mDeviceLock);
1089 if (!mDeviceResetReason) {
1090 mDeviceResetReason = Some(DeviceResetReason::FORCED_RESET);
1091 }
1092 }
1093 }
1094
DisableD3D11AfterCrash()1095 void DeviceManagerDx::DisableD3D11AfterCrash() {
1096 gfxConfig::Disable(Feature::D3D11_COMPOSITING,
1097 FeatureStatus::CrashedInHandler,
1098 "Crashed while acquiring a Direct3D11 device",
1099 "FEATURE_FAILURE_D3D11_CRASH"_ns);
1100 ResetDevices();
1101 }
1102
GetCompositorDevice()1103 RefPtr<ID3D11Device> DeviceManagerDx::GetCompositorDevice() {
1104 MutexAutoLock lock(mDeviceLock);
1105 return mCompositorDevice;
1106 }
1107
GetContentDevice()1108 RefPtr<ID3D11Device> DeviceManagerDx::GetContentDevice() {
1109 MOZ_ASSERT(XRE_IsGPUProcess() ||
1110 gfxPlatform::GetPlatform()->DevicesInitialized());
1111
1112 MutexAutoLock lock(mDeviceLock);
1113 return mContentDevice;
1114 }
1115
GetImageDevice()1116 RefPtr<ID3D11Device> DeviceManagerDx::GetImageDevice() {
1117 MutexAutoLock lock(mDeviceLock);
1118 if (mImageDevice) {
1119 return mImageDevice;
1120 }
1121
1122 RefPtr<ID3D11Device> device = mContentDevice;
1123 if (!device) {
1124 device = mCompositorDevice;
1125 }
1126
1127 if (!device) {
1128 return nullptr;
1129 }
1130
1131 RefPtr<ID3D10Multithread> multi;
1132 HRESULT hr =
1133 device->QueryInterface((ID3D10Multithread**)getter_AddRefs(multi));
1134 if (FAILED(hr) || !multi) {
1135 gfxWarning() << "Multithread safety interface not supported. " << hr;
1136 return nullptr;
1137 }
1138 multi->SetMultithreadProtected(TRUE);
1139
1140 mImageDevice = device;
1141
1142 return mImageDevice;
1143 }
1144
GetVRDevice()1145 RefPtr<ID3D11Device> DeviceManagerDx::GetVRDevice() {
1146 MutexAutoLock lock(mDeviceLock);
1147 if (!mVRDevice) {
1148 CreateVRDevice();
1149 }
1150 return mVRDevice;
1151 }
1152
GetCanvasDevice()1153 RefPtr<ID3D11Device> DeviceManagerDx::GetCanvasDevice() {
1154 MutexAutoLock lock(mDeviceLock);
1155 return mCanvasDevice;
1156 }
1157
GetDirectCompositionDevice()1158 RefPtr<IDCompositionDevice2> DeviceManagerDx::GetDirectCompositionDevice() {
1159 MutexAutoLock lock(mDeviceLock);
1160 return mDirectCompositionDevice;
1161 }
1162
GetCompositorFeatureLevel() const1163 unsigned DeviceManagerDx::GetCompositorFeatureLevel() const {
1164 if (!mDeviceStatus) {
1165 return 0;
1166 }
1167 return mDeviceStatus->featureLevel();
1168 }
1169
TextureSharingWorks()1170 bool DeviceManagerDx::TextureSharingWorks() {
1171 MutexAutoLock lock(mDeviceLock);
1172 if (!mDeviceStatus) {
1173 return false;
1174 }
1175 return mDeviceStatus->textureSharingWorks();
1176 }
1177
CanInitializeKeyedMutexTextures()1178 bool DeviceManagerDx::CanInitializeKeyedMutexTextures() {
1179 MutexAutoLock lock(mDeviceLock);
1180 return mDeviceStatus && StaticPrefs::gfx_direct3d11_allow_keyed_mutex() &&
1181 gfxVars::AllowD3D11KeyedMutex();
1182 }
1183
HasCrashyInitData()1184 bool DeviceManagerDx::HasCrashyInitData() {
1185 MutexAutoLock lock(mDeviceLock);
1186 if (!mDeviceStatus) {
1187 return false;
1188 }
1189
1190 return (mDeviceStatus->adapter().VendorId == 0x8086 && !IsWin10OrLater());
1191 }
1192
CheckRemotePresentSupport()1193 bool DeviceManagerDx::CheckRemotePresentSupport() {
1194 MOZ_ASSERT(XRE_IsParentProcess());
1195
1196 RefPtr<IDXGIAdapter1> adapter = GetDXGIAdapter();
1197 if (!adapter) {
1198 return false;
1199 }
1200 if (!D3D11Checks::DoesRemotePresentWork(adapter)) {
1201 return false;
1202 }
1203 return true;
1204 }
1205
IsWARP()1206 bool DeviceManagerDx::IsWARP() {
1207 MutexAutoLock lock(mDeviceLock);
1208 if (!mDeviceStatus) {
1209 return false;
1210 }
1211 return mDeviceStatus->isWARP();
1212 }
1213
CanUseNV12()1214 bool DeviceManagerDx::CanUseNV12() {
1215 MutexAutoLock lock(mDeviceLock);
1216 if (!mDeviceStatus) {
1217 return false;
1218 }
1219 return mDeviceStatus->formatOptions().contains(
1220 D3D11Checks::VideoFormatOption::NV12);
1221 }
1222
CanUseP010()1223 bool DeviceManagerDx::CanUseP010() {
1224 MutexAutoLock lock(mDeviceLock);
1225 if (!mDeviceStatus) {
1226 return false;
1227 }
1228 return mDeviceStatus->formatOptions().contains(
1229 D3D11Checks::VideoFormatOption::P010);
1230 }
1231
CanUseP016()1232 bool DeviceManagerDx::CanUseP016() {
1233 MutexAutoLock lock(mDeviceLock);
1234 if (!mDeviceStatus) {
1235 return false;
1236 }
1237 return mDeviceStatus->formatOptions().contains(
1238 D3D11Checks::VideoFormatOption::P016);
1239 }
1240
CanUseDComp()1241 bool DeviceManagerDx::CanUseDComp() {
1242 MutexAutoLock lock(mDeviceLock);
1243 return !!mDirectCompositionDevice;
1244 }
1245
InitializeDirectDraw()1246 void DeviceManagerDx::InitializeDirectDraw() {
1247 MOZ_ASSERT(layers::CompositorThreadHolder::IsInCompositorThread());
1248
1249 if (mDirectDraw) {
1250 // Already initialized.
1251 return;
1252 }
1253
1254 FeatureState& ddraw = gfxConfig::GetFeature(Feature::DIRECT_DRAW);
1255 if (!ddraw.IsEnabled()) {
1256 return;
1257 }
1258
1259 // Check if DirectDraw is available on this system.
1260 mDirectDrawDLL.own(LoadLibrarySystem32(L"ddraw.dll"));
1261 if (!mDirectDrawDLL) {
1262 ddraw.SetFailed(FeatureStatus::Unavailable,
1263 "DirectDraw not available on this computer",
1264 "FEATURE_FAILURE_DDRAW_LIB"_ns);
1265 return;
1266 }
1267
1268 sDirectDrawCreateExFn = (decltype(DirectDrawCreateEx)*)GetProcAddress(
1269 mDirectDrawDLL, "DirectDrawCreateEx");
1270 if (!sDirectDrawCreateExFn) {
1271 ddraw.SetFailed(FeatureStatus::Unavailable,
1272 "DirectDraw not available on this computer",
1273 "FEATURE_FAILURE_DDRAW_LIB"_ns);
1274 return;
1275 }
1276
1277 HRESULT hr;
1278 MOZ_SEH_TRY {
1279 hr = sDirectDrawCreateExFn(nullptr, getter_AddRefs(mDirectDraw),
1280 IID_IDirectDraw7, nullptr);
1281 }
1282 MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
1283 ddraw.SetFailed(FeatureStatus::Failed, "Failed to create DirectDraw",
1284 "FEATURE_FAILURE_DDRAW_LIB"_ns);
1285 gfxCriticalNote << "DoesCreatingDirectDrawFailed";
1286 return;
1287 }
1288 if (FAILED(hr)) {
1289 ddraw.SetFailed(FeatureStatus::Failed, "Failed to create DirectDraw",
1290 "FEATURE_FAILURE_DDRAW_LIB"_ns);
1291 gfxCriticalNote << "DoesCreatingDirectDrawFailed " << hexa(hr);
1292 return;
1293 }
1294 }
1295
GetDirectDraw()1296 IDirectDraw7* DeviceManagerDx::GetDirectDraw() { return mDirectDraw; }
1297
GetCompositorDevices(RefPtr<ID3D11Device> * aOutDevice,RefPtr<layers::DeviceAttachmentsD3D11> * aOutAttachments)1298 void DeviceManagerDx::GetCompositorDevices(
1299 RefPtr<ID3D11Device>* aOutDevice,
1300 RefPtr<layers::DeviceAttachmentsD3D11>* aOutAttachments) {
1301 RefPtr<ID3D11Device> device;
1302 {
1303 MutexAutoLock lock(mDeviceLock);
1304 if (!mCompositorDevice) {
1305 return;
1306 }
1307 if (mCompositorAttachments) {
1308 *aOutDevice = mCompositorDevice;
1309 *aOutAttachments = mCompositorAttachments;
1310 return;
1311 }
1312
1313 // Otherwise, we'll try to create attachments outside the lock.
1314 device = mCompositorDevice;
1315 }
1316
1317 // We save the attachments object even if it fails to initialize, so the
1318 // compositor can grab the failure ID.
1319 RefPtr<layers::DeviceAttachmentsD3D11> attachments =
1320 layers::DeviceAttachmentsD3D11::Create(device);
1321 {
1322 MutexAutoLock lock(mDeviceLock);
1323 if (device != mCompositorDevice) {
1324 return;
1325 }
1326 mCompositorAttachments = attachments;
1327 }
1328
1329 *aOutDevice = device;
1330 *aOutAttachments = attachments;
1331 }
1332
1333 /* static */
PreloadAttachmentsOnCompositorThread()1334 void DeviceManagerDx::PreloadAttachmentsOnCompositorThread() {
1335 if (!CompositorThread()) {
1336 return;
1337 }
1338
1339 RefPtr<Runnable> task = NS_NewRunnableFunction(
1340 "DeviceManagerDx::PreloadAttachmentsOnCompositorThread", []() -> void {
1341 if (DeviceManagerDx* dm = DeviceManagerDx::Get()) {
1342 RefPtr<ID3D11Device> device;
1343 RefPtr<layers::DeviceAttachmentsD3D11> attachments;
1344 dm->GetCompositorDevices(&device, &attachments);
1345 }
1346 });
1347 CompositorThread()->Dispatch(task.forget());
1348 }
1349
1350 } // namespace gfx
1351 } // namespace mozilla
1352