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