Bug 1919083 - [ci] Enable os-integration variant for more suites, r=jmaher
[gecko.git] / gfx / layers / d3d11 / TextureD3D11.cpp
blobda861115e6ed25b8602cfc89aee8818d1144aa7a
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/. */
7 #include "TextureD3D11.h"
9 #include "CompositorD3D11.h"
10 #include "DXVA2Manager.h"
11 #include "Effects.h"
12 #include "MainThreadUtils.h"
13 #include "gfx2DGlue.h"
14 #include "gfxContext.h"
15 #include "gfxWindowsPlatform.h"
16 #include "mozilla/DataMutex.h"
17 #include "mozilla/StaticPrefs_gfx.h"
18 #include "mozilla/gfx/DataSurfaceHelpers.h"
19 #include "mozilla/gfx/DeviceManagerDx.h"
20 #include "mozilla/gfx/FileHandleWrapper.h"
21 #include "mozilla/gfx/Logging.h"
22 #include "mozilla/gfx/gfxVars.h"
23 #include "mozilla/ipc/FileDescriptor.h"
24 #include "mozilla/layers/CompositorBridgeChild.h"
25 #include "mozilla/layers/D3D11TextureIMFSampleImage.h"
26 #include "mozilla/layers/GpuProcessD3D11QueryMap.h"
27 #include "mozilla/layers/GpuProcessD3D11TextureMap.h"
28 #include "mozilla/layers/HelpersD3D11.h"
29 #include "mozilla/layers/VideoProcessorD3D11.h"
30 #include "mozilla/webrender/RenderD3D11TextureHost.h"
31 #include "mozilla/webrender/RenderThread.h"
32 #include "mozilla/webrender/WebRenderAPI.h"
34 namespace mozilla {
36 using namespace gfx;
38 namespace layers {
40 gfx::DeviceResetReason DXGIErrorToDeviceResetReason(HRESULT aError) {
41 switch (aError) {
42 case S_OK:
43 return gfx::DeviceResetReason::OK;
44 case DXGI_ERROR_DEVICE_REMOVED:
45 return gfx::DeviceResetReason::REMOVED;
46 case DXGI_ERROR_DRIVER_INTERNAL_ERROR:
47 return gfx::DeviceResetReason::DRIVER_ERROR;
48 case DXGI_ERROR_DEVICE_HUNG:
49 return gfx::DeviceResetReason::HUNG;
50 case DXGI_ERROR_DEVICE_RESET:
51 return gfx::DeviceResetReason::RESET;
52 case DXGI_ERROR_INVALID_CALL:
53 return gfx::DeviceResetReason::INVALID_CALL;
54 default:
55 gfxCriticalNote << "Device reset with D3D11Device unexpected reason: "
56 << gfx::hexa(aError);
57 break;
59 return gfx::DeviceResetReason::UNKNOWN;
62 static const GUID sD3D11TextureUsage = {
63 0xd89275b0,
64 0x6c7d,
65 0x4038,
66 {0xb5, 0xfa, 0x4d, 0x87, 0x16, 0xd5, 0xcc, 0x4e}};
68 /* This class gets its lifetime tied to a D3D texture
69 * and increments memory usage on construction and decrements
70 * on destruction */
71 class TextureMemoryMeasurer final : public IUnknown {
72 public:
73 explicit TextureMemoryMeasurer(size_t aMemoryUsed) {
74 mMemoryUsed = aMemoryUsed;
75 gfxWindowsPlatform::sD3D11SharedTextures += mMemoryUsed;
76 mRefCnt = 0;
78 STDMETHODIMP_(ULONG) AddRef() {
79 mRefCnt++;
80 return mRefCnt;
82 STDMETHODIMP QueryInterface(REFIID riid, void** ppvObject) {
83 IUnknown* punk = nullptr;
84 if (riid == IID_IUnknown) {
85 punk = this;
87 *ppvObject = punk;
88 if (punk) {
89 punk->AddRef();
90 return S_OK;
91 } else {
92 return E_NOINTERFACE;
96 STDMETHODIMP_(ULONG) Release() {
97 int refCnt = --mRefCnt;
98 if (refCnt == 0) {
99 gfxWindowsPlatform::sD3D11SharedTextures -= mMemoryUsed;
100 delete this;
102 return refCnt;
105 private:
106 int mRefCnt;
107 int mMemoryUsed;
109 ~TextureMemoryMeasurer() = default;
112 static DXGI_FORMAT SurfaceFormatToDXGIFormat(gfx::SurfaceFormat aFormat) {
113 switch (aFormat) {
114 case SurfaceFormat::B8G8R8A8:
115 return DXGI_FORMAT_B8G8R8A8_UNORM;
116 case SurfaceFormat::B8G8R8X8:
117 return DXGI_FORMAT_B8G8R8A8_UNORM;
118 case SurfaceFormat::R8G8B8A8:
119 return DXGI_FORMAT_R8G8B8A8_UNORM;
120 case SurfaceFormat::R8G8B8X8:
121 return DXGI_FORMAT_R8G8B8A8_UNORM;
122 case SurfaceFormat::A8:
123 return DXGI_FORMAT_R8_UNORM;
124 case SurfaceFormat::A16:
125 return DXGI_FORMAT_R16_UNORM;
126 default:
127 MOZ_ASSERT(false, "unsupported format");
128 return DXGI_FORMAT_UNKNOWN;
132 void ReportTextureMemoryUsage(ID3D11Texture2D* aTexture, size_t aBytes) {
133 aTexture->SetPrivateDataInterface(sD3D11TextureUsage,
134 new TextureMemoryMeasurer(aBytes));
137 static uint32_t GetRequiredTilesD3D11(uint32_t aSize, uint32_t aMaxSize) {
138 uint32_t requiredTiles = aSize / aMaxSize;
139 if (aSize % aMaxSize) {
140 requiredTiles++;
142 return requiredTiles;
145 static IntRect GetTileRectD3D11(uint32_t aID, IntSize aSize,
146 uint32_t aMaxSize) {
147 uint32_t horizontalTiles = GetRequiredTilesD3D11(aSize.width, aMaxSize);
148 uint32_t verticalTiles = GetRequiredTilesD3D11(aSize.height, aMaxSize);
150 uint32_t verticalTile = aID / horizontalTiles;
151 uint32_t horizontalTile = aID % horizontalTiles;
153 return IntRect(
154 horizontalTile * aMaxSize, verticalTile * aMaxSize,
155 horizontalTile < (horizontalTiles - 1) ? aMaxSize
156 : aSize.width % aMaxSize,
157 verticalTile < (verticalTiles - 1) ? aMaxSize : aSize.height % aMaxSize);
160 AutoTextureLock::AutoTextureLock(IDXGIKeyedMutex* aMutex, HRESULT& aResult,
161 uint32_t aTimeout) {
162 mMutex = aMutex;
163 if (mMutex) {
164 mResult = mMutex->AcquireSync(0, aTimeout);
165 aResult = mResult;
166 } else {
167 aResult = E_INVALIDARG;
171 AutoTextureLock::~AutoTextureLock() {
172 if (mMutex && !FAILED(mResult) && mResult != WAIT_TIMEOUT &&
173 mResult != WAIT_ABANDONED) {
174 mMutex->ReleaseSync(0);
178 ID3D11ShaderResourceView* TextureSourceD3D11::GetShaderResourceView() {
179 MOZ_ASSERT(mTexture == GetD3D11Texture(),
180 "You need to override GetShaderResourceView if you're overriding "
181 "GetD3D11Texture!");
183 if (!mSRV && mTexture) {
184 RefPtr<ID3D11Device> device;
185 mTexture->GetDevice(getter_AddRefs(device));
187 // see comment in CompositingRenderTargetD3D11 constructor
188 CD3D11_SHADER_RESOURCE_VIEW_DESC srvDesc(D3D11_SRV_DIMENSION_TEXTURE2D,
189 mFormatOverride);
190 D3D11_SHADER_RESOURCE_VIEW_DESC* desc =
191 mFormatOverride == DXGI_FORMAT_UNKNOWN ? nullptr : &srvDesc;
193 HRESULT hr =
194 device->CreateShaderResourceView(mTexture, desc, getter_AddRefs(mSRV));
195 if (FAILED(hr)) {
196 gfxCriticalNote << "[D3D11] TextureSourceD3D11:GetShaderResourceView "
197 "CreateSRV failure "
198 << gfx::hexa(hr);
199 return nullptr;
202 return mSRV;
205 DataTextureSourceD3D11::DataTextureSourceD3D11(ID3D11Device* aDevice,
206 SurfaceFormat aFormat,
207 TextureFlags aFlags)
208 : mDevice(aDevice),
209 mFormat(aFormat),
210 mFlags(aFlags),
211 mCurrentTile(0),
212 mIsTiled(false),
213 mIterating(false),
214 mAllowTextureUploads(true) {}
216 DataTextureSourceD3D11::DataTextureSourceD3D11(ID3D11Device* aDevice,
217 SurfaceFormat aFormat,
218 ID3D11Texture2D* aTexture)
219 : mDevice(aDevice),
220 mFormat(aFormat),
221 mFlags(TextureFlags::NO_FLAGS),
222 mCurrentTile(0),
223 mIsTiled(false),
224 mIterating(false),
225 mAllowTextureUploads(false) {
226 mTexture = aTexture;
227 D3D11_TEXTURE2D_DESC desc;
228 aTexture->GetDesc(&desc);
230 mSize = IntSize(desc.Width, desc.Height);
233 DataTextureSourceD3D11::DataTextureSourceD3D11(gfx::SurfaceFormat aFormat,
234 TextureSourceProvider* aProvider,
235 ID3D11Texture2D* aTexture)
236 : DataTextureSourceD3D11(aProvider->GetD3D11Device(), aFormat, aTexture) {}
238 DataTextureSourceD3D11::DataTextureSourceD3D11(gfx::SurfaceFormat aFormat,
239 TextureSourceProvider* aProvider,
240 TextureFlags aFlags)
241 : DataTextureSourceD3D11(aProvider->GetD3D11Device(), aFormat, aFlags) {}
243 DataTextureSourceD3D11::~DataTextureSourceD3D11() {}
245 enum class SerializeWithMoz2D : bool { No, Yes };
247 template <typename T> // ID3D10Texture2D or ID3D11Texture2D
248 static bool LockD3DTexture(
249 T* aTexture, SerializeWithMoz2D aSerialize = SerializeWithMoz2D::No) {
250 MOZ_ASSERT(aTexture);
251 RefPtr<IDXGIKeyedMutex> mutex;
252 aTexture->QueryInterface((IDXGIKeyedMutex**)getter_AddRefs(mutex));
253 // Textures created by the DXVA decoders don't have a mutex for
254 // synchronization
255 if (mutex) {
256 HRESULT hr;
257 if (aSerialize == SerializeWithMoz2D::Yes) {
258 AutoSerializeWithMoz2D serializeWithMoz2D(BackendType::DIRECT2D1_1);
259 hr = mutex->AcquireSync(0, 10000);
260 } else {
261 hr = mutex->AcquireSync(0, 10000);
263 if (hr == WAIT_TIMEOUT) {
264 RefPtr<ID3D11Device> device;
265 aTexture->GetDevice(getter_AddRefs(device));
266 if (!device) {
267 gfxCriticalNote << "GFX: D3D11 lock mutex timeout - no device returned";
268 } else if (device->GetDeviceRemovedReason() != S_OK) {
269 gfxCriticalNote << "GFX: D3D11 lock mutex timeout - device removed";
270 } else {
271 gfxDevCrash(LogReason::D3DLockTimeout)
272 << "D3D lock mutex timeout - device not removed";
274 } else if (hr == WAIT_ABANDONED) {
275 gfxCriticalNote << "GFX: D3D11 lock mutex abandoned";
278 if (FAILED(hr)) {
279 NS_WARNING("Failed to lock the texture");
280 return false;
283 return true;
286 template <typename T>
287 static bool HasKeyedMutex(T* aTexture) {
288 MOZ_ASSERT(aTexture);
289 RefPtr<IDXGIKeyedMutex> mutex;
290 aTexture->QueryInterface((IDXGIKeyedMutex**)getter_AddRefs(mutex));
291 return !!mutex;
294 template <typename T> // ID3D10Texture2D or ID3D11Texture2D
295 static void UnlockD3DTexture(
296 T* aTexture, SerializeWithMoz2D aSerialize = SerializeWithMoz2D::No) {
297 MOZ_ASSERT(aTexture);
298 RefPtr<IDXGIKeyedMutex> mutex;
299 aTexture->QueryInterface((IDXGIKeyedMutex**)getter_AddRefs(mutex));
300 if (mutex) {
301 HRESULT hr;
302 if (aSerialize == SerializeWithMoz2D::Yes) {
303 AutoSerializeWithMoz2D serializeWithMoz2D(BackendType::DIRECT2D1_1);
304 hr = mutex->ReleaseSync(0);
305 } else {
306 hr = mutex->ReleaseSync(0);
308 if (FAILED(hr)) {
309 NS_WARNING("Failed to unlock the texture");
314 D3D11TextureData::D3D11TextureData(ID3D11Texture2D* aTexture,
315 uint32_t aArrayIndex,
316 RefPtr<gfx::FileHandleWrapper> aSharedHandle,
317 gfx::IntSize aSize,
318 gfx::SurfaceFormat aFormat,
319 TextureAllocationFlags aFlags)
320 : mSize(aSize),
321 mFormat(aFormat),
322 mNeedsClear(aFlags & ALLOC_CLEAR_BUFFER),
323 mHasKeyedMutex(HasKeyedMutex(aTexture)),
324 mTexture(aTexture),
325 mSharedHandle(std::move(aSharedHandle)),
326 mArrayIndex(aArrayIndex),
327 mAllocationFlags(aFlags) {
328 MOZ_ASSERT(aTexture);
331 static void DestroyDrawTarget(RefPtr<DrawTarget>& aDT,
332 RefPtr<ID3D11Texture2D>& aTexture) {
333 // An Azure DrawTarget needs to be locked when it gets nullptr'ed as this is
334 // when it calls EndDraw. This EndDraw should not execute anything so it
335 // shouldn't -really- need the lock but the debug layer chokes on this.
336 LockD3DTexture(aTexture.get(), SerializeWithMoz2D::Yes);
337 aDT = nullptr;
339 // Do the serialization here, so we can hold it while destroying the texture.
340 AutoSerializeWithMoz2D serializeWithMoz2D(BackendType::DIRECT2D1_1);
341 UnlockD3DTexture(aTexture.get(), SerializeWithMoz2D::No);
342 aTexture = nullptr;
345 D3D11TextureData::~D3D11TextureData() {
346 if (mDrawTarget) {
347 DestroyDrawTarget(mDrawTarget, mTexture);
350 if (mGpuProcessTextureId.isSome()) {
351 auto* textureMap = GpuProcessD3D11TextureMap::Get();
352 if (textureMap) {
353 textureMap->Unregister(mGpuProcessTextureId.ref());
354 } else {
355 gfxCriticalNoteOnce << "GpuProcessD3D11TextureMap does not exist";
359 if (mGpuProcessQueryId.isSome()) {
360 auto* queryMap = GpuProcessD3D11QueryMap::Get();
361 if (queryMap) {
362 queryMap->Unregister(mGpuProcessQueryId.ref());
363 } else {
364 gfxCriticalNoteOnce << "GpuProcessD3D11QueryMap does not exist";
369 bool D3D11TextureData::Lock(OpenMode aMode) {
370 if (mHasKeyedMutex &&
371 !LockD3DTexture(mTexture.get(), SerializeWithMoz2D::Yes)) {
372 return false;
375 if (NS_IsMainThread()) {
376 if (!PrepareDrawTargetInLock(aMode)) {
377 Unlock();
378 return false;
382 return true;
385 bool D3D11TextureData::PrepareDrawTargetInLock(OpenMode aMode) {
386 // Make sure that successful write-lock means we will have a DrawTarget to
387 // write into.
388 if (!mDrawTarget && (aMode & OpenMode::OPEN_WRITE || mNeedsClear)) {
389 mDrawTarget = BorrowDrawTarget();
390 if (!mDrawTarget) {
391 return false;
395 // Reset transform
396 mDrawTarget->SetTransform(Matrix());
398 if (mNeedsClear) {
399 mDrawTarget->ClearRect(Rect(0, 0, mSize.width, mSize.height));
400 mNeedsClear = false;
403 return true;
406 void D3D11TextureData::Unlock() {
407 if (mHasKeyedMutex) {
408 UnlockD3DTexture(mTexture.get(), SerializeWithMoz2D::Yes);
412 void D3D11TextureData::FillInfo(TextureData::Info& aInfo) const {
413 aInfo.size = mSize;
414 aInfo.format = mFormat;
415 aInfo.supportsMoz2D = true;
416 aInfo.hasSynchronization = mHasKeyedMutex;
419 void D3D11TextureData::SyncWithObject(RefPtr<SyncObjectClient> aSyncObject) {
420 if (!aSyncObject || mHasKeyedMutex) {
421 // When we have per texture synchronization we sync using the keyed mutex.
422 return;
425 MOZ_ASSERT(aSyncObject->GetSyncType() == SyncObjectClient::SyncType::D3D11);
426 SyncObjectD3D11Client* sync =
427 static_cast<SyncObjectD3D11Client*>(aSyncObject.get());
428 sync->RegisterTexture(mTexture);
431 bool D3D11TextureData::SerializeSpecific(
432 SurfaceDescriptorD3D10* const aOutDesc) {
433 if (mGpuProcessTextureId.isNothing()) {
435 *aOutDesc = SurfaceDescriptorD3D10(
436 mSharedHandle, mGpuProcessTextureId, mArrayIndex, mFormat, mSize,
437 mColorSpace, mColorRange, /* hasKeyedMutex */ mHasKeyedMutex,
438 /* fenceInfo */ Nothing(), mGpuProcessQueryId);
439 return true;
442 bool D3D11TextureData::Serialize(SurfaceDescriptor& aOutDescriptor) {
443 SurfaceDescriptorD3D10 desc;
444 if (!SerializeSpecific(&desc)) return false;
446 aOutDescriptor = std::move(desc);
447 return true;
450 void D3D11TextureData::GetSubDescriptor(
451 RemoteDecoderVideoSubDescriptor* const aOutDesc) {
452 SurfaceDescriptorD3D10 ret;
453 if (!SerializeSpecific(&ret)) return;
455 *aOutDesc = std::move(ret);
458 /* static */
459 already_AddRefed<TextureClient> D3D11TextureData::CreateTextureClient(
460 ID3D11Texture2D* aTexture, uint32_t aIndex, gfx::IntSize aSize,
461 gfx::SurfaceFormat aFormat, gfx::ColorSpace2 aColorSpace,
462 gfx::ColorRange aColorRange, KnowsCompositor* aKnowsCompositor,
463 RefPtr<IMFSampleUsageInfo> aUsageInfo) {
464 D3D11TextureData* data = new D3D11TextureData(
465 aTexture, aIndex, nullptr, aSize, aFormat,
466 TextureAllocationFlags::ALLOC_MANUAL_SYNCHRONIZATION);
467 data->mColorSpace = aColorSpace;
468 data->SetColorRange(aColorRange);
470 RefPtr<TextureClient> textureClient = MakeAndAddRef<TextureClient>(
471 data, TextureFlags::NO_FLAGS, aKnowsCompositor->GetTextureForwarder());
472 const auto textureId = GpuProcessD3D11TextureMap::GetNextTextureId();
473 data->SetGpuProcessTextureId(textureId);
475 // Register ID3D11Texture2D to GpuProcessD3D11TextureMap
476 auto* textureMap = GpuProcessD3D11TextureMap::Get();
477 if (textureMap) {
478 textureMap->Register(textureId, aTexture, aIndex, aSize, aUsageInfo);
479 } else {
480 gfxCriticalNoteOnce << "GpuProcessD3D11TextureMap does not exist";
483 return textureClient.forget();
486 D3D11TextureData* D3D11TextureData::Create(IntSize aSize, SurfaceFormat aFormat,
487 TextureAllocationFlags aFlags,
488 ID3D11Device* aDevice) {
489 return Create(aSize, aFormat, nullptr, aFlags, aDevice);
492 D3D11TextureData* D3D11TextureData::Create(SourceSurface* aSurface,
493 TextureAllocationFlags aFlags,
494 ID3D11Device* aDevice) {
495 return Create(aSurface->GetSize(), aSurface->GetFormat(), aSurface, aFlags,
496 aDevice);
499 D3D11TextureData* D3D11TextureData::Create(IntSize aSize, SurfaceFormat aFormat,
500 SourceSurface* aSurface,
501 TextureAllocationFlags aFlags,
502 ID3D11Device* aDevice) {
503 if (aFormat == SurfaceFormat::A8) {
504 // Currently we don't support A8 surfaces. Fallback.
505 return nullptr;
508 // Just grab any device. We never use the immediate context, so the devices
509 // are fine to use from any thread.
510 RefPtr<ID3D11Device> device = aDevice;
511 if (!device) {
512 device = DeviceManagerDx::Get()->GetContentDevice();
513 if (!device) {
514 return nullptr;
518 CD3D11_TEXTURE2D_DESC newDesc(
519 DXGI_FORMAT_B8G8R8A8_UNORM, aSize.width, aSize.height, 1, 1,
520 D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE);
522 if (aFormat == SurfaceFormat::NV12) {
523 newDesc.Format = DXGI_FORMAT_NV12;
524 } else if (aFormat == SurfaceFormat::P010) {
525 newDesc.Format = DXGI_FORMAT_P010;
526 } else if (aFormat == SurfaceFormat::P016) {
527 newDesc.Format = DXGI_FORMAT_P016;
530 newDesc.MiscFlags =
531 D3D11_RESOURCE_MISC_SHARED_NTHANDLE | D3D11_RESOURCE_MISC_SHARED;
532 bool useKeyedMutex = false;
533 if (!NS_IsMainThread()) {
534 // On the main thread we use the syncobject to handle synchronization.
535 if (!(aFlags & ALLOC_MANUAL_SYNCHRONIZATION)) {
536 newDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED_NTHANDLE |
537 D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX;
538 useKeyedMutex = true;
542 if (aSurface && useKeyedMutex &&
543 !DeviceManagerDx::Get()->CanInitializeKeyedMutexTextures()) {
544 return nullptr;
547 D3D11_SUBRESOURCE_DATA uploadData;
548 D3D11_SUBRESOURCE_DATA* uploadDataPtr = nullptr;
549 RefPtr<DataSourceSurface> srcSurf;
551 if (aSurface) {
552 srcSurf = aSurface->GetDataSurface();
554 if (!srcSurf) {
555 gfxCriticalError()
556 << "Failed to GetDataSurface in D3D11TextureData::Create";
557 return nullptr;
560 DataSourceSurface::MappedSurface sourceMap;
561 if (!srcSurf->Map(DataSourceSurface::READ, &sourceMap)) {
562 gfxCriticalError()
563 << "Failed to map source surface for D3D11TextureData::Create";
564 return nullptr;
567 uploadData.pSysMem = sourceMap.mData;
568 uploadData.SysMemPitch = sourceMap.mStride;
569 uploadData.SysMemSlicePitch = 0; // unused
571 uploadDataPtr = &uploadData;
574 // See bug 1397040
575 RefPtr<ID3D10Multithread> mt;
576 device->QueryInterface((ID3D10Multithread**)getter_AddRefs(mt));
578 RefPtr<ID3D11Texture2D> texture11;
581 AutoSerializeWithMoz2D serializeWithMoz2D(BackendType::DIRECT2D1_1);
582 D3D11MTAutoEnter lock(mt.forget());
584 HRESULT hr = device->CreateTexture2D(&newDesc, uploadDataPtr,
585 getter_AddRefs(texture11));
587 if (FAILED(hr) || !texture11) {
588 gfxCriticalNote << "[D3D11] 2 CreateTexture2D failure Size: " << aSize
589 << "texture11: " << texture11
590 << " Code: " << gfx::hexa(hr);
591 return nullptr;
595 if (srcSurf) {
596 srcSurf->Unmap();
599 // If we created the texture with a keyed mutex, then we expect all operations
600 // on it to be synchronized using it. If we did an initial upload using
601 // aSurface then bizarely this isn't covered, so we insert a manual
602 // lock/unlock pair to force this.
603 if (aSurface && useKeyedMutex) {
604 if (!LockD3DTexture(texture11.get(), SerializeWithMoz2D::Yes)) {
605 return nullptr;
607 UnlockD3DTexture(texture11.get(), SerializeWithMoz2D::Yes);
610 RefPtr<IDXGIResource1> resource;
611 texture11->QueryInterface((IDXGIResource1**)getter_AddRefs(resource));
612 if (!resource) {
613 gfxCriticalNoteOnce << "Failed to get IDXGIResource";
614 return nullptr;
617 HANDLE sharedHandle;
618 HRESULT hr = resource->GetSharedHandle(&sharedHandle);
619 hr = resource->CreateSharedHandle(
620 nullptr, DXGI_SHARED_RESOURCE_READ | DXGI_SHARED_RESOURCE_WRITE, nullptr,
621 &sharedHandle);
622 if (FAILED(hr)) {
623 gfxCriticalNoteOnce << "GetSharedHandle failed: " << gfx::hexa(hr);
624 return nullptr;
627 texture11->SetPrivateDataInterface(
628 sD3D11TextureUsage,
629 new TextureMemoryMeasurer(newDesc.Width * newDesc.Height * 4));
631 RefPtr<gfx::FileHandleWrapper> handle =
632 new gfx::FileHandleWrapper(UniqueFileHandle(sharedHandle));
634 D3D11TextureData* data =
635 new D3D11TextureData(texture11, 0, handle, aSize, aFormat, aFlags);
637 texture11->GetDevice(getter_AddRefs(device));
638 if (XRE_IsGPUProcess() &&
639 device == gfx::DeviceManagerDx::Get()->GetCompositorDevice()) {
640 const auto textureId = GpuProcessD3D11TextureMap::GetNextTextureId();
641 data->SetGpuProcessTextureId(textureId);
642 // Register ID3D11Texture2D to GpuProcessD3D11TextureMap
643 auto* textureMap = GpuProcessD3D11TextureMap::Get();
644 if (textureMap) {
645 textureMap->Register(textureId, texture11, 0, aSize, nullptr, handle);
646 } else {
647 gfxCriticalNoteOnce << "GpuProcessD3D11TextureMap does not exist";
651 return data;
654 void D3D11TextureData::Deallocate(LayersIPCChannel* aAllocator) {
655 mDrawTarget = nullptr;
656 mTexture = nullptr;
659 TextureData* D3D11TextureData::CreateSimilar(
660 LayersIPCChannel* aAllocator, LayersBackend aLayersBackend,
661 TextureFlags aFlags, TextureAllocationFlags aAllocFlags) const {
662 return D3D11TextureData::Create(mSize, mFormat, aAllocFlags);
665 TextureFlags D3D11TextureData::GetTextureFlags() const {
666 // With WebRender, resource open happens asynchronously on RenderThread.
667 // During opening the resource on host side, TextureClient needs to be alive.
668 // With WAIT_HOST_USAGE_END, keep TextureClient alive during host side usage.
669 return TextureFlags::WAIT_HOST_USAGE_END;
672 void D3D11TextureData::RegisterQuery(RefPtr<ID3D11Query> aQuery,
673 bool aOnlyForOverlay) {
674 MOZ_ASSERT(XRE_IsGPUProcess());
675 MOZ_ASSERT(GpuProcessD3D11QueryMap::Get());
677 if (!GpuProcessD3D11QueryMap::Get()) {
678 return;
681 if (mGpuProcessQueryId.isNothing()) {
682 mGpuProcessQueryId = Some(GpuProcessQueryId::GetNext());
684 mGpuProcessQueryId.ref().mOnlyForOverlay = aOnlyForOverlay;
685 GpuProcessD3D11QueryMap::Get()->Register(mGpuProcessQueryId.ref(), aQuery);
688 DXGIYCbCrTextureData* DXGIYCbCrTextureData::Create(
689 ID3D11Texture2D* aTextureY, ID3D11Texture2D* aTextureCb,
690 ID3D11Texture2D* aTextureCr, const gfx::IntSize& aSize,
691 const gfx::IntSize& aSizeY, const gfx::IntSize& aSizeCbCr,
692 gfx::ColorDepth aColorDepth, YUVColorSpace aYUVColorSpace,
693 gfx::ColorRange aColorRange) {
694 if (!aTextureY || !aTextureCb || !aTextureCr) {
695 return nullptr;
698 aTextureY->SetPrivateDataInterface(
699 sD3D11TextureUsage,
700 new TextureMemoryMeasurer(aSizeY.width * aSizeY.height));
701 aTextureCb->SetPrivateDataInterface(
702 sD3D11TextureUsage,
703 new TextureMemoryMeasurer(aSizeCbCr.width * aSizeCbCr.height));
704 aTextureCr->SetPrivateDataInterface(
705 sD3D11TextureUsage,
706 new TextureMemoryMeasurer(aSizeCbCr.width * aSizeCbCr.height));
708 RefPtr<IDXGIResource1> resource;
710 aTextureY->QueryInterface((IDXGIResource1**)getter_AddRefs(resource));
712 HANDLE handleY;
713 HRESULT hr = resource->CreateSharedHandle(
714 nullptr, DXGI_SHARED_RESOURCE_READ | DXGI_SHARED_RESOURCE_WRITE, nullptr,
715 &handleY);
716 if (FAILED(hr)) {
717 return nullptr;
719 const RefPtr<gfx::FileHandleWrapper> sharedHandleY =
720 new gfx::FileHandleWrapper(UniqueFileHandle(handleY));
722 aTextureCb->QueryInterface((IDXGIResource1**)getter_AddRefs(resource));
724 HANDLE handleCb;
725 hr = resource->CreateSharedHandle(
726 nullptr, DXGI_SHARED_RESOURCE_READ | DXGI_SHARED_RESOURCE_WRITE, nullptr,
727 &handleCb);
728 if (FAILED(hr)) {
729 return nullptr;
731 const RefPtr<gfx::FileHandleWrapper> sharedHandleCb =
732 new gfx::FileHandleWrapper(UniqueFileHandle(handleCb));
734 aTextureCr->QueryInterface((IDXGIResource1**)getter_AddRefs(resource));
735 HANDLE handleCr;
736 hr = resource->CreateSharedHandle(
737 nullptr, DXGI_SHARED_RESOURCE_READ | DXGI_SHARED_RESOURCE_WRITE, nullptr,
738 &handleCr);
739 if (FAILED(hr)) {
740 return nullptr;
742 const RefPtr<gfx::FileHandleWrapper> sharedHandleCr =
743 new gfx::FileHandleWrapper(UniqueFileHandle(handleCr));
745 DXGIYCbCrTextureData* texture = new DXGIYCbCrTextureData();
746 texture->mHandles[0] = sharedHandleY;
747 texture->mHandles[1] = sharedHandleCb;
748 texture->mHandles[2] = sharedHandleCr;
749 texture->mD3D11Textures[0] = aTextureY;
750 texture->mD3D11Textures[1] = aTextureCb;
751 texture->mD3D11Textures[2] = aTextureCr;
752 texture->mSize = aSize;
753 texture->mSizeY = aSizeY;
754 texture->mSizeCbCr = aSizeCbCr;
755 texture->mColorDepth = aColorDepth;
756 texture->mYUVColorSpace = aYUVColorSpace;
757 texture->mColorRange = aColorRange;
759 return texture;
762 void DXGIYCbCrTextureData::FillInfo(TextureData::Info& aInfo) const {
763 aInfo.size = mSize;
764 aInfo.format = gfx::SurfaceFormat::YUV420;
765 aInfo.supportsMoz2D = false;
766 aInfo.hasSynchronization = false;
769 void DXGIYCbCrTextureData::SerializeSpecific(
770 SurfaceDescriptorDXGIYCbCr* const aOutDesc) {
771 *aOutDesc = SurfaceDescriptorDXGIYCbCr(mHandles[0], mHandles[1], mHandles[2],
772 mSize, mSizeY, mSizeCbCr, mColorDepth,
773 mYUVColorSpace, mColorRange);
776 bool DXGIYCbCrTextureData::Serialize(SurfaceDescriptor& aOutDescriptor) {
777 SurfaceDescriptorDXGIYCbCr desc;
778 SerializeSpecific(&desc);
780 aOutDescriptor = std::move(desc);
781 return true;
784 void DXGIYCbCrTextureData::GetSubDescriptor(
785 RemoteDecoderVideoSubDescriptor* const aOutDesc) {
786 SurfaceDescriptorDXGIYCbCr desc;
787 SerializeSpecific(&desc);
789 *aOutDesc = std::move(desc);
792 void DXGIYCbCrTextureData::Deallocate(LayersIPCChannel*) {
793 mD3D11Textures[0] = nullptr;
794 mD3D11Textures[1] = nullptr;
795 mD3D11Textures[2] = nullptr;
798 TextureFlags DXGIYCbCrTextureData::GetTextureFlags() const {
799 // With WebRender, resource open happens asynchronously on RenderThread.
800 // During opening the resource on host side, TextureClient needs to be alive.
801 // With WAIT_HOST_USAGE_END, keep TextureClient alive during host side usage.
802 return TextureFlags::WAIT_HOST_USAGE_END;
805 already_AddRefed<TextureHost> CreateTextureHostD3D11(
806 const SurfaceDescriptor& aDesc, ISurfaceAllocator* aDeallocator,
807 LayersBackend aBackend, TextureFlags aFlags) {
808 RefPtr<TextureHost> result;
809 switch (aDesc.type()) {
810 case SurfaceDescriptor::TSurfaceDescriptorD3D10: {
811 result =
812 new DXGITextureHostD3D11(aFlags, aDesc.get_SurfaceDescriptorD3D10());
813 break;
815 case SurfaceDescriptor::TSurfaceDescriptorDXGIYCbCr: {
816 result = new DXGIYCbCrTextureHostD3D11(
817 aFlags, aDesc.get_SurfaceDescriptorDXGIYCbCr());
818 break;
820 default: {
821 MOZ_ASSERT_UNREACHABLE("Unsupported SurfaceDescriptor type");
824 return result.forget();
827 already_AddRefed<DrawTarget> D3D11TextureData::BorrowDrawTarget() {
828 MOZ_ASSERT(NS_IsMainThread() || NS_IsInCanvasThreadOrWorker());
830 if (!mDrawTarget && mTexture) {
831 // This may return a null DrawTarget
832 mDrawTarget = Factory::CreateDrawTargetForD3D11Texture(mTexture, mFormat);
833 if (!mDrawTarget) {
834 gfxCriticalNote << "Could not borrow DrawTarget (D3D11) " << (int)mFormat;
838 RefPtr<DrawTarget> result = mDrawTarget;
839 return result.forget();
842 bool D3D11TextureData::UpdateFromSurface(gfx::SourceSurface* aSurface) {
843 // Supporting texture updates after creation requires an ID3D11DeviceContext
844 // and those aren't threadsafe. We'd need to either lock, or have a device for
845 // whatever thread this runs on and we're trying to avoid extra devices (bug
846 // 1284672).
847 MOZ_ASSERT(false,
848 "UpdateFromSurface not supported for D3D11! Use CreateFromSurface "
849 "instead");
850 return false;
853 static RefPtr<ID3D11Texture2D> OpenSharedD3D11Texture(
854 ID3D11Device* const aDevice, const HANDLE handle) {
855 MOZ_ASSERT(aDevice);
857 RefPtr<ID3D11Device1> device1;
858 aDevice->QueryInterface((ID3D11Device1**)getter_AddRefs(device1));
859 if (!device1) {
860 gfxCriticalNoteOnce << "Failed to get ID3D11Device1";
861 return nullptr;
864 RefPtr<ID3D11Texture2D> tex;
865 auto hr = device1->OpenSharedResource1(
866 (HANDLE)handle, __uuidof(ID3D11Texture2D),
867 (void**)(ID3D11Texture2D**)getter_AddRefs(tex));
868 if (FAILED(hr)) {
869 gfxCriticalNote << "Error code from OpenSharedResource1: " << gfx::hexa(hr);
870 return nullptr;
873 return tex;
876 static RefPtr<ID3D11Texture2D> OpenSharedD3D11Texture(
877 DXGITextureHostD3D11* aTextureHost, ID3D11Device* const aDevice) {
878 MOZ_ASSERT(aDevice);
879 MOZ_ASSERT(aTextureHost);
881 const auto& handle = aTextureHost->mHandle;
882 const auto& gpuProcessTextureId = aTextureHost->mGpuProcessTextureId;
884 RefPtr<ID3D11Texture2D> texture;
885 if (gpuProcessTextureId.isSome()) {
886 auto* textureMap = layers::GpuProcessD3D11TextureMap::Get();
887 if (textureMap) {
888 texture = textureMap->GetTexture(gpuProcessTextureId.ref());
890 } else if (handle) {
891 texture = OpenSharedD3D11Texture(aDevice, handle->GetHandle());
894 if (!texture) {
895 return nullptr;
897 return texture;
900 DXGITextureHostD3D11::DXGITextureHostD3D11(
901 TextureFlags aFlags, const SurfaceDescriptorD3D10& aDescriptor)
902 : TextureHost(TextureHostType::DXGI, aFlags),
903 mHandle(aDescriptor.handle()),
904 mGpuProcessTextureId(aDescriptor.gpuProcessTextureId()),
905 mArrayIndex(aDescriptor.arrayIndex()),
906 mGpuProcessQueryId(aDescriptor.gpuProcessQueryId()),
907 mSize(aDescriptor.size()),
908 mFormat(aDescriptor.format()),
909 mHasKeyedMutex(aDescriptor.hasKeyedMutex()),
910 mAcquireFenceInfo(aDescriptor.fenceInfo().isSome()
911 ? aDescriptor.fenceInfo().ref()
912 : gfx::FenceInfo()),
913 mColorSpace(aDescriptor.colorSpace()),
914 mColorRange(aDescriptor.colorRange()) {}
916 already_AddRefed<gfx::DataSourceSurface> DXGITextureHostD3D11::GetAsSurface(
917 gfx::DataSourceSurface* aSurface) {
918 RefPtr<ID3D11Device> d3d11Device =
919 DeviceManagerDx::Get()->GetCompositorDevice();
920 if (!d3d11Device) {
921 return nullptr;
924 RefPtr<ID3D11Texture2D> d3dTexture =
925 OpenSharedD3D11Texture(this, d3d11Device);
926 if (!d3dTexture) {
927 return nullptr;
930 bool isLocked = LockD3DTexture(d3dTexture.get());
931 if (!isLocked) {
932 return nullptr;
935 const auto onExit =
936 mozilla::MakeScopeExit([&]() { UnlockD3DTexture(d3dTexture.get()); });
938 bool isRGB = [&]() {
939 switch (mFormat) {
940 case gfx::SurfaceFormat::R8G8B8X8:
941 case gfx::SurfaceFormat::R8G8B8A8:
942 case gfx::SurfaceFormat::B8G8R8A8:
943 case gfx::SurfaceFormat::B8G8R8X8:
944 return true;
945 default:
946 break;
948 return false;
949 }();
951 if (!isRGB) {
952 return nullptr;
955 D3D11_TEXTURE2D_DESC textureDesc = {0};
956 d3dTexture->GetDesc(&textureDesc);
958 RefPtr<ID3D11DeviceContext> context;
959 d3d11Device->GetImmediateContext(getter_AddRefs(context));
961 textureDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
962 textureDesc.Usage = D3D11_USAGE_STAGING;
963 textureDesc.BindFlags = 0;
964 textureDesc.MiscFlags = 0;
965 textureDesc.MipLevels = 1;
966 RefPtr<ID3D11Texture2D> cpuTexture;
967 HRESULT hr = d3d11Device->CreateTexture2D(&textureDesc, nullptr,
968 getter_AddRefs(cpuTexture));
969 if (FAILED(hr)) {
970 return nullptr;
973 context->CopyResource(cpuTexture, d3dTexture);
975 D3D11_MAPPED_SUBRESOURCE mappedSubresource;
976 hr = context->Map(cpuTexture, 0, D3D11_MAP_READ, 0, &mappedSubresource);
977 if (FAILED(hr)) {
978 return nullptr;
981 RefPtr<DataSourceSurface> surf = gfx::CreateDataSourceSurfaceFromData(
982 IntSize(textureDesc.Width, textureDesc.Height), GetFormat(),
983 (uint8_t*)mappedSubresource.pData, mappedSubresource.RowPitch);
984 context->Unmap(cpuTexture, 0);
985 return surf.forget();
988 already_AddRefed<gfx::DataSourceSurface>
989 DXGITextureHostD3D11::GetAsSurfaceWithDevice(
990 ID3D11Device* const aDevice,
991 DataMutex<RefPtr<VideoProcessorD3D11>>& aVideoProcessorD3D11) {
992 if (!aDevice) {
993 return nullptr;
996 RefPtr<ID3D11Texture2D> d3dTexture = OpenSharedD3D11Texture(this, aDevice);
997 if (!d3dTexture) {
998 return nullptr;
1001 bool isLocked = LockD3DTexture(d3dTexture.get());
1002 if (!isLocked) {
1003 return nullptr;
1006 const auto onExit =
1007 mozilla::MakeScopeExit([&]() { UnlockD3DTexture(d3dTexture.get()); });
1009 bool isRGB = [&]() {
1010 switch (mFormat) {
1011 case gfx::SurfaceFormat::R8G8B8X8:
1012 case gfx::SurfaceFormat::R8G8B8A8:
1013 case gfx::SurfaceFormat::B8G8R8A8:
1014 case gfx::SurfaceFormat::B8G8R8X8:
1015 return true;
1016 default:
1017 break;
1019 return false;
1020 }();
1022 if (isRGB) {
1023 RefPtr<gfx::DrawTarget> dt =
1024 gfx::Factory::CreateDrawTargetForD3D11Texture(d3dTexture, mFormat);
1025 if (!dt) {
1026 return nullptr;
1028 RefPtr<gfx::SourceSurface> surface = dt->Snapshot();
1029 if (!surface) {
1030 return nullptr;
1032 RefPtr<DataSourceSurface> dataSurface = surface->GetDataSurface();
1033 if (!dataSurface) {
1034 return nullptr;
1036 return dataSurface.forget();
1039 if (mFormat != gfx::SurfaceFormat::NV12 &&
1040 mFormat != gfx::SurfaceFormat::P010 &&
1041 mFormat != gfx::SurfaceFormat::P016) {
1042 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
1043 return nullptr;
1046 RefPtr<ID3D11Device> device;
1047 d3dTexture->GetDevice(getter_AddRefs(device));
1048 if (!device) {
1049 gfxCriticalNoteOnce << "Failed to get D3D11 device from source texture";
1050 return nullptr;
1053 RefPtr<ID3D11DeviceContext> context;
1054 device->GetImmediateContext(getter_AddRefs(context));
1056 auto* queryMap = GpuProcessD3D11QueryMap::Get();
1057 if (queryMap && mGpuProcessQueryId.isSome()) {
1058 auto query = queryMap->GetQuery(mGpuProcessQueryId.ref());
1059 if (query) {
1060 // Wait ID3D11Query of D3D11Texture2D copy complete just before blitting
1061 // for video overlay with non Intel GPUs. See Bug 1817617.
1062 BOOL result;
1063 bool ret = layers::WaitForFrameGPUQuery(device, context, query, &result);
1064 if (!ret) {
1065 gfxCriticalNoteOnce << "WaitForFrameGPUQuery() failed";
1067 } else {
1068 gfxCriticalNoteOnce << "Failed to get ID3D11Query";
1072 CD3D11_TEXTURE2D_DESC desc;
1073 d3dTexture->GetDesc(&desc);
1075 desc = CD3D11_TEXTURE2D_DESC(
1076 DXGI_FORMAT_B8G8R8A8_UNORM, desc.Width, desc.Height, 1, 1,
1077 D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE);
1078 desc.MiscFlags =
1079 D3D11_RESOURCE_MISC_SHARED_NTHANDLE | D3D11_RESOURCE_MISC_SHARED;
1081 RefPtr<ID3D11Texture2D> copiedTexture;
1082 HRESULT hr =
1083 device->CreateTexture2D(&desc, nullptr, getter_AddRefs(copiedTexture));
1084 if (FAILED(hr)) {
1085 gfxCriticalNoteOnce << "Failed to create copiedTexture: " << gfx::hexa(hr);
1086 return nullptr;
1090 auto lock = aVideoProcessorD3D11.Lock();
1091 auto& videoProcessor = lock.ref();
1092 if (videoProcessor && (videoProcessor->mDevice != device)) {
1093 videoProcessor = nullptr;
1096 if (!videoProcessor) {
1097 videoProcessor = VideoProcessorD3D11::Create(device);
1098 if (!videoProcessor) {
1099 gfxCriticalNoteOnce << "Failed to create VideoProcessorD3D11";
1100 return nullptr;
1104 if (!videoProcessor->Init(mSize)) {
1105 gfxCriticalNoteOnce << "Failed to init VideoProcessorD3D11";
1106 return nullptr;
1109 if (!videoProcessor->CallVideoProcessorBlt(this, d3dTexture,
1110 copiedTexture)) {
1111 gfxCriticalNoteOnce << "CallVideoProcessorBlt failed";
1112 return nullptr;
1117 // Wait VideoProcessorBlt gpu task complete.
1118 RefPtr<ID3D11Query> query;
1119 CD3D11_QUERY_DESC desc(D3D11_QUERY_EVENT);
1120 hr = device->CreateQuery(&desc, getter_AddRefs(query));
1121 if (FAILED(hr) || !query) {
1122 gfxWarning() << "Could not create D3D11_QUERY_EVENT: " << gfx::hexa(hr);
1123 return nullptr;
1126 context->End(query);
1128 BOOL result;
1129 bool ret = WaitForFrameGPUQuery(device, context, query, &result);
1130 if (!ret) {
1131 gfxCriticalNoteOnce << "WaitForFrameGPUQuery() failed";
1135 RefPtr<IDXGIResource1> resource;
1136 copiedTexture->QueryInterface((IDXGIResource1**)getter_AddRefs(resource));
1137 if (!resource) {
1138 gfxCriticalNoteOnce << "Failed to get IDXGIResource";
1139 return nullptr;
1142 HANDLE sharedHandle;
1143 hr = resource->CreateSharedHandle(
1144 nullptr, DXGI_SHARED_RESOURCE_READ | DXGI_SHARED_RESOURCE_WRITE, nullptr,
1145 &sharedHandle);
1146 if (FAILED(hr)) {
1147 gfxCriticalNoteOnce << "GetSharedHandle failed: " << gfx::hexa(hr);
1148 return nullptr;
1151 RefPtr<gfx::FileHandleWrapper> handle =
1152 new gfx::FileHandleWrapper(UniqueFileHandle(sharedHandle));
1154 d3dTexture = OpenSharedD3D11Texture(aDevice, handle->GetHandle());
1155 if (!d3dTexture) {
1156 gfxCriticalNoteOnce << "Failed to open copied texture handle";
1157 return nullptr;
1160 RefPtr<gfx::DrawTarget> dt = gfx::Factory::CreateDrawTargetForD3D11Texture(
1161 d3dTexture, gfx::SurfaceFormat::B8G8R8A8);
1162 if (!dt) {
1163 gfxCriticalNote << "Failed to create DrawTarget (D3D11)";
1164 return nullptr;
1166 RefPtr<gfx::SourceSurface> surface = dt->Snapshot();
1167 if (!surface) {
1168 return nullptr;
1170 RefPtr<DataSourceSurface> dataSurface = surface->GetDataSurface();
1171 if (!dataSurface) {
1172 return nullptr;
1175 return dataSurface.forget();
1178 void DXGITextureHostD3D11::CreateRenderTexture(
1179 const wr::ExternalImageId& aExternalImageId) {
1180 MOZ_ASSERT(mExternalImageId.isSome());
1182 RefPtr<wr::RenderDXGITextureHost> texture = new wr::RenderDXGITextureHost(
1183 mHandle, mGpuProcessTextureId, mArrayIndex, mFormat, mColorSpace,
1184 mColorRange, mSize, mHasKeyedMutex, mAcquireFenceInfo,
1185 mGpuProcessQueryId);
1186 if (mFlags & TextureFlags::SOFTWARE_DECODED_VIDEO) {
1187 texture->SetIsSoftwareDecodedVideo();
1189 if (mFlags & TextureFlags::DRM_SOURCE) {
1190 texture->SetIsFromDRMSource(/* aIsFromDRMSource */ true);
1192 wr::RenderThread::Get()->RegisterExternalImage(aExternalImageId,
1193 texture.forget());
1196 uint32_t DXGITextureHostD3D11::NumSubTextures() {
1197 switch (GetFormat()) {
1198 case gfx::SurfaceFormat::R8G8B8X8:
1199 case gfx::SurfaceFormat::R8G8B8A8:
1200 case gfx::SurfaceFormat::B8G8R8A8:
1201 case gfx::SurfaceFormat::B8G8R8X8: {
1202 return 1;
1204 case gfx::SurfaceFormat::NV12:
1205 case gfx::SurfaceFormat::P010:
1206 case gfx::SurfaceFormat::P016: {
1207 return 2;
1209 default: {
1210 MOZ_ASSERT_UNREACHABLE("unexpected format");
1211 return 1;
1216 void DXGITextureHostD3D11::PushResourceUpdates(
1217 wr::TransactionBuilder& aResources, ResourceUpdateOp aOp,
1218 const Range<wr::ImageKey>& aImageKeys, const wr::ExternalImageId& aExtID) {
1219 if (!gfx::gfxVars::UseWebRenderANGLE()) {
1220 MOZ_ASSERT_UNREACHABLE("unexpected to be called without ANGLE");
1221 return;
1224 MOZ_ASSERT(mHandle || mGpuProcessTextureId.isSome());
1225 auto method = aOp == TextureHost::ADD_IMAGE
1226 ? &wr::TransactionBuilder::AddExternalImage
1227 : &wr::TransactionBuilder::UpdateExternalImage;
1228 switch (mFormat) {
1229 case gfx::SurfaceFormat::R8G8B8X8:
1230 case gfx::SurfaceFormat::R8G8B8A8:
1231 case gfx::SurfaceFormat::B8G8R8A8:
1232 case gfx::SurfaceFormat::B8G8R8X8: {
1233 MOZ_ASSERT(aImageKeys.length() == 1);
1235 wr::ImageDescriptor descriptor(mSize, GetFormat());
1236 // Prefer TextureExternal unless the backend requires TextureRect.
1237 TextureHost::NativeTexturePolicy policy =
1238 TextureHost::BackendNativeTexturePolicy(aResources.GetBackendType(),
1239 mSize);
1240 auto imageType = policy == TextureHost::NativeTexturePolicy::REQUIRE
1241 ? wr::ExternalImageType::TextureHandle(
1242 wr::ImageBufferKind::TextureRect)
1243 : wr::ExternalImageType::TextureHandle(
1244 wr::ImageBufferKind::TextureExternal);
1245 (aResources.*method)(aImageKeys[0], descriptor, aExtID, imageType, 0,
1246 /* aNormalizedUvs */ false);
1247 break;
1249 case gfx::SurfaceFormat::P010:
1250 case gfx::SurfaceFormat::P016:
1251 case gfx::SurfaceFormat::NV12: {
1252 MOZ_ASSERT(aImageKeys.length() == 2);
1253 MOZ_ASSERT(mSize.width % 2 == 0);
1254 MOZ_ASSERT(mSize.height % 2 == 0);
1256 wr::ImageDescriptor descriptor0(mSize, mFormat == gfx::SurfaceFormat::NV12
1257 ? gfx::SurfaceFormat::A8
1258 : gfx::SurfaceFormat::A16);
1259 wr::ImageDescriptor descriptor1(mSize / 2,
1260 mFormat == gfx::SurfaceFormat::NV12
1261 ? gfx::SurfaceFormat::R8G8
1262 : gfx::SurfaceFormat::R16G16);
1263 // Prefer TextureExternal unless the backend requires TextureRect.
1264 TextureHost::NativeTexturePolicy policy =
1265 TextureHost::BackendNativeTexturePolicy(aResources.GetBackendType(),
1266 mSize);
1267 auto imageType = policy == TextureHost::NativeTexturePolicy::REQUIRE
1268 ? wr::ExternalImageType::TextureHandle(
1269 wr::ImageBufferKind::TextureRect)
1270 : wr::ExternalImageType::TextureHandle(
1271 wr::ImageBufferKind::TextureExternal);
1272 (aResources.*method)(aImageKeys[0], descriptor0, aExtID, imageType, 0,
1273 /* aNormalizedUvs */ false);
1274 (aResources.*method)(aImageKeys[1], descriptor1, aExtID, imageType, 1,
1275 /* aNormalizedUvs */ false);
1276 break;
1278 default: {
1279 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
1284 void DXGITextureHostD3D11::PushDisplayItems(
1285 wr::DisplayListBuilder& aBuilder, const wr::LayoutRect& aBounds,
1286 const wr::LayoutRect& aClip, wr::ImageRendering aFilter,
1287 const Range<wr::ImageKey>& aImageKeys, PushDisplayItemFlagSet aFlags) {
1288 bool preferCompositorSurface =
1289 aFlags.contains(PushDisplayItemFlag::PREFER_COMPOSITOR_SURFACE);
1290 if (!gfx::gfxVars::UseWebRenderANGLE()) {
1291 MOZ_ASSERT_UNREACHABLE("unexpected to be called without ANGLE");
1292 return;
1295 bool preferExternalCompositing =
1296 SupportsExternalCompositing(aBuilder.GetBackendType());
1297 if (aFlags.contains(PushDisplayItemFlag::EXTERNAL_COMPOSITING_DISABLED)) {
1298 MOZ_ASSERT(aBuilder.GetBackendType() != WebRenderBackend::SOFTWARE);
1299 preferExternalCompositing = false;
1302 switch (GetFormat()) {
1303 case gfx::SurfaceFormat::R8G8B8X8:
1304 case gfx::SurfaceFormat::R8G8B8A8:
1305 case gfx::SurfaceFormat::B8G8R8A8:
1306 case gfx::SurfaceFormat::B8G8R8X8: {
1307 MOZ_ASSERT(aImageKeys.length() == 1);
1308 aBuilder.PushImage(aBounds, aClip, true, false, aFilter, aImageKeys[0],
1309 !(mFlags & TextureFlags::NON_PREMULTIPLIED),
1310 wr::ColorF{1.0f, 1.0f, 1.0f, 1.0f},
1311 preferCompositorSurface, preferExternalCompositing);
1312 break;
1314 case gfx::SurfaceFormat::P010:
1315 case gfx::SurfaceFormat::P016:
1316 case gfx::SurfaceFormat::NV12: {
1317 // DXGI_FORMAT_P010 stores its 10 bit value in the most significant bits
1318 // of each 16 bit word with the unused lower bits cleared to zero so that
1319 // it may be handled as if it was DXGI_FORMAT_P016. This is approximately
1320 // perceptually correct. However, due to rounding error, the precise
1321 // quantized value after sampling may be off by 1.
1322 MOZ_ASSERT(aImageKeys.length() == 2);
1323 aBuilder.PushNV12Image(
1324 aBounds, aClip, true, aImageKeys[0], aImageKeys[1],
1325 GetFormat() == gfx::SurfaceFormat::NV12 ? wr::ColorDepth::Color8
1326 : wr::ColorDepth::Color16,
1327 wr::ToWrYuvColorSpace(ToYUVColorSpace(mColorSpace)),
1328 wr::ToWrColorRange(mColorRange), aFilter, preferCompositorSurface,
1329 preferExternalCompositing);
1330 break;
1332 default: {
1333 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
1338 bool DXGITextureHostD3D11::SupportsExternalCompositing(
1339 WebRenderBackend aBackend) {
1340 if (aBackend == WebRenderBackend::SOFTWARE) {
1341 return true;
1343 // XXX Add P010 and P016 support.
1344 if (GetFormat() == gfx::SurfaceFormat::NV12) {
1345 if ((mFlags & TextureFlags::SOFTWARE_DECODED_VIDEO) &&
1346 (gfx::gfxVars::UseWebRenderDCompVideoSwOverlayWin())) {
1347 return true;
1349 if (!(mFlags & TextureFlags::SOFTWARE_DECODED_VIDEO) &&
1350 (gfx::gfxVars::UseWebRenderDCompVideoHwOverlayWin())) {
1351 return true;
1354 return false;
1357 DXGIYCbCrTextureHostD3D11::DXGIYCbCrTextureHostD3D11(
1358 TextureFlags aFlags, const SurfaceDescriptorDXGIYCbCr& aDescriptor)
1359 : TextureHost(TextureHostType::DXGIYCbCr, aFlags),
1360 mSize(aDescriptor.size()),
1361 mSizeY(aDescriptor.sizeY()),
1362 mSizeCbCr(aDescriptor.sizeCbCr()),
1363 mIsLocked(false),
1364 mColorDepth(aDescriptor.colorDepth()),
1365 mYUVColorSpace(aDescriptor.yUVColorSpace()),
1366 mColorRange(aDescriptor.colorRange()) {
1367 mHandles[0] = aDescriptor.handleY();
1368 mHandles[1] = aDescriptor.handleCb();
1369 mHandles[2] = aDescriptor.handleCr();
1372 void DXGIYCbCrTextureHostD3D11::CreateRenderTexture(
1373 const wr::ExternalImageId& aExternalImageId) {
1374 MOZ_ASSERT(mExternalImageId.isSome());
1376 RefPtr<wr::RenderTextureHost> texture = new wr::RenderDXGIYCbCrTextureHost(
1377 mHandles, mYUVColorSpace, mColorDepth, mColorRange, mSizeY, mSizeCbCr);
1379 wr::RenderThread::Get()->RegisterExternalImage(aExternalImageId,
1380 texture.forget());
1383 uint32_t DXGIYCbCrTextureHostD3D11::NumSubTextures() {
1384 // ycbcr use 3 sub textures.
1385 return 3;
1388 void DXGIYCbCrTextureHostD3D11::PushResourceUpdates(
1389 wr::TransactionBuilder& aResources, ResourceUpdateOp aOp,
1390 const Range<wr::ImageKey>& aImageKeys, const wr::ExternalImageId& aExtID) {
1391 if (!gfx::gfxVars::UseWebRenderANGLE()) {
1392 MOZ_ASSERT_UNREACHABLE("unexpected to be called without ANGLE");
1393 return;
1396 MOZ_ASSERT(mHandles[0] && mHandles[1] && mHandles[2]);
1397 MOZ_ASSERT(aImageKeys.length() == 3);
1398 // Assume the chroma planes are rounded up if the luma plane is odd sized.
1399 MOZ_ASSERT((mSizeCbCr.width == mSizeY.width ||
1400 mSizeCbCr.width == (mSizeY.width + 1) >> 1) &&
1401 (mSizeCbCr.height == mSizeY.height ||
1402 mSizeCbCr.height == (mSizeY.height + 1) >> 1));
1404 auto method = aOp == TextureHost::ADD_IMAGE
1405 ? &wr::TransactionBuilder::AddExternalImage
1406 : &wr::TransactionBuilder::UpdateExternalImage;
1408 // Prefer TextureExternal unless the backend requires TextureRect.
1409 // Use a size that is the maximum of the Y and CbCr sizes.
1410 IntSize textureSize = std::max(mSizeY, mSizeCbCr);
1411 TextureHost::NativeTexturePolicy policy =
1412 TextureHost::BackendNativeTexturePolicy(aResources.GetBackendType(),
1413 textureSize);
1414 auto imageType = policy == TextureHost::NativeTexturePolicy::REQUIRE
1415 ? wr::ExternalImageType::TextureHandle(
1416 wr::ImageBufferKind::TextureRect)
1417 : wr::ExternalImageType::TextureHandle(
1418 wr::ImageBufferKind::TextureExternal);
1420 // y
1421 wr::ImageDescriptor descriptor0(mSizeY, gfx::SurfaceFormat::A8);
1422 // cb and cr
1423 wr::ImageDescriptor descriptor1(mSizeCbCr, gfx::SurfaceFormat::A8);
1424 (aResources.*method)(aImageKeys[0], descriptor0, aExtID, imageType, 0,
1425 /* aNormalizedUvs */ false);
1426 (aResources.*method)(aImageKeys[1], descriptor1, aExtID, imageType, 1,
1427 /* aNormalizedUvs */ false);
1428 (aResources.*method)(aImageKeys[2], descriptor1, aExtID, imageType, 2,
1429 /* aNormalizedUvs */ false);
1432 void DXGIYCbCrTextureHostD3D11::PushDisplayItems(
1433 wr::DisplayListBuilder& aBuilder, const wr::LayoutRect& aBounds,
1434 const wr::LayoutRect& aClip, wr::ImageRendering aFilter,
1435 const Range<wr::ImageKey>& aImageKeys, PushDisplayItemFlagSet aFlags) {
1436 if (!gfx::gfxVars::UseWebRenderANGLE()) {
1437 MOZ_ASSERT_UNREACHABLE("unexpected to be called without ANGLE");
1438 return;
1441 MOZ_ASSERT(aImageKeys.length() == 3);
1443 aBuilder.PushYCbCrPlanarImage(
1444 aBounds, aClip, true, aImageKeys[0], aImageKeys[1], aImageKeys[2],
1445 wr::ToWrColorDepth(mColorDepth), wr::ToWrYuvColorSpace(mYUVColorSpace),
1446 wr::ToWrColorRange(mColorRange), aFilter,
1447 aFlags.contains(PushDisplayItemFlag::PREFER_COMPOSITOR_SURFACE),
1448 SupportsExternalCompositing(aBuilder.GetBackendType()));
1451 bool DXGIYCbCrTextureHostD3D11::SupportsExternalCompositing(
1452 WebRenderBackend aBackend) {
1453 return aBackend == WebRenderBackend::SOFTWARE;
1456 bool DataTextureSourceD3D11::Update(DataSourceSurface* aSurface,
1457 nsIntRegion* aDestRegion,
1458 IntPoint* aSrcOffset,
1459 IntPoint* aDstOffset) {
1460 // Incremental update with a source offset is only used on Mac so it is not
1461 // clear that we ever will need to support it for D3D.
1462 MOZ_ASSERT(!aSrcOffset);
1463 MOZ_RELEASE_ASSERT(!aDstOffset);
1464 MOZ_ASSERT(aSurface);
1466 MOZ_ASSERT(mAllowTextureUploads);
1467 if (!mAllowTextureUploads) {
1468 return false;
1471 HRESULT hr;
1473 if (!mDevice) {
1474 return false;
1477 uint32_t bpp = BytesPerPixel(aSurface->GetFormat());
1478 DXGI_FORMAT dxgiFormat = SurfaceFormatToDXGIFormat(aSurface->GetFormat());
1480 mSize = aSurface->GetSize();
1481 mFormat = aSurface->GetFormat();
1483 CD3D11_TEXTURE2D_DESC desc(dxgiFormat, mSize.width, mSize.height, 1, 1);
1485 int32_t maxSize = GetMaxTextureSizeFromDevice(mDevice);
1486 if ((mSize.width <= maxSize && mSize.height <= maxSize) ||
1487 (mFlags & TextureFlags::DISALLOW_BIGIMAGE)) {
1488 if (mTexture) {
1489 D3D11_TEXTURE2D_DESC currentDesc;
1490 mTexture->GetDesc(&currentDesc);
1492 // Make sure there's no size mismatch, if there is, recreate.
1493 if (static_cast<int32_t>(currentDesc.Width) != mSize.width ||
1494 static_cast<int32_t>(currentDesc.Height) != mSize.height ||
1495 currentDesc.Format != dxgiFormat) {
1496 mTexture = nullptr;
1497 // Make sure we upload the whole surface.
1498 aDestRegion = nullptr;
1502 nsIntRegion* regionToUpdate = aDestRegion;
1503 if (!mTexture) {
1504 hr = mDevice->CreateTexture2D(&desc, nullptr, getter_AddRefs(mTexture));
1505 mIsTiled = false;
1506 if (FAILED(hr) || !mTexture) {
1507 Reset();
1508 return false;
1511 if (mFlags & TextureFlags::COMPONENT_ALPHA) {
1512 regionToUpdate = nullptr;
1516 DataSourceSurface::MappedSurface map;
1517 if (!aSurface->Map(DataSourceSurface::MapType::READ, &map)) {
1518 gfxCriticalError() << "Failed to map surface.";
1519 Reset();
1520 return false;
1523 RefPtr<ID3D11DeviceContext> context;
1524 mDevice->GetImmediateContext(getter_AddRefs(context));
1526 if (regionToUpdate) {
1527 for (auto iter = regionToUpdate->RectIter(); !iter.Done(); iter.Next()) {
1528 const IntRect& rect = iter.Get();
1529 D3D11_BOX box;
1530 box.front = 0;
1531 box.back = 1;
1532 box.left = rect.X();
1533 box.top = rect.Y();
1534 box.right = rect.XMost();
1535 box.bottom = rect.YMost();
1537 void* data = map.mData + map.mStride * rect.Y() +
1538 BytesPerPixel(aSurface->GetFormat()) * rect.X();
1540 context->UpdateSubresource(mTexture, 0, &box, data, map.mStride,
1541 map.mStride * rect.Height());
1543 } else {
1544 context->UpdateSubresource(mTexture, 0, nullptr, map.mData, map.mStride,
1545 map.mStride * mSize.height);
1548 aSurface->Unmap();
1549 } else {
1550 mIsTiled = true;
1551 uint32_t tileCount = GetRequiredTilesD3D11(mSize.width, maxSize) *
1552 GetRequiredTilesD3D11(mSize.height, maxSize);
1554 mTileTextures.resize(tileCount);
1555 mTileSRVs.resize(tileCount);
1556 mTexture = nullptr;
1558 DataSourceSurface::ScopedMap map(aSurface, DataSourceSurface::READ);
1559 if (!map.IsMapped()) {
1560 gfxCriticalError() << "Failed to map surface.";
1561 Reset();
1562 return false;
1565 for (uint32_t i = 0; i < tileCount; i++) {
1566 IntRect tileRect = GetTileRect(i);
1568 desc.Width = tileRect.Width();
1569 desc.Height = tileRect.Height();
1570 desc.Usage = D3D11_USAGE_IMMUTABLE;
1572 D3D11_SUBRESOURCE_DATA initData;
1573 initData.pSysMem =
1574 map.GetData() + tileRect.Y() * map.GetStride() + tileRect.X() * bpp;
1575 initData.SysMemPitch = map.GetStride();
1577 hr = mDevice->CreateTexture2D(&desc, &initData,
1578 getter_AddRefs(mTileTextures[i]));
1579 if (FAILED(hr) || !mTileTextures[i]) {
1580 Reset();
1581 return false;
1585 return true;
1588 ID3D11Texture2D* DataTextureSourceD3D11::GetD3D11Texture() const {
1589 return mIterating ? mTileTextures[mCurrentTile] : mTexture;
1592 RefPtr<TextureSource> DataTextureSourceD3D11::ExtractCurrentTile() {
1593 MOZ_ASSERT(mIterating);
1594 return new DataTextureSourceD3D11(mDevice, mFormat,
1595 mTileTextures[mCurrentTile]);
1598 ID3D11ShaderResourceView* DataTextureSourceD3D11::GetShaderResourceView() {
1599 if (mIterating) {
1600 if (!mTileSRVs[mCurrentTile]) {
1601 if (!mTileTextures[mCurrentTile]) {
1602 return nullptr;
1605 RefPtr<ID3D11Device> device;
1606 mTileTextures[mCurrentTile]->GetDevice(getter_AddRefs(device));
1607 HRESULT hr = device->CreateShaderResourceView(
1608 mTileTextures[mCurrentTile], nullptr,
1609 getter_AddRefs(mTileSRVs[mCurrentTile]));
1610 if (FAILED(hr)) {
1611 gfxCriticalNote
1612 << "[D3D11] DataTextureSourceD3D11:GetShaderResourceView CreateSRV "
1613 "failure "
1614 << gfx::hexa(hr);
1615 return nullptr;
1618 return mTileSRVs[mCurrentTile];
1621 return TextureSourceD3D11::GetShaderResourceView();
1624 void DataTextureSourceD3D11::Reset() {
1625 mTexture = nullptr;
1626 mTileSRVs.resize(0);
1627 mTileTextures.resize(0);
1628 mIsTiled = false;
1629 mSize.width = 0;
1630 mSize.height = 0;
1633 IntRect DataTextureSourceD3D11::GetTileRect(uint32_t aIndex) const {
1634 return GetTileRectD3D11(aIndex, mSize, GetMaxTextureSizeFromDevice(mDevice));
1637 IntRect DataTextureSourceD3D11::GetTileRect() {
1638 IntRect rect = GetTileRect(mCurrentTile);
1639 return IntRect(rect.X(), rect.Y(), rect.Width(), rect.Height());
1642 CompositingRenderTargetD3D11::CompositingRenderTargetD3D11(
1643 ID3D11Texture2D* aTexture, const gfx::IntPoint& aOrigin,
1644 DXGI_FORMAT aFormatOverride)
1645 : CompositingRenderTarget(aOrigin) {
1646 MOZ_ASSERT(aTexture);
1648 mTexture = aTexture;
1650 RefPtr<ID3D11Device> device;
1651 mTexture->GetDevice(getter_AddRefs(device));
1653 mFormatOverride = aFormatOverride;
1655 // If we happen to have a typeless underlying DXGI surface, we need to be
1656 // explicit about the format here. (Such a surface could come from an external
1657 // source, such as the Oculus compositor)
1658 CD3D11_RENDER_TARGET_VIEW_DESC rtvDesc(D3D11_RTV_DIMENSION_TEXTURE2D,
1659 mFormatOverride);
1660 D3D11_RENDER_TARGET_VIEW_DESC* desc =
1661 aFormatOverride == DXGI_FORMAT_UNKNOWN ? nullptr : &rtvDesc;
1663 HRESULT hr =
1664 device->CreateRenderTargetView(mTexture, desc, getter_AddRefs(mRTView));
1666 if (FAILED(hr)) {
1667 LOGD3D11("Failed to create RenderTargetView.");
1671 void CompositingRenderTargetD3D11::BindRenderTarget(
1672 ID3D11DeviceContext* aContext) {
1673 if (mClearOnBind) {
1674 FLOAT clear[] = {0, 0, 0, 0};
1675 aContext->ClearRenderTargetView(mRTView, clear);
1676 mClearOnBind = false;
1678 ID3D11RenderTargetView* view = mRTView;
1679 aContext->OMSetRenderTargets(1, &view, nullptr);
1682 IntSize CompositingRenderTargetD3D11::GetSize() const {
1683 return TextureSourceD3D11::GetSize();
1686 static inline bool ShouldDevCrashOnSyncInitFailure() {
1687 // Compositor shutdown does not wait for video decoding to finish, so it is
1688 // possible for the compositor to destroy the SyncObject before video has a
1689 // chance to initialize it.
1690 if (!NS_IsMainThread()) {
1691 return false;
1694 // Note: CompositorIsInGPUProcess is a main-thread-only function.
1695 return !CompositorBridgeChild::CompositorIsInGPUProcess() &&
1696 !DeviceManagerDx::Get()->HasDeviceReset();
1699 SyncObjectD3D11Host::SyncObjectD3D11Host(ID3D11Device* aDevice)
1700 : mSyncHandle(nullptr), mDevice(aDevice) {
1701 MOZ_ASSERT(aDevice);
1704 bool SyncObjectD3D11Host::Init() {
1705 CD3D11_TEXTURE2D_DESC desc(
1706 DXGI_FORMAT_B8G8R8A8_UNORM, 1, 1, 1, 1,
1707 D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET);
1708 desc.MiscFlags = D3D11_RESOURCE_MISC_SHARED_NTHANDLE |
1709 D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX;
1711 RefPtr<ID3D11Texture2D> texture;
1712 HRESULT hr =
1713 mDevice->CreateTexture2D(&desc, nullptr, getter_AddRefs(texture));
1714 if (FAILED(hr) || !texture) {
1715 gfxWarning() << "Could not create a sync texture: " << gfx::hexa(hr);
1716 return false;
1719 hr = texture->QueryInterface((IDXGIResource1**)getter_AddRefs(mSyncTexture));
1720 if (FAILED(hr) || !mSyncTexture) {
1721 gfxWarning() << "Could not QI sync texture: " << gfx::hexa(hr);
1722 return false;
1725 hr = mSyncTexture->QueryInterface(
1726 (IDXGIKeyedMutex**)getter_AddRefs(mKeyedMutex));
1727 if (FAILED(hr) || !mKeyedMutex) {
1728 gfxWarning() << "Could not QI keyed-mutex: " << gfx::hexa(hr);
1729 return false;
1732 HANDLE sharedHandle;
1733 hr = mSyncTexture->CreateSharedHandle(
1734 nullptr, DXGI_SHARED_RESOURCE_READ | DXGI_SHARED_RESOURCE_WRITE, nullptr,
1735 &sharedHandle);
1736 if (FAILED(hr)) {
1737 gfxWarning() << "Could not get sync texture shared handle: "
1738 << gfx::hexa(hr);
1739 return false;
1741 mSyncHandle = new gfx::FileHandleWrapper(UniqueFileHandle(sharedHandle));
1743 return true;
1746 SyncHandle SyncObjectD3D11Host::GetSyncHandle() { return mSyncHandle; }
1748 bool SyncObjectD3D11Host::Synchronize(bool aFallible) {
1749 HRESULT hr;
1750 AutoTextureLock lock(mKeyedMutex, hr, 10000);
1752 if (hr == WAIT_TIMEOUT) {
1753 hr = mDevice->GetDeviceRemovedReason();
1754 if (hr != S_OK) {
1755 // Since the timeout is related to the driver-removed. Return false for
1756 // error handling.
1757 gfxCriticalNote << "GFX: D3D11 timeout with device-removed:"
1758 << gfx::hexa(hr);
1759 } else if (aFallible) {
1760 gfxCriticalNote << "GFX: D3D11 timeout on the D3D11 sync lock.";
1761 } else {
1762 // There is no driver-removed event. Crash with this timeout.
1763 MOZ_CRASH("GFX: D3D11 normal status timeout");
1766 return false;
1768 if (hr == WAIT_ABANDONED) {
1769 gfxCriticalNote << "GFX: AL_D3D11 abandoned sync";
1772 return true;
1775 SyncObjectD3D11Client::SyncObjectD3D11Client(SyncHandle aSyncHandle,
1776 ID3D11Device* aDevice)
1777 : mSyncLock("SyncObjectD3D11"), mSyncHandle(aSyncHandle), mDevice(aDevice) {
1778 MOZ_ASSERT(aDevice);
1781 SyncObjectD3D11Client::SyncObjectD3D11Client(SyncHandle aSyncHandle)
1782 : mSyncLock("SyncObjectD3D11"), mSyncHandle(aSyncHandle) {}
1784 bool SyncObjectD3D11Client::Init(ID3D11Device* aDevice, bool aFallible) {
1785 if (mKeyedMutex) {
1786 return true;
1789 if (!mSyncHandle) {
1790 return false;
1793 RefPtr<ID3D11Device1> device1;
1794 aDevice->QueryInterface((ID3D11Device1**)getter_AddRefs(device1));
1795 if (!device1) {
1796 gfxCriticalNoteOnce << "Failed to get ID3D11Device1";
1797 return 0;
1800 HRESULT hr = device1->OpenSharedResource1(
1801 mSyncHandle->GetHandle(), __uuidof(ID3D11Texture2D),
1802 (void**)(ID3D11Texture2D**)getter_AddRefs(mSyncTexture));
1803 if (FAILED(hr) || !mSyncTexture) {
1804 gfxCriticalNote << "Failed to OpenSharedResource1 for SyncObjectD3D11: "
1805 << hexa(hr);
1806 if (!aFallible && ShouldDevCrashOnSyncInitFailure()) {
1807 gfxDevCrash(LogReason::D3D11FinalizeFrame)
1808 << "Without device reset: " << hexa(hr);
1810 return false;
1813 hr = mSyncTexture->QueryInterface(__uuidof(IDXGIKeyedMutex),
1814 getter_AddRefs(mKeyedMutex));
1815 if (FAILED(hr) || !mKeyedMutex) {
1816 // Leave both the critical error and MOZ_CRASH for now; the critical error
1817 // lets us "save" the hr value. We will probably eventually replace this
1818 // with gfxDevCrash.
1819 if (!aFallible) {
1820 gfxCriticalError() << "Failed to get KeyedMutex (2): " << hexa(hr);
1821 MOZ_CRASH("GFX: Cannot get D3D11 KeyedMutex");
1822 } else {
1823 gfxCriticalNote << "Failed to get KeyedMutex (3): " << hexa(hr);
1825 return false;
1828 return true;
1831 void SyncObjectD3D11Client::RegisterTexture(ID3D11Texture2D* aTexture) {
1832 mSyncedTextures.push_back(aTexture);
1835 bool SyncObjectD3D11Client::IsSyncObjectValid() {
1836 MOZ_ASSERT(mDevice);
1837 return true;
1840 // We have only 1 sync object. As a thing that somehow works,
1841 // we copy each of the textures that need to be synced with the compositor
1842 // into our sync object and only use a lock for this sync object.
1843 // This way, we don't have to sync every texture we send to the compositor.
1844 // We only have to do this once per transaction.
1845 bool SyncObjectD3D11Client::Synchronize(bool aFallible) {
1846 MOZ_ASSERT(mDevice);
1847 // Since this can be called from either the Paint or Main thread.
1848 // We don't want this to race since we initialize the sync texture here
1849 // too.
1850 MutexAutoLock syncLock(mSyncLock);
1852 if (!mSyncedTextures.size()) {
1853 return true;
1855 if (!Init(mDevice, aFallible)) {
1856 return false;
1859 return SynchronizeInternal(mDevice, aFallible);
1862 bool SyncObjectD3D11Client::SynchronizeInternal(ID3D11Device* aDevice,
1863 bool aFallible) {
1864 mSyncLock.AssertCurrentThreadOwns();
1866 HRESULT hr;
1867 AutoTextureLock lock(mKeyedMutex, hr, 20000);
1869 if (hr == WAIT_TIMEOUT) {
1870 if (DeviceManagerDx::Get()->HasDeviceReset()) {
1871 gfxWarning() << "AcquireSync timed out because of device reset.";
1872 return false;
1874 if (aFallible) {
1875 gfxWarning() << "Timeout on the D3D11 sync lock.";
1876 } else {
1877 gfxDevCrash(LogReason::D3D11SyncLock)
1878 << "Timeout on the D3D11 sync lock.";
1880 return false;
1883 D3D11_BOX box;
1884 box.front = box.top = box.left = 0;
1885 box.back = box.bottom = box.right = 1;
1887 RefPtr<ID3D11DeviceContext> ctx;
1888 aDevice->GetImmediateContext(getter_AddRefs(ctx));
1890 for (auto iter = mSyncedTextures.begin(); iter != mSyncedTextures.end();
1891 iter++) {
1892 ctx->CopySubresourceRegion(mSyncTexture, 0, 0, 0, 0, *iter, 0, &box);
1895 mSyncedTextures.clear();
1897 return true;
1900 uint32_t GetMaxTextureSizeFromDevice(ID3D11Device* aDevice) {
1901 return GetMaxTextureSizeForFeatureLevel(aDevice->GetFeatureLevel());
1904 AutoLockD3D11Texture::AutoLockD3D11Texture(ID3D11Texture2D* aTexture) {
1905 aTexture->QueryInterface((IDXGIKeyedMutex**)getter_AddRefs(mMutex));
1906 if (!mMutex) {
1907 return;
1909 HRESULT hr = mMutex->AcquireSync(0, 10000);
1910 if (hr == WAIT_TIMEOUT) {
1911 MOZ_CRASH("GFX: IMFYCbCrImage timeout");
1914 if (FAILED(hr)) {
1915 NS_WARNING("Failed to lock the texture");
1919 AutoLockD3D11Texture::~AutoLockD3D11Texture() {
1920 if (!mMutex) {
1921 return;
1923 HRESULT hr = mMutex->ReleaseSync(0);
1924 if (FAILED(hr)) {
1925 NS_WARNING("Failed to unlock the texture");
1929 SyncObjectD3D11ClientContentDevice::SyncObjectD3D11ClientContentDevice(
1930 SyncHandle aSyncHandle)
1931 : SyncObjectD3D11Client(aSyncHandle) {}
1933 bool SyncObjectD3D11ClientContentDevice::Synchronize(bool aFallible) {
1934 // Since this can be called from either the Paint or Main thread.
1935 // We don't want this to race since we initialize the sync texture here
1936 // too.
1937 MutexAutoLock syncLock(mSyncLock);
1939 MOZ_ASSERT(mContentDevice);
1941 if (!mSyncedTextures.size()) {
1942 return true;
1945 if (!Init(mContentDevice, aFallible)) {
1946 return false;
1949 RefPtr<ID3D11Device> dev;
1950 mSyncTexture->GetDevice(getter_AddRefs(dev));
1952 if (dev == DeviceManagerDx::Get()->GetContentDevice()) {
1953 if (DeviceManagerDx::Get()->HasDeviceReset()) {
1954 return false;
1958 if (dev != mContentDevice) {
1959 gfxWarning() << "Attempt to sync texture from invalid device.";
1960 return false;
1963 return SyncObjectD3D11Client::SynchronizeInternal(dev, aFallible);
1966 bool SyncObjectD3D11ClientContentDevice::IsSyncObjectValid() {
1967 RefPtr<ID3D11Device> dev;
1968 // There is a case that devices are not initialized yet with WebRender.
1969 if (gfxPlatform::GetPlatform()->DevicesInitialized()) {
1970 dev = DeviceManagerDx::Get()->GetContentDevice();
1973 // Update mDevice if the ContentDevice initialization is detected.
1974 if (!mContentDevice && dev && NS_IsMainThread()) {
1975 mContentDevice = dev;
1978 if (!dev || (NS_IsMainThread() && dev != mContentDevice)) {
1979 return false;
1981 return true;
1984 void SyncObjectD3D11ClientContentDevice::EnsureInitialized() {
1985 if (mContentDevice) {
1986 return;
1989 if (XRE_IsGPUProcess() || !gfxPlatform::GetPlatform()->DevicesInitialized()) {
1990 return;
1993 mContentDevice = DeviceManagerDx::Get()->GetContentDevice();
1996 } // namespace layers
1997 } // namespace mozilla