Bug 1839315: part 4) Link from `SheetLoadData::mWasAlternate` to spec. r=emilio DONTBUILD
[gecko.git] / gfx / layers / d3d11 / TextureHostWrapperD3D11.cpp
blob067935a7824243c36c95612551aa8db352469dda
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"
9 #include <d3d11.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"
19 namespace mozilla {
20 namespace layers {
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);
37 mDevice = nullptr;
40 if (!mDevice) {
41 mDevice = device;
42 MOZ_ASSERT(mDevice == gfx::DeviceManagerDx::Get()->GetCompositorDevice());
45 if (!mDevice) {
46 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
47 return nullptr;
50 if (aSurfaceFormat != gfx::SurfaceFormat::NV12) {
51 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
52 return nullptr;
55 if (mSize != aSize) {
56 ClearAllTextures(lock);
57 mSize = aSize;
60 if (!mRecycledTextures.empty()) {
61 RefPtr<ID3D11Texture2D> texture2D = mRecycledTextures.front();
62 mRecycledTextures.pop_front();
63 return texture2D;
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;
72 HRESULT hr =
73 device->CreateTexture2D(&desc, nullptr, getter_AddRefs(texture2D));
74 if (FAILED(hr) || !texture2D) {
75 return nullptr;
78 EnsureStagingTextureNV12(device);
79 if (!mStagingTexture) {
80 return nullptr;
83 return texture2D;
86 void TextureWrapperD3D11Allocator::EnsureStagingTextureNV12(
87 RefPtr<ID3D11Device> aDevice) {
88 MOZ_ASSERT(mThread->IsOnCurrentThread());
89 MOZ_ASSERT(aDevice);
91 if (mStagingTexture) {
92 return;
95 D3D11_TEXTURE2D_DESC desc = {};
96 desc.Width = mSize.width;
97 desc.Height = mSize.height;
98 desc.Format = DXGI_FORMAT_NV12;
99 desc.MipLevels = 1;
100 desc.ArraySize = 1;
101 desc.Usage = D3D11_USAGE_STAGING;
102 desc.BindFlags = 0;
103 desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
104 desc.MiscFlags = 0;
105 desc.SampleDesc.Count = 1;
107 RefPtr<ID3D11Texture2D> stagingTexture;
108 HRESULT hr =
109 aDevice->CreateTexture2D(&desc, nullptr, getter_AddRefs(stagingTexture));
110 if (FAILED(hr) || !stagingTexture) {
111 return;
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);
126 return mDevice;
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)) {
153 return;
156 const auto kMaxPooledSized = 5;
157 if (mRecycledTextures.size() > kMaxPooledSized) {
158 return;
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");
172 return;
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");
184 return;
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()) {
195 return nullptr;
197 return it->second;
200 // static
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()) {
209 return nullptr;
212 auto* bufferTexture = aTextureHost->AsBufferTextureHost();
213 if (!bufferTexture || bufferTexture->GetFormat() != gfx::SurfaceFormat::YUV) {
214 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
215 return nullptr;
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());
224 if (textureHost) {
225 return textureHost;
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) {
239 return nullptr;
242 auto id = GpuProcessD3D11TextureMap::GetNextTextureId();
243 auto flags = aTextureHost->GetFlags() | TextureFlags::SOFTWARE_DECODED_VIDEO;
245 auto colorSpace = ToColorSpace2(bufferTexture->GetYUVColorSpace());
247 auto descD3D10 =
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();
262 textureHost =
263 new WebRenderTextureHost(flags, textureHostWrapper, externalImageId);
264 aAllocator->RegisterTextureHostWrapper(extId.ref(), textureHost);
266 return 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();
293 if (textureMap) {
294 RefPtr<ID3D11Texture2D> texture = textureMap->GetTexture(mTextureId);
295 if (texture) {
296 mAllocator->RecycleTexture(texture);
297 textureMap->Unregister(mTextureId);
299 } else {
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,
353 aImageKeys, aFlags);
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() {
381 return nullptr;
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