Bug 1874684 - Part 28: Return DateDuration from DifferenceISODateTime. r=mgaudet
[gecko.git] / gfx / thebes / D3D11Checks.cpp
blob72af5a3ed2507020599bcafcc8ef919135b66299
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>
24 #include <d3d11_1.h>
26 namespace mozilla {
27 namespace gfx {
29 using namespace mozilla::widget;
30 using mozilla::layers::AutoTextureLock;
32 /* static */
33 bool D3D11Checks::DoesRenderTargetViewNeedRecreating(ID3D11Device* aDevice) {
34 bool result = false;
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) {
38 return true;
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));
65 if (FAILED(hr)) {
66 gfxCriticalNote << "DoesRecreatingCreateTexture2DFail";
67 return false;
70 hr = offscreenTexture->QueryInterface(__uuidof(IDXGIKeyedMutex),
71 (void**)getter_AddRefs(keyedMutex));
72 if (FAILED(hr)) {
73 gfxCriticalNote << "DoesRecreatingKeyedMutexFailed";
74 return false;
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));
84 if (FAILED(hr)) {
85 gfxCriticalNote << "DoesRecreatingCreateRenderTargetViewFailed";
86 return false;
90 // Acquire and clear
91 HRESULT hr;
92 AutoTextureLock lock(keyedMutex, hr, INFINITE);
93 FLOAT color1[4] = {1, 1, 0.5, 1};
94 deviceContext->ClearRenderTargetView(offscreenRTView, color1);
98 HRESULT hr;
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;
108 desc.MiscFlags = 0;
109 desc.BindFlags = 0;
110 RefPtr<ID3D11Texture2D> cpuTexture;
111 hr = aDevice->CreateTexture2D(&desc, NULL, getter_AddRefs(cpuTexture));
112 if (FAILED(hr)) {
113 gfxCriticalNote << "DoesRecreatingCreateCPUTextureFailed";
114 return false;
117 deviceContext->CopyResource(cpuTexture, offscreenTexture);
119 D3D11_MAPPED_SUBRESOURCE mapped;
120 hr = deviceContext->Map(cpuTexture, 0, D3D11_MAP_READ, 0, &mapped);
121 if (FAILED(hr)) {
122 gfxCriticalNote << "DoesRecreatingMapFailed " << hexa(hr);
123 return false;
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
130 // match the clear
131 if (resultColor != 0xffffff00) {
132 gfxCriticalNote << "RenderTargetViewNeedsRecreating";
133 result = true;
136 return result;
139 /* static */
140 bool D3D11Checks::DoesDeviceWork() {
141 static bool checked = false;
142 static bool result = false;
144 if (checked) return result;
145 checked = true;
147 if (StaticPrefs::gfx_direct2d_force_enabled_AtStartup() ||
148 gfxConfig::IsForcedOnByUser(Feature::HW_COMPOSITING)) {
149 result = true;
150 return true;
153 if (GetModuleHandleW(L"igd10umd32.dll")) {
154 const wchar_t* checkModules[] = {L"dlumd32.dll", L"dlumd11.dll",
155 L"dlumd10.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)) {
164 gfxCriticalError()
165 << "DisplayLink: could not parse version " << checkModules[i];
166 return false;
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();
172 return false;
177 result = true;
178 return true;
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.
186 MOZ_SEH_TRY {
187 return !FAILED(
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.";
194 return false;
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) {
205 return false;
208 if (StaticPrefs::gfx_direct2d_force_enabled_AtStartup() ||
209 gfxConfig::IsForcedOnByUser(Feature::HW_COMPOSITING)) {
210 return true;
213 if (GetModuleHandleW(L"atidxx32.dll")) {
214 nsCOMPtr<nsIGfxInfo> gfxInfo = components::GfxInfo::Service();
215 if (gfxInfo) {
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()) {
221 return false;
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;
234 desc.MipLevels = 1;
235 desc.ArraySize = 1;
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";
254 return false;
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
263 return false;
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))) {
274 gfxCriticalError()
275 << "DoesD3D11TextureSharingWork_SourceReleaseSyncTimeout";
276 return false;
279 RefPtr<IDXGIResource1> otherResource;
280 if (FAILED(texture->QueryInterface(__uuidof(IDXGIResource1),
281 getter_AddRefs(otherResource)))) {
282 gfxCriticalError() << "DoesD3D11TextureSharingWork_GetResourceFailure";
283 return false;
286 HANDLE sharedHandle;
287 if (FAILED(otherResource->CreateSharedHandle(
288 nullptr, DXGI_SHARED_RESOURCE_READ | DXGI_SHARED_RESOURCE_WRITE,
289 nullptr, &sharedHandle))) {
290 gfxCriticalError() << "DoesD3D11TextureSharingWork_GetSharedTextureFailure";
291 return false;
294 auto handle = ipc::FileDescriptor(UniqueFileHandle(sharedHandle));
296 RefPtr<ID3D11Device1> device1;
297 device->QueryInterface((ID3D11Device1**)getter_AddRefs(device1));
298 if (!device1) {
299 gfxCriticalNoteOnce << "Failed to get ID3D11Device1";
300 return false;
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;
310 return false;
313 if (FAILED(sharedResource->QueryInterface(__uuidof(ID3D11Texture2D),
314 getter_AddRefs(sharedTexture)))) {
315 gfxCriticalError() << "DoesD3D11TextureSharingWork_GetSharedTextureFailure";
316 return false;
319 // create a staging texture for readback
320 RefPtr<ID3D11Texture2D> cpuTexture;
321 desc.Usage = D3D11_USAGE_STAGING;
322 desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
323 desc.MiscFlags = 0;
324 desc.BindFlags = 0;
325 if (FAILED(device->CreateTexture2D(&desc, nullptr,
326 getter_AddRefs(cpuTexture)))) {
327 gfxCriticalError() << "DoesD3D11TextureSharingWork_CreateTextureFailure";
328 return false;
331 RefPtr<IDXGIKeyedMutex> sharedMutex;
332 sharedResource->QueryInterface(__uuidof(IDXGIKeyedMutex),
333 (void**)getter_AddRefs(sharedMutex));
335 HRESULT hr;
336 AutoTextureLock lock(sharedMutex, hr, 30 * 1000);
337 if (FAILED(hr)) {
338 gfxCriticalError() << "DoesD3D11TextureSharingWork_AcquireSyncTimeout";
339 // only wait for 30 seconds
340 return false;
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;
352 if (SUCCEEDED(
353 deviceContext->Map(cpuTexture, 0, D3D11_MAP_READ, 0, &mapped))) {
354 // read the texture
355 resultColor = *(uint32_t*)mapped.pData;
356 deviceContext->Unmap(cpuTexture, 0);
357 } else {
358 gfxCriticalError() << "DoesD3D11TextureSharingWork_MapFailed";
359 return false;
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
365 // AMD GPU
366 gfxCriticalNote << "DoesD3D11TextureSharingWork_ColorMismatch";
367 return false;
370 RefPtr<ID3D11ShaderResourceView> sharedView;
372 // This if(FAILED()) is the one that actually fails on systems affected by bug
373 // 1083071.
374 if (FAILED(device->CreateShaderResourceView(sharedTexture, NULL,
375 getter_AddRefs(sharedView)))) {
376 gfxCriticalNote << "CreateShaderResourceView failed for format" << format;
377 return false;
380 return true;
383 /* static */
384 bool D3D11Checks::DoesTextureSharingWork(ID3D11Device* device) {
385 return DoesTextureSharingWorkInternal(
386 device, DXGI_FORMAT_B8G8R8A8_UNORM,
387 D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE);
390 /* static */
391 bool D3D11Checks::DoesAlphaTextureSharingWork(ID3D11Device* device) {
392 return DoesTextureSharingWorkInternal(device, DXGI_FORMAT_R8_UNORM,
393 D3D11_BIND_SHADER_RESOURCE);
396 /* static */
397 bool D3D11Checks::GetDxgiDesc(ID3D11Device* device, DXGI_ADAPTER_DESC* out) {
398 RefPtr<IDXGIDevice> dxgiDevice;
399 HRESULT hr =
400 device->QueryInterface(__uuidof(IDXGIDevice), getter_AddRefs(dxgiDevice));
401 if (FAILED(hr)) {
402 return false;
405 RefPtr<IDXGIAdapter> dxgiAdapter;
406 if (FAILED(dxgiDevice->GetAdapter(getter_AddRefs(dxgiAdapter)))) {
407 return false;
410 return SUCCEEDED(dxgiAdapter->GetDesc(out));
413 /* static */
414 void D3D11Checks::WarnOnAdapterMismatch(ID3D11Device* device) {
415 DXGI_ADAPTER_DESC desc;
416 PodZero(&desc);
417 GetDxgiDesc(device, &desc);
419 nsCOMPtr<nsIGfxInfo> gfxInfo = components::GfxInfo::Service();
420 nsString vendorID;
421 gfxInfo->GetAdapterVendorID(vendorID);
422 nsresult ec;
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);
430 /* static */
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;
435 HRESULT hr =
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()) {
444 return false;
447 DXGI_ADAPTER_DESC desc;
448 PodZero(&desc);
449 if (!GetDxgiDesc(device, &desc)) {
450 // Failed to retrieve device information, assume it doesn't work
451 return false;
454 UINT formatSupport;
455 HRESULT hr = device->CheckFormatSupport(DXGI_FORMAT_NV12, &formatSupport);
456 if (FAILED(hr) || !(formatSupport & D3D11_FORMAT_SUPPORT_TEXTURE2D)) {
457 return false;
460 nsString version;
461 nsCOMPtr<nsIGfxInfo> gfxInfo = components::GfxInfo::Service();
462 if (gfxInfo) {
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()) {
471 return false;
473 UINT formatSupport;
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()) {
481 return false;
483 UINT formatSupport;
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
491 // P010 and P016.
492 return options;
494 options += VideoFormatOption::NV12;
495 if (doesP010Work()) {
496 options += VideoFormatOption::P010;
498 if (doesP016Work()) {
499 options += VideoFormatOption::P016;
501 return options;
504 } // namespace gfx
505 } // namespace mozilla