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/. */
6 #include "D3D11Checks.h"
7 #include "DXVA2Manager.h"
9 #include "GfxDriverInfo.h"
10 #include "gfxWindowsPlatform.h"
11 #include "mozilla/Components.h"
12 #include "mozilla/RefPtr.h"
13 #include "mozilla/StaticPrefs_gfx.h"
14 #include "mozilla/StaticPrefs_layers.h"
15 #include "mozilla/StaticPrefs_media.h"
16 #include "mozilla/gfx/gfxVars.h"
17 #include "mozilla/gfx/Logging.h"
18 #include "mozilla/layers/TextureD3D11.h"
19 #include "nsIGfxInfo.h"
29 using namespace mozilla::widget
;
30 using mozilla::layers::AutoTextureLock
;
33 bool D3D11Checks::DoesRenderTargetViewNeedRecreating(ID3D11Device
* aDevice
) {
35 // CreateTexture2D is known to crash on lower feature levels, see bugs
36 // 1170211 and 1089413.
37 if (aDevice
->GetFeatureLevel() < D3D_FEATURE_LEVEL_10_0
) {
41 RefPtr
<ID3D11DeviceContext
> deviceContext
;
42 aDevice
->GetImmediateContext(getter_AddRefs(deviceContext
));
43 int backbufferWidth
= 32;
44 int backbufferHeight
= 32;
45 RefPtr
<ID3D11Texture2D
> offscreenTexture
;
46 RefPtr
<IDXGIKeyedMutex
> keyedMutex
;
48 D3D11_TEXTURE2D_DESC offscreenTextureDesc
= {0};
49 offscreenTextureDesc
.Width
= backbufferWidth
;
50 offscreenTextureDesc
.Height
= backbufferHeight
;
51 offscreenTextureDesc
.Format
= DXGI_FORMAT_B8G8R8A8_UNORM
;
52 offscreenTextureDesc
.MipLevels
= 0;
53 offscreenTextureDesc
.ArraySize
= 1;
54 offscreenTextureDesc
.SampleDesc
.Count
= 1;
55 offscreenTextureDesc
.SampleDesc
.Quality
= 0;
56 offscreenTextureDesc
.Usage
= D3D11_USAGE_DEFAULT
;
57 offscreenTextureDesc
.BindFlags
=
58 D3D11_BIND_RENDER_TARGET
| D3D11_BIND_SHADER_RESOURCE
;
59 offscreenTextureDesc
.CPUAccessFlags
= 0;
60 offscreenTextureDesc
.MiscFlags
= D3D11_RESOURCE_MISC_SHARED_NTHANDLE
|
61 D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX
;
63 HRESULT hr
= aDevice
->CreateTexture2D(&offscreenTextureDesc
, NULL
,
64 getter_AddRefs(offscreenTexture
));
66 gfxCriticalNote
<< "DoesRecreatingCreateTexture2DFail";
70 hr
= offscreenTexture
->QueryInterface(__uuidof(IDXGIKeyedMutex
),
71 (void**)getter_AddRefs(keyedMutex
));
73 gfxCriticalNote
<< "DoesRecreatingKeyedMutexFailed";
76 D3D11_RENDER_TARGET_VIEW_DESC offscreenRTVDesc
;
77 offscreenRTVDesc
.Format
= DXGI_FORMAT_B8G8R8A8_UNORM
;
78 offscreenRTVDesc
.ViewDimension
= D3D11_RTV_DIMENSION_TEXTURE2D
;
79 offscreenRTVDesc
.Texture2D
.MipSlice
= 0;
81 RefPtr
<ID3D11RenderTargetView
> offscreenRTView
;
82 hr
= aDevice
->CreateRenderTargetView(offscreenTexture
, &offscreenRTVDesc
,
83 getter_AddRefs(offscreenRTView
));
85 gfxCriticalNote
<< "DoesRecreatingCreateRenderTargetViewFailed";
92 AutoTextureLock
lock(keyedMutex
, hr
, INFINITE
);
93 FLOAT color1
[4] = {1, 1, 0.5, 1};
94 deviceContext
->ClearRenderTargetView(offscreenRTView
, color1
);
99 AutoTextureLock
lock(keyedMutex
, hr
, INFINITE
);
100 FLOAT color2
[4] = {1, 1, 0, 1};
102 deviceContext
->ClearRenderTargetView(offscreenRTView
, color2
);
103 D3D11_TEXTURE2D_DESC desc
;
105 offscreenTexture
->GetDesc(&desc
);
106 desc
.Usage
= D3D11_USAGE_STAGING
;
107 desc
.CPUAccessFlags
= D3D11_CPU_ACCESS_READ
;
110 RefPtr
<ID3D11Texture2D
> cpuTexture
;
111 hr
= aDevice
->CreateTexture2D(&desc
, NULL
, getter_AddRefs(cpuTexture
));
113 gfxCriticalNote
<< "DoesRecreatingCreateCPUTextureFailed";
117 deviceContext
->CopyResource(cpuTexture
, offscreenTexture
);
119 D3D11_MAPPED_SUBRESOURCE mapped
;
120 hr
= deviceContext
->Map(cpuTexture
, 0, D3D11_MAP_READ
, 0, &mapped
);
122 gfxCriticalNote
<< "DoesRecreatingMapFailed " << hexa(hr
);
125 uint32_t resultColor
= *(uint32_t*)mapped
.pData
;
126 deviceContext
->Unmap(cpuTexture
, 0);
127 cpuTexture
= nullptr;
129 // XXX on some drivers resultColor will not have changed to
131 if (resultColor
!= 0xffffff00) {
132 gfxCriticalNote
<< "RenderTargetViewNeedsRecreating";
140 bool D3D11Checks::DoesDeviceWork() {
141 static bool checked
= false;
142 static bool result
= false;
144 if (checked
) return result
;
147 if (StaticPrefs::gfx_direct2d_force_enabled_AtStartup() ||
148 gfxConfig::IsForcedOnByUser(Feature::HW_COMPOSITING
)) {
153 if (GetModuleHandleW(L
"igd10umd32.dll")) {
154 const wchar_t* checkModules
[] = {L
"dlumd32.dll", L
"dlumd11.dll",
156 for (size_t i
= 0; i
< PR_ARRAY_SIZE(checkModules
); i
+= 1) {
157 if (GetModuleHandleW(checkModules
[i
])) {
158 nsString displayLinkModuleVersionString
;
159 gfxWindowsPlatform::GetDLLVersion(checkModules
[i
],
160 displayLinkModuleVersionString
);
161 uint64_t displayLinkModuleVersion
;
162 if (!ParseDriverVersion(displayLinkModuleVersionString
,
163 &displayLinkModuleVersion
)) {
165 << "DisplayLink: could not parse version " << checkModules
[i
];
168 if (displayLinkModuleVersion
<= V(8, 6, 1, 36484)) {
169 NS_ConvertUTF16toUTF8
version(displayLinkModuleVersionString
);
170 gfxCriticalError(CriticalLog::DefaultOptions(false))
171 << "DisplayLink: too old version " << version
.get();
181 static bool TryCreateTexture2D(ID3D11Device
* device
, D3D11_TEXTURE2D_DESC
* desc
,
182 D3D11_SUBRESOURCE_DATA
* data
,
183 RefPtr
<ID3D11Texture2D
>& texture
) {
184 // Older Intel driver version (see bug 1221348 for version #s) crash when
185 // creating a texture with shared keyed mutex and data.
188 device
->CreateTexture2D(desc
, data
, getter_AddRefs(texture
)));
190 MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER
) {
191 // For now we want to aggregrate all the crash signature to a known crash.
192 gfxDevCrash(LogReason::TextureCreation
)
193 << "Crash creating texture. See bug 1221348.";
198 // See bug 1083071. On some drivers, Direct3D 11 CreateShaderResourceView fails
199 // with E_OUTOFMEMORY.
200 static bool DoesTextureSharingWorkInternal(ID3D11Device
* device
,
201 DXGI_FORMAT format
, UINT bindflags
) {
202 // CreateTexture2D is known to crash on lower feature levels, see bugs
203 // 1170211 and 1089413.
204 if (device
->GetFeatureLevel() < D3D_FEATURE_LEVEL_10_0
) {
208 if (StaticPrefs::gfx_direct2d_force_enabled_AtStartup() ||
209 gfxConfig::IsForcedOnByUser(Feature::HW_COMPOSITING
)) {
213 if (GetModuleHandleW(L
"atidxx32.dll")) {
214 nsCOMPtr
<nsIGfxInfo
> gfxInfo
= components::GfxInfo::Service();
216 nsString vendorID
, vendorID2
;
217 gfxInfo
->GetAdapterVendorID(vendorID
);
218 gfxInfo
->GetAdapterVendorID2(vendorID2
);
219 if (vendorID
.EqualsLiteral("0x8086") && vendorID2
.IsEmpty()) {
220 if (!StaticPrefs::layers_amd_switchable_gfx_enabled_AtStartup()) {
223 gfxCriticalError(CriticalLog::DefaultOptions(false))
224 << "PossiblyBrokenSurfaceSharing_UnexpectedAMDGPU";
229 RefPtr
<ID3D11Texture2D
> texture
;
230 D3D11_TEXTURE2D_DESC desc
;
231 const int texture_size
= 32;
232 desc
.Width
= texture_size
;
233 desc
.Height
= texture_size
;
236 desc
.Format
= format
;
237 desc
.SampleDesc
.Count
= 1;
238 desc
.SampleDesc
.Quality
= 0;
239 desc
.Usage
= D3D11_USAGE_DEFAULT
;
240 desc
.CPUAccessFlags
= 0;
241 desc
.MiscFlags
= D3D11_RESOURCE_MISC_SHARED_NTHANDLE
|
242 D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX
;
243 desc
.BindFlags
= bindflags
;
245 uint32_t color
[texture_size
* texture_size
];
246 for (size_t i
= 0; i
< sizeof(color
) / sizeof(color
[0]); i
++) {
247 color
[i
] = 0xff00ffff;
249 // XXX If we pass the data directly at texture creation time we
250 // get a crash on Intel 8.5.10.[18xx-1994] drivers.
251 // We can work around this issue by doing UpdateSubresource.
252 if (!TryCreateTexture2D(device
, &desc
, nullptr, texture
)) {
253 gfxCriticalNote
<< "DoesD3D11TextureSharingWork_TryCreateTextureFailure";
257 RefPtr
<IDXGIKeyedMutex
> sourceSharedMutex
;
258 texture
->QueryInterface(__uuidof(IDXGIKeyedMutex
),
259 (void**)getter_AddRefs(sourceSharedMutex
));
260 if (FAILED(sourceSharedMutex
->AcquireSync(0, 30 * 1000))) {
261 gfxCriticalError() << "DoesD3D11TextureSharingWork_SourceMutexTimeout";
262 // only wait for 30 seconds
266 RefPtr
<ID3D11DeviceContext
> deviceContext
;
267 device
->GetImmediateContext(getter_AddRefs(deviceContext
));
269 int stride
= texture_size
* 4;
270 deviceContext
->UpdateSubresource(texture
, 0, nullptr, color
, stride
,
271 stride
* texture_size
);
273 if (FAILED(sourceSharedMutex
->ReleaseSync(0))) {
275 << "DoesD3D11TextureSharingWork_SourceReleaseSyncTimeout";
279 RefPtr
<IDXGIResource1
> otherResource
;
280 if (FAILED(texture
->QueryInterface(__uuidof(IDXGIResource1
),
281 getter_AddRefs(otherResource
)))) {
282 gfxCriticalError() << "DoesD3D11TextureSharingWork_GetResourceFailure";
287 if (FAILED(otherResource
->CreateSharedHandle(
288 nullptr, DXGI_SHARED_RESOURCE_READ
| DXGI_SHARED_RESOURCE_WRITE
,
289 nullptr, &sharedHandle
))) {
290 gfxCriticalError() << "DoesD3D11TextureSharingWork_GetSharedTextureFailure";
294 auto handle
= ipc::FileDescriptor(UniqueFileHandle(sharedHandle
));
296 RefPtr
<ID3D11Device1
> device1
;
297 device
->QueryInterface((ID3D11Device1
**)getter_AddRefs(device1
));
299 gfxCriticalNoteOnce
<< "Failed to get ID3D11Device1";
303 RefPtr
<ID3D11Resource
> sharedResource
;
304 RefPtr
<ID3D11Texture2D
> sharedTexture
;
305 auto raw
= handle
.TakePlatformHandle();
306 if (FAILED(device1
->OpenSharedResource1(raw
.get(), __uuidof(ID3D11Resource
),
307 getter_AddRefs(sharedResource
)))) {
308 gfxCriticalError(CriticalLog::DefaultOptions(false))
309 << "OpenSharedResource failed for format " << format
;
313 if (FAILED(sharedResource
->QueryInterface(__uuidof(ID3D11Texture2D
),
314 getter_AddRefs(sharedTexture
)))) {
315 gfxCriticalError() << "DoesD3D11TextureSharingWork_GetSharedTextureFailure";
319 // create a staging texture for readback
320 RefPtr
<ID3D11Texture2D
> cpuTexture
;
321 desc
.Usage
= D3D11_USAGE_STAGING
;
322 desc
.CPUAccessFlags
= D3D11_CPU_ACCESS_READ
;
325 if (FAILED(device
->CreateTexture2D(&desc
, nullptr,
326 getter_AddRefs(cpuTexture
)))) {
327 gfxCriticalError() << "DoesD3D11TextureSharingWork_CreateTextureFailure";
331 RefPtr
<IDXGIKeyedMutex
> sharedMutex
;
332 sharedResource
->QueryInterface(__uuidof(IDXGIKeyedMutex
),
333 (void**)getter_AddRefs(sharedMutex
));
336 AutoTextureLock
lock(sharedMutex
, hr
, 30 * 1000);
338 gfxCriticalError() << "DoesD3D11TextureSharingWork_AcquireSyncTimeout";
339 // only wait for 30 seconds
343 // Copy to the cpu texture so that we can readback
344 deviceContext
->CopyResource(cpuTexture
, sharedTexture
);
346 // We only need to hold on to the mutex during the copy.
347 sharedMutex
->ReleaseSync(0);
350 D3D11_MAPPED_SUBRESOURCE mapped
;
351 uint32_t resultColor
= 0;
353 deviceContext
->Map(cpuTexture
, 0, D3D11_MAP_READ
, 0, &mapped
))) {
355 resultColor
= *(uint32_t*)mapped
.pData
;
356 deviceContext
->Unmap(cpuTexture
, 0);
358 gfxCriticalError() << "DoesD3D11TextureSharingWork_MapFailed";
362 // check that the color we put in is the color we get out
363 if (resultColor
!= color
[0]) {
364 // Shared surfaces seem to be broken on dual AMD & Intel HW when using the
366 gfxCriticalNote
<< "DoesD3D11TextureSharingWork_ColorMismatch";
370 RefPtr
<ID3D11ShaderResourceView
> sharedView
;
372 // This if(FAILED()) is the one that actually fails on systems affected by bug
374 if (FAILED(device
->CreateShaderResourceView(sharedTexture
, NULL
,
375 getter_AddRefs(sharedView
)))) {
376 gfxCriticalNote
<< "CreateShaderResourceView failed for format" << format
;
384 bool D3D11Checks::DoesTextureSharingWork(ID3D11Device
* device
) {
385 return DoesTextureSharingWorkInternal(
386 device
, DXGI_FORMAT_B8G8R8A8_UNORM
,
387 D3D11_BIND_RENDER_TARGET
| D3D11_BIND_SHADER_RESOURCE
);
391 bool D3D11Checks::DoesAlphaTextureSharingWork(ID3D11Device
* device
) {
392 return DoesTextureSharingWorkInternal(device
, DXGI_FORMAT_R8_UNORM
,
393 D3D11_BIND_SHADER_RESOURCE
);
397 bool D3D11Checks::GetDxgiDesc(ID3D11Device
* device
, DXGI_ADAPTER_DESC
* out
) {
398 RefPtr
<IDXGIDevice
> dxgiDevice
;
400 device
->QueryInterface(__uuidof(IDXGIDevice
), getter_AddRefs(dxgiDevice
));
405 RefPtr
<IDXGIAdapter
> dxgiAdapter
;
406 if (FAILED(dxgiDevice
->GetAdapter(getter_AddRefs(dxgiAdapter
)))) {
410 return SUCCEEDED(dxgiAdapter
->GetDesc(out
));
414 void D3D11Checks::WarnOnAdapterMismatch(ID3D11Device
* device
) {
415 DXGI_ADAPTER_DESC desc
;
417 GetDxgiDesc(device
, &desc
);
419 nsCOMPtr
<nsIGfxInfo
> gfxInfo
= components::GfxInfo::Service();
421 gfxInfo
->GetAdapterVendorID(vendorID
);
423 int32_t vendor
= vendorID
.ToInteger(&ec
, 16);
424 if (vendor
!= static_cast<int32_t>(desc
.VendorId
)) {
425 gfxCriticalNote
<< "VendorIDMismatch V " << hexa(vendor
) << " "
426 << hexa(desc
.VendorId
);
431 bool D3D11Checks::DoesRemotePresentWork(IDXGIAdapter
* adapter
) {
432 // Remote presentation was added in DXGI 1.2, for Windows 8 and the Platform
433 // Update to Windows 7.
434 RefPtr
<IDXGIAdapter2
> check
;
436 adapter
->QueryInterface(__uuidof(IDXGIAdapter2
), getter_AddRefs(check
));
437 return SUCCEEDED(hr
) && check
;
440 /* static */ D3D11Checks::VideoFormatOptionSet
D3D11Checks::FormatOptions(
441 ID3D11Device
* device
) {
442 auto doesNV12Work
= [&]() {
443 if (gfxVars::DXNV12Blocked()) {
447 DXGI_ADAPTER_DESC desc
;
449 if (!GetDxgiDesc(device
, &desc
)) {
450 // Failed to retrieve device information, assume it doesn't work
455 HRESULT hr
= device
->CheckFormatSupport(DXGI_FORMAT_NV12
, &formatSupport
);
456 if (FAILED(hr
) || !(formatSupport
& D3D11_FORMAT_SUPPORT_TEXTURE2D
)) {
461 nsCOMPtr
<nsIGfxInfo
> gfxInfo
= components::GfxInfo::Service();
463 gfxInfo
->GetAdapterDriverVersion(version
);
465 return DXVA2Manager::IsNV12Supported(desc
.VendorId
, desc
.DeviceId
, version
);
468 auto doesP010Work
= [&]() {
469 if (gfxVars::DXP010Blocked() &&
470 !StaticPrefs::media_wmf_force_allow_p010_format()) {
474 HRESULT hr
= device
->CheckFormatSupport(DXGI_FORMAT_P010
, &formatSupport
);
475 return (SUCCEEDED(hr
) && (formatSupport
& D3D11_FORMAT_SUPPORT_TEXTURE2D
));
478 auto doesP016Work
= [&]() {
479 if (gfxVars::DXP016Blocked() &&
480 !StaticPrefs::media_wmf_force_allow_p010_format()) {
484 HRESULT hr
= device
->CheckFormatSupport(DXGI_FORMAT_P016
, &formatSupport
);
485 return (SUCCEEDED(hr
) && (formatSupport
& D3D11_FORMAT_SUPPORT_TEXTURE2D
));
488 VideoFormatOptionSet options
;
489 if (!doesNV12Work()) {
490 // If the device doesn't support NV12, there's really no point testing for
494 options
+= VideoFormatOption::NV12
;
495 if (doesP010Work()) {
496 options
+= VideoFormatOption::P010
;
498 if (doesP016Work()) {
499 options
+= VideoFormatOption::P016
;
505 } // namespace mozilla