1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2  * This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 
6 #include "TextureD3D11.h"
7 #include "CompositorD3D11.h"
8 #include "gfxContext.h"
9 #include "Effects.h"
10 #include "gfxWindowsPlatform.h"
11 #include "gfx2DGlue.h"
12 #include "gfxPrefs.h"
13 #include "ReadbackManagerD3D11.h"
14 #include "mozilla/gfx/DeviceManagerDx.h"
15 #include "mozilla/gfx/Logging.h"
16 
17 namespace mozilla {
18 
19 using namespace gfx;
20 
21 namespace layers {
22 
23 static const GUID sD3D11TextureUsage =
24 { 0xd89275b0, 0x6c7d, 0x4038, { 0xb5, 0xfa, 0x4d, 0x87, 0x16, 0xd5, 0xcc, 0x4e } };
25 
26 /* This class gets its lifetime tied to a D3D texture
27  * and increments memory usage on construction and decrements
28  * on destruction */
29 class TextureMemoryMeasurer : public IUnknown
30 {
31 public:
TextureMemoryMeasurer(size_t aMemoryUsed)32   TextureMemoryMeasurer(size_t aMemoryUsed)
33   {
34     mMemoryUsed = aMemoryUsed;
35     gfxWindowsPlatform::sD3D11SharedTextures += mMemoryUsed;
36     mRefCnt = 0;
37   }
AddRef()38   STDMETHODIMP_(ULONG) AddRef() {
39     mRefCnt++;
40     return mRefCnt;
41   }
QueryInterface(REFIID riid,void ** ppvObject)42   STDMETHODIMP QueryInterface(REFIID riid,
43                               void **ppvObject)
44   {
45     IUnknown *punk = nullptr;
46     if (riid == IID_IUnknown) {
47       punk = this;
48     }
49     *ppvObject = punk;
50     if (punk) {
51       punk->AddRef();
52       return S_OK;
53     } else {
54       return E_NOINTERFACE;
55     }
56   }
57 
Release()58   STDMETHODIMP_(ULONG) Release() {
59     int refCnt = --mRefCnt;
60     if (refCnt == 0) {
61       gfxWindowsPlatform::sD3D11SharedTextures -= mMemoryUsed;
62       delete this;
63     }
64     return refCnt;
65   }
66 private:
67   int mRefCnt;
68   int mMemoryUsed;
69 };
70 
71 static DXGI_FORMAT
SurfaceFormatToDXGIFormat(gfx::SurfaceFormat aFormat)72 SurfaceFormatToDXGIFormat(gfx::SurfaceFormat aFormat)
73 {
74   switch (aFormat) {
75     case SurfaceFormat::B8G8R8A8:
76       return DXGI_FORMAT_B8G8R8A8_UNORM;
77     case SurfaceFormat::B8G8R8X8:
78       return DXGI_FORMAT_B8G8R8A8_UNORM;
79     case SurfaceFormat::R8G8B8A8:
80       return DXGI_FORMAT_R8G8B8A8_UNORM;
81     case SurfaceFormat::R8G8B8X8:
82       return DXGI_FORMAT_R8G8B8A8_UNORM;
83     case SurfaceFormat::A8:
84       return DXGI_FORMAT_R8_UNORM;
85     default:
86       MOZ_ASSERT(false, "unsupported format");
87       return DXGI_FORMAT_UNKNOWN;
88   }
89 }
90 
91 static uint32_t
GetRequiredTilesD3D11(uint32_t aSize,uint32_t aMaxSize)92 GetRequiredTilesD3D11(uint32_t aSize, uint32_t aMaxSize)
93 {
94   uint32_t requiredTiles = aSize / aMaxSize;
95   if (aSize % aMaxSize) {
96     requiredTiles++;
97   }
98   return requiredTiles;
99 }
100 
101 static IntRect
GetTileRectD3D11(uint32_t aID,IntSize aSize,uint32_t aMaxSize)102 GetTileRectD3D11(uint32_t aID, IntSize aSize, uint32_t aMaxSize)
103 {
104   uint32_t horizontalTiles = GetRequiredTilesD3D11(aSize.width, aMaxSize);
105   uint32_t verticalTiles = GetRequiredTilesD3D11(aSize.height, aMaxSize);
106 
107   uint32_t verticalTile = aID / horizontalTiles;
108   uint32_t horizontalTile = aID % horizontalTiles;
109 
110   return IntRect(horizontalTile * aMaxSize,
111                  verticalTile * aMaxSize,
112                  horizontalTile < (horizontalTiles - 1) ? aMaxSize : aSize.width % aMaxSize,
113                  verticalTile < (verticalTiles - 1) ? aMaxSize : aSize.height % aMaxSize);
114 }
115 
AutoTextureLock(IDXGIKeyedMutex * aMutex,HRESULT & aResult,uint32_t aTimeout)116 AutoTextureLock::AutoTextureLock(IDXGIKeyedMutex* aMutex,
117                                  HRESULT& aResult,
118                                  uint32_t aTimeout)
119 {
120   mMutex = aMutex;
121   mResult = mMutex->AcquireSync(0, aTimeout);
122   aResult = mResult;
123 }
124 
~AutoTextureLock()125 AutoTextureLock::~AutoTextureLock()
126 {
127   if (!FAILED(mResult) && mResult != WAIT_TIMEOUT &&
128       mResult != WAIT_ABANDONED) {
129     mMutex->ReleaseSync(0);
130   }
131 }
132 
133 ID3D11ShaderResourceView*
GetShaderResourceView()134 TextureSourceD3D11::GetShaderResourceView()
135 {
136   MOZ_ASSERT(mTexture == GetD3D11Texture(), "You need to override GetShaderResourceView if you're overriding GetD3D11Texture!");
137 
138   if (!mSRV && mTexture) {
139     RefPtr<ID3D11Device> device;
140     mTexture->GetDevice(getter_AddRefs(device));
141 
142     // see comment in CompositingRenderTargetD3D11 constructor
143     CD3D11_SHADER_RESOURCE_VIEW_DESC srvDesc(D3D11_SRV_DIMENSION_TEXTURE2D, mFormatOverride);
144     D3D11_SHADER_RESOURCE_VIEW_DESC *desc = mFormatOverride == DXGI_FORMAT_UNKNOWN ? nullptr : &srvDesc;
145 
146     HRESULT hr = device->CreateShaderResourceView(mTexture, desc, getter_AddRefs(mSRV));
147     if (FAILED(hr)) {
148       gfxCriticalNote << "[D3D11] TextureSourceD3D11:GetShaderResourceView CreateSRV failure " << gfx::hexa(hr);
149       return nullptr;
150     }
151   }
152   return mSRV;
153 }
154 
DataTextureSourceD3D11(SurfaceFormat aFormat,CompositorD3D11 * aCompositor,TextureFlags aFlags)155 DataTextureSourceD3D11::DataTextureSourceD3D11(SurfaceFormat aFormat,
156                                                CompositorD3D11* aCompositor,
157                                                TextureFlags aFlags)
158   : mCompositor(aCompositor)
159   , mFormat(aFormat)
160   , mFlags(aFlags)
161   , mCurrentTile(0)
162   , mIsTiled(false)
163   , mIterating(false)
164   , mAllowTextureUploads(true)
165 {
166   MOZ_COUNT_CTOR(DataTextureSourceD3D11);
167 }
168 
DataTextureSourceD3D11(SurfaceFormat aFormat,CompositorD3D11 * aCompositor,ID3D11Texture2D * aTexture)169 DataTextureSourceD3D11::DataTextureSourceD3D11(SurfaceFormat aFormat,
170                                                CompositorD3D11* aCompositor,
171                                                ID3D11Texture2D* aTexture)
172 : mCompositor(aCompositor)
173 , mFormat(aFormat)
174 , mFlags(TextureFlags::NO_FLAGS)
175 , mCurrentTile(0)
176 , mIsTiled(false)
177 , mIterating(false)
178 , mAllowTextureUploads(false)
179 {
180   MOZ_COUNT_CTOR(DataTextureSourceD3D11);
181 
182   mTexture = aTexture;
183   D3D11_TEXTURE2D_DESC desc;
184   aTexture->GetDesc(&desc);
185 
186   mSize = IntSize(desc.Width, desc.Height);
187 }
188 
189 
190 
~DataTextureSourceD3D11()191 DataTextureSourceD3D11::~DataTextureSourceD3D11()
192 {
193   MOZ_COUNT_DTOR(DataTextureSourceD3D11);
194 }
195 
196 
197 template<typename T> // ID3D10Texture2D or ID3D11Texture2D
LockD3DTexture(T * aTexture)198 static bool LockD3DTexture(T* aTexture)
199 {
200   MOZ_ASSERT(aTexture);
201   RefPtr<IDXGIKeyedMutex> mutex;
202   aTexture->QueryInterface((IDXGIKeyedMutex**)getter_AddRefs(mutex));
203   // Textures created by the DXVA decoders don't have a mutex for synchronization
204   if (mutex) {
205     HRESULT hr = mutex->AcquireSync(0, 10000);
206     if (hr == WAIT_TIMEOUT) {
207       gfxDevCrash(LogReason::D3DLockTimeout) << "D3D lock mutex timeout";
208     } else if (hr == WAIT_ABANDONED) {
209       gfxCriticalNote << "GFX: D3D11 lock mutex abandoned";
210     }
211 
212     if (FAILED(hr)) {
213       NS_WARNING("Failed to lock the texture");
214       return false;
215     }
216   }
217   return true;
218 }
219 
220 template<typename T>
HasKeyedMutex(T * aTexture)221 static bool HasKeyedMutex(T* aTexture)
222 {
223   RefPtr<IDXGIKeyedMutex> mutex;
224   aTexture->QueryInterface((IDXGIKeyedMutex**)getter_AddRefs(mutex));
225   return !!mutex;
226 }
227 
228 template<typename T> // ID3D10Texture2D or ID3D11Texture2D
UnlockD3DTexture(T * aTexture)229 static void UnlockD3DTexture(T* aTexture)
230 {
231   MOZ_ASSERT(aTexture);
232   RefPtr<IDXGIKeyedMutex> mutex;
233   aTexture->QueryInterface((IDXGIKeyedMutex**)getter_AddRefs(mutex));
234   if (mutex) {
235     HRESULT hr = mutex->ReleaseSync(0);
236     if (FAILED(hr)) {
237       NS_WARNING("Failed to unlock the texture");
238     }
239   }
240 }
241 
DXGITextureData(gfx::IntSize aSize,gfx::SurfaceFormat aFormat,bool aNeedsClear,bool aNeedsClearWhite,bool aIsForOutOfBandContent)242 DXGITextureData::DXGITextureData(gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
243                                  bool aNeedsClear, bool aNeedsClearWhite,
244                                  bool aIsForOutOfBandContent)
245 : mSize(aSize)
246 , mFormat(aFormat)
247 , mNeedsClear(aNeedsClear)
248 , mNeedsClearWhite(aNeedsClearWhite)
249 , mHasSynchronization(false)
250 , mIsForOutOfBandContent(aIsForOutOfBandContent)
251 {}
252 
D3D11TextureData(ID3D11Texture2D * aTexture,gfx::IntSize aSize,gfx::SurfaceFormat aFormat,bool aNeedsClear,bool aNeedsClearWhite,bool aIsForOutOfBandContent)253 D3D11TextureData::D3D11TextureData(ID3D11Texture2D* aTexture,
254                                    gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
255                                    bool aNeedsClear, bool aNeedsClearWhite,
256                                    bool aIsForOutOfBandContent)
257 : DXGITextureData(aSize, aFormat, aNeedsClear, aNeedsClearWhite, aIsForOutOfBandContent)
258 , mTexture(aTexture)
259 {
260   MOZ_ASSERT(aTexture);
261   mHasSynchronization = HasKeyedMutex(aTexture);
262 }
263 
~D3D11TextureData()264 D3D11TextureData::~D3D11TextureData()
265 {
266 #ifdef DEBUG
267   // An Azure DrawTarget needs to be locked when it gets nullptr'ed as this is
268   // when it calls EndDraw. This EndDraw should not execute anything so it
269   // shouldn't -really- need the lock but the debug layer chokes on this.
270   if (mDrawTarget) {
271     Lock(OpenMode::OPEN_NONE);
272     mDrawTarget = nullptr;
273     Unlock();
274   }
275 #endif
276 }
277 
278 bool
Lock(OpenMode aMode)279 D3D11TextureData::Lock(OpenMode aMode)
280 {
281   if (!LockD3DTexture(mTexture.get())) {
282     return false;
283   }
284 
285   if (NS_IsMainThread() && !mIsForOutOfBandContent) {
286     if (!PrepareDrawTargetInLock(aMode)) {
287       Unlock();
288       return false;
289     }
290   }
291 
292   return true;
293 }
294 
295 bool
PrepareDrawTargetInLock(OpenMode aMode)296 DXGITextureData::PrepareDrawTargetInLock(OpenMode aMode)
297 {
298   // Make sure that successful write-lock means we will have a DrawTarget to
299   // write into.
300   if (!mDrawTarget && (aMode & OpenMode::OPEN_WRITE || mNeedsClear || mNeedsClearWhite)) {
301     mDrawTarget = BorrowDrawTarget();
302     if (!mDrawTarget) {
303       return false;
304     }
305   }
306 
307   if (mNeedsClear) {
308     mDrawTarget->ClearRect(Rect(0, 0, mSize.width, mSize.height));
309     mNeedsClear = false;
310   }
311   if (mNeedsClearWhite) {
312     mDrawTarget->FillRect(Rect(0, 0, mSize.width, mSize.height), ColorPattern(Color(1.0, 1.0, 1.0, 1.0)));
313     mNeedsClearWhite = false;
314   }
315 
316   return true;
317 }
318 
319 void
Unlock()320 D3D11TextureData::Unlock()
321 {
322   UnlockD3DTexture(mTexture.get());
323 }
324 
325 
326 void
FillInfo(TextureData::Info & aInfo) const327 DXGITextureData::FillInfo(TextureData::Info& aInfo) const
328 {
329   aInfo.size = mSize;
330   aInfo.format = mFormat;
331   aInfo.supportsMoz2D = true;
332   aInfo.hasIntermediateBuffer = false;
333   aInfo.hasSynchronization = mHasSynchronization;
334 }
335 
336 void
SyncWithObject(SyncObject * aSyncObject)337 D3D11TextureData::SyncWithObject(SyncObject* aSyncObject)
338 {
339   if (!aSyncObject || !NS_IsMainThread() || mIsForOutOfBandContent) {
340     // When off the main thread we sync using a keyed mutex per texture.
341     return;
342   }
343 
344   MOZ_ASSERT(aSyncObject->GetSyncType() == SyncObject::SyncType::D3D11);
345   SyncObjectD3D11* sync = static_cast<SyncObjectD3D11*>(aSyncObject);
346   sync->RegisterTexture(mTexture);
347 }
348 
349 bool
Serialize(SurfaceDescriptor & aOutDescriptor)350 DXGITextureData::Serialize(SurfaceDescriptor& aOutDescriptor)
351 {
352   RefPtr<IDXGIResource> resource;
353   GetDXGIResource((IDXGIResource**)getter_AddRefs(resource));
354   if (!resource) {
355     return false;
356   }
357   HANDLE sharedHandle;
358   HRESULT hr = resource->GetSharedHandle(&sharedHandle);
359   if (FAILED(hr)) {
360     LOGD3D11("Error getting shared handle for texture.");
361     return false;
362   }
363 
364   aOutDescriptor = SurfaceDescriptorD3D10((WindowsHandle)sharedHandle, mFormat, mSize);
365   return true;
366 }
367 
368 DXGITextureData*
Create(IntSize aSize,SurfaceFormat aFormat,TextureAllocationFlags aFlags)369 DXGITextureData::Create(IntSize aSize, SurfaceFormat aFormat, TextureAllocationFlags aFlags)
370 {
371   if (aFormat == SurfaceFormat::A8) {
372     // Currently we don't support A8 surfaces. Fallback.
373     return nullptr;
374   }
375 
376   return D3D11TextureData::Create(aSize, aFormat, aFlags);
377 }
378 
379 DXGITextureData*
Create(IntSize aSize,SurfaceFormat aFormat,SourceSurface * aSurface,TextureAllocationFlags aFlags,ID3D11Device * aDevice)380 D3D11TextureData::Create(IntSize aSize, SurfaceFormat aFormat, SourceSurface* aSurface,
381                          TextureAllocationFlags aFlags, ID3D11Device* aDevice)
382 {
383   // Just grab any device. We never use the immediate context, so the devices are fine
384   // to use from any thread.
385   RefPtr<ID3D11Device> device = aDevice;
386   if (!device) {
387     device = DeviceManagerDx::Get()->GetContentDevice();
388     if (!device) {
389       return nullptr;
390     }
391   }
392 
393   CD3D11_TEXTURE2D_DESC newDesc(DXGI_FORMAT_B8G8R8A8_UNORM,
394                                 aSize.width, aSize.height, 1, 1,
395                                 D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE);
396 
397   newDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED;
398   if (!NS_IsMainThread() || !!(aFlags & ALLOC_FOR_OUT_OF_BAND_CONTENT)) {
399     // On the main thread we use the syncobject to handle synchronization.
400     if (!(aFlags & ALLOC_MANUAL_SYNCHRONIZATION)) {
401       newDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX;
402     }
403   }
404 
405   if (aSurface && newDesc.MiscFlags == D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX &&
406       !DeviceManagerDx::Get()->CanInitializeKeyedMutexTextures()) {
407     return nullptr;
408   }
409 
410   D3D11_SUBRESOURCE_DATA uploadData;
411   D3D11_SUBRESOURCE_DATA* uploadDataPtr = nullptr;
412   RefPtr<DataSourceSurface> srcSurf;
413   if (aSurface) {
414     srcSurf = aSurface->GetDataSurface();
415 
416     if (!srcSurf) {
417       gfxCriticalError() << "Failed to GetDataSurface in D3D11TextureData::Create";
418       return nullptr;
419     }
420 
421     DataSourceSurface::MappedSurface sourceMap;
422     if (!srcSurf->Map(DataSourceSurface::READ, &sourceMap)) {
423       gfxCriticalError() << "Failed to map source surface for D3D11TextureData::Create";
424       return nullptr;
425     }
426 
427     uploadData.pSysMem = sourceMap.mData;
428     uploadData.SysMemPitch = sourceMap.mStride;
429     uploadData.SysMemSlicePitch = 0; // unused
430 
431     uploadDataPtr = &uploadData;
432   }
433 
434   RefPtr<ID3D11Texture2D> texture11;
435   HRESULT hr = device->CreateTexture2D(&newDesc, uploadDataPtr, getter_AddRefs(texture11));
436   if (srcSurf) {
437     srcSurf->Unmap();
438   }
439   if (FAILED(hr)) {
440     gfxCriticalError(CriticalLog::DefaultOptions(Factory::ReasonableSurfaceSize(aSize)))
441       << "[D3D11] 2 CreateTexture2D failure " << aSize << " Code: " << gfx::hexa(hr);
442     return nullptr;
443   }
444 
445   // If we created the texture with a keyed mutex, then we expect all operations
446   // on it to be synchronized using it. If we did an initial upload using aSurface
447   // then bizarely this isn't covered, so we insert a manual lock/unlock pair
448   // to force this.
449   if (aSurface && newDesc.MiscFlags == D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX) {
450     if (!LockD3DTexture(texture11.get())) {
451       return nullptr;
452     }
453     UnlockD3DTexture(texture11.get());
454   }
455   texture11->SetPrivateDataInterface(sD3D11TextureUsage,
456                                      new TextureMemoryMeasurer(newDesc.Width * newDesc.Height * 4));
457   return new D3D11TextureData(texture11, aSize, aFormat,
458                               aFlags & ALLOC_CLEAR_BUFFER,
459                               aFlags & ALLOC_CLEAR_BUFFER_WHITE,
460                               aFlags & ALLOC_FOR_OUT_OF_BAND_CONTENT);
461 }
462 
463 DXGITextureData*
Create(IntSize aSize,SurfaceFormat aFormat,TextureAllocationFlags aFlags,ID3D11Device * aDevice)464 D3D11TextureData::Create(IntSize aSize, SurfaceFormat aFormat,
465                          TextureAllocationFlags aFlags, ID3D11Device* aDevice)
466 {
467   return D3D11TextureData::Create(aSize, aFormat, nullptr, aFlags, aDevice);
468 }
469 
470 DXGITextureData*
Create(SourceSurface * aSurface,TextureAllocationFlags aFlags,ID3D11Device * aDevice)471 D3D11TextureData::Create(SourceSurface* aSurface,
472                          TextureAllocationFlags aFlags, ID3D11Device* aDevice)
473 {
474   if (aSurface->GetFormat() == SurfaceFormat::A8) {
475     // Currently we don't support A8 surfaces. Fallback.
476     return nullptr;
477   }
478 
479   return D3D11TextureData::Create(aSurface->GetSize(), aSurface->GetFormat(),
480                                   aSurface, aFlags, aDevice);
481 }
482 
483 void
Deallocate(LayersIPCChannel * aAllocator)484 D3D11TextureData::Deallocate(LayersIPCChannel* aAllocator)
485 {
486   mDrawTarget = nullptr;
487   mTexture = nullptr;
488 }
489 
490 already_AddRefed<TextureClient>
CreateD3D11TextureClientWithDevice(IntSize aSize,SurfaceFormat aFormat,TextureFlags aTextureFlags,TextureAllocationFlags aAllocFlags,ID3D11Device * aDevice,LayersIPCChannel * aAllocator)491 CreateD3D11TextureClientWithDevice(IntSize aSize, SurfaceFormat aFormat,
492                                    TextureFlags aTextureFlags, TextureAllocationFlags aAllocFlags,
493                                    ID3D11Device* aDevice,
494                                    LayersIPCChannel* aAllocator)
495 {
496   TextureData* data = D3D11TextureData::Create(aSize, aFormat, aAllocFlags, aDevice);
497   if (!data) {
498     return nullptr;
499   }
500   return MakeAndAddRef<TextureClient>(data, aTextureFlags, aAllocator);
501 }
502 
503 TextureData*
CreateSimilar(LayersIPCChannel * aAllocator,LayersBackend aLayersBackend,TextureFlags aFlags,TextureAllocationFlags aAllocFlags) const504 D3D11TextureData::CreateSimilar(LayersIPCChannel* aAllocator,
505                                 LayersBackend aLayersBackend,
506                                 TextureFlags aFlags,
507                                 TextureAllocationFlags aAllocFlags) const
508 {
509   return D3D11TextureData::Create(mSize, mFormat, aAllocFlags);
510 }
511 
512 void
GetDXGIResource(IDXGIResource ** aOutResource)513 D3D11TextureData::GetDXGIResource(IDXGIResource** aOutResource)
514 {
515   mTexture->QueryInterface(aOutResource);
516 }
517 
518 DXGIYCbCrTextureData*
Create(TextureFlags aFlags,IUnknown * aTextureY,IUnknown * aTextureCb,IUnknown * aTextureCr,HANDLE aHandleY,HANDLE aHandleCb,HANDLE aHandleCr,const gfx::IntSize & aSize,const gfx::IntSize & aSizeY,const gfx::IntSize & aSizeCbCr)519 DXGIYCbCrTextureData::Create(TextureFlags aFlags,
520                              IUnknown* aTextureY,
521                              IUnknown* aTextureCb,
522                              IUnknown* aTextureCr,
523                              HANDLE aHandleY,
524                              HANDLE aHandleCb,
525                              HANDLE aHandleCr,
526                              const gfx::IntSize& aSize,
527                              const gfx::IntSize& aSizeY,
528                              const gfx::IntSize& aSizeCbCr)
529 {
530   if (!aHandleY || !aHandleCb || !aHandleCr ||
531       !aTextureY || !aTextureCb || !aTextureCr) {
532     return nullptr;
533   }
534 
535   DXGIYCbCrTextureData* texture = new DXGIYCbCrTextureData();
536   texture->mHandles[0] = aHandleY;
537   texture->mHandles[1] = aHandleCb;
538   texture->mHandles[2] = aHandleCr;
539   texture->mHoldRefs[0] = aTextureY;
540   texture->mHoldRefs[1] = aTextureCb;
541   texture->mHoldRefs[2] = aTextureCr;
542   texture->mSize = aSize;
543   texture->mSizeY = aSizeY;
544   texture->mSizeCbCr = aSizeCbCr;
545 
546   return texture;
547 }
548 
549 DXGIYCbCrTextureData*
Create(TextureFlags aFlags,ID3D11Texture2D * aTextureY,ID3D11Texture2D * aTextureCb,ID3D11Texture2D * aTextureCr,const gfx::IntSize & aSize,const gfx::IntSize & aSizeY,const gfx::IntSize & aSizeCbCr)550 DXGIYCbCrTextureData::Create(TextureFlags aFlags,
551                              ID3D11Texture2D* aTextureY,
552                              ID3D11Texture2D* aTextureCb,
553                              ID3D11Texture2D* aTextureCr,
554                              const gfx::IntSize& aSize,
555                              const gfx::IntSize& aSizeY,
556                              const gfx::IntSize& aSizeCbCr)
557 {
558   if (!aTextureY || !aTextureCb || !aTextureCr) {
559     return nullptr;
560   }
561 
562   aTextureY->SetPrivateDataInterface(sD3D11TextureUsage,
563     new TextureMemoryMeasurer(aSize.width * aSize.height));
564   aTextureCb->SetPrivateDataInterface(sD3D11TextureUsage,
565     new TextureMemoryMeasurer(aSizeCbCr.width * aSizeCbCr.height));
566   aTextureCr->SetPrivateDataInterface(sD3D11TextureUsage,
567     new TextureMemoryMeasurer(aSizeCbCr.width * aSizeCbCr.height));
568 
569   RefPtr<IDXGIResource> resource;
570 
571   aTextureY->QueryInterface((IDXGIResource**)getter_AddRefs(resource));
572 
573   HANDLE handleY;
574   HRESULT hr = resource->GetSharedHandle(&handleY);
575   if (FAILED(hr)) {
576     return nullptr;
577   }
578 
579   aTextureCb->QueryInterface((IDXGIResource**)getter_AddRefs(resource));
580 
581   HANDLE handleCb;
582   hr = resource->GetSharedHandle(&handleCb);
583   if (FAILED(hr)) {
584     return nullptr;
585   }
586 
587   aTextureCr->QueryInterface((IDXGIResource**)getter_AddRefs(resource));
588   HANDLE handleCr;
589   hr = resource->GetSharedHandle(&handleCr);
590   if (FAILED(hr)) {
591     return nullptr;
592   }
593 
594   return DXGIYCbCrTextureData::Create(aFlags,
595                                       aTextureY, aTextureCb, aTextureCr,
596                                       handleY, handleCb, handleCr,
597                                       aSize, aSizeY, aSizeCbCr);
598 }
599 
600 void
FillInfo(TextureData::Info & aInfo) const601 DXGIYCbCrTextureData::FillInfo(TextureData::Info& aInfo) const
602 {
603   aInfo.size = mSize;
604   aInfo.format = gfx::SurfaceFormat::YUV;
605   aInfo.supportsMoz2D = false;
606   aInfo.hasIntermediateBuffer = false;
607   aInfo.hasSynchronization = false;
608 }
609 
610 bool
Serialize(SurfaceDescriptor & aOutDescriptor)611 DXGIYCbCrTextureData::Serialize(SurfaceDescriptor& aOutDescriptor)
612 {
613   aOutDescriptor = SurfaceDescriptorDXGIYCbCr(
614     (WindowsHandle)mHandles[0], (WindowsHandle)mHandles[1], (WindowsHandle)mHandles[2],
615     mSize, mSizeY, mSizeCbCr
616   );
617   return true;
618 }
619 
620 void
Deallocate(LayersIPCChannel *)621 DXGIYCbCrTextureData::Deallocate(LayersIPCChannel*)
622 {
623   mHoldRefs[0] = nullptr;
624   mHoldRefs[1] = nullptr;
625   mHoldRefs[2] = nullptr;
626 }
627 
628 already_AddRefed<TextureHost>
CreateTextureHostD3D11(const SurfaceDescriptor & aDesc,ISurfaceAllocator * aDeallocator,TextureFlags aFlags)629 CreateTextureHostD3D11(const SurfaceDescriptor& aDesc,
630                        ISurfaceAllocator* aDeallocator,
631                        TextureFlags aFlags)
632 {
633   RefPtr<TextureHost> result;
634   switch (aDesc.type()) {
635     case SurfaceDescriptor::TSurfaceDescriptorD3D10: {
636       result = new DXGITextureHostD3D11(aFlags,
637                                         aDesc.get_SurfaceDescriptorD3D10());
638       break;
639     }
640     case SurfaceDescriptor::TSurfaceDescriptorDXGIYCbCr: {
641       result = new DXGIYCbCrTextureHostD3D11(aFlags,
642                                              aDesc.get_SurfaceDescriptorDXGIYCbCr());
643       break;
644     }
645     default: {
646       MOZ_ASSERT_UNREACHABLE("Unsupported SurfaceDescriptor type");
647     }
648   }
649   return result.forget();
650 }
651 
652 
653 already_AddRefed<DrawTarget>
BorrowDrawTarget()654 D3D11TextureData::BorrowDrawTarget()
655 {
656   MOZ_ASSERT(NS_IsMainThread());
657 
658   if (!mDrawTarget && mTexture) {
659     // This may return a null DrawTarget
660     mDrawTarget = Factory::CreateDrawTargetForD3D11Texture(mTexture, mFormat);
661     if (!mDrawTarget) {
662       gfxCriticalNote << "Could not borrow DrawTarget (D3D11) " << (int)mFormat;
663     }
664   }
665 
666   RefPtr<DrawTarget> result = mDrawTarget;
667   return result.forget();
668 }
669 
670 bool
UpdateFromSurface(gfx::SourceSurface * aSurface)671 D3D11TextureData::UpdateFromSurface(gfx::SourceSurface* aSurface)
672 {
673   // Supporting texture updates after creation requires an ID3D11DeviceContext and those
674   // aren't threadsafe. We'd need to either lock, or have a device for whatever thread
675   // this runs on and we're trying to avoid extra devices (bug 1284672).
676   MOZ_ASSERT(false, "UpdateFromSurface not supported for D3D11! Use CreateFromSurface instead");
677   return false;
678 }
679 
DXGITextureHostD3D11(TextureFlags aFlags,const SurfaceDescriptorD3D10 & aDescriptor)680 DXGITextureHostD3D11::DXGITextureHostD3D11(TextureFlags aFlags,
681                                            const SurfaceDescriptorD3D10& aDescriptor)
682   : TextureHost(aFlags)
683   , mSize(aDescriptor.size())
684   , mHandle(aDescriptor.handle())
685   , mFormat(aDescriptor.format())
686   , mIsLocked(false)
687 {
688 }
689 
690 bool
OpenSharedHandle()691 DXGITextureHostD3D11::OpenSharedHandle()
692 {
693   if (!GetDevice()) {
694     return false;
695   }
696 
697   HRESULT hr = GetDevice()->OpenSharedResource((HANDLE)mHandle,
698                                                __uuidof(ID3D11Texture2D),
699                                                (void**)(ID3D11Texture2D**)getter_AddRefs(mTexture));
700   if (FAILED(hr)) {
701     NS_WARNING("Failed to open shared texture");
702     return false;
703   }
704 
705   D3D11_TEXTURE2D_DESC desc;
706   mTexture->GetDesc(&desc);
707   mSize = IntSize(desc.Width, desc.Height);
708   return true;
709 }
710 
711 RefPtr<ID3D11Device>
GetDevice()712 DXGITextureHostD3D11::GetDevice()
713 {
714   if (mFlags & TextureFlags::INVALID_COMPOSITOR) {
715     return nullptr;
716   }
717 
718   return DeviceManagerDx::Get()->GetCompositorDevice();
719 }
720 
AssertD3D11Compositor(Compositor * aCompositor)721 static CompositorD3D11* AssertD3D11Compositor(Compositor* aCompositor)
722 {
723   CompositorD3D11* compositor = aCompositor ? aCompositor->AsCompositorD3D11()
724                                             : nullptr;
725   if (!compositor) {
726     gfxCriticalNote << "[D3D11] Attempt to set an incompatible compositor";
727   }
728   return compositor;
729 }
730 
731 void
SetCompositor(Compositor * aCompositor)732 DXGITextureHostD3D11::SetCompositor(Compositor* aCompositor)
733 {
734   CompositorD3D11* d3dCompositor = AssertD3D11Compositor(aCompositor);
735   if (!d3dCompositor) {
736     mCompositor = nullptr;
737     mTextureSource = nullptr;
738     return;
739   }
740   mCompositor = d3dCompositor;
741   if (mTextureSource) {
742     mTextureSource->SetCompositor(aCompositor);
743   }
744 }
745 
746 Compositor*
GetCompositor()747 DXGITextureHostD3D11::GetCompositor()
748 {
749   return mCompositor;
750 }
751 
752 bool
Lock()753 DXGITextureHostD3D11::Lock()
754 {
755   if (!mCompositor) {
756     // Make an early return here if we call SetCompositor() with an incompatible
757     // compositor. This check tries to prevent the problem where we use that
758     // incompatible compositor to compose this texture.
759     return false;
760   }
761 
762   return LockInternal();
763 }
764 
765 bool
LockWithoutCompositor()766 DXGITextureHostD3D11::LockWithoutCompositor()
767 {
768   // Unlike the normal Lock() function, this function may be called when
769   // mCompositor is nullptr such as during WebVR frame submission. So, there is
770   // no 'mCompositor' checking here.
771   return LockInternal();
772 }
773 
774 void
Unlock()775 DXGITextureHostD3D11::Unlock()
776 {
777   UnlockInternal();
778 }
779 
780 void
UnlockWithoutCompositor()781 DXGITextureHostD3D11::UnlockWithoutCompositor()
782 {
783   UnlockInternal();
784 }
785 
786 bool
LockInternal()787 DXGITextureHostD3D11::LockInternal()
788 {
789   if (!GetDevice()) {
790     NS_WARNING("trying to lock a TextureHost without a D3D device");
791     return false;
792   }
793 
794   if (!mTextureSource) {
795     if (!mTexture && !OpenSharedHandle()) {
796       DeviceManagerDx::Get()->ForceDeviceReset(ForcedDeviceResetReason::OPENSHAREDHANDLE);
797       return false;
798     }
799 
800     mTextureSource = new DataTextureSourceD3D11(mFormat, mCompositor, mTexture);
801   }
802 
803   mIsLocked = LockD3DTexture(mTextureSource->GetD3D11Texture());
804 
805   return mIsLocked;
806 }
807 
808 void
UnlockInternal()809 DXGITextureHostD3D11::UnlockInternal()
810 {
811   UnlockD3DTexture(mTextureSource->GetD3D11Texture());
812 }
813 
814 bool
BindTextureSource(CompositableTextureSourceRef & aTexture)815 DXGITextureHostD3D11::BindTextureSource(CompositableTextureSourceRef& aTexture)
816 {
817   MOZ_ASSERT(mIsLocked);
818   // If Lock was successful we must have a valid TextureSource.
819   MOZ_ASSERT(mTextureSource);
820   aTexture = mTextureSource;
821   return !!aTexture;
822 }
823 
DXGIYCbCrTextureHostD3D11(TextureFlags aFlags,const SurfaceDescriptorDXGIYCbCr & aDescriptor)824 DXGIYCbCrTextureHostD3D11::DXGIYCbCrTextureHostD3D11(TextureFlags aFlags,
825   const SurfaceDescriptorDXGIYCbCr& aDescriptor)
826   : TextureHost(aFlags)
827   , mSize(aDescriptor.size())
828   , mIsLocked(false)
829 {
830   mHandles[0] = aDescriptor.handleY();
831   mHandles[1] = aDescriptor.handleCb();
832   mHandles[2] = aDescriptor.handleCr();
833 }
834 
835 bool
OpenSharedHandle()836 DXGIYCbCrTextureHostD3D11::OpenSharedHandle()
837 {
838   RefPtr<ID3D11Device> device = GetDevice();
839   if (!device) {
840     return false;
841   }
842 
843   RefPtr<ID3D11Texture2D> textures[3];
844 
845   HRESULT hr = device->OpenSharedResource((HANDLE)mHandles[0],
846                                           __uuidof(ID3D11Texture2D),
847                                           (void**)(ID3D11Texture2D**)getter_AddRefs(textures[0]));
848   if (FAILED(hr)) {
849     NS_WARNING("Failed to open shared texture for Y Plane");
850     return false;
851   }
852 
853   hr = device->OpenSharedResource((HANDLE)mHandles[1],
854                                   __uuidof(ID3D11Texture2D),
855                                   (void**)(ID3D11Texture2D**)getter_AddRefs(textures[1]));
856   if (FAILED(hr)) {
857     NS_WARNING("Failed to open shared texture for Cb Plane");
858     return false;
859   }
860 
861   hr = device->OpenSharedResource((HANDLE)mHandles[2],
862                                   __uuidof(ID3D11Texture2D),
863                                   (void**)(ID3D11Texture2D**)getter_AddRefs(textures[2]));
864   if (FAILED(hr)) {
865     NS_WARNING("Failed to open shared texture for Cr Plane");
866     return false;
867   }
868 
869   mTextures[0] = textures[0].forget();
870   mTextures[1] = textures[1].forget();
871   mTextures[2] = textures[2].forget();
872 
873   return true;
874 }
875 
876 RefPtr<ID3D11Device>
GetDevice()877 DXGIYCbCrTextureHostD3D11::GetDevice()
878 {
879   if (mFlags & TextureFlags::INVALID_COMPOSITOR) {
880     return nullptr;
881   }
882 
883   return DeviceManagerDx::Get()->GetCompositorDevice();
884 }
885 
886 void
SetCompositor(Compositor * aCompositor)887 DXGIYCbCrTextureHostD3D11::SetCompositor(Compositor* aCompositor)
888 {
889   mCompositor = AssertD3D11Compositor(aCompositor);
890   if (!mCompositor) {
891     mTextureSources[0] = nullptr;
892     mTextureSources[1] = nullptr;
893     mTextureSources[2] = nullptr;
894     return;
895   }
896 
897   if (mTextureSources[0]) {
898     mTextureSources[0]->SetCompositor(aCompositor);
899   }
900 }
901 
902 Compositor*
GetCompositor()903 DXGIYCbCrTextureHostD3D11::GetCompositor()
904 {
905   return mCompositor;
906 }
907 
908 bool
Lock()909 DXGIYCbCrTextureHostD3D11::Lock()
910 {
911   if (!mCompositor) {
912     NS_WARNING("no suitable compositor");
913     return false;
914   }
915 
916   if (!GetDevice()) {
917     NS_WARNING("trying to lock a TextureHost without a D3D device");
918     return false;
919   }
920   if (!mTextureSources[0]) {
921     if (!mTextures[0] && !OpenSharedHandle()) {
922       return false;
923     }
924 
925     MOZ_ASSERT(mTextures[1] && mTextures[2]);
926 
927     mTextureSources[0] = new DataTextureSourceD3D11(SurfaceFormat::A8, mCompositor, mTextures[0]);
928     mTextureSources[1] = new DataTextureSourceD3D11(SurfaceFormat::A8, mCompositor, mTextures[1]);
929     mTextureSources[2] = new DataTextureSourceD3D11(SurfaceFormat::A8, mCompositor, mTextures[2]);
930     mTextureSources[0]->SetNextSibling(mTextureSources[1]);
931     mTextureSources[1]->SetNextSibling(mTextureSources[2]);
932   }
933 
934   mIsLocked = LockD3DTexture(mTextureSources[0]->GetD3D11Texture()) &&
935               LockD3DTexture(mTextureSources[1]->GetD3D11Texture()) &&
936               LockD3DTexture(mTextureSources[2]->GetD3D11Texture());
937 
938   return mIsLocked;
939 }
940 
941 void
Unlock()942 DXGIYCbCrTextureHostD3D11::Unlock()
943 {
944   MOZ_ASSERT(mIsLocked);
945   UnlockD3DTexture(mTextureSources[0]->GetD3D11Texture());
946   UnlockD3DTexture(mTextureSources[1]->GetD3D11Texture());
947   UnlockD3DTexture(mTextureSources[2]->GetD3D11Texture());
948   mIsLocked = false;
949 }
950 
951 bool
BindTextureSource(CompositableTextureSourceRef & aTexture)952 DXGIYCbCrTextureHostD3D11::BindTextureSource(CompositableTextureSourceRef& aTexture)
953 {
954   MOZ_ASSERT(mIsLocked);
955   // If Lock was successful we must have a valid TextureSource.
956   MOZ_ASSERT(mTextureSources[0] && mTextureSources[1] && mTextureSources[2]);
957   aTexture = mTextureSources[0].get();
958   return !!aTexture;
959 }
960 
961 bool
Update(DataSourceSurface * aSurface,nsIntRegion * aDestRegion,IntPoint * aSrcOffset)962 DataTextureSourceD3D11::Update(DataSourceSurface* aSurface,
963                                nsIntRegion* aDestRegion,
964                                IntPoint* aSrcOffset)
965 {
966   // Incremental update with a source offset is only used on Mac so it is not
967   // clear that we ever will need to support it for D3D.
968   MOZ_ASSERT(!aSrcOffset);
969   MOZ_ASSERT(aSurface);
970 
971   MOZ_ASSERT(mAllowTextureUploads);
972   if (!mAllowTextureUploads) {
973     return false;
974   }
975 
976   HRESULT hr;
977 
978   if (!mCompositor || !mCompositor->GetDevice()) {
979     return false;
980   }
981 
982   uint32_t bpp = BytesPerPixel(aSurface->GetFormat());
983   DXGI_FORMAT dxgiFormat = SurfaceFormatToDXGIFormat(aSurface->GetFormat());
984 
985   mSize = aSurface->GetSize();
986   mFormat = aSurface->GetFormat();
987 
988   CD3D11_TEXTURE2D_DESC desc(dxgiFormat, mSize.width, mSize.height, 1, 1);
989 
990   int32_t maxSize = mCompositor->GetMaxTextureSize();
991   if ((mSize.width <= maxSize && mSize.height <= maxSize) ||
992       (mFlags & TextureFlags::DISALLOW_BIGIMAGE)) {
993 
994     if (mTexture) {
995       D3D11_TEXTURE2D_DESC currentDesc;
996       mTexture->GetDesc(&currentDesc);
997 
998       // Make sure there's no size mismatch, if there is, recreate.
999       if (currentDesc.Width != mSize.width || currentDesc.Height != mSize.height ||
1000           currentDesc.Format != dxgiFormat) {
1001         mTexture = nullptr;
1002         // Make sure we upload the whole surface.
1003         aDestRegion = nullptr;
1004       }
1005     }
1006 
1007     nsIntRegion *regionToUpdate = aDestRegion;
1008     if (!mTexture) {
1009       hr = mCompositor->GetDevice()->CreateTexture2D(&desc, nullptr, getter_AddRefs(mTexture));
1010       mIsTiled = false;
1011       if (FAILED(hr) || !mTexture) {
1012         Reset();
1013         return false;
1014       }
1015 
1016       if (mFlags & TextureFlags::COMPONENT_ALPHA) {
1017         regionToUpdate = nullptr;
1018       }
1019     }
1020 
1021     DataSourceSurface::MappedSurface map;
1022     if (!aSurface->Map(DataSourceSurface::MapType::READ, &map)) {
1023       gfxCriticalError() << "Failed to map surface.";
1024       Reset();
1025       return false;
1026     }
1027 
1028     if (regionToUpdate) {
1029       for (auto iter = regionToUpdate->RectIter(); !iter.Done(); iter.Next()) {
1030         const IntRect& rect = iter.Get();
1031         D3D11_BOX box;
1032         box.front = 0;
1033         box.back = 1;
1034         box.left = rect.x;
1035         box.top = rect.y;
1036         box.right = rect.XMost();
1037         box.bottom = rect.YMost();
1038 
1039         void* data = map.mData + map.mStride * rect.y + BytesPerPixel(aSurface->GetFormat()) * rect.x;
1040 
1041         mCompositor->GetDC()->UpdateSubresource(mTexture, 0, &box, data, map.mStride, map.mStride * rect.height);
1042       }
1043     } else {
1044       mCompositor->GetDC()->UpdateSubresource(mTexture, 0, nullptr, aSurface->GetData(),
1045                                               aSurface->Stride(), aSurface->Stride() * mSize.height);
1046     }
1047 
1048     aSurface->Unmap();
1049   } else {
1050     mIsTiled = true;
1051     uint32_t tileCount = GetRequiredTilesD3D11(mSize.width, maxSize) *
1052                          GetRequiredTilesD3D11(mSize.height, maxSize);
1053 
1054     mTileTextures.resize(tileCount);
1055     mTileSRVs.resize(tileCount);
1056     mTexture = nullptr;
1057 
1058     for (uint32_t i = 0; i < tileCount; i++) {
1059       IntRect tileRect = GetTileRect(i);
1060 
1061       desc.Width = tileRect.width;
1062       desc.Height = tileRect.height;
1063       desc.Usage = D3D11_USAGE_IMMUTABLE;
1064 
1065       D3D11_SUBRESOURCE_DATA initData;
1066       initData.pSysMem = aSurface->GetData() +
1067                          tileRect.y * aSurface->Stride() +
1068                          tileRect.x * bpp;
1069       initData.SysMemPitch = aSurface->Stride();
1070 
1071       hr = mCompositor->GetDevice()->CreateTexture2D(&desc, &initData, getter_AddRefs(mTileTextures[i]));
1072       if (FAILED(hr) || !mTileTextures[i]) {
1073         Reset();
1074         return false;
1075       }
1076     }
1077   }
1078   return true;
1079 }
1080 
1081 ID3D11Texture2D*
GetD3D11Texture() const1082 DataTextureSourceD3D11::GetD3D11Texture() const
1083 {
1084   return mIterating ? mTileTextures[mCurrentTile]
1085                     : mTexture;
1086 }
1087 
1088 ID3D11ShaderResourceView*
GetShaderResourceView()1089 DataTextureSourceD3D11::GetShaderResourceView()
1090 {
1091   if (mIterating) {
1092     if (!mTileSRVs[mCurrentTile]) {
1093       if (!mTileTextures[mCurrentTile]) {
1094         return nullptr;
1095       }
1096 
1097       RefPtr<ID3D11Device> device;
1098       mTileTextures[mCurrentTile]->GetDevice(getter_AddRefs(device));
1099       HRESULT hr = device->CreateShaderResourceView(mTileTextures[mCurrentTile], nullptr, getter_AddRefs(mTileSRVs[mCurrentTile]));
1100       if (FAILED(hr)) {
1101         gfxCriticalNote << "[D3D11] DataTextureSourceD3D11:GetShaderResourceView CreateSRV failure " << gfx::hexa(hr);
1102         return nullptr;
1103       }
1104     }
1105     return mTileSRVs[mCurrentTile];
1106   }
1107 
1108   return TextureSourceD3D11::GetShaderResourceView();
1109 }
1110 
1111 void
Reset()1112 DataTextureSourceD3D11::Reset()
1113 {
1114   mTexture = nullptr;
1115   mTileSRVs.resize(0);
1116   mTileTextures.resize(0);
1117   mIsTiled = false;
1118   mSize.width = 0;
1119   mSize.height = 0;
1120 }
1121 
1122 IntRect
GetTileRect(uint32_t aIndex) const1123 DataTextureSourceD3D11::GetTileRect(uint32_t aIndex) const
1124 {
1125   return GetTileRectD3D11(aIndex, mSize, mCompositor->GetMaxTextureSize());
1126 }
1127 
1128 IntRect
GetTileRect()1129 DataTextureSourceD3D11::GetTileRect()
1130 {
1131   IntRect rect = GetTileRect(mCurrentTile);
1132   return IntRect(rect.x, rect.y, rect.width, rect.height);
1133 }
1134 
1135 void
SetCompositor(Compositor * aCompositor)1136 DataTextureSourceD3D11::SetCompositor(Compositor* aCompositor)
1137 {
1138   CompositorD3D11* d3dCompositor = AssertD3D11Compositor(aCompositor);
1139   if (!d3dCompositor) {
1140     return;
1141   }
1142   mCompositor = d3dCompositor;
1143   if (mNextSibling) {
1144     mNextSibling->SetCompositor(aCompositor);
1145   }
1146 }
1147 
CompositingRenderTargetD3D11(ID3D11Texture2D * aTexture,const gfx::IntPoint & aOrigin,DXGI_FORMAT aFormatOverride)1148 CompositingRenderTargetD3D11::CompositingRenderTargetD3D11(ID3D11Texture2D* aTexture,
1149                                                            const gfx::IntPoint& aOrigin,
1150                                                            DXGI_FORMAT aFormatOverride)
1151   : CompositingRenderTarget(aOrigin)
1152 {
1153   MOZ_ASSERT(aTexture);
1154 
1155   mTexture = aTexture;
1156 
1157   RefPtr<ID3D11Device> device;
1158   mTexture->GetDevice(getter_AddRefs(device));
1159 
1160   mFormatOverride = aFormatOverride;
1161 
1162   // If we happen to have a typeless underlying DXGI surface, we need to be explicit
1163   // about the format here. (Such a surface could come from an external source, such
1164   // as the Oculus compositor)
1165   CD3D11_RENDER_TARGET_VIEW_DESC rtvDesc(D3D11_RTV_DIMENSION_TEXTURE2D, mFormatOverride);
1166   D3D11_RENDER_TARGET_VIEW_DESC *desc = aFormatOverride == DXGI_FORMAT_UNKNOWN ? nullptr : &rtvDesc;
1167 
1168   HRESULT hr = device->CreateRenderTargetView(mTexture, desc, getter_AddRefs(mRTView));
1169 
1170   if (FAILED(hr)) {
1171     LOGD3D11("Failed to create RenderTargetView.");
1172   }
1173 }
1174 
1175 void
BindRenderTarget(ID3D11DeviceContext * aContext)1176 CompositingRenderTargetD3D11::BindRenderTarget(ID3D11DeviceContext* aContext)
1177 {
1178   if (mClearOnBind) {
1179     FLOAT clear[] = { 0, 0, 0, 0 };
1180     aContext->ClearRenderTargetView(mRTView, clear);
1181     mClearOnBind = false;
1182   }
1183   ID3D11RenderTargetView* view = mRTView;
1184   aContext->OMSetRenderTargets(1, &view, nullptr);
1185 }
1186 
1187 IntSize
GetSize() const1188 CompositingRenderTargetD3D11::GetSize() const
1189 {
1190   return TextureSourceD3D11::GetSize();
1191 }
1192 
SyncObjectD3D11(SyncHandle aHandle)1193 SyncObjectD3D11::SyncObjectD3D11(SyncHandle aHandle)
1194 {
1195   MOZ_ASSERT(aHandle);
1196   mD3D11Device = DeviceManagerDx::Get()->GetContentDevice();
1197   mHandle = aHandle;
1198 }
1199 
1200 void
RegisterTexture(ID3D11Texture2D * aTexture)1201 SyncObjectD3D11::RegisterTexture(ID3D11Texture2D* aTexture)
1202 {
1203   mD3D11SyncedTextures.push_back(aTexture);
1204 }
1205 
1206 bool
IsSyncObjectValid()1207 SyncObjectD3D11::IsSyncObjectValid()
1208 {
1209   RefPtr<ID3D11Device> dev = DeviceManagerDx::Get()->GetContentDevice();
1210   if (!dev || (dev != mD3D11Device)) {
1211     return false;
1212   }
1213   return true;
1214 }
1215 
1216 void
FinalizeFrame()1217 SyncObjectD3D11::FinalizeFrame()
1218 {
1219   HRESULT hr;
1220 
1221   if (!mD3D11Texture && mD3D11SyncedTextures.size()) {
1222     RefPtr<ID3D11Device> device = DeviceManagerDx::Get()->GetContentDevice();
1223 
1224     hr = device->OpenSharedResource(mHandle, __uuidof(ID3D11Texture2D), (void**)(ID3D11Texture2D**)getter_AddRefs(mD3D11Texture));
1225 
1226     if (FAILED(hr) || !mD3D11Texture) {
1227       gfxCriticalError() << "Failed to D3D11 OpenSharedResource for frame finalization: " << hexa(hr);
1228 
1229       if (DeviceManagerDx::Get()->HasDeviceReset()) {
1230         return;
1231       }
1232 
1233       gfxDevCrash(LogReason::D3D11FinalizeFrame) << "Without device reset: " << hexa(hr);
1234     }
1235 
1236     // test QI
1237     RefPtr<IDXGIKeyedMutex> mutex;
1238     hr = mD3D11Texture->QueryInterface((IDXGIKeyedMutex**)getter_AddRefs(mutex));
1239 
1240     if (FAILED(hr) || !mutex) {
1241       // Leave both the critical error and MOZ_CRASH for now; the critical error lets
1242       // us "save" the hr value.  We will probably eventuall replace this with gfxDevCrash.
1243       gfxCriticalError() << "Failed to get KeyedMutex (2): " << hexa(hr);
1244       MOZ_CRASH("GFX: Cannot get D3D11 KeyedMutex");
1245     }
1246   }
1247 
1248   if (mD3D11SyncedTextures.size()) {
1249     RefPtr<IDXGIKeyedMutex> mutex;
1250     hr = mD3D11Texture->QueryInterface((IDXGIKeyedMutex**)getter_AddRefs(mutex));
1251     {
1252       AutoTextureLock lock(mutex, hr, 20000);
1253 
1254       if (hr == WAIT_TIMEOUT) {
1255         if (DeviceManagerDx::Get()->HasDeviceReset()) {
1256           gfxWarning() << "AcquireSync timed out because of device reset.";
1257           return;
1258         }
1259         gfxDevCrash(LogReason::D3D11SyncLock) << "Timeout on the D3D11 sync lock";
1260       }
1261 
1262       D3D11_BOX box;
1263       box.front = box.top = box.left = 0;
1264       box.back = box.bottom = box.right = 1;
1265 
1266       RefPtr<ID3D11Device> dev = DeviceManagerDx::Get()->GetContentDevice();
1267       if (!dev) {
1268         if (DeviceManagerDx::Get()->HasDeviceReset()) {
1269           return;
1270         }
1271         MOZ_CRASH("GFX: Invalid D3D11 content device");
1272       }
1273 
1274       RefPtr<ID3D11DeviceContext> ctx;
1275       dev->GetImmediateContext(getter_AddRefs(ctx));
1276 
1277       for (auto iter = mD3D11SyncedTextures.begin(); iter != mD3D11SyncedTextures.end(); iter++) {
1278         ctx->CopySubresourceRegion(mD3D11Texture, 0, 0, 0, 0, *iter, 0, &box);
1279       }
1280     }
1281 
1282     mD3D11SyncedTextures.clear();
1283   }
1284 }
1285 
1286 }
1287 }
1288