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 "TextureHostWrapperD3D11.h"
11 #include "mozilla/gfx/DeviceManagerDx.h"
12 #include "mozilla/layers/AsyncImagePipelineManager.h"
13 #include "mozilla/layers/CompositorThread.h"
14 #include "mozilla/layers/GpuProcessD3D11TextureMap.h"
15 #include "mozilla/layers/TextureD3D11.h"
16 #include "mozilla/layers/WebRenderTextureHost.h"
17 #include "mozilla/SharedThreadPool.h"
22 TextureWrapperD3D11Allocator::TextureWrapperD3D11Allocator()
23 : mThread(SharedThreadPool::Get("TextureUpdate"_ns
, 1)),
24 mMutex("TextureWrapperD3D11Allocator::mMutex") {}
25 TextureWrapperD3D11Allocator::~TextureWrapperD3D11Allocator() = default;
27 RefPtr
<ID3D11Texture2D
> TextureWrapperD3D11Allocator::CreateOrRecycle(
28 gfx::SurfaceFormat aSurfaceFormat
, gfx::IntSize aSize
) {
29 MOZ_ASSERT(mThread
->IsOnCurrentThread());
31 RefPtr
<ID3D11Device
> device
= gfx::DeviceManagerDx::Get()->GetImageDevice();
33 MutexAutoLock
lock(mMutex
);
34 if (!!mDevice
&& mDevice
!= device
) {
35 // Device reset might happen
36 ClearAllTextures(lock
);
42 MOZ_ASSERT(mDevice
== gfx::DeviceManagerDx::Get()->GetCompositorDevice());
46 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
50 if (aSurfaceFormat
!= gfx::SurfaceFormat::NV12
) {
51 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
56 ClearAllTextures(lock
);
60 if (!mRecycledTextures
.empty()) {
61 RefPtr
<ID3D11Texture2D
> texture2D
= mRecycledTextures
.front();
62 mRecycledTextures
.pop_front();
67 CD3D11_TEXTURE2D_DESC
desc(
68 DXGI_FORMAT_NV12
, mSize
.width
, mSize
.height
, 1, 1,
69 D3D11_BIND_RENDER_TARGET
| D3D11_BIND_SHADER_RESOURCE
);
71 RefPtr
<ID3D11Texture2D
> texture2D
;
73 device
->CreateTexture2D(&desc
, nullptr, getter_AddRefs(texture2D
));
74 if (FAILED(hr
) || !texture2D
) {
78 EnsureStagingTextureNV12(device
);
79 if (!mStagingTexture
) {
86 void TextureWrapperD3D11Allocator::EnsureStagingTextureNV12(
87 RefPtr
<ID3D11Device
> aDevice
) {
88 MOZ_ASSERT(mThread
->IsOnCurrentThread());
91 if (mStagingTexture
) {
95 D3D11_TEXTURE2D_DESC desc
= {};
96 desc
.Width
= mSize
.width
;
97 desc
.Height
= mSize
.height
;
98 desc
.Format
= DXGI_FORMAT_NV12
;
101 desc
.Usage
= D3D11_USAGE_STAGING
;
103 desc
.CPUAccessFlags
= D3D11_CPU_ACCESS_WRITE
;
105 desc
.SampleDesc
.Count
= 1;
107 RefPtr
<ID3D11Texture2D
> stagingTexture
;
109 aDevice
->CreateTexture2D(&desc
, nullptr, getter_AddRefs(stagingTexture
));
110 if (FAILED(hr
) || !stagingTexture
) {
113 mStagingTexture
= stagingTexture
;
116 RefPtr
<ID3D11Texture2D
> TextureWrapperD3D11Allocator::GetStagingTextureNV12() {
117 MOZ_ASSERT(mThread
->IsOnCurrentThread());
119 return mStagingTexture
;
122 RefPtr
<ID3D11Device
> TextureWrapperD3D11Allocator::GetDevice() {
123 MOZ_ASSERT(mThread
->IsOnCurrentThread());
125 MutexAutoLock
lock(mMutex
);
129 void TextureWrapperD3D11Allocator::ClearAllTextures(
130 const MutexAutoLock
& aProofOfLock
) {
131 MOZ_ASSERT(mThread
->IsOnCurrentThread());
133 mStagingTexture
= nullptr;
134 mRecycledTextures
.clear();
137 void TextureWrapperD3D11Allocator::RecycleTexture(
138 RefPtr
<ID3D11Texture2D
>& aTexture
) {
139 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
140 MOZ_ASSERT(aTexture
);
142 RefPtr
<ID3D11Device
> device
;
143 aTexture
->GetDevice(getter_AddRefs(device
));
145 D3D11_TEXTURE2D_DESC desc
;
146 aTexture
->GetDesc(&desc
);
149 MutexAutoLock
lock(mMutex
);
150 if (device
!= mDevice
|| desc
.Format
!= DXGI_FORMAT_NV12
||
151 desc
.Width
!= static_cast<UINT
>(mSize
.width
) ||
152 desc
.Height
!= static_cast<UINT
>(mSize
.height
)) {
156 const auto kMaxPooledSized
= 5;
157 if (mRecycledTextures
.size() > kMaxPooledSized
) {
160 mRecycledTextures
.emplace_back(aTexture
);
164 void TextureWrapperD3D11Allocator::RegisterTextureHostWrapper(
165 const wr::ExternalImageId
& aExternalImageId
,
166 RefPtr
<TextureHost
> aTextureHost
) {
167 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
169 auto it
= mTextureHostWrappers
.find(wr::AsUint64(aExternalImageId
));
170 if (it
!= mTextureHostWrappers
.end()) {
171 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
174 mTextureHostWrappers
.emplace(wr::AsUint64(aExternalImageId
), aTextureHost
);
177 void TextureWrapperD3D11Allocator::UnregisterTextureHostWrapper(
178 const wr::ExternalImageId
& aExternalImageId
) {
179 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
181 auto it
= mTextureHostWrappers
.find(wr::AsUint64(aExternalImageId
));
182 if (it
== mTextureHostWrappers
.end()) {
183 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
186 mTextureHostWrappers
.erase(it
);
189 RefPtr
<TextureHost
> TextureWrapperD3D11Allocator::GetTextureHostWrapper(
190 const wr::ExternalImageId
& aExternalImageId
) {
191 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
193 auto it
= mTextureHostWrappers
.find(wr::AsUint64(aExternalImageId
));
194 if (it
== mTextureHostWrappers
.end()) {
201 RefPtr
<TextureHost
> TextureHostWrapperD3D11::CreateFromBufferTexture(
202 const RefPtr
<TextureWrapperD3D11Allocator
>& aAllocator
,
203 TextureHost
* aTextureHost
) {
204 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
205 MOZ_ASSERT(aAllocator
);
206 MOZ_ASSERT(aTextureHost
);
208 if (!XRE_IsGPUProcess()) {
212 auto* bufferTexture
= aTextureHost
->AsBufferTextureHost();
213 if (!bufferTexture
|| bufferTexture
->GetFormat() != gfx::SurfaceFormat::YUV
) {
214 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
218 auto extId
= aTextureHost
->GetMaybeExternalImageId();
219 MOZ_RELEASE_ASSERT(extId
.isSome());
221 // Reuse TextureHostWrapperD3D11 if it is still valid.
222 RefPtr
<TextureHost
> textureHost
=
223 aAllocator
->GetTextureHostWrapper(extId
.ref());
228 auto size
= bufferTexture
->GetSize();
229 auto colorDepth
= bufferTexture
->GetColorDepth();
230 auto colorRange
= bufferTexture
->GetColorRange();
231 auto chromaSubsampling
= bufferTexture
->GetChromaSubsampling();
233 // Check if data could be used with NV12
234 // XXX support gfx::ColorRange::FULL
235 if (size
.width
% 2 != 0 || size
.height
% 2 != 0 ||
236 colorDepth
!= gfx::ColorDepth::COLOR_8
||
237 colorRange
!= gfx::ColorRange::LIMITED
||
238 chromaSubsampling
!= gfx::ChromaSubsampling::HALF_WIDTH_AND_HEIGHT
) {
242 auto id
= GpuProcessD3D11TextureMap::GetNextTextureId();
243 auto flags
= aTextureHost
->GetFlags() | TextureFlags::SOFTWARE_DECODED_VIDEO
;
245 auto colorSpace
= ToColorSpace2(bufferTexture
->GetYUVColorSpace());
248 SurfaceDescriptorD3D10(WindowsHandle(nullptr), Some(id
),
249 /* arrayIndex */ 0, gfx::SurfaceFormat::NV12
, size
,
250 colorSpace
, colorRange
, /* hasKeyedMutex */ false);
252 RefPtr
<DXGITextureHostD3D11
> textureHostD3D11
=
253 new DXGITextureHostD3D11(flags
, descD3D10
);
255 RefPtr
<TextureHostWrapperD3D11
> textureHostWrapper
=
256 new TextureHostWrapperD3D11(flags
, aAllocator
, id
, textureHostD3D11
,
257 aTextureHost
, extId
.ref());
258 textureHostWrapper
->PostTask();
260 auto externalImageId
= AsyncImagePipelineManager::GetNextExternalImageId();
263 new WebRenderTextureHost(flags
, textureHostWrapper
, externalImageId
);
264 aAllocator
->RegisterTextureHostWrapper(extId
.ref(), textureHost
);
269 TextureHostWrapperD3D11::TextureHostWrapperD3D11(
270 TextureFlags aFlags
, const RefPtr
<TextureWrapperD3D11Allocator
>& aAllocator
,
271 const GpuProcessTextureId aTextureId
,
272 DXGITextureHostD3D11
* aTextureHostD3D11
, TextureHost
* aWrappedTextureHost
,
273 const wr::ExternalImageId aWrappedExternalImageId
)
274 : TextureHost(TextureHostType::DXGI
, aFlags
),
275 mAllocator(aAllocator
),
276 mTextureId(aTextureId
),
277 mTextureHostD3D11(aTextureHostD3D11
),
278 mWrappedTextureHost(aWrappedTextureHost
),
279 mWrappedExternalImageId(aWrappedExternalImageId
) {
280 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
281 MOZ_ASSERT(mAllocator
);
282 MOZ_ASSERT(mTextureHostD3D11
);
283 MOZ_ASSERT(mWrappedTextureHost
);
285 MOZ_COUNT_CTOR(TextureHostWrapperD3D11
);
288 TextureHostWrapperD3D11::~TextureHostWrapperD3D11() {
289 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
290 MOZ_COUNT_DTOR(TextureHostWrapperD3D11
);
292 auto* textureMap
= GpuProcessD3D11TextureMap::Get();
294 RefPtr
<ID3D11Texture2D
> texture
= textureMap
->GetTexture(mTextureId
);
296 mAllocator
->RecycleTexture(texture
);
297 textureMap
->Unregister(mTextureId
);
300 gfxCriticalNoteOnce
<< "GpuProcessD3D11TextureMap does not exist";
304 void TextureHostWrapperD3D11::PostTask() {
305 GpuProcessD3D11TextureMap::Get()->PostUpdateTextureDataTask(
306 mTextureId
, this, mWrappedTextureHost
, mAllocator
);
309 bool TextureHostWrapperD3D11::IsValid() { return true; }
311 gfx::ColorRange
TextureHostWrapperD3D11::GetColorRange() const {
312 return mTextureHostD3D11
->GetColorRange();
315 gfx::IntSize
TextureHostWrapperD3D11::GetSize() const {
316 return mTextureHostD3D11
->GetSize();
319 gfx::SurfaceFormat
TextureHostWrapperD3D11::GetFormat() const {
320 return mTextureHostD3D11
->GetFormat();
323 void TextureHostWrapperD3D11::CreateRenderTexture(
324 const wr::ExternalImageId
& aExternalImageId
) {
325 MOZ_ASSERT(mExternalImageId
.isSome());
327 mTextureHostD3D11
->EnsureRenderTexture(mExternalImageId
);
330 void TextureHostWrapperD3D11::MaybeDestroyRenderTexture() {
331 // TextureHostWrapperD3D11 does not create RenderTexture, then
332 // TextureHostWrapperD3D11 does not need to destroy RenderTexture.
333 mExternalImageId
= Nothing();
336 uint32_t TextureHostWrapperD3D11::NumSubTextures() {
337 return mTextureHostD3D11
->NumSubTextures();
340 void TextureHostWrapperD3D11::PushResourceUpdates(
341 wr::TransactionBuilder
& aResources
, ResourceUpdateOp aOp
,
342 const Range
<wr::ImageKey
>& aImageKeys
, const wr::ExternalImageId
& aExtID
) {
343 mTextureHostD3D11
->PushResourceUpdates(aResources
, aOp
, aImageKeys
, aExtID
);
346 void TextureHostWrapperD3D11::PushDisplayItems(
347 wr::DisplayListBuilder
& aBuilder
, const wr::LayoutRect
& aBounds
,
348 const wr::LayoutRect
& aClip
, wr::ImageRendering aFilter
,
349 const Range
<wr::ImageKey
>& aImageKeys
, PushDisplayItemFlagSet aFlags
) {
350 MOZ_ASSERT(aImageKeys
.length() > 0);
352 mTextureHostD3D11
->PushDisplayItems(aBuilder
, aBounds
, aClip
, aFilter
,
356 bool TextureHostWrapperD3D11::SupportsExternalCompositing(
357 WebRenderBackend aBackend
) {
358 return mTextureHostD3D11
->SupportsExternalCompositing(aBackend
);
361 void TextureHostWrapperD3D11::UnbindTextureSource() {
362 mTextureHostD3D11
->UnbindTextureSource();
363 // Handle read unlock
364 TextureHost::UnbindTextureSource();
367 void TextureHostWrapperD3D11::NotifyNotUsed() {
368 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
370 mAllocator
->UnregisterTextureHostWrapper(mWrappedExternalImageId
);
372 MOZ_ASSERT(mWrappedTextureHost
);
373 if (mWrappedTextureHost
) {
374 mWrappedTextureHost
= nullptr;
376 mTextureHostD3D11
->NotifyNotUsed();
377 TextureHost::NotifyNotUsed();
380 BufferTextureHost
* TextureHostWrapperD3D11::AsBufferTextureHost() {
384 bool TextureHostWrapperD3D11::IsWrappingSurfaceTextureHost() { return false; }
386 TextureHostType
TextureHostWrapperD3D11::GetTextureHostType() {
387 return mTextureHostD3D11
->GetTextureHostType();
390 bool TextureHostWrapperD3D11::NeedsDeferredDeletion() const {
391 return mTextureHostD3D11
->NeedsDeferredDeletion();
394 } // namespace layers
395 } // namespace mozilla