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(&currentDesc);
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