1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 #include "TextureD3D11.h"
8
9 #include "CompositorD3D11.h"
10 #include "Effects.h"
11 #include "MainThreadUtils.h"
12 #include "gfx2DGlue.h"
13 #include "gfxContext.h"
14 #include "gfxWindowsPlatform.h"
15 #include "mozilla/StaticPrefs_gfx.h"
16 #include "mozilla/Telemetry.h"
17 #include "mozilla/gfx/DataSurfaceHelpers.h"
18 #include "mozilla/gfx/DeviceManagerDx.h"
19 #include "mozilla/gfx/Logging.h"
20 #include "mozilla/gfx/gfxVars.h"
21 #include "mozilla/layers/CompositorBridgeChild.h"
22 #include "mozilla/webrender/RenderD3D11TextureHost.h"
23 #include "mozilla/webrender/RenderThread.h"
24 #include "mozilla/webrender/WebRenderAPI.h"
25
26 namespace mozilla {
27
28 using namespace gfx;
29
30 namespace layers {
31
32 static const GUID sD3D11TextureUsage = {
33 0xd89275b0,
34 0x6c7d,
35 0x4038,
36 {0xb5, 0xfa, 0x4d, 0x87, 0x16, 0xd5, 0xcc, 0x4e}};
37
38 /* This class gets its lifetime tied to a D3D texture
39 * and increments memory usage on construction and decrements
40 * on destruction */
41 class TextureMemoryMeasurer final : public IUnknown {
42 public:
TextureMemoryMeasurer(size_t aMemoryUsed)43 explicit TextureMemoryMeasurer(size_t aMemoryUsed) {
44 mMemoryUsed = aMemoryUsed;
45 gfxWindowsPlatform::sD3D11SharedTextures += mMemoryUsed;
46 mRefCnt = 0;
47 }
AddRef()48 STDMETHODIMP_(ULONG) AddRef() {
49 mRefCnt++;
50 return mRefCnt;
51 }
QueryInterface(REFIID riid,void ** ppvObject)52 STDMETHODIMP QueryInterface(REFIID riid, void** ppvObject) {
53 IUnknown* punk = nullptr;
54 if (riid == IID_IUnknown) {
55 punk = this;
56 }
57 *ppvObject = punk;
58 if (punk) {
59 punk->AddRef();
60 return S_OK;
61 } else {
62 return E_NOINTERFACE;
63 }
64 }
65
Release()66 STDMETHODIMP_(ULONG) Release() {
67 int refCnt = --mRefCnt;
68 if (refCnt == 0) {
69 gfxWindowsPlatform::sD3D11SharedTextures -= mMemoryUsed;
70 delete this;
71 }
72 return refCnt;
73 }
74
75 private:
76 int mRefCnt;
77 int mMemoryUsed;
78
79 ~TextureMemoryMeasurer() = default;
80 };
81
SurfaceFormatToDXGIFormat(gfx::SurfaceFormat aFormat)82 static DXGI_FORMAT SurfaceFormatToDXGIFormat(gfx::SurfaceFormat aFormat) {
83 switch (aFormat) {
84 case SurfaceFormat::B8G8R8A8:
85 return DXGI_FORMAT_B8G8R8A8_UNORM;
86 case SurfaceFormat::B8G8R8X8:
87 return DXGI_FORMAT_B8G8R8A8_UNORM;
88 case SurfaceFormat::R8G8B8A8:
89 return DXGI_FORMAT_R8G8B8A8_UNORM;
90 case SurfaceFormat::R8G8B8X8:
91 return DXGI_FORMAT_R8G8B8A8_UNORM;
92 case SurfaceFormat::A8:
93 return DXGI_FORMAT_R8_UNORM;
94 case SurfaceFormat::A16:
95 return DXGI_FORMAT_R16_UNORM;
96 default:
97 MOZ_ASSERT(false, "unsupported format");
98 return DXGI_FORMAT_UNKNOWN;
99 }
100 }
101
ReportTextureMemoryUsage(ID3D11Texture2D * aTexture,size_t aBytes)102 void ReportTextureMemoryUsage(ID3D11Texture2D* aTexture, size_t aBytes) {
103 aTexture->SetPrivateDataInterface(sD3D11TextureUsage,
104 new TextureMemoryMeasurer(aBytes));
105 }
106
GetRequiredTilesD3D11(uint32_t aSize,uint32_t aMaxSize)107 static uint32_t GetRequiredTilesD3D11(uint32_t aSize, uint32_t aMaxSize) {
108 uint32_t requiredTiles = aSize / aMaxSize;
109 if (aSize % aMaxSize) {
110 requiredTiles++;
111 }
112 return requiredTiles;
113 }
114
GetTileRectD3D11(uint32_t aID,IntSize aSize,uint32_t aMaxSize)115 static IntRect GetTileRectD3D11(uint32_t aID, IntSize aSize,
116 uint32_t aMaxSize) {
117 uint32_t horizontalTiles = GetRequiredTilesD3D11(aSize.width, aMaxSize);
118 uint32_t verticalTiles = GetRequiredTilesD3D11(aSize.height, aMaxSize);
119
120 uint32_t verticalTile = aID / horizontalTiles;
121 uint32_t horizontalTile = aID % horizontalTiles;
122
123 return IntRect(
124 horizontalTile * aMaxSize, verticalTile * aMaxSize,
125 horizontalTile < (horizontalTiles - 1) ? aMaxSize
126 : aSize.width % aMaxSize,
127 verticalTile < (verticalTiles - 1) ? aMaxSize : aSize.height % aMaxSize);
128 }
129
AutoTextureLock(IDXGIKeyedMutex * aMutex,HRESULT & aResult,uint32_t aTimeout)130 AutoTextureLock::AutoTextureLock(IDXGIKeyedMutex* aMutex, HRESULT& aResult,
131 uint32_t aTimeout) {
132 mMutex = aMutex;
133 if (mMutex) {
134 mResult = mMutex->AcquireSync(0, aTimeout);
135 aResult = mResult;
136 } else {
137 aResult = E_INVALIDARG;
138 }
139 }
140
~AutoTextureLock()141 AutoTextureLock::~AutoTextureLock() {
142 if (mMutex && !FAILED(mResult) && mResult != WAIT_TIMEOUT &&
143 mResult != WAIT_ABANDONED) {
144 mMutex->ReleaseSync(0);
145 }
146 }
147
GetShaderResourceView()148 ID3D11ShaderResourceView* TextureSourceD3D11::GetShaderResourceView() {
149 MOZ_ASSERT(mTexture == GetD3D11Texture(),
150 "You need to override GetShaderResourceView if you're overriding "
151 "GetD3D11Texture!");
152
153 if (!mSRV && mTexture) {
154 RefPtr<ID3D11Device> device;
155 mTexture->GetDevice(getter_AddRefs(device));
156
157 // see comment in CompositingRenderTargetD3D11 constructor
158 CD3D11_SHADER_RESOURCE_VIEW_DESC srvDesc(D3D11_SRV_DIMENSION_TEXTURE2D,
159 mFormatOverride);
160 D3D11_SHADER_RESOURCE_VIEW_DESC* desc =
161 mFormatOverride == DXGI_FORMAT_UNKNOWN ? nullptr : &srvDesc;
162
163 HRESULT hr =
164 device->CreateShaderResourceView(mTexture, desc, getter_AddRefs(mSRV));
165 if (FAILED(hr)) {
166 gfxCriticalNote << "[D3D11] TextureSourceD3D11:GetShaderResourceView "
167 "CreateSRV failure "
168 << gfx::hexa(hr);
169 return nullptr;
170 }
171 }
172 return mSRV;
173 }
174
DataTextureSourceD3D11(ID3D11Device * aDevice,SurfaceFormat aFormat,TextureFlags aFlags)175 DataTextureSourceD3D11::DataTextureSourceD3D11(ID3D11Device* aDevice,
176 SurfaceFormat aFormat,
177 TextureFlags aFlags)
178 : mDevice(aDevice),
179 mFormat(aFormat),
180 mFlags(aFlags),
181 mCurrentTile(0),
182 mIsTiled(false),
183 mIterating(false),
184 mAllowTextureUploads(true) {}
185
DataTextureSourceD3D11(ID3D11Device * aDevice,SurfaceFormat aFormat,ID3D11Texture2D * aTexture)186 DataTextureSourceD3D11::DataTextureSourceD3D11(ID3D11Device* aDevice,
187 SurfaceFormat aFormat,
188 ID3D11Texture2D* aTexture)
189 : mDevice(aDevice),
190 mFormat(aFormat),
191 mFlags(TextureFlags::NO_FLAGS),
192 mCurrentTile(0),
193 mIsTiled(false),
194 mIterating(false),
195 mAllowTextureUploads(false) {
196 mTexture = aTexture;
197 D3D11_TEXTURE2D_DESC desc;
198 aTexture->GetDesc(&desc);
199
200 mSize = IntSize(desc.Width, desc.Height);
201 }
202
DataTextureSourceD3D11(gfx::SurfaceFormat aFormat,TextureSourceProvider * aProvider,ID3D11Texture2D * aTexture)203 DataTextureSourceD3D11::DataTextureSourceD3D11(gfx::SurfaceFormat aFormat,
204 TextureSourceProvider* aProvider,
205 ID3D11Texture2D* aTexture)
206 : DataTextureSourceD3D11(aProvider->GetD3D11Device(), aFormat, aTexture) {}
207
DataTextureSourceD3D11(gfx::SurfaceFormat aFormat,TextureSourceProvider * aProvider,TextureFlags aFlags)208 DataTextureSourceD3D11::DataTextureSourceD3D11(gfx::SurfaceFormat aFormat,
209 TextureSourceProvider* aProvider,
210 TextureFlags aFlags)
211 : DataTextureSourceD3D11(aProvider->GetD3D11Device(), aFormat, aFlags) {}
212
~DataTextureSourceD3D11()213 DataTextureSourceD3D11::~DataTextureSourceD3D11() {}
214
215 enum class SerializeWithMoz2D : bool { No, Yes };
216
217 template <typename T> // ID3D10Texture2D or ID3D11Texture2D
LockD3DTexture(T * aTexture,SerializeWithMoz2D aSerialize=SerializeWithMoz2D::No)218 static bool LockD3DTexture(
219 T* aTexture, SerializeWithMoz2D aSerialize = SerializeWithMoz2D::No) {
220 MOZ_ASSERT(aTexture);
221 RefPtr<IDXGIKeyedMutex> mutex;
222 aTexture->QueryInterface((IDXGIKeyedMutex**)getter_AddRefs(mutex));
223 // Textures created by the DXVA decoders don't have a mutex for
224 // synchronization
225 if (mutex) {
226 HRESULT hr;
227 if (aSerialize == SerializeWithMoz2D::Yes) {
228 AutoSerializeWithMoz2D serializeWithMoz2D(BackendType::DIRECT2D1_1);
229 hr = mutex->AcquireSync(0, 10000);
230 } else {
231 hr = mutex->AcquireSync(0, 10000);
232 }
233 if (hr == WAIT_TIMEOUT) {
234 RefPtr<ID3D11Device> device;
235 aTexture->GetDevice(getter_AddRefs(device));
236 if (!device) {
237 gfxCriticalNote << "GFX: D3D11 lock mutex timeout - no device returned";
238 } else if (device->GetDeviceRemovedReason() != S_OK) {
239 gfxCriticalNote << "GFX: D3D11 lock mutex timeout - device removed";
240 } else {
241 gfxDevCrash(LogReason::D3DLockTimeout)
242 << "D3D lock mutex timeout - device not removed";
243 }
244 } else if (hr == WAIT_ABANDONED) {
245 gfxCriticalNote << "GFX: D3D11 lock mutex abandoned";
246 }
247
248 if (FAILED(hr)) {
249 NS_WARNING("Failed to lock the texture");
250 return false;
251 }
252 }
253 return true;
254 }
255
256 template <typename T>
HasKeyedMutex(T * aTexture)257 static bool HasKeyedMutex(T* aTexture) {
258 MOZ_ASSERT(aTexture);
259 RefPtr<IDXGIKeyedMutex> mutex;
260 aTexture->QueryInterface((IDXGIKeyedMutex**)getter_AddRefs(mutex));
261 return !!mutex;
262 }
263
264 template <typename T> // ID3D10Texture2D or ID3D11Texture2D
UnlockD3DTexture(T * aTexture,SerializeWithMoz2D aSerialize=SerializeWithMoz2D::No)265 static void UnlockD3DTexture(
266 T* aTexture, SerializeWithMoz2D aSerialize = SerializeWithMoz2D::No) {
267 MOZ_ASSERT(aTexture);
268 RefPtr<IDXGIKeyedMutex> mutex;
269 aTexture->QueryInterface((IDXGIKeyedMutex**)getter_AddRefs(mutex));
270 if (mutex) {
271 HRESULT hr;
272 if (aSerialize == SerializeWithMoz2D::Yes) {
273 AutoSerializeWithMoz2D serializeWithMoz2D(BackendType::DIRECT2D1_1);
274 hr = mutex->ReleaseSync(0);
275 } else {
276 hr = mutex->ReleaseSync(0);
277 }
278 if (FAILED(hr)) {
279 NS_WARNING("Failed to unlock the texture");
280 }
281 }
282 }
283
D3D11TextureData(ID3D11Texture2D * aTexture,uint32_t aArrayIndex,gfx::IntSize aSize,gfx::SurfaceFormat aFormat,TextureAllocationFlags aFlags)284 D3D11TextureData::D3D11TextureData(ID3D11Texture2D* aTexture,
285 uint32_t aArrayIndex, gfx::IntSize aSize,
286 gfx::SurfaceFormat aFormat,
287 TextureAllocationFlags aFlags)
288 : mSize(aSize),
289 mFormat(aFormat),
290 mNeedsClear(aFlags & ALLOC_CLEAR_BUFFER),
291 mHasSynchronization(HasKeyedMutex(aTexture)),
292 mTexture(aTexture),
293 mArrayIndex(aArrayIndex),
294 mAllocationFlags(aFlags) {
295 MOZ_ASSERT(aTexture);
296 }
297
DestroyDrawTarget(RefPtr<DrawTarget> & aDT,RefPtr<ID3D11Texture2D> & aTexture)298 static void DestroyDrawTarget(RefPtr<DrawTarget>& aDT,
299 RefPtr<ID3D11Texture2D>& aTexture) {
300 // An Azure DrawTarget needs to be locked when it gets nullptr'ed as this is
301 // when it calls EndDraw. This EndDraw should not execute anything so it
302 // shouldn't -really- need the lock but the debug layer chokes on this.
303 LockD3DTexture(aTexture.get(), SerializeWithMoz2D::Yes);
304 aDT = nullptr;
305
306 // Do the serialization here, so we can hold it while destroying the texture.
307 AutoSerializeWithMoz2D serializeWithMoz2D(BackendType::DIRECT2D1_1);
308 UnlockD3DTexture(aTexture.get(), SerializeWithMoz2D::No);
309 aTexture = nullptr;
310 }
311
~D3D11TextureData()312 D3D11TextureData::~D3D11TextureData() {
313 if (mDrawTarget) {
314 DestroyDrawTarget(mDrawTarget, mTexture);
315 }
316 }
317
Lock(OpenMode aMode)318 bool D3D11TextureData::Lock(OpenMode aMode) {
319 if (!LockD3DTexture(mTexture.get(), SerializeWithMoz2D::Yes)) {
320 return false;
321 }
322
323 if (NS_IsMainThread()) {
324 if (!PrepareDrawTargetInLock(aMode)) {
325 Unlock();
326 return false;
327 }
328 }
329
330 return true;
331 }
332
PrepareDrawTargetInLock(OpenMode aMode)333 bool D3D11TextureData::PrepareDrawTargetInLock(OpenMode aMode) {
334 // Make sure that successful write-lock means we will have a DrawTarget to
335 // write into.
336 if (!mDrawTarget && (aMode & OpenMode::OPEN_WRITE || mNeedsClear)) {
337 mDrawTarget = BorrowDrawTarget();
338 if (!mDrawTarget) {
339 return false;
340 }
341 }
342
343 // Reset transform
344 mDrawTarget->SetTransform(Matrix());
345
346 if (mNeedsClear) {
347 mDrawTarget->ClearRect(Rect(0, 0, mSize.width, mSize.height));
348 mNeedsClear = false;
349 }
350
351 return true;
352 }
353
Unlock()354 void D3D11TextureData::Unlock() {
355 UnlockD3DTexture(mTexture.get(), SerializeWithMoz2D::Yes);
356 }
357
FillInfo(TextureData::Info & aInfo) const358 void D3D11TextureData::FillInfo(TextureData::Info& aInfo) const {
359 aInfo.size = mSize;
360 aInfo.format = mFormat;
361 aInfo.supportsMoz2D = true;
362 aInfo.hasSynchronization = mHasSynchronization;
363 }
364
SyncWithObject(RefPtr<SyncObjectClient> aSyncObject)365 void D3D11TextureData::SyncWithObject(RefPtr<SyncObjectClient> aSyncObject) {
366 if (!aSyncObject || mHasSynchronization) {
367 // When we have per texture synchronization we sync using the keyed mutex.
368 return;
369 }
370
371 MOZ_ASSERT(aSyncObject->GetSyncType() == SyncObjectClient::SyncType::D3D11);
372 SyncObjectD3D11Client* sync =
373 static_cast<SyncObjectD3D11Client*>(aSyncObject.get());
374 sync->RegisterTexture(mTexture);
375 }
376
SerializeSpecific(SurfaceDescriptorD3D10 * const aOutDesc)377 bool D3D11TextureData::SerializeSpecific(
378 SurfaceDescriptorD3D10* const aOutDesc) {
379 RefPtr<IDXGIResource> resource;
380 GetDXGIResource((IDXGIResource**)getter_AddRefs(resource));
381 if (!resource) {
382 return false;
383 }
384 HANDLE sharedHandle;
385 HRESULT hr = resource->GetSharedHandle(&sharedHandle);
386 if (FAILED(hr)) {
387 LOGD3D11("Error getting shared handle for texture.");
388 return false;
389 }
390 *aOutDesc =
391 SurfaceDescriptorD3D10((WindowsHandle)sharedHandle, mArrayIndex, mFormat,
392 mSize, mYUVColorSpace, mColorRange);
393 return true;
394 }
395
Serialize(SurfaceDescriptor & aOutDescriptor)396 bool D3D11TextureData::Serialize(SurfaceDescriptor& aOutDescriptor) {
397 SurfaceDescriptorD3D10 desc;
398 if (!SerializeSpecific(&desc)) return false;
399
400 aOutDescriptor = std::move(desc);
401 return true;
402 }
403
GetSubDescriptor(RemoteDecoderVideoSubDescriptor * const aOutDesc)404 void D3D11TextureData::GetSubDescriptor(
405 RemoteDecoderVideoSubDescriptor* const aOutDesc) {
406 SurfaceDescriptorD3D10 ret;
407 if (!SerializeSpecific(&ret)) return;
408
409 *aOutDesc = std::move(ret);
410 }
411
412 /* static */
CreateTextureClient(ID3D11Texture2D * aTexture,uint32_t aIndex,gfx::IntSize aSize,gfx::SurfaceFormat aFormat,gfx::YUVColorSpace aColorSpace,gfx::ColorRange aColorRange,KnowsCompositor * aKnowsCompositor)413 already_AddRefed<TextureClient> D3D11TextureData::CreateTextureClient(
414 ID3D11Texture2D* aTexture, uint32_t aIndex, gfx::IntSize aSize,
415 gfx::SurfaceFormat aFormat, gfx::YUVColorSpace aColorSpace,
416 gfx::ColorRange aColorRange, KnowsCompositor* aKnowsCompositor) {
417 D3D11TextureData* data = new D3D11TextureData(
418 aTexture, aIndex, aSize, aFormat,
419 TextureAllocationFlags::ALLOC_MANUAL_SYNCHRONIZATION);
420 data->SetYUVColorSpace(aColorSpace);
421 data->SetColorRange(aColorRange);
422
423 RefPtr<TextureClient> textureClient = MakeAndAddRef<TextureClient>(
424 data, TextureFlags::NO_FLAGS, aKnowsCompositor->GetTextureForwarder());
425
426 return textureClient.forget();
427 }
428
Create(IntSize aSize,SurfaceFormat aFormat,TextureAllocationFlags aFlags,ID3D11Device * aDevice)429 D3D11TextureData* D3D11TextureData::Create(IntSize aSize, SurfaceFormat aFormat,
430 TextureAllocationFlags aFlags,
431 ID3D11Device* aDevice) {
432 return Create(aSize, aFormat, nullptr, aFlags, aDevice);
433 }
434
Create(SourceSurface * aSurface,TextureAllocationFlags aFlags,ID3D11Device * aDevice)435 D3D11TextureData* D3D11TextureData::Create(SourceSurface* aSurface,
436 TextureAllocationFlags aFlags,
437 ID3D11Device* aDevice) {
438 return Create(aSurface->GetSize(), aSurface->GetFormat(), aSurface, aFlags,
439 aDevice);
440 }
441
Create(IntSize aSize,SurfaceFormat aFormat,SourceSurface * aSurface,TextureAllocationFlags aFlags,ID3D11Device * aDevice)442 D3D11TextureData* D3D11TextureData::Create(IntSize aSize, SurfaceFormat aFormat,
443 SourceSurface* aSurface,
444 TextureAllocationFlags aFlags,
445 ID3D11Device* aDevice) {
446 if (aFormat == SurfaceFormat::A8) {
447 // Currently we don't support A8 surfaces. Fallback.
448 return nullptr;
449 }
450
451 // Just grab any device. We never use the immediate context, so the devices
452 // are fine to use from any thread.
453 RefPtr<ID3D11Device> device = aDevice;
454 if (!device) {
455 device = DeviceManagerDx::Get()->GetContentDevice();
456 if (!device) {
457 return nullptr;
458 }
459 }
460
461 CD3D11_TEXTURE2D_DESC newDesc(
462 DXGI_FORMAT_B8G8R8A8_UNORM, aSize.width, aSize.height, 1, 1,
463 D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE);
464
465 if (aFormat == SurfaceFormat::NV12) {
466 newDesc.Format = DXGI_FORMAT_NV12;
467 } else if (aFormat == SurfaceFormat::P010) {
468 newDesc.Format = DXGI_FORMAT_P010;
469 } else if (aFormat == SurfaceFormat::P016) {
470 newDesc.Format = DXGI_FORMAT_P016;
471 }
472
473 newDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED;
474 if (!NS_IsMainThread()) {
475 // On the main thread we use the syncobject to handle synchronization.
476 if (!(aFlags & ALLOC_MANUAL_SYNCHRONIZATION)) {
477 newDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX;
478 }
479 }
480
481 if (aSurface && newDesc.MiscFlags == D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX &&
482 !DeviceManagerDx::Get()->CanInitializeKeyedMutexTextures()) {
483 return nullptr;
484 }
485
486 D3D11_SUBRESOURCE_DATA uploadData;
487 D3D11_SUBRESOURCE_DATA* uploadDataPtr = nullptr;
488 RefPtr<DataSourceSurface> srcSurf;
489 DataSourceSurface::MappedSurface sourceMap;
490
491 if (aSurface) {
492 srcSurf = aSurface->GetDataSurface();
493
494 if (!srcSurf) {
495 gfxCriticalError()
496 << "Failed to GetDataSurface in D3D11TextureData::Create";
497 return nullptr;
498 }
499
500 if (!srcSurf->Map(DataSourceSurface::READ, &sourceMap)) {
501 gfxCriticalError()
502 << "Failed to map source surface for D3D11TextureData::Create";
503 return nullptr;
504 }
505 }
506
507 if (srcSurf && !DeviceManagerDx::Get()->HasCrashyInitData()) {
508 uploadData.pSysMem = sourceMap.mData;
509 uploadData.SysMemPitch = sourceMap.mStride;
510 uploadData.SysMemSlicePitch = 0; // unused
511
512 uploadDataPtr = &uploadData;
513 }
514
515 // See bug 1397040
516 RefPtr<ID3D10Multithread> mt;
517 device->QueryInterface((ID3D10Multithread**)getter_AddRefs(mt));
518
519 RefPtr<ID3D11Texture2D> texture11;
520
521 {
522 AutoSerializeWithMoz2D serializeWithMoz2D(BackendType::DIRECT2D1_1);
523 D3D11MTAutoEnter lock(mt.forget());
524
525 HRESULT hr = device->CreateTexture2D(&newDesc, uploadDataPtr,
526 getter_AddRefs(texture11));
527
528 if (FAILED(hr) || !texture11) {
529 gfxCriticalNote << "[D3D11] 2 CreateTexture2D failure Size: " << aSize
530 << "texture11: " << texture11
531 << " Code: " << gfx::hexa(hr);
532 return nullptr;
533 }
534
535 if (srcSurf && DeviceManagerDx::Get()->HasCrashyInitData()) {
536 D3D11_BOX box;
537 box.front = box.top = box.left = 0;
538 box.back = 1;
539 box.right = aSize.width;
540 box.bottom = aSize.height;
541 RefPtr<ID3D11DeviceContext> ctx;
542 device->GetImmediateContext(getter_AddRefs(ctx));
543 ctx->UpdateSubresource(texture11, 0, &box, sourceMap.mData,
544 sourceMap.mStride, 0);
545 }
546 }
547
548 if (srcSurf) {
549 srcSurf->Unmap();
550 }
551
552 // If we created the texture with a keyed mutex, then we expect all operations
553 // on it to be synchronized using it. If we did an initial upload using
554 // aSurface then bizarely this isn't covered, so we insert a manual
555 // lock/unlock pair to force this.
556 if (aSurface && newDesc.MiscFlags == D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX) {
557 if (!LockD3DTexture(texture11.get(), SerializeWithMoz2D::Yes)) {
558 return nullptr;
559 }
560 UnlockD3DTexture(texture11.get(), SerializeWithMoz2D::Yes);
561 }
562 texture11->SetPrivateDataInterface(
563 sD3D11TextureUsage,
564 new TextureMemoryMeasurer(newDesc.Width * newDesc.Height * 4));
565 return new D3D11TextureData(texture11, 0, aSize, aFormat, aFlags);
566 }
567
Deallocate(LayersIPCChannel * aAllocator)568 void D3D11TextureData::Deallocate(LayersIPCChannel* aAllocator) {
569 mDrawTarget = nullptr;
570 mTexture = nullptr;
571 }
572
CreateSimilar(LayersIPCChannel * aAllocator,LayersBackend aLayersBackend,TextureFlags aFlags,TextureAllocationFlags aAllocFlags) const573 TextureData* D3D11TextureData::CreateSimilar(
574 LayersIPCChannel* aAllocator, LayersBackend aLayersBackend,
575 TextureFlags aFlags, TextureAllocationFlags aAllocFlags) const {
576 return D3D11TextureData::Create(mSize, mFormat, aAllocFlags);
577 }
578
GetDXGIResource(IDXGIResource ** aOutResource)579 void D3D11TextureData::GetDXGIResource(IDXGIResource** aOutResource) {
580 mTexture->QueryInterface(aOutResource);
581 }
582
GetTextureFlags() const583 TextureFlags D3D11TextureData::GetTextureFlags() const {
584 TextureFlags flags = TextureFlags::NO_FLAGS;
585 // With WebRender, resource open happens asynchronously on RenderThread.
586 // During opening the resource on host side, TextureClient needs to be alive.
587 // With WAIT_HOST_USAGE_END, keep TextureClient alive during host side usage.
588 if (gfx::gfxVars::UseWebRender()) {
589 flags |= TextureFlags::WAIT_HOST_USAGE_END;
590 }
591 return flags;
592 }
593
Create(IDirect3DTexture9 * aTextureY,IDirect3DTexture9 * aTextureCb,IDirect3DTexture9 * aTextureCr,HANDLE aHandleY,HANDLE aHandleCb,HANDLE aHandleCr,const gfx::IntSize & aSize,const gfx::IntSize & aSizeY,const gfx::IntSize & aSizeCbCr,gfx::ColorDepth aColorDepth,YUVColorSpace aYUVColorSpace,gfx::ColorRange aColorRange)594 DXGIYCbCrTextureData* DXGIYCbCrTextureData::Create(
595 IDirect3DTexture9* aTextureY, IDirect3DTexture9* aTextureCb,
596 IDirect3DTexture9* aTextureCr, HANDLE aHandleY, HANDLE aHandleCb,
597 HANDLE aHandleCr, const gfx::IntSize& aSize, const gfx::IntSize& aSizeY,
598 const gfx::IntSize& aSizeCbCr, gfx::ColorDepth aColorDepth,
599 YUVColorSpace aYUVColorSpace, gfx::ColorRange aColorRange) {
600 if (!aHandleY || !aHandleCb || !aHandleCr || !aTextureY || !aTextureCb ||
601 !aTextureCr) {
602 return nullptr;
603 }
604
605 DXGIYCbCrTextureData* texture = new DXGIYCbCrTextureData();
606 texture->mHandles[0] = aHandleY;
607 texture->mHandles[1] = aHandleCb;
608 texture->mHandles[2] = aHandleCr;
609 texture->mD3D9Textures[0] = aTextureY;
610 texture->mD3D9Textures[1] = aTextureCb;
611 texture->mD3D9Textures[2] = aTextureCr;
612 texture->mSize = aSize;
613 texture->mSizeY = aSizeY;
614 texture->mSizeCbCr = aSizeCbCr;
615 texture->mColorDepth = aColorDepth;
616 texture->mYUVColorSpace = aYUVColorSpace;
617 texture->mColorRange = aColorRange;
618
619 return texture;
620 }
621
Create(ID3D11Texture2D * aTextureY,ID3D11Texture2D * aTextureCb,ID3D11Texture2D * aTextureCr,const gfx::IntSize & aSize,const gfx::IntSize & aSizeY,const gfx::IntSize & aSizeCbCr,gfx::ColorDepth aColorDepth,YUVColorSpace aYUVColorSpace,gfx::ColorRange aColorRange)622 DXGIYCbCrTextureData* DXGIYCbCrTextureData::Create(
623 ID3D11Texture2D* aTextureY, ID3D11Texture2D* aTextureCb,
624 ID3D11Texture2D* aTextureCr, const gfx::IntSize& aSize,
625 const gfx::IntSize& aSizeY, const gfx::IntSize& aSizeCbCr,
626 gfx::ColorDepth aColorDepth, YUVColorSpace aYUVColorSpace,
627 gfx::ColorRange aColorRange) {
628 if (!aTextureY || !aTextureCb || !aTextureCr) {
629 return nullptr;
630 }
631
632 aTextureY->SetPrivateDataInterface(
633 sD3D11TextureUsage,
634 new TextureMemoryMeasurer(aSizeY.width * aSizeY.height));
635 aTextureCb->SetPrivateDataInterface(
636 sD3D11TextureUsage,
637 new TextureMemoryMeasurer(aSizeCbCr.width * aSizeCbCr.height));
638 aTextureCr->SetPrivateDataInterface(
639 sD3D11TextureUsage,
640 new TextureMemoryMeasurer(aSizeCbCr.width * aSizeCbCr.height));
641
642 RefPtr<IDXGIResource> resource;
643
644 aTextureY->QueryInterface((IDXGIResource**)getter_AddRefs(resource));
645
646 HANDLE handleY;
647 HRESULT hr = resource->GetSharedHandle(&handleY);
648 if (FAILED(hr)) {
649 return nullptr;
650 }
651
652 aTextureCb->QueryInterface((IDXGIResource**)getter_AddRefs(resource));
653
654 HANDLE handleCb;
655 hr = resource->GetSharedHandle(&handleCb);
656 if (FAILED(hr)) {
657 return nullptr;
658 }
659
660 aTextureCr->QueryInterface((IDXGIResource**)getter_AddRefs(resource));
661 HANDLE handleCr;
662 hr = resource->GetSharedHandle(&handleCr);
663 if (FAILED(hr)) {
664 return nullptr;
665 }
666
667 DXGIYCbCrTextureData* texture = new DXGIYCbCrTextureData();
668 texture->mHandles[0] = handleY;
669 texture->mHandles[1] = handleCb;
670 texture->mHandles[2] = handleCr;
671 texture->mD3D11Textures[0] = aTextureY;
672 texture->mD3D11Textures[1] = aTextureCb;
673 texture->mD3D11Textures[2] = aTextureCr;
674 texture->mSize = aSize;
675 texture->mSizeY = aSizeY;
676 texture->mSizeCbCr = aSizeCbCr;
677 texture->mColorDepth = aColorDepth;
678 texture->mYUVColorSpace = aYUVColorSpace;
679 texture->mColorRange = aColorRange;
680
681 return texture;
682 }
683
FillInfo(TextureData::Info & aInfo) const684 void DXGIYCbCrTextureData::FillInfo(TextureData::Info& aInfo) const {
685 aInfo.size = mSize;
686 aInfo.format = gfx::SurfaceFormat::YUV;
687 aInfo.supportsMoz2D = false;
688 aInfo.hasSynchronization = false;
689 }
690
SerializeSpecific(SurfaceDescriptorDXGIYCbCr * const aOutDesc)691 void DXGIYCbCrTextureData::SerializeSpecific(
692 SurfaceDescriptorDXGIYCbCr* const aOutDesc) {
693 *aOutDesc = SurfaceDescriptorDXGIYCbCr(
694 (WindowsHandle)mHandles[0], (WindowsHandle)mHandles[1],
695 (WindowsHandle)mHandles[2], mSize, mSizeY, mSizeCbCr, mColorDepth,
696 mYUVColorSpace, mColorRange);
697 }
698
Serialize(SurfaceDescriptor & aOutDescriptor)699 bool DXGIYCbCrTextureData::Serialize(SurfaceDescriptor& aOutDescriptor) {
700 SurfaceDescriptorDXGIYCbCr desc;
701 SerializeSpecific(&desc);
702
703 aOutDescriptor = std::move(desc);
704 return true;
705 }
706
GetSubDescriptor(RemoteDecoderVideoSubDescriptor * const aOutDesc)707 void DXGIYCbCrTextureData::GetSubDescriptor(
708 RemoteDecoderVideoSubDescriptor* const aOutDesc) {
709 SurfaceDescriptorDXGIYCbCr desc;
710 SerializeSpecific(&desc);
711
712 *aOutDesc = std::move(desc);
713 }
714
Deallocate(LayersIPCChannel *)715 void DXGIYCbCrTextureData::Deallocate(LayersIPCChannel*) {
716 mD3D9Textures[0] = nullptr;
717 mD3D9Textures[1] = nullptr;
718 mD3D9Textures[2] = nullptr;
719 mD3D11Textures[0] = nullptr;
720 mD3D11Textures[1] = nullptr;
721 mD3D11Textures[2] = nullptr;
722 }
723
GetTextureFlags() const724 TextureFlags DXGIYCbCrTextureData::GetTextureFlags() const {
725 TextureFlags flags = TextureFlags::NO_FLAGS;
726 // With WebRender, resource open happens asynchronously on RenderThread.
727 // During opening the resource on host side, TextureClient needs to be alive.
728 // With WAIT_HOST_USAGE_END, keep TextureClient alive during host side usage.
729 if (gfx::gfxVars::UseWebRender()) {
730 flags |= TextureFlags::WAIT_HOST_USAGE_END;
731 }
732 return flags;
733 }
734
CreateTextureHostD3D11(const SurfaceDescriptor & aDesc,ISurfaceAllocator * aDeallocator,LayersBackend aBackend,TextureFlags aFlags)735 already_AddRefed<TextureHost> CreateTextureHostD3D11(
736 const SurfaceDescriptor& aDesc, ISurfaceAllocator* aDeallocator,
737 LayersBackend aBackend, TextureFlags aFlags) {
738 RefPtr<TextureHost> result;
739 switch (aDesc.type()) {
740 case SurfaceDescriptor::TSurfaceDescriptorD3D10: {
741 result =
742 new DXGITextureHostD3D11(aFlags, aDesc.get_SurfaceDescriptorD3D10());
743 break;
744 }
745 case SurfaceDescriptor::TSurfaceDescriptorDXGIYCbCr: {
746 result = new DXGIYCbCrTextureHostD3D11(
747 aFlags, aDesc.get_SurfaceDescriptorDXGIYCbCr());
748 break;
749 }
750 default: {
751 MOZ_ASSERT_UNREACHABLE("Unsupported SurfaceDescriptor type");
752 }
753 }
754 return result.forget();
755 }
756
BorrowDrawTarget()757 already_AddRefed<DrawTarget> D3D11TextureData::BorrowDrawTarget() {
758 MOZ_ASSERT(NS_IsMainThread() || NS_IsInCanvasThreadOrWorker());
759
760 if (!mDrawTarget && mTexture) {
761 // This may return a null DrawTarget
762 mDrawTarget = Factory::CreateDrawTargetForD3D11Texture(mTexture, mFormat);
763 if (!mDrawTarget) {
764 gfxCriticalNote << "Could not borrow DrawTarget (D3D11) " << (int)mFormat;
765 }
766 }
767
768 RefPtr<DrawTarget> result = mDrawTarget;
769 return result.forget();
770 }
771
UpdateFromSurface(gfx::SourceSurface * aSurface)772 bool D3D11TextureData::UpdateFromSurface(gfx::SourceSurface* aSurface) {
773 // Supporting texture updates after creation requires an ID3D11DeviceContext
774 // and those aren't threadsafe. We'd need to either lock, or have a device for
775 // whatever thread this runs on and we're trying to avoid extra devices (bug
776 // 1284672).
777 MOZ_ASSERT(false,
778 "UpdateFromSurface not supported for D3D11! Use CreateFromSurface "
779 "instead");
780 return false;
781 }
782
DXGITextureHostD3D11(TextureFlags aFlags,const SurfaceDescriptorD3D10 & aDescriptor)783 DXGITextureHostD3D11::DXGITextureHostD3D11(
784 TextureFlags aFlags, const SurfaceDescriptorD3D10& aDescriptor)
785 : TextureHost(aFlags),
786 mArrayIndex(aDescriptor.arrayIndex()),
787 mSize(aDescriptor.size()),
788 mHandle(aDescriptor.handle()),
789 mFormat(aDescriptor.format()),
790 mYUVColorSpace(aDescriptor.yUVColorSpace()),
791 mColorRange(aDescriptor.colorRange()),
792 mIsLocked(false) {}
793
EnsureTexture()794 bool DXGITextureHostD3D11::EnsureTexture() {
795 RefPtr<ID3D11Device> device;
796 if (mTexture) {
797 mTexture->GetDevice(getter_AddRefs(device));
798 if (device == DeviceManagerDx::Get()->GetCompositorDevice()) {
799 NS_WARNING("Incompatible texture.");
800 return true;
801 }
802 mTexture = nullptr;
803 }
804
805 device = GetDevice();
806 if (!device || device != DeviceManagerDx::Get()->GetCompositorDevice()) {
807 NS_WARNING("No device or incompatible device.");
808 return false;
809 }
810
811 HRESULT hr = device->OpenSharedResource(
812 (HANDLE)mHandle, __uuidof(ID3D11Texture2D),
813 (void**)(ID3D11Texture2D**)getter_AddRefs(mTexture));
814 if (FAILED(hr)) {
815 MOZ_ASSERT(false, "Failed to open shared texture");
816 return false;
817 }
818
819 D3D11_TEXTURE2D_DESC desc;
820 mTexture->GetDesc(&desc);
821 mSize = IntSize(desc.Width, desc.Height);
822 return true;
823 }
824
GetDevice()825 RefPtr<ID3D11Device> DXGITextureHostD3D11::GetDevice() {
826 if (mFlags & TextureFlags::INVALID_COMPOSITOR) {
827 return nullptr;
828 }
829
830 return mDevice;
831 }
832
LockWithoutCompositor()833 bool DXGITextureHostD3D11::LockWithoutCompositor() {
834 if (!mDevice) {
835 mDevice = DeviceManagerDx::Get()->GetCompositorDevice();
836 }
837 return LockInternal();
838 }
839
UnlockWithoutCompositor()840 void DXGITextureHostD3D11::UnlockWithoutCompositor() { UnlockInternal(); }
841
LockInternal()842 bool DXGITextureHostD3D11::LockInternal() {
843 if (!GetDevice()) {
844 NS_WARNING("trying to lock a TextureHost without a D3D device");
845 return false;
846 }
847
848 if (!EnsureTextureSource()) {
849 return false;
850 }
851
852 mIsLocked = LockD3DTexture(mTextureSource->GetD3D11Texture());
853
854 return mIsLocked;
855 }
856
GetAsSurface()857 already_AddRefed<gfx::DataSourceSurface> DXGITextureHostD3D11::GetAsSurface() {
858 if (!gfxVars::UseWebRender()) {
859 return nullptr;
860 }
861
862 switch (GetFormat()) {
863 case gfx::SurfaceFormat::R8G8B8X8:
864 case gfx::SurfaceFormat::R8G8B8A8:
865 case gfx::SurfaceFormat::B8G8R8A8:
866 case gfx::SurfaceFormat::B8G8R8X8:
867 break;
868 default: {
869 MOZ_ASSERT_UNREACHABLE("DXGITextureHostD3D11: unsupported format!");
870 return nullptr;
871 }
872 }
873
874 AutoLockTextureHostWithoutCompositor autoLock(this);
875 if (autoLock.Failed()) {
876 NS_WARNING("Failed to lock the D3DTexture");
877 return nullptr;
878 }
879
880 RefPtr<ID3D11Device> device;
881 mTexture->GetDevice(getter_AddRefs(device));
882
883 D3D11_TEXTURE2D_DESC textureDesc = {0};
884 mTexture->GetDesc(&textureDesc);
885
886 RefPtr<ID3D11DeviceContext> context;
887 device->GetImmediateContext(getter_AddRefs(context));
888
889 textureDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
890 textureDesc.Usage = D3D11_USAGE_STAGING;
891 textureDesc.BindFlags = 0;
892 textureDesc.MiscFlags = 0;
893 textureDesc.MipLevels = 1;
894 RefPtr<ID3D11Texture2D> cpuTexture;
895 HRESULT hr = device->CreateTexture2D(&textureDesc, nullptr,
896 getter_AddRefs(cpuTexture));
897 if (FAILED(hr)) {
898 return nullptr;
899 }
900
901 context->CopyResource(cpuTexture, mTexture);
902
903 D3D11_MAPPED_SUBRESOURCE mappedSubresource;
904 hr = context->Map(cpuTexture, 0, D3D11_MAP_READ, 0, &mappedSubresource);
905 if (FAILED(hr)) {
906 return nullptr;
907 }
908
909 RefPtr<DataSourceSurface> surf = gfx::CreateDataSourceSurfaceFromData(
910 IntSize(textureDesc.Width, textureDesc.Height), GetFormat(),
911 (uint8_t*)mappedSubresource.pData, mappedSubresource.RowPitch);
912 context->Unmap(cpuTexture, 0);
913 return surf.forget();
914 }
915
EnsureTextureSource()916 bool DXGITextureHostD3D11::EnsureTextureSource() {
917 if (mTextureSource) {
918 return true;
919 }
920
921 if (!EnsureTexture()) {
922 DeviceManagerDx::Get()->ForceDeviceReset(
923 ForcedDeviceResetReason::OPENSHAREDHANDLE);
924 return false;
925 }
926
927 mTextureSource = new DataTextureSourceD3D11(mDevice, mFormat, mTexture);
928 return true;
929 }
930
UnlockInternal()931 void DXGITextureHostD3D11::UnlockInternal() {
932 UnlockD3DTexture(mTextureSource->GetD3D11Texture());
933 }
934
CreateRenderTexture(const wr::ExternalImageId & aExternalImageId)935 void DXGITextureHostD3D11::CreateRenderTexture(
936 const wr::ExternalImageId& aExternalImageId) {
937 RefPtr<wr::RenderTextureHost> texture = new wr::RenderDXGITextureHost(
938 mHandle, mArrayIndex, mFormat, mYUVColorSpace, mColorRange, mSize);
939 wr::RenderThread::Get()->RegisterExternalImage(aExternalImageId,
940 texture.forget());
941 }
942
NumSubTextures()943 uint32_t DXGITextureHostD3D11::NumSubTextures() {
944 switch (GetFormat()) {
945 case gfx::SurfaceFormat::R8G8B8X8:
946 case gfx::SurfaceFormat::R8G8B8A8:
947 case gfx::SurfaceFormat::B8G8R8A8:
948 case gfx::SurfaceFormat::B8G8R8X8: {
949 return 1;
950 }
951 case gfx::SurfaceFormat::NV12:
952 case gfx::SurfaceFormat::P010:
953 case gfx::SurfaceFormat::P016: {
954 return 2;
955 }
956 default: {
957 MOZ_ASSERT_UNREACHABLE("unexpected format");
958 return 1;
959 }
960 }
961 }
962
PushResourceUpdates(wr::TransactionBuilder & aResources,ResourceUpdateOp aOp,const Range<wr::ImageKey> & aImageKeys,const wr::ExternalImageId & aExtID)963 void DXGITextureHostD3D11::PushResourceUpdates(
964 wr::TransactionBuilder& aResources, ResourceUpdateOp aOp,
965 const Range<wr::ImageKey>& aImageKeys, const wr::ExternalImageId& aExtID) {
966 if (!gfx::gfxVars::UseWebRenderANGLE()) {
967 MOZ_ASSERT_UNREACHABLE("unexpected to be called without ANGLE");
968 return;
969 }
970
971 MOZ_ASSERT(mHandle);
972 auto method = aOp == TextureHost::ADD_IMAGE
973 ? &wr::TransactionBuilder::AddExternalImage
974 : &wr::TransactionBuilder::UpdateExternalImage;
975 switch (mFormat) {
976 case gfx::SurfaceFormat::R8G8B8X8:
977 case gfx::SurfaceFormat::R8G8B8A8:
978 case gfx::SurfaceFormat::B8G8R8A8:
979 case gfx::SurfaceFormat::B8G8R8X8: {
980 MOZ_ASSERT(aImageKeys.length() == 1);
981
982 wr::ImageDescriptor descriptor(mSize, GetFormat());
983 // Prefer TextureExternal unless the backend requires TextureRect.
984 TextureHost::NativeTexturePolicy policy =
985 TextureHost::BackendNativeTexturePolicy(aResources.GetBackendType(),
986 mSize);
987 auto imageType = policy == TextureHost::NativeTexturePolicy::REQUIRE
988 ? wr::ExternalImageType::TextureHandle(
989 wr::ImageBufferKind::TextureRect)
990 : wr::ExternalImageType::TextureHandle(
991 wr::ImageBufferKind::TextureExternal);
992 (aResources.*method)(aImageKeys[0], descriptor, aExtID, imageType, 0);
993 break;
994 }
995 case gfx::SurfaceFormat::P010:
996 case gfx::SurfaceFormat::P016:
997 case gfx::SurfaceFormat::NV12: {
998 MOZ_ASSERT(aImageKeys.length() == 2);
999 MOZ_ASSERT(mSize.width % 2 == 0);
1000 MOZ_ASSERT(mSize.height % 2 == 0);
1001
1002 wr::ImageDescriptor descriptor0(mSize, mFormat == gfx::SurfaceFormat::NV12
1003 ? gfx::SurfaceFormat::A8
1004 : gfx::SurfaceFormat::A16);
1005 wr::ImageDescriptor descriptor1(mSize / 2,
1006 mFormat == gfx::SurfaceFormat::NV12
1007 ? gfx::SurfaceFormat::R8G8
1008 : gfx::SurfaceFormat::R16G16);
1009 // Prefer TextureExternal unless the backend requires TextureRect.
1010 TextureHost::NativeTexturePolicy policy =
1011 TextureHost::BackendNativeTexturePolicy(aResources.GetBackendType(),
1012 mSize);
1013 auto imageType = policy == TextureHost::NativeTexturePolicy::REQUIRE
1014 ? wr::ExternalImageType::TextureHandle(
1015 wr::ImageBufferKind::TextureRect)
1016 : wr::ExternalImageType::TextureHandle(
1017 wr::ImageBufferKind::TextureExternal);
1018 (aResources.*method)(aImageKeys[0], descriptor0, aExtID, imageType, 0);
1019 (aResources.*method)(aImageKeys[1], descriptor1, aExtID, imageType, 1);
1020 break;
1021 }
1022 default: {
1023 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
1024 }
1025 }
1026 }
1027
PushDisplayItems(wr::DisplayListBuilder & aBuilder,const wr::LayoutRect & aBounds,const wr::LayoutRect & aClip,wr::ImageRendering aFilter,const Range<wr::ImageKey> & aImageKeys,PushDisplayItemFlagSet aFlags)1028 void DXGITextureHostD3D11::PushDisplayItems(
1029 wr::DisplayListBuilder& aBuilder, const wr::LayoutRect& aBounds,
1030 const wr::LayoutRect& aClip, wr::ImageRendering aFilter,
1031 const Range<wr::ImageKey>& aImageKeys, PushDisplayItemFlagSet aFlags) {
1032 bool preferCompositorSurface =
1033 aFlags.contains(PushDisplayItemFlag::PREFER_COMPOSITOR_SURFACE);
1034 if (!gfx::gfxVars::UseWebRenderANGLE()) {
1035 MOZ_ASSERT_UNREACHABLE("unexpected to be called without ANGLE");
1036 return;
1037 }
1038
1039 switch (GetFormat()) {
1040 case gfx::SurfaceFormat::R8G8B8X8:
1041 case gfx::SurfaceFormat::R8G8B8A8:
1042 case gfx::SurfaceFormat::B8G8R8A8:
1043 case gfx::SurfaceFormat::B8G8R8X8: {
1044 MOZ_ASSERT(aImageKeys.length() == 1);
1045 aBuilder.PushImage(
1046 aBounds, aClip, true, false, aFilter, aImageKeys[0],
1047 !(mFlags & TextureFlags::NON_PREMULTIPLIED),
1048 wr::ColorF{1.0f, 1.0f, 1.0f, 1.0f}, preferCompositorSurface,
1049 SupportsExternalCompositing(aBuilder.GetBackendType()));
1050 break;
1051 }
1052 case gfx::SurfaceFormat::P010:
1053 case gfx::SurfaceFormat::P016:
1054 case gfx::SurfaceFormat::NV12: {
1055 // DXGI_FORMAT_P010 stores its 10 bit value in the most significant bits
1056 // of each 16 bit word with the unused lower bits cleared to zero so that
1057 // it may be handled as if it was DXGI_FORMAT_P016. This is approximately
1058 // perceptually correct. However, due to rounding error, the precise
1059 // quantized value after sampling may be off by 1.
1060 MOZ_ASSERT(aImageKeys.length() == 2);
1061 aBuilder.PushNV12Image(
1062 aBounds, aClip, true, aImageKeys[0], aImageKeys[1],
1063 GetFormat() == gfx::SurfaceFormat::NV12 ? wr::ColorDepth::Color8
1064 : wr::ColorDepth::Color16,
1065 wr::ToWrYuvColorSpace(mYUVColorSpace),
1066 wr::ToWrColorRange(mColorRange), aFilter, preferCompositorSurface,
1067 SupportsExternalCompositing(aBuilder.GetBackendType()));
1068 break;
1069 }
1070 default: {
1071 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
1072 }
1073 }
1074 }
1075
SupportsExternalCompositing(WebRenderBackend aBackend)1076 bool DXGITextureHostD3D11::SupportsExternalCompositing(
1077 WebRenderBackend aBackend) {
1078 if (aBackend == WebRenderBackend::SOFTWARE) {
1079 return true;
1080 }
1081 // XXX Add P010 and P016 support.
1082 if (GetFormat() == gfx::SurfaceFormat::NV12 &&
1083 gfx::gfxVars::UseWebRenderDCompVideoOverlayWin()) {
1084 return true;
1085 }
1086 return false;
1087 }
1088
DXGIYCbCrTextureHostD3D11(TextureFlags aFlags,const SurfaceDescriptorDXGIYCbCr & aDescriptor)1089 DXGIYCbCrTextureHostD3D11::DXGIYCbCrTextureHostD3D11(
1090 TextureFlags aFlags, const SurfaceDescriptorDXGIYCbCr& aDescriptor)
1091 : TextureHost(aFlags),
1092 mSize(aDescriptor.size()),
1093 mSizeY(aDescriptor.sizeY()),
1094 mSizeCbCr(aDescriptor.sizeCbCr()),
1095 mIsLocked(false),
1096 mColorDepth(aDescriptor.colorDepth()),
1097 mYUVColorSpace(aDescriptor.yUVColorSpace()),
1098 mColorRange(aDescriptor.colorRange()) {
1099 mHandles[0] = aDescriptor.handleY();
1100 mHandles[1] = aDescriptor.handleCb();
1101 mHandles[2] = aDescriptor.handleCr();
1102 }
1103
EnsureTexture()1104 bool DXGIYCbCrTextureHostD3D11::EnsureTexture() {
1105 RefPtr<ID3D11Device> device;
1106 if (mTextures[0]) {
1107 mTextures[0]->GetDevice(getter_AddRefs(device));
1108 if (device == DeviceManagerDx::Get()->GetCompositorDevice()) {
1109 NS_WARNING("Incompatible texture.");
1110 return true;
1111 }
1112 mTextures[0] = nullptr;
1113 mTextures[1] = nullptr;
1114 mTextures[2] = nullptr;
1115 }
1116
1117 if (!GetDevice() ||
1118 GetDevice() != DeviceManagerDx::Get()->GetCompositorDevice()) {
1119 NS_WARNING("No device or incompatible device.");
1120 return false;
1121 }
1122
1123 device = GetDevice();
1124 RefPtr<ID3D11Texture2D> textures[3];
1125
1126 HRESULT hr = device->OpenSharedResource(
1127 (HANDLE)mHandles[0], __uuidof(ID3D11Texture2D),
1128 (void**)(ID3D11Texture2D**)getter_AddRefs(textures[0]));
1129 if (FAILED(hr)) {
1130 NS_WARNING("Failed to open shared texture for Y Plane");
1131 return false;
1132 }
1133
1134 hr = device->OpenSharedResource(
1135 (HANDLE)mHandles[1], __uuidof(ID3D11Texture2D),
1136 (void**)(ID3D11Texture2D**)getter_AddRefs(textures[1]));
1137 if (FAILED(hr)) {
1138 NS_WARNING("Failed to open shared texture for Cb Plane");
1139 return false;
1140 }
1141
1142 hr = device->OpenSharedResource(
1143 (HANDLE)mHandles[2], __uuidof(ID3D11Texture2D),
1144 (void**)(ID3D11Texture2D**)getter_AddRefs(textures[2]));
1145 if (FAILED(hr)) {
1146 NS_WARNING("Failed to open shared texture for Cr Plane");
1147 return false;
1148 }
1149
1150 mTextures[0] = textures[0].forget();
1151 mTextures[1] = textures[1].forget();
1152 mTextures[2] = textures[2].forget();
1153
1154 return true;
1155 }
1156
GetDevice()1157 RefPtr<ID3D11Device> DXGIYCbCrTextureHostD3D11::GetDevice() { return nullptr; }
1158
EnsureTextureSource()1159 bool DXGIYCbCrTextureHostD3D11::EnsureTextureSource() { return false; }
1160
CreateRenderTexture(const wr::ExternalImageId & aExternalImageId)1161 void DXGIYCbCrTextureHostD3D11::CreateRenderTexture(
1162 const wr::ExternalImageId& aExternalImageId) {
1163 RefPtr<wr::RenderTextureHost> texture = new wr::RenderDXGIYCbCrTextureHost(
1164 mHandles, mYUVColorSpace, mColorDepth, mColorRange, mSizeY, mSizeCbCr);
1165
1166 wr::RenderThread::Get()->RegisterExternalImage(aExternalImageId,
1167 texture.forget());
1168 }
1169
NumSubTextures()1170 uint32_t DXGIYCbCrTextureHostD3D11::NumSubTextures() {
1171 // ycbcr use 3 sub textures.
1172 return 3;
1173 }
1174
PushResourceUpdates(wr::TransactionBuilder & aResources,ResourceUpdateOp aOp,const Range<wr::ImageKey> & aImageKeys,const wr::ExternalImageId & aExtID)1175 void DXGIYCbCrTextureHostD3D11::PushResourceUpdates(
1176 wr::TransactionBuilder& aResources, ResourceUpdateOp aOp,
1177 const Range<wr::ImageKey>& aImageKeys, const wr::ExternalImageId& aExtID) {
1178 if (!gfx::gfxVars::UseWebRenderANGLE()) {
1179 MOZ_ASSERT_UNREACHABLE("unexpected to be called without ANGLE");
1180 return;
1181 }
1182
1183 MOZ_ASSERT(mHandles[0] && mHandles[1] && mHandles[2]);
1184 MOZ_ASSERT(aImageKeys.length() == 3);
1185 // Assume the chroma planes are rounded up if the luma plane is odd sized.
1186 MOZ_ASSERT((mSizeCbCr.width == mSizeY.width ||
1187 mSizeCbCr.width == (mSizeY.width + 1) >> 1) &&
1188 (mSizeCbCr.height == mSizeY.height ||
1189 mSizeCbCr.height == (mSizeY.height + 1) >> 1));
1190
1191 auto method = aOp == TextureHost::ADD_IMAGE
1192 ? &wr::TransactionBuilder::AddExternalImage
1193 : &wr::TransactionBuilder::UpdateExternalImage;
1194
1195 // Prefer TextureExternal unless the backend requires TextureRect.
1196 // Use a size that is the maximum of the Y and CbCr sizes.
1197 IntSize textureSize = std::max(mSizeY, mSizeCbCr);
1198 TextureHost::NativeTexturePolicy policy =
1199 TextureHost::BackendNativeTexturePolicy(aResources.GetBackendType(),
1200 textureSize);
1201 auto imageType = policy == TextureHost::NativeTexturePolicy::REQUIRE
1202 ? wr::ExternalImageType::TextureHandle(
1203 wr::ImageBufferKind::TextureRect)
1204 : wr::ExternalImageType::TextureHandle(
1205 wr::ImageBufferKind::TextureExternal);
1206
1207 // y
1208 wr::ImageDescriptor descriptor0(mSizeY, gfx::SurfaceFormat::A8);
1209 // cb and cr
1210 wr::ImageDescriptor descriptor1(mSizeCbCr, gfx::SurfaceFormat::A8);
1211 (aResources.*method)(aImageKeys[0], descriptor0, aExtID, imageType, 0);
1212 (aResources.*method)(aImageKeys[1], descriptor1, aExtID, imageType, 1);
1213 (aResources.*method)(aImageKeys[2], descriptor1, aExtID, imageType, 2);
1214 }
1215
PushDisplayItems(wr::DisplayListBuilder & aBuilder,const wr::LayoutRect & aBounds,const wr::LayoutRect & aClip,wr::ImageRendering aFilter,const Range<wr::ImageKey> & aImageKeys,PushDisplayItemFlagSet aFlags)1216 void DXGIYCbCrTextureHostD3D11::PushDisplayItems(
1217 wr::DisplayListBuilder& aBuilder, const wr::LayoutRect& aBounds,
1218 const wr::LayoutRect& aClip, wr::ImageRendering aFilter,
1219 const Range<wr::ImageKey>& aImageKeys, PushDisplayItemFlagSet aFlags) {
1220 if (!gfx::gfxVars::UseWebRenderANGLE()) {
1221 MOZ_ASSERT_UNREACHABLE("unexpected to be called without ANGLE");
1222 return;
1223 }
1224
1225 MOZ_ASSERT(aImageKeys.length() == 3);
1226
1227 aBuilder.PushYCbCrPlanarImage(
1228 aBounds, aClip, true, aImageKeys[0], aImageKeys[1], aImageKeys[2],
1229 wr::ToWrColorDepth(mColorDepth), wr::ToWrYuvColorSpace(mYUVColorSpace),
1230 wr::ToWrColorRange(mColorRange), aFilter,
1231 aFlags.contains(PushDisplayItemFlag::PREFER_COMPOSITOR_SURFACE),
1232 SupportsExternalCompositing(aBuilder.GetBackendType()));
1233 }
1234
SupportsExternalCompositing(WebRenderBackend aBackend)1235 bool DXGIYCbCrTextureHostD3D11::SupportsExternalCompositing(
1236 WebRenderBackend aBackend) {
1237 return aBackend == WebRenderBackend::SOFTWARE;
1238 }
1239
Update(DataSourceSurface * aSurface,nsIntRegion * aDestRegion,IntPoint * aSrcOffset,IntPoint * aDstOffset)1240 bool DataTextureSourceD3D11::Update(DataSourceSurface* aSurface,
1241 nsIntRegion* aDestRegion,
1242 IntPoint* aSrcOffset,
1243 IntPoint* aDstOffset) {
1244 // Incremental update with a source offset is only used on Mac so it is not
1245 // clear that we ever will need to support it for D3D.
1246 MOZ_ASSERT(!aSrcOffset);
1247 MOZ_RELEASE_ASSERT(!aDstOffset);
1248 MOZ_ASSERT(aSurface);
1249
1250 MOZ_ASSERT(mAllowTextureUploads);
1251 if (!mAllowTextureUploads) {
1252 return false;
1253 }
1254
1255 HRESULT hr;
1256
1257 if (!mDevice) {
1258 return false;
1259 }
1260
1261 uint32_t bpp = BytesPerPixel(aSurface->GetFormat());
1262 DXGI_FORMAT dxgiFormat = SurfaceFormatToDXGIFormat(aSurface->GetFormat());
1263
1264 mSize = aSurface->GetSize();
1265 mFormat = aSurface->GetFormat();
1266
1267 CD3D11_TEXTURE2D_DESC desc(dxgiFormat, mSize.width, mSize.height, 1, 1);
1268
1269 int32_t maxSize = GetMaxTextureSizeFromDevice(mDevice);
1270 if ((mSize.width <= maxSize && mSize.height <= maxSize) ||
1271 (mFlags & TextureFlags::DISALLOW_BIGIMAGE)) {
1272 if (mTexture) {
1273 D3D11_TEXTURE2D_DESC currentDesc;
1274 mTexture->GetDesc(¤tDesc);
1275
1276 // Make sure there's no size mismatch, if there is, recreate.
1277 if (currentDesc.Width != mSize.width ||
1278 currentDesc.Height != mSize.height ||
1279 currentDesc.Format != dxgiFormat) {
1280 mTexture = nullptr;
1281 // Make sure we upload the whole surface.
1282 aDestRegion = nullptr;
1283 }
1284 }
1285
1286 nsIntRegion* regionToUpdate = aDestRegion;
1287 if (!mTexture) {
1288 hr = mDevice->CreateTexture2D(&desc, nullptr, getter_AddRefs(mTexture));
1289 mIsTiled = false;
1290 if (FAILED(hr) || !mTexture) {
1291 Reset();
1292 return false;
1293 }
1294
1295 if (mFlags & TextureFlags::COMPONENT_ALPHA) {
1296 regionToUpdate = nullptr;
1297 }
1298 }
1299
1300 DataSourceSurface::MappedSurface map;
1301 if (!aSurface->Map(DataSourceSurface::MapType::READ, &map)) {
1302 gfxCriticalError() << "Failed to map surface.";
1303 Reset();
1304 return false;
1305 }
1306
1307 RefPtr<ID3D11DeviceContext> context;
1308 mDevice->GetImmediateContext(getter_AddRefs(context));
1309
1310 if (regionToUpdate) {
1311 for (auto iter = regionToUpdate->RectIter(); !iter.Done(); iter.Next()) {
1312 const IntRect& rect = iter.Get();
1313 D3D11_BOX box;
1314 box.front = 0;
1315 box.back = 1;
1316 box.left = rect.X();
1317 box.top = rect.Y();
1318 box.right = rect.XMost();
1319 box.bottom = rect.YMost();
1320
1321 void* data = map.mData + map.mStride * rect.Y() +
1322 BytesPerPixel(aSurface->GetFormat()) * rect.X();
1323
1324 context->UpdateSubresource(mTexture, 0, &box, data, map.mStride,
1325 map.mStride * rect.Height());
1326 }
1327 } else {
1328 context->UpdateSubresource(mTexture, 0, nullptr, map.mData, map.mStride,
1329 map.mStride * mSize.height);
1330 }
1331
1332 aSurface->Unmap();
1333 } else {
1334 mIsTiled = true;
1335 uint32_t tileCount = GetRequiredTilesD3D11(mSize.width, maxSize) *
1336 GetRequiredTilesD3D11(mSize.height, maxSize);
1337
1338 mTileTextures.resize(tileCount);
1339 mTileSRVs.resize(tileCount);
1340 mTexture = nullptr;
1341
1342 DataSourceSurface::ScopedMap map(aSurface, DataSourceSurface::READ);
1343 if (!map.IsMapped()) {
1344 gfxCriticalError() << "Failed to map surface.";
1345 Reset();
1346 return false;
1347 }
1348
1349 for (uint32_t i = 0; i < tileCount; i++) {
1350 IntRect tileRect = GetTileRect(i);
1351
1352 desc.Width = tileRect.Width();
1353 desc.Height = tileRect.Height();
1354 desc.Usage = D3D11_USAGE_IMMUTABLE;
1355
1356 D3D11_SUBRESOURCE_DATA initData;
1357 initData.pSysMem =
1358 map.GetData() + tileRect.Y() * map.GetStride() + tileRect.X() * bpp;
1359 initData.SysMemPitch = map.GetStride();
1360
1361 hr = mDevice->CreateTexture2D(&desc, &initData,
1362 getter_AddRefs(mTileTextures[i]));
1363 if (FAILED(hr) || !mTileTextures[i]) {
1364 Reset();
1365 return false;
1366 }
1367 }
1368 }
1369 return true;
1370 }
1371
GetD3D11Texture() const1372 ID3D11Texture2D* DataTextureSourceD3D11::GetD3D11Texture() const {
1373 return mIterating ? mTileTextures[mCurrentTile] : mTexture;
1374 }
1375
ExtractCurrentTile()1376 RefPtr<TextureSource> DataTextureSourceD3D11::ExtractCurrentTile() {
1377 MOZ_ASSERT(mIterating);
1378 return new DataTextureSourceD3D11(mDevice, mFormat,
1379 mTileTextures[mCurrentTile]);
1380 }
1381
GetShaderResourceView()1382 ID3D11ShaderResourceView* DataTextureSourceD3D11::GetShaderResourceView() {
1383 if (mIterating) {
1384 if (!mTileSRVs[mCurrentTile]) {
1385 if (!mTileTextures[mCurrentTile]) {
1386 return nullptr;
1387 }
1388
1389 RefPtr<ID3D11Device> device;
1390 mTileTextures[mCurrentTile]->GetDevice(getter_AddRefs(device));
1391 HRESULT hr = device->CreateShaderResourceView(
1392 mTileTextures[mCurrentTile], nullptr,
1393 getter_AddRefs(mTileSRVs[mCurrentTile]));
1394 if (FAILED(hr)) {
1395 gfxCriticalNote
1396 << "[D3D11] DataTextureSourceD3D11:GetShaderResourceView CreateSRV "
1397 "failure "
1398 << gfx::hexa(hr);
1399 return nullptr;
1400 }
1401 }
1402 return mTileSRVs[mCurrentTile];
1403 }
1404
1405 return TextureSourceD3D11::GetShaderResourceView();
1406 }
1407
Reset()1408 void DataTextureSourceD3D11::Reset() {
1409 mTexture = nullptr;
1410 mTileSRVs.resize(0);
1411 mTileTextures.resize(0);
1412 mIsTiled = false;
1413 mSize.width = 0;
1414 mSize.height = 0;
1415 }
1416
GetTileRect(uint32_t aIndex) const1417 IntRect DataTextureSourceD3D11::GetTileRect(uint32_t aIndex) const {
1418 return GetTileRectD3D11(aIndex, mSize, GetMaxTextureSizeFromDevice(mDevice));
1419 }
1420
GetTileRect()1421 IntRect DataTextureSourceD3D11::GetTileRect() {
1422 IntRect rect = GetTileRect(mCurrentTile);
1423 return IntRect(rect.X(), rect.Y(), rect.Width(), rect.Height());
1424 }
1425
CompositingRenderTargetD3D11(ID3D11Texture2D * aTexture,const gfx::IntPoint & aOrigin,DXGI_FORMAT aFormatOverride)1426 CompositingRenderTargetD3D11::CompositingRenderTargetD3D11(
1427 ID3D11Texture2D* aTexture, const gfx::IntPoint& aOrigin,
1428 DXGI_FORMAT aFormatOverride)
1429 : CompositingRenderTarget(aOrigin) {
1430 MOZ_ASSERT(aTexture);
1431
1432 mTexture = aTexture;
1433
1434 RefPtr<ID3D11Device> device;
1435 mTexture->GetDevice(getter_AddRefs(device));
1436
1437 mFormatOverride = aFormatOverride;
1438
1439 // If we happen to have a typeless underlying DXGI surface, we need to be
1440 // explicit about the format here. (Such a surface could come from an external
1441 // source, such as the Oculus compositor)
1442 CD3D11_RENDER_TARGET_VIEW_DESC rtvDesc(D3D11_RTV_DIMENSION_TEXTURE2D,
1443 mFormatOverride);
1444 D3D11_RENDER_TARGET_VIEW_DESC* desc =
1445 aFormatOverride == DXGI_FORMAT_UNKNOWN ? nullptr : &rtvDesc;
1446
1447 HRESULT hr =
1448 device->CreateRenderTargetView(mTexture, desc, getter_AddRefs(mRTView));
1449
1450 if (FAILED(hr)) {
1451 LOGD3D11("Failed to create RenderTargetView.");
1452 }
1453 }
1454
BindRenderTarget(ID3D11DeviceContext * aContext)1455 void CompositingRenderTargetD3D11::BindRenderTarget(
1456 ID3D11DeviceContext* aContext) {
1457 if (mClearOnBind) {
1458 FLOAT clear[] = {0, 0, 0, 0};
1459 aContext->ClearRenderTargetView(mRTView, clear);
1460 mClearOnBind = false;
1461 }
1462 ID3D11RenderTargetView* view = mRTView;
1463 aContext->OMSetRenderTargets(1, &view, nullptr);
1464 }
1465
GetSize() const1466 IntSize CompositingRenderTargetD3D11::GetSize() const {
1467 return TextureSourceD3D11::GetSize();
1468 }
1469
ShouldDevCrashOnSyncInitFailure()1470 static inline bool ShouldDevCrashOnSyncInitFailure() {
1471 // Compositor shutdown does not wait for video decoding to finish, so it is
1472 // possible for the compositor to destroy the SyncObject before video has a
1473 // chance to initialize it.
1474 if (!NS_IsMainThread()) {
1475 return false;
1476 }
1477
1478 // Note: CompositorIsInGPUProcess is a main-thread-only function.
1479 return !CompositorBridgeChild::CompositorIsInGPUProcess() &&
1480 !DeviceManagerDx::Get()->HasDeviceReset();
1481 }
1482
SyncObjectD3D11Host(ID3D11Device * aDevice)1483 SyncObjectD3D11Host::SyncObjectD3D11Host(ID3D11Device* aDevice)
1484 : mSyncHandle(0), mDevice(aDevice) {
1485 MOZ_ASSERT(aDevice);
1486 }
1487
Init()1488 bool SyncObjectD3D11Host::Init() {
1489 CD3D11_TEXTURE2D_DESC desc(
1490 DXGI_FORMAT_B8G8R8A8_UNORM, 1, 1, 1, 1,
1491 D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET);
1492 desc.MiscFlags = D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX;
1493
1494 RefPtr<ID3D11Texture2D> texture;
1495 HRESULT hr =
1496 mDevice->CreateTexture2D(&desc, nullptr, getter_AddRefs(texture));
1497 if (FAILED(hr) || !texture) {
1498 gfxWarning() << "Could not create a sync texture: " << gfx::hexa(hr);
1499 return false;
1500 }
1501
1502 hr = texture->QueryInterface((IDXGIResource**)getter_AddRefs(mSyncTexture));
1503 if (FAILED(hr) || !mSyncTexture) {
1504 gfxWarning() << "Could not QI sync texture: " << gfx::hexa(hr);
1505 return false;
1506 }
1507
1508 hr = mSyncTexture->QueryInterface(
1509 (IDXGIKeyedMutex**)getter_AddRefs(mKeyedMutex));
1510 if (FAILED(hr) || !mKeyedMutex) {
1511 gfxWarning() << "Could not QI keyed-mutex: " << gfx::hexa(hr);
1512 return false;
1513 }
1514
1515 hr = mSyncTexture->GetSharedHandle(&mSyncHandle);
1516 if (FAILED(hr) || !mSyncHandle) {
1517 NS_DispatchToMainThread(NS_NewRunnableFunction(
1518 "layers::SyncObjectD3D11Renderer::Init",
1519 []() -> void { Accumulate(Telemetry::D3D11_SYNC_HANDLE_FAILURE, 1); }));
1520 gfxWarning() << "Could not get sync texture shared handle: "
1521 << gfx::hexa(hr);
1522 return false;
1523 }
1524
1525 return true;
1526 }
1527
GetSyncHandle()1528 SyncHandle SyncObjectD3D11Host::GetSyncHandle() { return mSyncHandle; }
1529
Synchronize(bool aFallible)1530 bool SyncObjectD3D11Host::Synchronize(bool aFallible) {
1531 HRESULT hr;
1532 AutoTextureLock lock(mKeyedMutex, hr, 10000);
1533
1534 if (hr == WAIT_TIMEOUT) {
1535 hr = mDevice->GetDeviceRemovedReason();
1536 if (hr != S_OK) {
1537 // Since the timeout is related to the driver-removed. Return false for
1538 // error handling.
1539 gfxCriticalNote << "GFX: D3D11 timeout with device-removed:"
1540 << gfx::hexa(hr);
1541 } else if (aFallible) {
1542 gfxCriticalNote << "GFX: D3D11 timeout on the D3D11 sync lock.";
1543 } else {
1544 // There is no driver-removed event. Crash with this timeout.
1545 MOZ_CRASH("GFX: D3D11 normal status timeout");
1546 }
1547
1548 return false;
1549 }
1550 if (hr == WAIT_ABANDONED) {
1551 gfxCriticalNote << "GFX: AL_D3D11 abandoned sync";
1552 }
1553
1554 return true;
1555 }
1556
SyncObjectD3D11Client(SyncHandle aSyncHandle,ID3D11Device * aDevice)1557 SyncObjectD3D11Client::SyncObjectD3D11Client(SyncHandle aSyncHandle,
1558 ID3D11Device* aDevice)
1559 : mSyncLock("SyncObjectD3D11"), mSyncHandle(aSyncHandle), mDevice(aDevice) {
1560 MOZ_ASSERT(aDevice);
1561 }
1562
SyncObjectD3D11Client(SyncHandle aSyncHandle)1563 SyncObjectD3D11Client::SyncObjectD3D11Client(SyncHandle aSyncHandle)
1564 : mSyncLock("SyncObjectD3D11"), mSyncHandle(aSyncHandle) {}
1565
Init(ID3D11Device * aDevice,bool aFallible)1566 bool SyncObjectD3D11Client::Init(ID3D11Device* aDevice, bool aFallible) {
1567 if (mKeyedMutex) {
1568 return true;
1569 }
1570
1571 HRESULT hr = aDevice->OpenSharedResource(
1572 mSyncHandle, __uuidof(ID3D11Texture2D),
1573 (void**)(ID3D11Texture2D**)getter_AddRefs(mSyncTexture));
1574 if (FAILED(hr) || !mSyncTexture) {
1575 gfxCriticalNote << "Failed to OpenSharedResource for SyncObjectD3D11: "
1576 << hexa(hr);
1577 if (!aFallible && ShouldDevCrashOnSyncInitFailure()) {
1578 gfxDevCrash(LogReason::D3D11FinalizeFrame)
1579 << "Without device reset: " << hexa(hr);
1580 }
1581 return false;
1582 }
1583
1584 hr = mSyncTexture->QueryInterface(__uuidof(IDXGIKeyedMutex),
1585 getter_AddRefs(mKeyedMutex));
1586 if (FAILED(hr) || !mKeyedMutex) {
1587 // Leave both the critical error and MOZ_CRASH for now; the critical error
1588 // lets us "save" the hr value. We will probably eventually replace this
1589 // with gfxDevCrash.
1590 if (!aFallible) {
1591 gfxCriticalError() << "Failed to get KeyedMutex (2): " << hexa(hr);
1592 MOZ_CRASH("GFX: Cannot get D3D11 KeyedMutex");
1593 } else {
1594 gfxCriticalNote << "Failed to get KeyedMutex (3): " << hexa(hr);
1595 }
1596 return false;
1597 }
1598
1599 return true;
1600 }
1601
RegisterTexture(ID3D11Texture2D * aTexture)1602 void SyncObjectD3D11Client::RegisterTexture(ID3D11Texture2D* aTexture) {
1603 mSyncedTextures.push_back(aTexture);
1604 }
1605
IsSyncObjectValid()1606 bool SyncObjectD3D11Client::IsSyncObjectValid() {
1607 MOZ_ASSERT(mDevice);
1608 return true;
1609 }
1610
1611 // We have only 1 sync object. As a thing that somehow works,
1612 // we copy each of the textures that need to be synced with the compositor
1613 // into our sync object and only use a lock for this sync object.
1614 // This way, we don't have to sync every texture we send to the compositor.
1615 // We only have to do this once per transaction.
Synchronize(bool aFallible)1616 bool SyncObjectD3D11Client::Synchronize(bool aFallible) {
1617 MOZ_ASSERT(mDevice);
1618 // Since this can be called from either the Paint or Main thread.
1619 // We don't want this to race since we initialize the sync texture here
1620 // too.
1621 MutexAutoLock syncLock(mSyncLock);
1622
1623 if (!mSyncedTextures.size()) {
1624 return true;
1625 }
1626 if (!Init(mDevice, aFallible)) {
1627 return false;
1628 }
1629
1630 return SynchronizeInternal(mDevice, aFallible);
1631 }
1632
SynchronizeInternal(ID3D11Device * aDevice,bool aFallible)1633 bool SyncObjectD3D11Client::SynchronizeInternal(ID3D11Device* aDevice,
1634 bool aFallible) {
1635 mSyncLock.AssertCurrentThreadOwns();
1636
1637 HRESULT hr;
1638 AutoTextureLock lock(mKeyedMutex, hr, 20000);
1639
1640 if (hr == WAIT_TIMEOUT) {
1641 if (DeviceManagerDx::Get()->HasDeviceReset()) {
1642 gfxWarning() << "AcquireSync timed out because of device reset.";
1643 return false;
1644 }
1645 if (aFallible) {
1646 gfxWarning() << "Timeout on the D3D11 sync lock.";
1647 } else {
1648 gfxDevCrash(LogReason::D3D11SyncLock)
1649 << "Timeout on the D3D11 sync lock.";
1650 }
1651 return false;
1652 }
1653
1654 D3D11_BOX box;
1655 box.front = box.top = box.left = 0;
1656 box.back = box.bottom = box.right = 1;
1657
1658 RefPtr<ID3D11DeviceContext> ctx;
1659 aDevice->GetImmediateContext(getter_AddRefs(ctx));
1660
1661 for (auto iter = mSyncedTextures.begin(); iter != mSyncedTextures.end();
1662 iter++) {
1663 ctx->CopySubresourceRegion(mSyncTexture, 0, 0, 0, 0, *iter, 0, &box);
1664 }
1665
1666 mSyncedTextures.clear();
1667
1668 return true;
1669 }
1670
GetMaxTextureSizeFromDevice(ID3D11Device * aDevice)1671 uint32_t GetMaxTextureSizeFromDevice(ID3D11Device* aDevice) {
1672 return GetMaxTextureSizeForFeatureLevel(aDevice->GetFeatureLevel());
1673 }
1674
AutoLockD3D11Texture(ID3D11Texture2D * aTexture)1675 AutoLockD3D11Texture::AutoLockD3D11Texture(ID3D11Texture2D* aTexture) {
1676 aTexture->QueryInterface((IDXGIKeyedMutex**)getter_AddRefs(mMutex));
1677 if (!mMutex) {
1678 return;
1679 }
1680 HRESULT hr = mMutex->AcquireSync(0, 10000);
1681 if (hr == WAIT_TIMEOUT) {
1682 MOZ_CRASH("GFX: IMFYCbCrImage timeout");
1683 }
1684
1685 if (FAILED(hr)) {
1686 NS_WARNING("Failed to lock the texture");
1687 }
1688 }
1689
~AutoLockD3D11Texture()1690 AutoLockD3D11Texture::~AutoLockD3D11Texture() {
1691 if (!mMutex) {
1692 return;
1693 }
1694 HRESULT hr = mMutex->ReleaseSync(0);
1695 if (FAILED(hr)) {
1696 NS_WARNING("Failed to unlock the texture");
1697 }
1698 }
1699
SyncObjectD3D11ClientContentDevice(SyncHandle aSyncHandle)1700 SyncObjectD3D11ClientContentDevice::SyncObjectD3D11ClientContentDevice(
1701 SyncHandle aSyncHandle)
1702 : SyncObjectD3D11Client(aSyncHandle) {}
1703
Synchronize(bool aFallible)1704 bool SyncObjectD3D11ClientContentDevice::Synchronize(bool aFallible) {
1705 // Since this can be called from either the Paint or Main thread.
1706 // We don't want this to race since we initialize the sync texture here
1707 // too.
1708 MutexAutoLock syncLock(mSyncLock);
1709
1710 MOZ_ASSERT(mContentDevice);
1711
1712 if (!mSyncedTextures.size()) {
1713 return true;
1714 }
1715
1716 if (!Init(mContentDevice, aFallible)) {
1717 return false;
1718 }
1719
1720 RefPtr<ID3D11Device> dev;
1721 mSyncTexture->GetDevice(getter_AddRefs(dev));
1722
1723 if (dev == DeviceManagerDx::Get()->GetContentDevice()) {
1724 if (DeviceManagerDx::Get()->HasDeviceReset()) {
1725 return false;
1726 }
1727 }
1728
1729 if (dev != mContentDevice) {
1730 gfxWarning() << "Attempt to sync texture from invalid device.";
1731 return false;
1732 }
1733
1734 return SyncObjectD3D11Client::SynchronizeInternal(dev, aFallible);
1735 }
1736
IsSyncObjectValid()1737 bool SyncObjectD3D11ClientContentDevice::IsSyncObjectValid() {
1738 RefPtr<ID3D11Device> dev;
1739 // There is a case that devices are not initialized yet with WebRender.
1740 if (gfxPlatform::GetPlatform()->DevicesInitialized()) {
1741 dev = DeviceManagerDx::Get()->GetContentDevice();
1742 }
1743
1744 // Update mDevice if the ContentDevice initialization is detected.
1745 if (!mContentDevice && dev && NS_IsMainThread() && gfxVars::UseWebRender()) {
1746 mContentDevice = dev;
1747 }
1748
1749 if (!dev || (NS_IsMainThread() && dev != mContentDevice)) {
1750 return false;
1751 }
1752 return true;
1753 }
1754
EnsureInitialized()1755 void SyncObjectD3D11ClientContentDevice::EnsureInitialized() {
1756 if (mContentDevice) {
1757 return;
1758 }
1759
1760 if (XRE_IsGPUProcess() || !gfxPlatform::GetPlatform()->DevicesInitialized()) {
1761 return;
1762 }
1763
1764 mContentDevice = DeviceManagerDx::Get()->GetContentDevice();
1765 }
1766
1767 } // namespace layers
1768 } // namespace mozilla
1769