1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
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 "gfxPrefs.h"
11 #include "gfxWindowsPlatform.h"
12 #include "mozilla/D3DMessageUtils.h"
13 #include "mozilla/Telemetry.h"
14 #include "mozilla/WindowsVersion.h"
15 #include "mozilla/gfx/GraphicsMessages.h"
16 #include "mozilla/gfx/Logging.h"
17 #include "mozilla/layers/CompositorThread.h"
18 #include "nsIGfxInfo.h"
19 #include <d3d11.h>
20 #include <ddraw.h>
21
22 namespace mozilla {
23 namespace gfx {
24
25 using namespace mozilla::widget;
26
27 StaticAutoPtr<DeviceManagerDx> DeviceManagerDx::sInstance;
28
29 // We don't have access to the D3D11CreateDevice type in gfxWindowsPlatform.h,
30 // since it doesn't include d3d11.h, so we use a static here. It should only
31 // be used within InitializeD3D11.
32 decltype(D3D11CreateDevice)* sD3D11CreateDeviceFn = nullptr;
33
34 // We don't have access to the DirectDrawCreateEx type in gfxWindowsPlatform.h,
35 // since it doesn't include ddraw.h, so we use a static here. It should only
36 // be used within InitializeDirectDrawConfig.
37 decltype(DirectDrawCreateEx)* sDirectDrawCreateExFn = nullptr;
38
39 /* static */ void
Init()40 DeviceManagerDx::Init()
41 {
42 sInstance = new DeviceManagerDx();
43 }
44
45 /* static */ void
Shutdown()46 DeviceManagerDx::Shutdown()
47 {
48 sInstance = nullptr;
49 }
50
DeviceManagerDx()51 DeviceManagerDx::DeviceManagerDx()
52 : mDeviceLock("gfxWindowsPlatform.mDeviceLock"),
53 mCompositorDeviceSupportsVideo(false)
54 {
55 // Set up the D3D11 feature levels we can ask for.
56 if (IsWin8OrLater()) {
57 mFeatureLevels.AppendElement(D3D_FEATURE_LEVEL_11_1);
58 }
59 mFeatureLevels.AppendElement(D3D_FEATURE_LEVEL_11_0);
60 mFeatureLevels.AppendElement(D3D_FEATURE_LEVEL_10_1);
61 mFeatureLevels.AppendElement(D3D_FEATURE_LEVEL_10_0);
62 }
63
64 bool
LoadD3D11()65 DeviceManagerDx::LoadD3D11()
66 {
67 FeatureState& d3d11 = gfxConfig::GetFeature(Feature::D3D11_COMPOSITING);
68 MOZ_ASSERT(d3d11.IsEnabled());
69
70 if (sD3D11CreateDeviceFn) {
71 return true;
72 }
73
74 nsModuleHandle module(LoadLibrarySystem32(L"d3d11.dll"));
75 if (!module) {
76 d3d11.SetFailed(FeatureStatus::Unavailable, "Direct3D11 not available on this computer",
77 NS_LITERAL_CSTRING("FEATURE_FAILURE_D3D11_LIB"));
78 return false;
79 }
80
81 sD3D11CreateDeviceFn =
82 (decltype(D3D11CreateDevice)*)GetProcAddress(module, "D3D11CreateDevice");
83 if (!sD3D11CreateDeviceFn) {
84 // We should just be on Windows Vista or XP in this case.
85 d3d11.SetFailed(FeatureStatus::Unavailable, "Direct3D11 not available on this computer",
86 NS_LITERAL_CSTRING("FEATURE_FAILURE_D3D11_FUNCPTR"));
87 return false;
88 }
89
90 mD3D11Module.steal(module);
91 return true;
92 }
93
94 void
ReleaseD3D11()95 DeviceManagerDx::ReleaseD3D11()
96 {
97 MOZ_ASSERT(!mCompositorDevice);
98 MOZ_ASSERT(!mContentDevice);
99 MOZ_ASSERT(!mDecoderDevice);
100
101 mD3D11Module.reset();
102 sD3D11CreateDeviceFn = nullptr;
103 }
104
105 static inline bool
ProcessOwnsCompositor()106 ProcessOwnsCompositor()
107 {
108 return XRE_GetProcessType() == GeckoProcessType_GPU ||
109 (XRE_IsParentProcess() && !gfxConfig::IsEnabled(Feature::GPU_PROCESS));
110 }
111
112 bool
CreateCompositorDevices()113 DeviceManagerDx::CreateCompositorDevices()
114 {
115 MOZ_ASSERT(ProcessOwnsCompositor());
116
117 FeatureState& d3d11 = gfxConfig::GetFeature(Feature::D3D11_COMPOSITING);
118 MOZ_ASSERT(d3d11.IsEnabled());
119
120 if (!LoadD3D11()) {
121 return false;
122 }
123
124 CreateCompositorDevice(d3d11);
125
126 if (!d3d11.IsEnabled()) {
127 MOZ_ASSERT(!mCompositorDevice);
128 ReleaseD3D11();
129 return false;
130 }
131
132 // We leak these everywhere and we need them our entire runtime anyway, let's
133 // leak it here as well. We keep the pointer to sD3D11CreateDeviceFn around
134 // as well for D2D1 and device resets.
135 mD3D11Module.disown();
136
137 MOZ_ASSERT(mCompositorDevice);
138 return d3d11.IsEnabled();
139 }
140
141 void
ImportDeviceInfo(const D3D11DeviceStatus & aDeviceStatus)142 DeviceManagerDx::ImportDeviceInfo(const D3D11DeviceStatus& aDeviceStatus)
143 {
144 MOZ_ASSERT(!ProcessOwnsCompositor());
145
146 mDeviceStatus = Some(aDeviceStatus);
147 }
148
149 void
ExportDeviceInfo(D3D11DeviceStatus * aOut)150 DeviceManagerDx::ExportDeviceInfo(D3D11DeviceStatus* aOut)
151 {
152 // Even though the parent process might not own the compositor, we still
153 // populate DeviceManagerDx with device statistics (for simplicity).
154 // That means it still gets queried for compositor information.
155 MOZ_ASSERT(XRE_IsParentProcess() || XRE_GetProcessType() == GeckoProcessType_GPU);
156
157 if (mDeviceStatus) {
158 *aOut = mDeviceStatus.value();
159 }
160 }
161
162 void
CreateContentDevices()163 DeviceManagerDx::CreateContentDevices()
164 {
165 MOZ_ASSERT(gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING));
166
167 if (!LoadD3D11()) {
168 return;
169 }
170
171 // We should have been assigned a DeviceStatus from the parent process,
172 // GPU process, or the same process if using in-process compositing.
173 MOZ_ASSERT(mDeviceStatus);
174
175 if (CreateContentDevice() == FeatureStatus::CrashedInHandler) {
176 DisableD3D11AfterCrash();
177 }
178 }
179
180 IDXGIAdapter1*
GetDXGIAdapter()181 DeviceManagerDx::GetDXGIAdapter()
182 {
183 if (mAdapter) {
184 return mAdapter;
185 }
186
187 nsModuleHandle dxgiModule(LoadLibrarySystem32(L"dxgi.dll"));
188 decltype(CreateDXGIFactory1)* createDXGIFactory1 = (decltype(CreateDXGIFactory1)*)
189 GetProcAddress(dxgiModule, "CreateDXGIFactory1");
190
191 if (!createDXGIFactory1) {
192 return nullptr;
193 }
194
195 // Try to use a DXGI 1.1 adapter in order to share resources
196 // across processes.
197 RefPtr<IDXGIFactory1> factory1;
198 HRESULT hr = createDXGIFactory1(__uuidof(IDXGIFactory1),
199 getter_AddRefs(factory1));
200 if (FAILED(hr) || !factory1) {
201 // This seems to happen with some people running the iZ3D driver.
202 // They won't get acceleration.
203 return nullptr;
204 }
205
206 if (!mDeviceStatus) {
207 // If we haven't created a device yet, and have no existing device status,
208 // then this must be the compositor device. Pick the first adapter we can.
209 if (FAILED(factory1->EnumAdapters1(0, getter_AddRefs(mAdapter)))) {
210 return nullptr;
211 }
212 } else {
213 // In the UI and GPU process, we clear mDeviceStatus on device reset, so we
214 // should never reach here. Furthermore, the UI process does not create
215 // devices when using a GPU process.
216 //
217 // So, this should only ever get called on the content process.
218 MOZ_ASSERT(XRE_IsContentProcess());
219
220 // In the child process, we search for the adapter that matches the parent
221 // process. The first adapter can be mismatched on dual-GPU systems.
222 for (UINT index = 0; ; index++) {
223 RefPtr<IDXGIAdapter1> adapter;
224 if (FAILED(factory1->EnumAdapters1(index, getter_AddRefs(adapter)))) {
225 break;
226 }
227
228 const DxgiAdapterDesc& preferred = mDeviceStatus->adapter();
229
230 DXGI_ADAPTER_DESC desc;
231 if (SUCCEEDED(adapter->GetDesc(&desc)) &&
232 desc.AdapterLuid.HighPart == preferred.AdapterLuid.HighPart &&
233 desc.AdapterLuid.LowPart == preferred.AdapterLuid.LowPart &&
234 desc.VendorId == preferred.VendorId &&
235 desc.DeviceId == preferred.DeviceId)
236 {
237 mAdapter = adapter.forget();
238 break;
239 }
240 }
241 }
242
243 if (!mAdapter) {
244 return nullptr;
245 }
246
247 // We leak this module everywhere, we might as well do so here as well.
248 dxgiModule.disown();
249 return mAdapter;
250 }
251
252 bool
CreateCompositorDeviceHelper(FeatureState & aD3d11,IDXGIAdapter1 * aAdapter,bool aAttemptVideoSupport,RefPtr<ID3D11Device> & aOutDevice)253 DeviceManagerDx::CreateCompositorDeviceHelper(
254 FeatureState& aD3d11, IDXGIAdapter1* aAdapter, bool aAttemptVideoSupport, RefPtr<ID3D11Device>& aOutDevice)
255 {
256 // Check if a failure was injected for testing.
257 if (gfxPrefs::DeviceFailForTesting()) {
258 aD3d11.SetFailed(FeatureStatus::Failed, "Direct3D11 device failure simulated by preference",
259 NS_LITERAL_CSTRING("FEATURE_FAILURE_D3D11_SIM"));
260 return false;
261 }
262
263 // Use D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS
264 // to prevent bug 1092260. IE 11 also uses this flag.
265 UINT flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT | D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS;
266 if (aAttemptVideoSupport) {
267 flags |= D3D11_CREATE_DEVICE_VIDEO_SUPPORT;
268 }
269
270 HRESULT hr;
271 RefPtr<ID3D11Device> device;
272 if (!CreateDevice(aAdapter, D3D_DRIVER_TYPE_UNKNOWN, flags, hr, device)) {
273 if (!aAttemptVideoSupport) {
274 gfxCriticalError() << "Crash during D3D11 device creation";
275 aD3d11.SetFailed(FeatureStatus::CrashedInHandler, "Crashed trying to acquire a D3D11 device",
276 NS_LITERAL_CSTRING("FEATURE_FAILURE_D3D11_DEVICE1"));
277 }
278 return false;
279 }
280
281 if (FAILED(hr) || !device) {
282 if (!aAttemptVideoSupport) {
283 aD3d11.SetFailed(FeatureStatus::Failed, "Failed to acquire a D3D11 device",
284 NS_LITERAL_CSTRING("FEATURE_FAILURE_D3D11_DEVICE2"));
285 }
286 return false;
287 }
288 if (!D3D11Checks::DoesDeviceWork()) {
289 if (!aAttemptVideoSupport) {
290 aD3d11.SetFailed(FeatureStatus::Broken, "Direct3D11 device was determined to be broken",
291 NS_LITERAL_CSTRING("FEATURE_FAILURE_D3D11_BROKEN"));
292 }
293 return false;
294 }
295
296 aOutDevice = device;
297 return true;
298 }
299
300 void
CreateCompositorDevice(FeatureState & d3d11)301 DeviceManagerDx::CreateCompositorDevice(FeatureState& d3d11)
302 {
303 if (gfxPrefs::LayersD3D11ForceWARP()) {
304 CreateWARPCompositorDevice();
305 return;
306 }
307
308 RefPtr<IDXGIAdapter1> adapter = GetDXGIAdapter();
309 if (!adapter) {
310 d3d11.SetFailed(FeatureStatus::Unavailable, "Failed to acquire a DXGI adapter",
311 NS_LITERAL_CSTRING("FEATURE_FAILURE_D3D11_DXGI"));
312 return;
313 }
314
315 if (XRE_IsGPUProcess() && !D3D11Checks::DoesRemotePresentWork(adapter)) {
316 d3d11.SetFailed(
317 FeatureStatus::Unavailable,
318 "DXGI does not support out-of-process presentation",
319 NS_LITERAL_CSTRING("FEATURE_FAILURE_D3D11_REMOTE_PRESENT"));
320 return;
321 }
322
323 RefPtr<ID3D11Device> device;
324 if (!CreateCompositorDeviceHelper(d3d11, adapter, true, device)) {
325 // Try again without video support and record that it failed.
326 mCompositorDeviceSupportsVideo = false;
327 if (!CreateCompositorDeviceHelper(d3d11, adapter, false, device)) {
328 return;
329 }
330 } else {
331 mCompositorDeviceSupportsVideo = true;
332 }
333
334 // Only test this when not using WARP since it can fail and cause
335 // GetDeviceRemovedReason to return weird values.
336 bool textureSharingWorks = D3D11Checks::DoesTextureSharingWork(device);
337
338 DXGI_ADAPTER_DESC desc;
339 PodZero(&desc);
340 adapter->GetDesc(&desc);
341
342 if (!textureSharingWorks) {
343 gfxConfig::SetFailed(Feature::D3D11_HW_ANGLE,
344 FeatureStatus::Broken,
345 "Texture sharing doesn't work");
346 }
347 if (D3D11Checks::DoesRenderTargetViewNeedRecreating(device)) {
348 gfxConfig::SetFailed(Feature::D3D11_HW_ANGLE,
349 FeatureStatus::Broken,
350 "RenderTargetViews need recreating");
351 }
352 if (XRE_IsParentProcess()) {
353 // It seems like this may only happen when we're using the NVIDIA gpu
354 D3D11Checks::WarnOnAdapterMismatch(device);
355 }
356
357 int featureLevel = device->GetFeatureLevel();
358 {
359 MutexAutoLock lock(mDeviceLock);
360 mCompositorDevice = device;
361 mDeviceStatus = Some(D3D11DeviceStatus(
362 false,
363 textureSharingWorks,
364 featureLevel,
365 DxgiAdapterDesc::From(desc)));
366 }
367 mCompositorDevice->SetExceptionMode(0);
368 }
369
370 bool
CreateDevice(IDXGIAdapter * aAdapter,D3D_DRIVER_TYPE aDriverType,UINT aFlags,HRESULT & aResOut,RefPtr<ID3D11Device> & aOutDevice)371 DeviceManagerDx::CreateDevice(IDXGIAdapter* aAdapter,
372 D3D_DRIVER_TYPE aDriverType,
373 UINT aFlags,
374 HRESULT& aResOut,
375 RefPtr<ID3D11Device>& aOutDevice)
376 {
377 MOZ_SEH_TRY {
378 aResOut = sD3D11CreateDeviceFn(
379 aAdapter, aDriverType, nullptr,
380 aFlags,
381 mFeatureLevels.Elements(), mFeatureLevels.Length(),
382 D3D11_SDK_VERSION, getter_AddRefs(aOutDevice), nullptr, nullptr);
383 } MOZ_SEH_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
384 return false;
385 }
386 return true;
387 }
388
389 void
CreateWARPCompositorDevice()390 DeviceManagerDx::CreateWARPCompositorDevice()
391 {
392 ScopedGfxFeatureReporter reporterWARP("D3D11-WARP", gfxPrefs::LayersD3D11ForceWARP());
393 FeatureState& d3d11 = gfxConfig::GetFeature(Feature::D3D11_COMPOSITING);
394
395 HRESULT hr;
396 RefPtr<ID3D11Device> device;
397
398 // Use D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS
399 // to prevent bug 1092260. IE 11 also uses this flag.
400 UINT flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
401 if (!CreateDevice(nullptr, D3D_DRIVER_TYPE_WARP, flags, hr, device)) {
402 gfxCriticalError() << "Exception occurred initializing WARP D3D11 device!";
403 d3d11.SetFailed(FeatureStatus::CrashedInHandler, "Crashed creating a D3D11 WARP device",
404 NS_LITERAL_CSTRING("FEATURE_FAILURE_D3D11_WARP_DEVICE"));
405 }
406
407 if (FAILED(hr) || !device) {
408 // This should always succeed... in theory.
409 gfxCriticalError() << "Failed to initialize WARP D3D11 device! " << hexa(hr);
410 d3d11.SetFailed(FeatureStatus::Failed, "Failed to create a D3D11 WARP device",
411 NS_LITERAL_CSTRING("FEATURE_FAILURE_D3D11_WARP_DEVICE2"));
412 return;
413 }
414
415 // Only test for texture sharing on Windows 8 since it puts the device into
416 // an unusable state if used on Windows 7
417 bool textureSharingWorks = false;
418 if (IsWin8OrLater()) {
419 textureSharingWorks = D3D11Checks::DoesTextureSharingWork(device);
420 }
421
422 DxgiAdapterDesc nullAdapter;
423 PodZero(&nullAdapter);
424
425 int featureLevel = device->GetFeatureLevel();
426 {
427 MutexAutoLock lock(mDeviceLock);
428 mCompositorDevice = device;
429 mDeviceStatus = Some(D3D11DeviceStatus(
430 true,
431 textureSharingWorks,
432 featureLevel,
433 nullAdapter));
434 }
435 mCompositorDevice->SetExceptionMode(0);
436
437 reporterWARP.SetSuccessful();
438 }
439
440 FeatureStatus
CreateContentDevice()441 DeviceManagerDx::CreateContentDevice()
442 {
443 RefPtr<IDXGIAdapter1> adapter;
444 if (!mDeviceStatus->isWARP()) {
445 adapter = GetDXGIAdapter();
446 if (!adapter) {
447 gfxCriticalNote << "Could not get a DXGI adapter";
448 return FeatureStatus::Unavailable;
449 }
450 }
451
452 HRESULT hr;
453 RefPtr<ID3D11Device> device;
454
455 UINT flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
456 D3D_DRIVER_TYPE type = mDeviceStatus->isWARP()
457 ? D3D_DRIVER_TYPE_WARP
458 : D3D_DRIVER_TYPE_UNKNOWN;
459 if (!CreateDevice(adapter, type, flags, hr, device)) {
460 gfxCriticalNote << "Recovered from crash while creating a D3D11 content device";
461 gfxWindowsPlatform::RecordContentDeviceFailure(TelemetryDeviceCode::Content);
462 return FeatureStatus::CrashedInHandler;
463 }
464
465 if (FAILED(hr) || !device) {
466 gfxCriticalNote << "Failed to create a D3D11 content device: " << hexa(hr);
467 gfxWindowsPlatform::RecordContentDeviceFailure(TelemetryDeviceCode::Content);
468 return FeatureStatus::Failed;
469 }
470
471 // InitializeD2D() will abort early if the compositor device did not support
472 // texture sharing. If we're in the content process, we can't rely on the
473 // parent device alone: some systems have dual GPUs that are capable of
474 // binding the parent and child processes to different GPUs. As a safety net,
475 // we re-check texture sharing against the newly created D3D11 content device.
476 // If it fails, we won't use Direct2D.
477 if (XRE_IsContentProcess()) {
478 if (!D3D11Checks::DoesTextureSharingWork(device)) {
479 return FeatureStatus::Failed;
480 }
481
482 DebugOnly<bool> ok = ContentAdapterIsParentAdapter(device);
483 MOZ_ASSERT(ok);
484 }
485
486 {
487 MutexAutoLock lock(mDeviceLock);
488 mContentDevice = device;
489 }
490 mContentDevice->SetExceptionMode(0);
491
492 RefPtr<ID3D10Multithread> multi;
493 hr = mContentDevice->QueryInterface(__uuidof(ID3D10Multithread), getter_AddRefs(multi));
494 if (SUCCEEDED(hr) && multi) {
495 multi->SetMultithreadProtected(TRUE);
496 }
497 return FeatureStatus::Available;
498 }
499
500 RefPtr<ID3D11Device>
CreateDecoderDevice()501 DeviceManagerDx::CreateDecoderDevice()
502 {
503 bool isAMD = false;
504 {
505 MutexAutoLock lock(mDeviceLock);
506 if (!mDeviceStatus) {
507 return nullptr;
508 }
509 isAMD = mDeviceStatus->adapter().VendorId == 0x1002;
510 }
511
512 bool reuseDevice = false;
513 if (gfxPrefs::Direct3D11ReuseDecoderDevice() < 0) {
514 // Use the default logic, which is to allow reuse of devices on AMD, but create
515 // separate devices everywhere else.
516 if (isAMD) {
517 reuseDevice = true;
518 }
519 } else if (gfxPrefs::Direct3D11ReuseDecoderDevice() > 0) {
520 reuseDevice = true;
521 }
522
523 if (reuseDevice) {
524 if (mCompositorDevice && mCompositorDeviceSupportsVideo && !mDecoderDevice) {
525 mDecoderDevice = mCompositorDevice;
526
527 RefPtr<ID3D10Multithread> multi;
528 mDecoderDevice->QueryInterface(__uuidof(ID3D10Multithread), getter_AddRefs(multi));
529 if (multi) {
530 multi->SetMultithreadProtected(TRUE);
531 }
532 }
533
534 if (mDecoderDevice) {
535 RefPtr<ID3D11Device> dev = mDecoderDevice;
536 return dev.forget();
537 }
538 }
539
540 if (!sD3D11CreateDeviceFn) {
541 // We should just be on Windows Vista or XP in this case.
542 return nullptr;
543 }
544
545 RefPtr<IDXGIAdapter1> adapter = GetDXGIAdapter();
546 if (!adapter) {
547 return nullptr;
548 }
549
550 HRESULT hr;
551 RefPtr<ID3D11Device> device;
552
553 UINT flags = D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS |
554 D3D11_CREATE_DEVICE_VIDEO_SUPPORT;
555 if (!CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, flags, hr, device)) {
556 return nullptr;
557 }
558 if (FAILED(hr) || !device || !D3D11Checks::DoesDeviceWork()) {
559 return nullptr;
560 }
561
562 RefPtr<ID3D10Multithread> multi;
563 device->QueryInterface(__uuidof(ID3D10Multithread), getter_AddRefs(multi));
564
565 multi->SetMultithreadProtected(TRUE);
566
567 if (reuseDevice) {
568 mDecoderDevice = device;
569 }
570 return device;
571 }
572
573 void
ResetDevices()574 DeviceManagerDx::ResetDevices()
575 {
576 MutexAutoLock lock(mDeviceLock);
577
578 mAdapter = nullptr;
579 mCompositorDevice = nullptr;
580 mContentDevice = nullptr;
581 mDeviceStatus = Nothing();
582 mDeviceResetReason = Nothing();
583 Factory::SetDirect3D11Device(nullptr);
584 }
585
586 bool
MaybeResetAndReacquireDevices()587 DeviceManagerDx::MaybeResetAndReacquireDevices()
588 {
589 DeviceResetReason resetReason;
590 if (!HasDeviceReset(&resetReason)) {
591 return false;
592 }
593
594 if (resetReason != DeviceResetReason::FORCED_RESET) {
595 Telemetry::Accumulate(Telemetry::DEVICE_RESET_REASON, uint32_t(resetReason));
596 }
597
598 bool createCompositorDevice = !!mCompositorDevice;
599 bool createContentDevice = !!mContentDevice;
600
601 ResetDevices();
602
603 if (createCompositorDevice && !CreateCompositorDevices()) {
604 // Just stop, don't try anything more
605 return true;
606 }
607 if (createContentDevice) {
608 CreateContentDevices();
609 }
610
611 return true;
612 }
613
614 bool
ContentAdapterIsParentAdapter(ID3D11Device * device)615 DeviceManagerDx::ContentAdapterIsParentAdapter(ID3D11Device* device)
616 {
617 DXGI_ADAPTER_DESC desc;
618 if (!D3D11Checks::GetDxgiDesc(device, &desc)) {
619 gfxCriticalNote << "Could not query device DXGI adapter info";
620 return false;
621 }
622
623 const DxgiAdapterDesc& preferred = mDeviceStatus->adapter();
624
625 if (desc.VendorId != preferred.VendorId ||
626 desc.DeviceId != preferred.DeviceId ||
627 desc.SubSysId != preferred.SubSysId ||
628 desc.AdapterLuid.HighPart != preferred.AdapterLuid.HighPart ||
629 desc.AdapterLuid.LowPart != preferred.AdapterLuid.LowPart)
630 {
631 gfxCriticalNote <<
632 "VendorIDMismatch P " <<
633 hexa(preferred.VendorId) << " " <<
634 hexa(desc.VendorId);
635 return false;
636 }
637
638 return true;
639 }
640
HResultToResetReason(HRESULT hr)641 static DeviceResetReason HResultToResetReason(HRESULT hr)
642 {
643 switch (hr) {
644 case DXGI_ERROR_DEVICE_HUNG:
645 return DeviceResetReason::HUNG;
646 case DXGI_ERROR_DEVICE_REMOVED:
647 return DeviceResetReason::REMOVED;
648 case DXGI_ERROR_DEVICE_RESET:
649 return DeviceResetReason::RESET;
650 case DXGI_ERROR_DRIVER_INTERNAL_ERROR:
651 return DeviceResetReason::DRIVER_ERROR;
652 case DXGI_ERROR_INVALID_CALL:
653 return DeviceResetReason::INVALID_CALL;
654 case E_OUTOFMEMORY:
655 return DeviceResetReason::OUT_OF_MEMORY;
656 default:
657 MOZ_ASSERT(false);
658 }
659 return DeviceResetReason::UNKNOWN;
660 }
661
662 bool
HasDeviceReset(DeviceResetReason * aOutReason)663 DeviceManagerDx::HasDeviceReset(DeviceResetReason* aOutReason)
664 {
665 MutexAutoLock lock(mDeviceLock);
666
667 if (mDeviceResetReason) {
668 if (aOutReason) {
669 *aOutReason = mDeviceResetReason.value();
670 }
671 return true;
672 }
673
674 DeviceResetReason reason;
675 if (GetAnyDeviceRemovedReason(&reason)) {
676 mDeviceResetReason = Some(reason);
677 if (aOutReason) {
678 *aOutReason = reason;
679 }
680 return true;
681 }
682
683 return false;
684 }
685
686 static inline bool
DidDeviceReset(const RefPtr<ID3D11Device> & aDevice,DeviceResetReason * aOutReason)687 DidDeviceReset(const RefPtr<ID3D11Device>& aDevice, DeviceResetReason* aOutReason)
688 {
689 if (!aDevice) {
690 return false;
691 }
692 HRESULT hr = aDevice->GetDeviceRemovedReason();
693 if (hr == S_OK) {
694 return false;
695 }
696
697 *aOutReason = HResultToResetReason(hr);
698 return true;
699 }
700
701 bool
GetAnyDeviceRemovedReason(DeviceResetReason * aOutReason)702 DeviceManagerDx::GetAnyDeviceRemovedReason(DeviceResetReason* aOutReason)
703 {
704 // Caller must own the lock, since we access devices directly, and can be
705 // called from any thread.
706 mDeviceLock.AssertCurrentThreadOwns();
707
708 if (DidDeviceReset(mCompositorDevice, aOutReason) ||
709 DidDeviceReset(mContentDevice, aOutReason))
710 {
711 return true;
712 }
713
714 if (XRE_IsParentProcess() &&
715 NS_IsMainThread() &&
716 gfxPrefs::DeviceResetForTesting())
717 {
718 gfxPrefs::SetDeviceResetForTesting(0);
719 *aOutReason = DeviceResetReason::FORCED_RESET;
720 return true;
721 }
722
723 return false;
724 }
725
726 void
ForceDeviceReset(ForcedDeviceResetReason aReason)727 DeviceManagerDx::ForceDeviceReset(ForcedDeviceResetReason aReason)
728 {
729 Telemetry::Accumulate(Telemetry::FORCED_DEVICE_RESET_REASON, uint32_t(aReason));
730 {
731 MutexAutoLock lock(mDeviceLock);
732 mDeviceResetReason = Some(DeviceResetReason::FORCED_RESET);
733 }
734 }
735
736 void
NotifyD3D9DeviceReset()737 DeviceManagerDx::NotifyD3D9DeviceReset()
738 {
739 MutexAutoLock lock(mDeviceLock);
740 mDeviceResetReason = Some(DeviceResetReason::D3D9_RESET);
741 }
742
743 void
DisableD3D11AfterCrash()744 DeviceManagerDx::DisableD3D11AfterCrash()
745 {
746 gfxConfig::Disable(Feature::D3D11_COMPOSITING,
747 FeatureStatus::CrashedInHandler,
748 "Crashed while acquiring a Direct3D11 device",
749 NS_LITERAL_CSTRING("FEATURE_FAILURE_D3D11_CRASH"));
750 ResetDevices();
751 }
752
753 RefPtr<ID3D11Device>
GetCompositorDevice()754 DeviceManagerDx::GetCompositorDevice()
755 {
756 MutexAutoLock lock(mDeviceLock);
757 return mCompositorDevice;
758 }
759
760 RefPtr<ID3D11Device>
GetContentDevice()761 DeviceManagerDx::GetContentDevice()
762 {
763 MutexAutoLock lock(mDeviceLock);
764 return mContentDevice;
765 }
766
767 unsigned
GetCompositorFeatureLevel() const768 DeviceManagerDx::GetCompositorFeatureLevel() const
769 {
770 if (!mDeviceStatus) {
771 return 0;
772 }
773 return mDeviceStatus->featureLevel();
774 }
775
776 bool
TextureSharingWorks()777 DeviceManagerDx::TextureSharingWorks()
778 {
779 MutexAutoLock lock(mDeviceLock);
780 if (!mDeviceStatus) {
781 return false;
782 }
783 return mDeviceStatus->textureSharingWorks();
784 }
785
786 bool
CanInitializeKeyedMutexTextures()787 DeviceManagerDx::CanInitializeKeyedMutexTextures()
788 {
789 MutexAutoLock lock(mDeviceLock);
790 if (!mDeviceStatus) {
791 return false;
792 }
793 // Disable this on all Intel devices because of crashes.
794 // See bug 1292923.
795 return mDeviceStatus->adapter().VendorId != 0x8086;
796 }
797
798 bool
CheckRemotePresentSupport()799 DeviceManagerDx::CheckRemotePresentSupport()
800 {
801 MOZ_ASSERT(XRE_IsParentProcess());
802
803 RefPtr<IDXGIAdapter1> adapter = GetDXGIAdapter();
804 if (!adapter) {
805 return false;
806 }
807 if (!D3D11Checks::DoesRemotePresentWork(adapter)) {
808 return false;
809 }
810 return true;
811 }
812
813 bool
IsWARP()814 DeviceManagerDx::IsWARP()
815 {
816 MutexAutoLock lock(mDeviceLock);
817 if (!mDeviceStatus) {
818 return false;
819 }
820 return mDeviceStatus->isWARP();
821 }
822
823 void
InitializeDirectDraw()824 DeviceManagerDx::InitializeDirectDraw()
825 {
826 MOZ_ASSERT(layers::CompositorThreadHolder::IsInCompositorThread());
827
828 if (mDirectDraw) {
829 // Already initialized.
830 return;
831 }
832
833 FeatureState& ddraw = gfxConfig::GetFeature(Feature::DIRECT_DRAW);
834 if (!ddraw.IsEnabled()) {
835 return;
836 }
837
838 // Check if DirectDraw is available on this system.
839 mDirectDrawDLL.own(LoadLibrarySystem32(L"ddraw.dll"));
840 if (!mDirectDrawDLL) {
841 ddraw.SetFailed(FeatureStatus::Unavailable, "DirectDraw not available on this computer",
842 NS_LITERAL_CSTRING("FEATURE_FAILURE_DDRAW_LIB"));
843 return;
844 }
845
846 sDirectDrawCreateExFn =
847 (decltype(DirectDrawCreateEx)*)GetProcAddress(mDirectDrawDLL, "DirectDrawCreateEx");
848 if (!sDirectDrawCreateExFn) {
849 ddraw.SetFailed(FeatureStatus::Unavailable, "DirectDraw not available on this computer",
850 NS_LITERAL_CSTRING("FEATURE_FAILURE_DDRAW_LIB"));
851 return;
852 }
853
854 HRESULT hr;
855 MOZ_SEH_TRY {
856 hr = sDirectDrawCreateExFn(nullptr, getter_AddRefs(mDirectDraw), IID_IDirectDraw7, nullptr);
857 } MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
858 ddraw.SetFailed(FeatureStatus::Failed, "Failed to create DirectDraw",
859 NS_LITERAL_CSTRING("FEATURE_FAILURE_DDRAW_LIB"));
860 gfxCriticalNote << "DoesCreatingDirectDrawFailed";
861 return;
862 }
863 if (FAILED(hr)) {
864 ddraw.SetFailed(FeatureStatus::Failed, "Failed to create DirectDraw",
865 NS_LITERAL_CSTRING("FEATURE_FAILURE_DDRAW_LIB"));
866 gfxCriticalNote << "DoesCreatingDirectDrawFailed " << hexa(hr);
867 return;
868 }
869 }
870
871 IDirectDraw7*
GetDirectDraw()872 DeviceManagerDx::GetDirectDraw()
873 {
874 return mDirectDraw;
875 }
876
877 } // namespace gfx
878 } // namespace mozilla
879