Source code

Revision control

Other Tools

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/. */
5
6
#include "D3D11Checks.h"
7
#include "DXVA2Manager.h"
8
#include "gfxConfig.h"
9
#include "GfxDriverInfo.h"
10
#include "gfxWindowsPlatform.h"
11
#include "mozilla/RefPtr.h"
12
#include "mozilla/StaticPrefs.h"
13
#include "mozilla/gfx/gfxVars.h"
14
#include "mozilla/gfx/Logging.h"
15
#include "mozilla/layers/TextureD3D11.h"
16
#include "nsIGfxInfo.h"
17
#include <dxgi.h>
18
#include <dxgi1_2.h>
19
#include <d3d10_1.h>
20
#include <d3d11.h>
21
22
namespace mozilla {
23
namespace gfx {
24
25
using namespace mozilla::widget;
26
using mozilla::layers::AutoTextureLock;
27
28
/* static */
29
bool D3D11Checks::DoesRenderTargetViewNeedRecreating(ID3D11Device* aDevice) {
30
bool result = false;
31
// CreateTexture2D is known to crash on lower feature levels, see bugs
32
// 1170211 and 1089413.
33
if (aDevice->GetFeatureLevel() < D3D_FEATURE_LEVEL_10_0) {
34
return true;
35
}
36
37
RefPtr<ID3D11DeviceContext> deviceContext;
38
aDevice->GetImmediateContext(getter_AddRefs(deviceContext));
39
int backbufferWidth = 32;
40
int backbufferHeight = 32;
41
RefPtr<ID3D11Texture2D> offscreenTexture;
42
RefPtr<IDXGIKeyedMutex> keyedMutex;
43
44
D3D11_TEXTURE2D_DESC offscreenTextureDesc = {0};
45
offscreenTextureDesc.Width = backbufferWidth;
46
offscreenTextureDesc.Height = backbufferHeight;
47
offscreenTextureDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
48
offscreenTextureDesc.MipLevels = 0;
49
offscreenTextureDesc.ArraySize = 1;
50
offscreenTextureDesc.SampleDesc.Count = 1;
51
offscreenTextureDesc.SampleDesc.Quality = 0;
52
offscreenTextureDesc.Usage = D3D11_USAGE_DEFAULT;
53
offscreenTextureDesc.BindFlags =
54
D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
55
offscreenTextureDesc.CPUAccessFlags = 0;
56
offscreenTextureDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX;
57
58
HRESULT hr = aDevice->CreateTexture2D(&offscreenTextureDesc, NULL,
59
getter_AddRefs(offscreenTexture));
60
if (FAILED(hr)) {
61
gfxCriticalNote << "DoesRecreatingCreateTexture2DFail";
62
return false;
63
}
64
65
hr = offscreenTexture->QueryInterface(__uuidof(IDXGIKeyedMutex),
66
(void**)getter_AddRefs(keyedMutex));
67
if (FAILED(hr)) {
68
gfxCriticalNote << "DoesRecreatingKeyedMutexFailed";
69
return false;
70
}
71
D3D11_RENDER_TARGET_VIEW_DESC offscreenRTVDesc;
72
offscreenRTVDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
73
offscreenRTVDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
74
offscreenRTVDesc.Texture2D.MipSlice = 0;
75
76
RefPtr<ID3D11RenderTargetView> offscreenRTView;
77
hr = aDevice->CreateRenderTargetView(offscreenTexture, &offscreenRTVDesc,
78
getter_AddRefs(offscreenRTView));
79
if (FAILED(hr)) {
80
gfxCriticalNote << "DoesRecreatingCreateRenderTargetViewFailed";
81
return false;
82
}
83
84
{
85
// Acquire and clear
86
HRESULT hr;
87
AutoTextureLock lock(keyedMutex, hr, INFINITE);
88
FLOAT color1[4] = {1, 1, 0.5, 1};
89
deviceContext->ClearRenderTargetView(offscreenRTView, color1);
90
}
91
92
{
93
HRESULT hr;
94
AutoTextureLock lock(keyedMutex, hr, INFINITE);
95
FLOAT color2[4] = {1, 1, 0, 1};
96
97
deviceContext->ClearRenderTargetView(offscreenRTView, color2);
98
D3D11_TEXTURE2D_DESC desc;
99
100
offscreenTexture->GetDesc(&desc);
101
desc.Usage = D3D11_USAGE_STAGING;
102
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
103
desc.MiscFlags = 0;
104
desc.BindFlags = 0;
105
RefPtr<ID3D11Texture2D> cpuTexture;
106
hr = aDevice->CreateTexture2D(&desc, NULL, getter_AddRefs(cpuTexture));
107
if (FAILED(hr)) {
108
gfxCriticalNote << "DoesRecreatingCreateCPUTextureFailed";
109
return false;
110
}
111
112
deviceContext->CopyResource(cpuTexture, offscreenTexture);
113
114
D3D11_MAPPED_SUBRESOURCE mapped;
115
hr = deviceContext->Map(cpuTexture, 0, D3D11_MAP_READ, 0, &mapped);
116
if (FAILED(hr)) {
117
gfxCriticalNote << "DoesRecreatingMapFailed " << hexa(hr);
118
return false;
119
}
120
int resultColor = *(int*)mapped.pData;
121
deviceContext->Unmap(cpuTexture, 0);
122
cpuTexture = nullptr;
123
124
// XXX on some drivers resultColor will not have changed to
125
// match the clear
126
if (resultColor != 0xffffff00) {
127
gfxCriticalNote << "RenderTargetViewNeedsRecreating";
128
result = true;
129
}
130
}
131
return result;
132
}
133
134
/* static */
135
bool D3D11Checks::DoesDeviceWork() {
136
static bool checked = false;
137
static bool result = false;
138
139
if (checked) return result;
140
checked = true;
141
142
if (StaticPrefs::Direct2DForceEnabled() ||
143
gfxConfig::IsForcedOnByUser(Feature::HW_COMPOSITING)) {
144
result = true;
145
return true;
146
}
147
148
if (GetModuleHandleW(L"igd10umd32.dll")) {
149
const wchar_t* checkModules[] = {L"dlumd32.dll", L"dlumd11.dll",
150
L"dlumd10.dll"};
151
for (int i = 0; i < PR_ARRAY_SIZE(checkModules); i += 1) {
152
if (GetModuleHandleW(checkModules[i])) {
153
nsString displayLinkModuleVersionString;
154
gfxWindowsPlatform::GetDLLVersion(checkModules[i],
155
displayLinkModuleVersionString);
156
uint64_t displayLinkModuleVersion;
157
if (!ParseDriverVersion(displayLinkModuleVersionString,
158
&displayLinkModuleVersion)) {
159
gfxCriticalError()
160
<< "DisplayLink: could not parse version " << checkModules[i];
161
return false;
162
}
163
if (displayLinkModuleVersion <= V(8, 6, 1, 36484)) {
164
NS_ConvertUTF16toUTF8 version(displayLinkModuleVersionString);
165
gfxCriticalError(CriticalLog::DefaultOptions(false))
166
<< "DisplayLink: too old version " << version.get();
167
return false;
168
}
169
}
170
}
171
}
172
result = true;
173
return true;
174
}
175
176
static bool TryCreateTexture2D(ID3D11Device* device, D3D11_TEXTURE2D_DESC* desc,
177
D3D11_SUBRESOURCE_DATA* data,
178
RefPtr<ID3D11Texture2D>& texture) {
179
// Older Intel driver version (see bug 1221348 for version #s) crash when
180
// creating a texture with shared keyed mutex and data.
181
MOZ_SEH_TRY {
182
return !FAILED(
183
device->CreateTexture2D(desc, data, getter_AddRefs(texture)));
184
}
185
MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
186
// For now we want to aggregrate all the crash signature to a known crash.
187
gfxDevCrash(LogReason::TextureCreation)
188
<< "Crash creating texture. See bug 1221348.";
189
return false;
190
}
191
}
192
193
// See bug 1083071. On some drivers, Direct3D 11 CreateShaderResourceView fails
194
// with E_OUTOFMEMORY.
195
static bool DoesTextureSharingWorkInternal(ID3D11Device* device,
196
DXGI_FORMAT format, UINT bindflags) {
197
// CreateTexture2D is known to crash on lower feature levels, see bugs
198
// 1170211 and 1089413.
199
if (device->GetFeatureLevel() < D3D_FEATURE_LEVEL_10_0) {
200
return false;
201
}
202
203
if (StaticPrefs::Direct2DForceEnabled() ||
204
gfxConfig::IsForcedOnByUser(Feature::HW_COMPOSITING)) {
205
return true;
206
}
207
208
if (GetModuleHandleW(L"atidxx32.dll")) {
209
nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
210
if (gfxInfo) {
211
nsString vendorID, vendorID2;
212
gfxInfo->GetAdapterVendorID(vendorID);
213
gfxInfo->GetAdapterVendorID2(vendorID2);
214
if (vendorID.EqualsLiteral("0x8086") && vendorID2.IsEmpty()) {
215
if (!StaticPrefs::LayersAMDSwitchableGfxEnabled()) {
216
return false;
217
}
218
gfxCriticalError(CriticalLog::DefaultOptions(false))
219
<< "PossiblyBrokenSurfaceSharing_UnexpectedAMDGPU";
220
}
221
}
222
}
223
224
RefPtr<ID3D11Texture2D> texture;
225
D3D11_TEXTURE2D_DESC desc;
226
const int texture_size = 32;
227
desc.Width = texture_size;
228
desc.Height = texture_size;
229
desc.MipLevels = 1;
230
desc.ArraySize = 1;
231
desc.Format = format;
232
desc.SampleDesc.Count = 1;
233
desc.SampleDesc.Quality = 0;
234
desc.Usage = D3D11_USAGE_DEFAULT;
235
desc.CPUAccessFlags = 0;
236
desc.MiscFlags = D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX;
237
desc.BindFlags = bindflags;
238
239
uint32_t color[texture_size * texture_size];
240
for (size_t i = 0; i < sizeof(color) / sizeof(color[0]); i++) {
241
color[i] = 0xff00ffff;
242
}
243
// XXX If we pass the data directly at texture creation time we
244
// get a crash on Intel 8.5.10.[18xx-1994] drivers.
245
// We can work around this issue by doing UpdateSubresource.
246
if (!TryCreateTexture2D(device, &desc, nullptr, texture)) {
247
gfxCriticalNote << "DoesD3D11TextureSharingWork_TryCreateTextureFailure";
248
return false;
249
}
250
251
RefPtr<IDXGIKeyedMutex> sourceSharedMutex;
252
texture->QueryInterface(__uuidof(IDXGIKeyedMutex),
253
(void**)getter_AddRefs(sourceSharedMutex));
254
if (FAILED(sourceSharedMutex->AcquireSync(0, 30 * 1000))) {
255
gfxCriticalError() << "DoesD3D11TextureSharingWork_SourceMutexTimeout";
256
// only wait for 30 seconds
257
return false;
258
}
259
260
RefPtr<ID3D11DeviceContext> deviceContext;
261
device->GetImmediateContext(getter_AddRefs(deviceContext));
262
263
int stride = texture_size * 4;
264
deviceContext->UpdateSubresource(texture, 0, nullptr, color, stride,
265
stride * texture_size);
266
267
if (FAILED(sourceSharedMutex->ReleaseSync(0))) {
268
gfxCriticalError()
269
<< "DoesD3D11TextureSharingWork_SourceReleaseSyncTimeout";
270
return false;
271
}
272
273
HANDLE shareHandle;
274
RefPtr<IDXGIResource> otherResource;
275
if (FAILED(texture->QueryInterface(__uuidof(IDXGIResource),
276
getter_AddRefs(otherResource)))) {
277
gfxCriticalError() << "DoesD3D11TextureSharingWork_GetResourceFailure";
278
return false;
279
}
280
281
if (FAILED(otherResource->GetSharedHandle(&shareHandle))) {
282
gfxCriticalError() << "DoesD3D11TextureSharingWork_GetSharedTextureFailure";
283
return false;
284
}
285
286
RefPtr<ID3D11Resource> sharedResource;
287
RefPtr<ID3D11Texture2D> sharedTexture;
288
if (FAILED(device->OpenSharedResource(shareHandle, __uuidof(ID3D11Resource),
289
getter_AddRefs(sharedResource)))) {
290
gfxCriticalError(CriticalLog::DefaultOptions(false))
291
<< "OpenSharedResource failed for format " << format;
292
return false;
293
}
294
295
if (FAILED(sharedResource->QueryInterface(__uuidof(ID3D11Texture2D),
296
getter_AddRefs(sharedTexture)))) {
297
gfxCriticalError() << "DoesD3D11TextureSharingWork_GetSharedTextureFailure";
298
return false;
299
}
300
301
// create a staging texture for readback
302
RefPtr<ID3D11Texture2D> cpuTexture;
303
desc.Usage = D3D11_USAGE_STAGING;
304
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
305
desc.MiscFlags = 0;
306
desc.BindFlags = 0;
307
if (FAILED(device->CreateTexture2D(&desc, nullptr,
308
getter_AddRefs(cpuTexture)))) {
309
gfxCriticalError() << "DoesD3D11TextureSharingWork_CreateTextureFailure";
310
return false;
311
}
312
313
RefPtr<IDXGIKeyedMutex> sharedMutex;
314
sharedResource->QueryInterface(__uuidof(IDXGIKeyedMutex),
315
(void**)getter_AddRefs(sharedMutex));
316
{
317
HRESULT hr;
318
AutoTextureLock lock(sharedMutex, hr, 30 * 1000);
319
if (FAILED(hr)) {
320
gfxCriticalError() << "DoesD3D11TextureSharingWork_AcquireSyncTimeout";
321
// only wait for 30 seconds
322
return false;
323
}
324
325
// Copy to the cpu texture so that we can readback
326
deviceContext->CopyResource(cpuTexture, sharedTexture);
327
328
// We only need to hold on to the mutex during the copy.
329
sharedMutex->ReleaseSync(0);
330
}
331
332
D3D11_MAPPED_SUBRESOURCE mapped;
333
uint32_t resultColor = 0;
334
if (SUCCEEDED(
335
deviceContext->Map(cpuTexture, 0, D3D11_MAP_READ, 0, &mapped))) {
336
// read the texture
337
resultColor = *(uint32_t*)mapped.pData;
338
deviceContext->Unmap(cpuTexture, 0);
339
} else {
340
gfxCriticalError() << "DoesD3D11TextureSharingWork_MapFailed";
341
return false;
342
}
343
344
// check that the color we put in is the color we get out
345
if (resultColor != color[0]) {
346
// Shared surfaces seem to be broken on dual AMD & Intel HW when using the
347
// AMD GPU
348
gfxCriticalNote << "DoesD3D11TextureSharingWork_ColorMismatch";
349
return false;
350
}
351
352
RefPtr<ID3D11ShaderResourceView> sharedView;
353
354
// This if(FAILED()) is the one that actually fails on systems affected by bug
355
// 1083071.
356
if (FAILED(device->CreateShaderResourceView(sharedTexture, NULL,
357
getter_AddRefs(sharedView)))) {
358
gfxCriticalNote << "CreateShaderResourceView failed for format" << format;
359
return false;
360
}
361
362
return true;
363
}
364
365
/* static */
366
bool D3D11Checks::DoesTextureSharingWork(ID3D11Device* device) {
367
return DoesTextureSharingWorkInternal(
368
device, DXGI_FORMAT_B8G8R8A8_UNORM,
369
D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE);
370
}
371
372
/* static */
373
bool D3D11Checks::DoesAlphaTextureSharingWork(ID3D11Device* device) {
374
return DoesTextureSharingWorkInternal(device, DXGI_FORMAT_R8_UNORM,
375
D3D11_BIND_SHADER_RESOURCE);
376
}
377
378
/* static */
379
bool D3D11Checks::GetDxgiDesc(ID3D11Device* device, DXGI_ADAPTER_DESC* out) {
380
RefPtr<IDXGIDevice> dxgiDevice;
381
HRESULT hr =
382
device->QueryInterface(__uuidof(IDXGIDevice), getter_AddRefs(dxgiDevice));
383
if (FAILED(hr)) {
384
return false;
385
}
386
387
RefPtr<IDXGIAdapter> dxgiAdapter;
388
if (FAILED(dxgiDevice->GetAdapter(getter_AddRefs(dxgiAdapter)))) {
389
return false;
390
}
391
392
return SUCCEEDED(dxgiAdapter->GetDesc(out));
393
}
394
395
/* static */
396
void D3D11Checks::WarnOnAdapterMismatch(ID3D11Device* device) {
397
DXGI_ADAPTER_DESC desc;
398
PodZero(&desc);
399
GetDxgiDesc(device, &desc);
400
401
nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
402
nsString vendorID;
403
gfxInfo->GetAdapterVendorID(vendorID);
404
nsresult ec;
405
int32_t vendor = vendorID.ToInteger(&ec, 16);
406
if (vendor != desc.VendorId) {
407
gfxCriticalNote << "VendorIDMismatch V " << hexa(vendor) << " "
408
<< hexa(desc.VendorId);
409
}
410
}
411
412
/* static */
413
bool D3D11Checks::DoesRemotePresentWork(IDXGIAdapter* adapter) {
414
// Remote presentation was added in DXGI 1.2, for Windows 8 and the Platform
415
// Update to Windows 7.
416
RefPtr<IDXGIAdapter2> check;
417
HRESULT hr =
418
adapter->QueryInterface(__uuidof(IDXGIAdapter2), getter_AddRefs(check));
419
return SUCCEEDED(hr) && check;
420
}
421
422
/* static */ D3D11Checks::VideoFormatOptionSet D3D11Checks::FormatOptions(
423
ID3D11Device* device) {
424
auto doesNV12Work = [&]() {
425
if (gfxVars::DXNV12Blocked()) {
426
return false;
427
}
428
429
DXGI_ADAPTER_DESC desc;
430
PodZero(&desc);
431
if (!GetDxgiDesc(device, &desc)) {
432
// Failed to retrieve device information, assume it doesn't work
433
return false;
434
}
435
436
UINT formatSupport;
437
HRESULT hr = device->CheckFormatSupport(DXGI_FORMAT_NV12, &formatSupport);
438
if (FAILED(hr) || !(formatSupport & D3D11_FORMAT_SUPPORT_TEXTURE2D)) {
439
return false;
440
}
441
442
nsString version;
443
nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
444
if (gfxInfo) {
445
gfxInfo->GetAdapterDriverVersion(version);
446
}
447
return DXVA2Manager::IsNV12Supported(desc.VendorId, desc.DeviceId, version);
448
};
449
450
auto doesP010Work = [&]() {
451
if (gfxVars::DXP010Blocked() &&
452
!StaticPrefs::PDMWMFForceAllowP010Format()) {
453
return false;
454
}
455
UINT formatSupport;
456
HRESULT hr = device->CheckFormatSupport(DXGI_FORMAT_P010, &formatSupport);
457
return (SUCCEEDED(hr) && (formatSupport & D3D11_FORMAT_SUPPORT_TEXTURE2D));
458
};
459
460
auto doesP016Work = [&]() {
461
if (gfxVars::DXP016Blocked() &&
462
!StaticPrefs::PDMWMFForceAllowP010Format()) {
463
return false;
464
}
465
UINT formatSupport;
466
HRESULT hr = device->CheckFormatSupport(DXGI_FORMAT_P016, &formatSupport);
467
return (SUCCEEDED(hr) && (formatSupport & D3D11_FORMAT_SUPPORT_TEXTURE2D));
468
};
469
470
VideoFormatOptionSet options;
471
if (!doesNV12Work()) {
472
// If the device doesn't support NV12, there's really no point testing for
473
// P010 and P016.
474
return options;
475
}
476
options += VideoFormatOption::NV12;
477
if (doesP010Work()) {
478
options += VideoFormatOption::P010;
479
}
480
if (doesP016Work()) {
481
options += VideoFormatOption::P016;
482
}
483
return options;
484
}
485
486
} // namespace gfx
487
} // namespace mozilla