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"
28 using namespace mozilla::widget
;
29 using mozilla::layers::AutoTextureLock
;
32 bool D3D11Checks::DoesRenderTargetViewNeedRecreating(ID3D11Device
* aDevice
) {
34 // CreateTexture2D is known to crash on lower feature levels, see bugs
35 // 1170211 and 1089413.
36 if (aDevice
->GetFeatureLevel() < D3D_FEATURE_LEVEL_10_0
) {
40 RefPtr
<ID3D11DeviceContext
> deviceContext
;
41 aDevice
->GetImmediateContext(getter_AddRefs(deviceContext
));
42 int backbufferWidth
= 32;
43 int backbufferHeight
= 32;
44 RefPtr
<ID3D11Texture2D
> offscreenTexture
;
45 RefPtr
<IDXGIKeyedMutex
> keyedMutex
;
47 D3D11_TEXTURE2D_DESC offscreenTextureDesc
= {0};
48 offscreenTextureDesc
.Width
= backbufferWidth
;
49 offscreenTextureDesc
.Height
= backbufferHeight
;
50 offscreenTextureDesc
.Format
= DXGI_FORMAT_B8G8R8A8_UNORM
;
51 offscreenTextureDesc
.MipLevels
= 0;
52 offscreenTextureDesc
.ArraySize
= 1;
53 offscreenTextureDesc
.SampleDesc
.Count
= 1;
54 offscreenTextureDesc
.SampleDesc
.Quality
= 0;
55 offscreenTextureDesc
.Usage
= D3D11_USAGE_DEFAULT
;
56 offscreenTextureDesc
.BindFlags
=
57 D3D11_BIND_RENDER_TARGET
| D3D11_BIND_SHADER_RESOURCE
;
58 offscreenTextureDesc
.CPUAccessFlags
= 0;
59 offscreenTextureDesc
.MiscFlags
= D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX
;
61 HRESULT hr
= aDevice
->CreateTexture2D(&offscreenTextureDesc
, NULL
,
62 getter_AddRefs(offscreenTexture
));
64 gfxCriticalNote
<< "DoesRecreatingCreateTexture2DFail";
68 hr
= offscreenTexture
->QueryInterface(__uuidof(IDXGIKeyedMutex
),
69 (void**)getter_AddRefs(keyedMutex
));
71 gfxCriticalNote
<< "DoesRecreatingKeyedMutexFailed";
74 D3D11_RENDER_TARGET_VIEW_DESC offscreenRTVDesc
;
75 offscreenRTVDesc
.Format
= DXGI_FORMAT_B8G8R8A8_UNORM
;
76 offscreenRTVDesc
.ViewDimension
= D3D11_RTV_DIMENSION_TEXTURE2D
;
77 offscreenRTVDesc
.Texture2D
.MipSlice
= 0;
79 RefPtr
<ID3D11RenderTargetView
> offscreenRTView
;
80 hr
= aDevice
->CreateRenderTargetView(offscreenTexture
, &offscreenRTVDesc
,
81 getter_AddRefs(offscreenRTView
));
83 gfxCriticalNote
<< "DoesRecreatingCreateRenderTargetViewFailed";
90 AutoTextureLock
lock(keyedMutex
, hr
, INFINITE
);
91 FLOAT color1
[4] = {1, 1, 0.5, 1};
92 deviceContext
->ClearRenderTargetView(offscreenRTView
, color1
);
97 AutoTextureLock
lock(keyedMutex
, hr
, INFINITE
);
98 FLOAT color2
[4] = {1, 1, 0, 1};
100 deviceContext
->ClearRenderTargetView(offscreenRTView
, color2
);
101 D3D11_TEXTURE2D_DESC desc
;
103 offscreenTexture
->GetDesc(&desc
);
104 desc
.Usage
= D3D11_USAGE_STAGING
;
105 desc
.CPUAccessFlags
= D3D11_CPU_ACCESS_READ
;
108 RefPtr
<ID3D11Texture2D
> cpuTexture
;
109 hr
= aDevice
->CreateTexture2D(&desc
, NULL
, getter_AddRefs(cpuTexture
));
111 gfxCriticalNote
<< "DoesRecreatingCreateCPUTextureFailed";
115 deviceContext
->CopyResource(cpuTexture
, offscreenTexture
);
117 D3D11_MAPPED_SUBRESOURCE mapped
;
118 hr
= deviceContext
->Map(cpuTexture
, 0, D3D11_MAP_READ
, 0, &mapped
);
120 gfxCriticalNote
<< "DoesRecreatingMapFailed " << hexa(hr
);
123 int resultColor
= *(int*)mapped
.pData
;
124 deviceContext
->Unmap(cpuTexture
, 0);
125 cpuTexture
= nullptr;
127 // XXX on some drivers resultColor will not have changed to
129 if (resultColor
!= 0xffffff00) {
130 gfxCriticalNote
<< "RenderTargetViewNeedsRecreating";
138 bool D3D11Checks::DoesDeviceWork() {
139 static bool checked
= false;
140 static bool result
= false;
142 if (checked
) return result
;
145 if (StaticPrefs::gfx_direct2d_force_enabled_AtStartup() ||
146 gfxConfig::IsForcedOnByUser(Feature::HW_COMPOSITING
)) {
151 if (GetModuleHandleW(L
"igd10umd32.dll")) {
152 const wchar_t* checkModules
[] = {L
"dlumd32.dll", L
"dlumd11.dll",
154 for (int i
= 0; i
< PR_ARRAY_SIZE(checkModules
); i
+= 1) {
155 if (GetModuleHandleW(checkModules
[i
])) {
156 nsString displayLinkModuleVersionString
;
157 gfxWindowsPlatform::GetDLLVersion(checkModules
[i
],
158 displayLinkModuleVersionString
);
159 uint64_t displayLinkModuleVersion
;
160 if (!ParseDriverVersion(displayLinkModuleVersionString
,
161 &displayLinkModuleVersion
)) {
163 << "DisplayLink: could not parse version " << checkModules
[i
];
166 if (displayLinkModuleVersion
<= V(8, 6, 1, 36484)) {
167 NS_ConvertUTF16toUTF8
version(displayLinkModuleVersionString
);
168 gfxCriticalError(CriticalLog::DefaultOptions(false))
169 << "DisplayLink: too old version " << version
.get();
179 static bool TryCreateTexture2D(ID3D11Device
* device
, D3D11_TEXTURE2D_DESC
* desc
,
180 D3D11_SUBRESOURCE_DATA
* data
,
181 RefPtr
<ID3D11Texture2D
>& texture
) {
182 // Older Intel driver version (see bug 1221348 for version #s) crash when
183 // creating a texture with shared keyed mutex and data.
186 device
->CreateTexture2D(desc
, data
, getter_AddRefs(texture
)));
188 MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER
) {
189 // For now we want to aggregrate all the crash signature to a known crash.
190 gfxDevCrash(LogReason::TextureCreation
)
191 << "Crash creating texture. See bug 1221348.";
196 // See bug 1083071. On some drivers, Direct3D 11 CreateShaderResourceView fails
197 // with E_OUTOFMEMORY.
198 static bool DoesTextureSharingWorkInternal(ID3D11Device
* device
,
199 DXGI_FORMAT format
, UINT bindflags
) {
200 // CreateTexture2D is known to crash on lower feature levels, see bugs
201 // 1170211 and 1089413.
202 if (device
->GetFeatureLevel() < D3D_FEATURE_LEVEL_10_0
) {
206 if (StaticPrefs::gfx_direct2d_force_enabled_AtStartup() ||
207 gfxConfig::IsForcedOnByUser(Feature::HW_COMPOSITING
)) {
211 if (GetModuleHandleW(L
"atidxx32.dll")) {
212 nsCOMPtr
<nsIGfxInfo
> gfxInfo
= components::GfxInfo::Service();
214 nsString vendorID
, vendorID2
;
215 gfxInfo
->GetAdapterVendorID(vendorID
);
216 gfxInfo
->GetAdapterVendorID2(vendorID2
);
217 if (vendorID
.EqualsLiteral("0x8086") && vendorID2
.IsEmpty()) {
218 if (!StaticPrefs::layers_amd_switchable_gfx_enabled_AtStartup()) {
221 gfxCriticalError(CriticalLog::DefaultOptions(false))
222 << "PossiblyBrokenSurfaceSharing_UnexpectedAMDGPU";
227 RefPtr
<ID3D11Texture2D
> texture
;
228 D3D11_TEXTURE2D_DESC desc
;
229 const int texture_size
= 32;
230 desc
.Width
= texture_size
;
231 desc
.Height
= texture_size
;
234 desc
.Format
= format
;
235 desc
.SampleDesc
.Count
= 1;
236 desc
.SampleDesc
.Quality
= 0;
237 desc
.Usage
= D3D11_USAGE_DEFAULT
;
238 desc
.CPUAccessFlags
= 0;
239 desc
.MiscFlags
= D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX
;
240 desc
.BindFlags
= bindflags
;
242 uint32_t color
[texture_size
* texture_size
];
243 for (size_t i
= 0; i
< sizeof(color
) / sizeof(color
[0]); i
++) {
244 color
[i
] = 0xff00ffff;
246 // XXX If we pass the data directly at texture creation time we
247 // get a crash on Intel 8.5.10.[18xx-1994] drivers.
248 // We can work around this issue by doing UpdateSubresource.
249 if (!TryCreateTexture2D(device
, &desc
, nullptr, texture
)) {
250 gfxCriticalNote
<< "DoesD3D11TextureSharingWork_TryCreateTextureFailure";
254 RefPtr
<IDXGIKeyedMutex
> sourceSharedMutex
;
255 texture
->QueryInterface(__uuidof(IDXGIKeyedMutex
),
256 (void**)getter_AddRefs(sourceSharedMutex
));
257 if (FAILED(sourceSharedMutex
->AcquireSync(0, 30 * 1000))) {
258 gfxCriticalError() << "DoesD3D11TextureSharingWork_SourceMutexTimeout";
259 // only wait for 30 seconds
263 RefPtr
<ID3D11DeviceContext
> deviceContext
;
264 device
->GetImmediateContext(getter_AddRefs(deviceContext
));
266 int stride
= texture_size
* 4;
267 deviceContext
->UpdateSubresource(texture
, 0, nullptr, color
, stride
,
268 stride
* texture_size
);
270 if (FAILED(sourceSharedMutex
->ReleaseSync(0))) {
272 << "DoesD3D11TextureSharingWork_SourceReleaseSyncTimeout";
277 RefPtr
<IDXGIResource
> otherResource
;
278 if (FAILED(texture
->QueryInterface(__uuidof(IDXGIResource
),
279 getter_AddRefs(otherResource
)))) {
280 gfxCriticalError() << "DoesD3D11TextureSharingWork_GetResourceFailure";
284 if (FAILED(otherResource
->GetSharedHandle(&shareHandle
))) {
285 gfxCriticalError() << "DoesD3D11TextureSharingWork_GetSharedTextureFailure";
289 RefPtr
<ID3D11Resource
> sharedResource
;
290 RefPtr
<ID3D11Texture2D
> sharedTexture
;
291 if (FAILED(device
->OpenSharedResource(shareHandle
, __uuidof(ID3D11Resource
),
292 getter_AddRefs(sharedResource
)))) {
293 gfxCriticalError(CriticalLog::DefaultOptions(false))
294 << "OpenSharedResource failed for format " << format
;
298 if (FAILED(sharedResource
->QueryInterface(__uuidof(ID3D11Texture2D
),
299 getter_AddRefs(sharedTexture
)))) {
300 gfxCriticalError() << "DoesD3D11TextureSharingWork_GetSharedTextureFailure";
304 // create a staging texture for readback
305 RefPtr
<ID3D11Texture2D
> cpuTexture
;
306 desc
.Usage
= D3D11_USAGE_STAGING
;
307 desc
.CPUAccessFlags
= D3D11_CPU_ACCESS_READ
;
310 if (FAILED(device
->CreateTexture2D(&desc
, nullptr,
311 getter_AddRefs(cpuTexture
)))) {
312 gfxCriticalError() << "DoesD3D11TextureSharingWork_CreateTextureFailure";
316 RefPtr
<IDXGIKeyedMutex
> sharedMutex
;
317 sharedResource
->QueryInterface(__uuidof(IDXGIKeyedMutex
),
318 (void**)getter_AddRefs(sharedMutex
));
321 AutoTextureLock
lock(sharedMutex
, hr
, 30 * 1000);
323 gfxCriticalError() << "DoesD3D11TextureSharingWork_AcquireSyncTimeout";
324 // only wait for 30 seconds
328 // Copy to the cpu texture so that we can readback
329 deviceContext
->CopyResource(cpuTexture
, sharedTexture
);
331 // We only need to hold on to the mutex during the copy.
332 sharedMutex
->ReleaseSync(0);
335 D3D11_MAPPED_SUBRESOURCE mapped
;
336 uint32_t resultColor
= 0;
338 deviceContext
->Map(cpuTexture
, 0, D3D11_MAP_READ
, 0, &mapped
))) {
340 resultColor
= *(uint32_t*)mapped
.pData
;
341 deviceContext
->Unmap(cpuTexture
, 0);
343 gfxCriticalError() << "DoesD3D11TextureSharingWork_MapFailed";
347 // check that the color we put in is the color we get out
348 if (resultColor
!= color
[0]) {
349 // Shared surfaces seem to be broken on dual AMD & Intel HW when using the
351 gfxCriticalNote
<< "DoesD3D11TextureSharingWork_ColorMismatch";
355 RefPtr
<ID3D11ShaderResourceView
> sharedView
;
357 // This if(FAILED()) is the one that actually fails on systems affected by bug
359 if (FAILED(device
->CreateShaderResourceView(sharedTexture
, NULL
,
360 getter_AddRefs(sharedView
)))) {
361 gfxCriticalNote
<< "CreateShaderResourceView failed for format" << format
;
369 bool D3D11Checks::DoesTextureSharingWork(ID3D11Device
* device
) {
370 return DoesTextureSharingWorkInternal(
371 device
, DXGI_FORMAT_B8G8R8A8_UNORM
,
372 D3D11_BIND_RENDER_TARGET
| D3D11_BIND_SHADER_RESOURCE
);
376 bool D3D11Checks::DoesAlphaTextureSharingWork(ID3D11Device
* device
) {
377 return DoesTextureSharingWorkInternal(device
, DXGI_FORMAT_R8_UNORM
,
378 D3D11_BIND_SHADER_RESOURCE
);
382 bool D3D11Checks::GetDxgiDesc(ID3D11Device
* device
, DXGI_ADAPTER_DESC
* out
) {
383 RefPtr
<IDXGIDevice
> dxgiDevice
;
385 device
->QueryInterface(__uuidof(IDXGIDevice
), getter_AddRefs(dxgiDevice
));
390 RefPtr
<IDXGIAdapter
> dxgiAdapter
;
391 if (FAILED(dxgiDevice
->GetAdapter(getter_AddRefs(dxgiAdapter
)))) {
395 return SUCCEEDED(dxgiAdapter
->GetDesc(out
));
399 void D3D11Checks::WarnOnAdapterMismatch(ID3D11Device
* device
) {
400 DXGI_ADAPTER_DESC desc
;
402 GetDxgiDesc(device
, &desc
);
404 nsCOMPtr
<nsIGfxInfo
> gfxInfo
= components::GfxInfo::Service();
406 gfxInfo
->GetAdapterVendorID(vendorID
);
408 int32_t vendor
= vendorID
.ToInteger(&ec
, 16);
409 if (vendor
!= desc
.VendorId
) {
410 gfxCriticalNote
<< "VendorIDMismatch V " << hexa(vendor
) << " "
411 << hexa(desc
.VendorId
);
416 bool D3D11Checks::DoesRemotePresentWork(IDXGIAdapter
* adapter
) {
417 // Remote presentation was added in DXGI 1.2, for Windows 8 and the Platform
418 // Update to Windows 7.
419 RefPtr
<IDXGIAdapter2
> check
;
421 adapter
->QueryInterface(__uuidof(IDXGIAdapter2
), getter_AddRefs(check
));
422 return SUCCEEDED(hr
) && check
;
425 /* static */ D3D11Checks::VideoFormatOptionSet
D3D11Checks::FormatOptions(
426 ID3D11Device
* device
) {
427 auto doesNV12Work
= [&]() {
428 if (gfxVars::DXNV12Blocked()) {
432 DXGI_ADAPTER_DESC desc
;
434 if (!GetDxgiDesc(device
, &desc
)) {
435 // Failed to retrieve device information, assume it doesn't work
440 HRESULT hr
= device
->CheckFormatSupport(DXGI_FORMAT_NV12
, &formatSupport
);
441 if (FAILED(hr
) || !(formatSupport
& D3D11_FORMAT_SUPPORT_TEXTURE2D
)) {
446 nsCOMPtr
<nsIGfxInfo
> gfxInfo
= components::GfxInfo::Service();
448 gfxInfo
->GetAdapterDriverVersion(version
);
450 return DXVA2Manager::IsNV12Supported(desc
.VendorId
, desc
.DeviceId
, version
);
453 auto doesP010Work
= [&]() {
454 if (gfxVars::DXP010Blocked() &&
455 !StaticPrefs::media_wmf_force_allow_p010_format()) {
459 HRESULT hr
= device
->CheckFormatSupport(DXGI_FORMAT_P010
, &formatSupport
);
460 return (SUCCEEDED(hr
) && (formatSupport
& D3D11_FORMAT_SUPPORT_TEXTURE2D
));
463 auto doesP016Work
= [&]() {
464 if (gfxVars::DXP016Blocked() &&
465 !StaticPrefs::media_wmf_force_allow_p010_format()) {
469 HRESULT hr
= device
->CheckFormatSupport(DXGI_FORMAT_P016
, &formatSupport
);
470 return (SUCCEEDED(hr
) && (formatSupport
& D3D11_FORMAT_SUPPORT_TEXTURE2D
));
473 VideoFormatOptionSet options
;
474 if (!doesNV12Work()) {
475 // If the device doesn't support NV12, there's really no point testing for
479 options
+= VideoFormatOption::NV12
;
480 if (doesP010Work()) {
481 options
+= VideoFormatOption::P010
;
483 if (doesP016Work()) {
484 options
+= VideoFormatOption::P016
;
490 } // namespace mozilla