Bug 1848468 - Mark k-rate-dynamics-compressor-connections.html subtest as failing...
[gecko.git] / gfx / thebes / D3D11Checks.cpp
blob2bf167efd3b1098db6517e8e06419d9d495c7467
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"
8 #include "gfxConfig.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"
20 #include <dxgi.h>
21 #include <dxgi1_2.h>
22 #include <d3d10_1.h>
23 #include <d3d11.h>
25 namespace mozilla {
26 namespace gfx {
28 using namespace mozilla::widget;
29 using mozilla::layers::AutoTextureLock;
31 /* static */
32 bool D3D11Checks::DoesRenderTargetViewNeedRecreating(ID3D11Device* aDevice) {
33 bool result = false;
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) {
37 return true;
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));
63 if (FAILED(hr)) {
64 gfxCriticalNote << "DoesRecreatingCreateTexture2DFail";
65 return false;
68 hr = offscreenTexture->QueryInterface(__uuidof(IDXGIKeyedMutex),
69 (void**)getter_AddRefs(keyedMutex));
70 if (FAILED(hr)) {
71 gfxCriticalNote << "DoesRecreatingKeyedMutexFailed";
72 return false;
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));
82 if (FAILED(hr)) {
83 gfxCriticalNote << "DoesRecreatingCreateRenderTargetViewFailed";
84 return false;
88 // Acquire and clear
89 HRESULT hr;
90 AutoTextureLock lock(keyedMutex, hr, INFINITE);
91 FLOAT color1[4] = {1, 1, 0.5, 1};
92 deviceContext->ClearRenderTargetView(offscreenRTView, color1);
96 HRESULT hr;
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;
106 desc.MiscFlags = 0;
107 desc.BindFlags = 0;
108 RefPtr<ID3D11Texture2D> cpuTexture;
109 hr = aDevice->CreateTexture2D(&desc, NULL, getter_AddRefs(cpuTexture));
110 if (FAILED(hr)) {
111 gfxCriticalNote << "DoesRecreatingCreateCPUTextureFailed";
112 return false;
115 deviceContext->CopyResource(cpuTexture, offscreenTexture);
117 D3D11_MAPPED_SUBRESOURCE mapped;
118 hr = deviceContext->Map(cpuTexture, 0, D3D11_MAP_READ, 0, &mapped);
119 if (FAILED(hr)) {
120 gfxCriticalNote << "DoesRecreatingMapFailed " << hexa(hr);
121 return false;
123 uint32_t resultColor = *(uint32_t*)mapped.pData;
124 deviceContext->Unmap(cpuTexture, 0);
125 cpuTexture = nullptr;
127 // XXX on some drivers resultColor will not have changed to
128 // match the clear
129 if (resultColor != 0xffffff00) {
130 gfxCriticalNote << "RenderTargetViewNeedsRecreating";
131 result = true;
134 return result;
137 /* static */
138 bool D3D11Checks::DoesDeviceWork() {
139 static bool checked = false;
140 static bool result = false;
142 if (checked) return result;
143 checked = true;
145 if (StaticPrefs::gfx_direct2d_force_enabled_AtStartup() ||
146 gfxConfig::IsForcedOnByUser(Feature::HW_COMPOSITING)) {
147 result = true;
148 return true;
151 if (GetModuleHandleW(L"igd10umd32.dll")) {
152 const wchar_t* checkModules[] = {L"dlumd32.dll", L"dlumd11.dll",
153 L"dlumd10.dll"};
154 for (size_t 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)) {
162 gfxCriticalError()
163 << "DisplayLink: could not parse version " << checkModules[i];
164 return false;
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();
170 return false;
175 result = true;
176 return true;
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.
184 MOZ_SEH_TRY {
185 return !FAILED(
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.";
192 return false;
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) {
203 return false;
206 if (StaticPrefs::gfx_direct2d_force_enabled_AtStartup() ||
207 gfxConfig::IsForcedOnByUser(Feature::HW_COMPOSITING)) {
208 return true;
211 if (GetModuleHandleW(L"atidxx32.dll")) {
212 nsCOMPtr<nsIGfxInfo> gfxInfo = components::GfxInfo::Service();
213 if (gfxInfo) {
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()) {
219 return false;
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;
232 desc.MipLevels = 1;
233 desc.ArraySize = 1;
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";
251 return false;
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
260 return false;
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))) {
271 gfxCriticalError()
272 << "DoesD3D11TextureSharingWork_SourceReleaseSyncTimeout";
273 return false;
276 HANDLE shareHandle;
277 RefPtr<IDXGIResource> otherResource;
278 if (FAILED(texture->QueryInterface(__uuidof(IDXGIResource),
279 getter_AddRefs(otherResource)))) {
280 gfxCriticalError() << "DoesD3D11TextureSharingWork_GetResourceFailure";
281 return false;
284 if (FAILED(otherResource->GetSharedHandle(&shareHandle))) {
285 gfxCriticalError() << "DoesD3D11TextureSharingWork_GetSharedTextureFailure";
286 return false;
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;
295 return false;
298 if (FAILED(sharedResource->QueryInterface(__uuidof(ID3D11Texture2D),
299 getter_AddRefs(sharedTexture)))) {
300 gfxCriticalError() << "DoesD3D11TextureSharingWork_GetSharedTextureFailure";
301 return false;
304 // create a staging texture for readback
305 RefPtr<ID3D11Texture2D> cpuTexture;
306 desc.Usage = D3D11_USAGE_STAGING;
307 desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
308 desc.MiscFlags = 0;
309 desc.BindFlags = 0;
310 if (FAILED(device->CreateTexture2D(&desc, nullptr,
311 getter_AddRefs(cpuTexture)))) {
312 gfxCriticalError() << "DoesD3D11TextureSharingWork_CreateTextureFailure";
313 return false;
316 RefPtr<IDXGIKeyedMutex> sharedMutex;
317 sharedResource->QueryInterface(__uuidof(IDXGIKeyedMutex),
318 (void**)getter_AddRefs(sharedMutex));
320 HRESULT hr;
321 AutoTextureLock lock(sharedMutex, hr, 30 * 1000);
322 if (FAILED(hr)) {
323 gfxCriticalError() << "DoesD3D11TextureSharingWork_AcquireSyncTimeout";
324 // only wait for 30 seconds
325 return false;
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;
337 if (SUCCEEDED(
338 deviceContext->Map(cpuTexture, 0, D3D11_MAP_READ, 0, &mapped))) {
339 // read the texture
340 resultColor = *(uint32_t*)mapped.pData;
341 deviceContext->Unmap(cpuTexture, 0);
342 } else {
343 gfxCriticalError() << "DoesD3D11TextureSharingWork_MapFailed";
344 return false;
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
350 // AMD GPU
351 gfxCriticalNote << "DoesD3D11TextureSharingWork_ColorMismatch";
352 return false;
355 RefPtr<ID3D11ShaderResourceView> sharedView;
357 // This if(FAILED()) is the one that actually fails on systems affected by bug
358 // 1083071.
359 if (FAILED(device->CreateShaderResourceView(sharedTexture, NULL,
360 getter_AddRefs(sharedView)))) {
361 gfxCriticalNote << "CreateShaderResourceView failed for format" << format;
362 return false;
365 return true;
368 /* static */
369 bool D3D11Checks::DoesTextureSharingWork(ID3D11Device* device) {
370 return DoesTextureSharingWorkInternal(
371 device, DXGI_FORMAT_B8G8R8A8_UNORM,
372 D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE);
375 /* static */
376 bool D3D11Checks::DoesAlphaTextureSharingWork(ID3D11Device* device) {
377 return DoesTextureSharingWorkInternal(device, DXGI_FORMAT_R8_UNORM,
378 D3D11_BIND_SHADER_RESOURCE);
381 /* static */
382 bool D3D11Checks::GetDxgiDesc(ID3D11Device* device, DXGI_ADAPTER_DESC* out) {
383 RefPtr<IDXGIDevice> dxgiDevice;
384 HRESULT hr =
385 device->QueryInterface(__uuidof(IDXGIDevice), getter_AddRefs(dxgiDevice));
386 if (FAILED(hr)) {
387 return false;
390 RefPtr<IDXGIAdapter> dxgiAdapter;
391 if (FAILED(dxgiDevice->GetAdapter(getter_AddRefs(dxgiAdapter)))) {
392 return false;
395 return SUCCEEDED(dxgiAdapter->GetDesc(out));
398 /* static */
399 void D3D11Checks::WarnOnAdapterMismatch(ID3D11Device* device) {
400 DXGI_ADAPTER_DESC desc;
401 PodZero(&desc);
402 GetDxgiDesc(device, &desc);
404 nsCOMPtr<nsIGfxInfo> gfxInfo = components::GfxInfo::Service();
405 nsString vendorID;
406 gfxInfo->GetAdapterVendorID(vendorID);
407 nsresult ec;
408 int32_t vendor = vendorID.ToInteger(&ec, 16);
409 if (vendor != static_cast<int32_t>(desc.VendorId)) {
410 gfxCriticalNote << "VendorIDMismatch V " << hexa(vendor) << " "
411 << hexa(desc.VendorId);
415 /* static */
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;
420 HRESULT hr =
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()) {
429 return false;
432 DXGI_ADAPTER_DESC desc;
433 PodZero(&desc);
434 if (!GetDxgiDesc(device, &desc)) {
435 // Failed to retrieve device information, assume it doesn't work
436 return false;
439 UINT formatSupport;
440 HRESULT hr = device->CheckFormatSupport(DXGI_FORMAT_NV12, &formatSupport);
441 if (FAILED(hr) || !(formatSupport & D3D11_FORMAT_SUPPORT_TEXTURE2D)) {
442 return false;
445 nsString version;
446 nsCOMPtr<nsIGfxInfo> gfxInfo = components::GfxInfo::Service();
447 if (gfxInfo) {
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()) {
456 return false;
458 UINT formatSupport;
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()) {
466 return false;
468 UINT formatSupport;
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
476 // P010 and P016.
477 return options;
479 options += VideoFormatOption::NV12;
480 if (doesP010Work()) {
481 options += VideoFormatOption::P010;
483 if (doesP016Work()) {
484 options += VideoFormatOption::P016;
486 return options;
489 } // namespace gfx
490 } // namespace mozilla