TextureHostWrapperD3D11.cpp (12792B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "TextureHostWrapperD3D11.h" 8 9 #include <d3d11.h> 10 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/ProfilerMarkers.h" 18 #include "mozilla/SharedThreadPool.h" 19 20 namespace mozilla { 21 namespace layers { 22 23 TextureWrapperD3D11Allocator::TextureWrapperD3D11Allocator() 24 : mThread(SharedThreadPool::Get("TextureUpdate"_ns, 1)), 25 mMutex("TextureWrapperD3D11Allocator::mMutex") {} 26 TextureWrapperD3D11Allocator::~TextureWrapperD3D11Allocator() = default; 27 28 RefPtr<ID3D11Texture2D> TextureWrapperD3D11Allocator::CreateOrRecycle( 29 gfx::SurfaceFormat aSurfaceFormat, gfx::IntSize aSize) { 30 MOZ_ASSERT(mThread->IsOnCurrentThread()); 31 32 RefPtr<ID3D11Device> device = gfx::DeviceManagerDx::Get()->GetImageDevice(); 33 { 34 MutexAutoLock lock(mMutex); 35 if (!!mDevice && mDevice != device) { 36 // Device reset might happen 37 ClearAllTextures(lock); 38 mDevice = nullptr; 39 } 40 41 if (!mDevice) { 42 mDevice = device; 43 MOZ_ASSERT(mDevice == gfx::DeviceManagerDx::Get()->GetCompositorDevice()); 44 } 45 46 if (!mDevice) { 47 MOZ_ASSERT_UNREACHABLE("unexpected to be called"); 48 return nullptr; 49 } 50 51 if (aSurfaceFormat != gfx::SurfaceFormat::NV12) { 52 MOZ_ASSERT_UNREACHABLE("unexpected to be called"); 53 return nullptr; 54 } 55 56 if (mSize != aSize) { 57 ClearAllTextures(lock); 58 mSize = aSize; 59 } 60 61 if (!mRecycledTextures.empty()) { 62 RefPtr<ID3D11Texture2D> texture2D = mRecycledTextures.front(); 63 mRecycledTextures.pop_front(); 64 return texture2D; 65 } 66 } 67 68 CD3D11_TEXTURE2D_DESC desc( 69 DXGI_FORMAT_NV12, mSize.width, mSize.height, 1, 1, 70 D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE); 71 72 RefPtr<ID3D11Texture2D> texture2D; 73 HRESULT hr = 74 device->CreateTexture2D(&desc, nullptr, getter_AddRefs(texture2D)); 75 if (FAILED(hr) || !texture2D) { 76 return nullptr; 77 } 78 79 EnsureStagingTextureNV12(device); 80 if (!mStagingTexture) { 81 return nullptr; 82 } 83 84 return texture2D; 85 } 86 87 void TextureWrapperD3D11Allocator::EnsureStagingTextureNV12( 88 RefPtr<ID3D11Device> aDevice) { 89 MOZ_ASSERT(mThread->IsOnCurrentThread()); 90 MOZ_ASSERT(aDevice); 91 92 if (mStagingTexture) { 93 return; 94 } 95 96 D3D11_TEXTURE2D_DESC desc = {}; 97 desc.Width = mSize.width; 98 desc.Height = mSize.height; 99 desc.Format = DXGI_FORMAT_NV12; 100 desc.MipLevels = 1; 101 desc.ArraySize = 1; 102 desc.Usage = D3D11_USAGE_STAGING; 103 desc.BindFlags = 0; 104 desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; 105 desc.MiscFlags = 0; 106 desc.SampleDesc.Count = 1; 107 108 RefPtr<ID3D11Texture2D> stagingTexture; 109 HRESULT hr = 110 aDevice->CreateTexture2D(&desc, nullptr, getter_AddRefs(stagingTexture)); 111 if (FAILED(hr) || !stagingTexture) { 112 return; 113 } 114 mStagingTexture = stagingTexture; 115 } 116 117 RefPtr<ID3D11Texture2D> TextureWrapperD3D11Allocator::GetStagingTextureNV12() { 118 MOZ_ASSERT(mThread->IsOnCurrentThread()); 119 120 return mStagingTexture; 121 } 122 123 RefPtr<ID3D11Device> TextureWrapperD3D11Allocator::GetDevice() { 124 MOZ_ASSERT(mThread->IsOnCurrentThread()); 125 126 MutexAutoLock lock(mMutex); 127 return mDevice; 128 }; 129 130 void TextureWrapperD3D11Allocator::ClearAllTextures( 131 const MutexAutoLock& aProofOfLock) { 132 MOZ_ASSERT(mThread->IsOnCurrentThread()); 133 134 mStagingTexture = nullptr; 135 mRecycledTextures.clear(); 136 } 137 138 void TextureWrapperD3D11Allocator::RecycleTexture( 139 RefPtr<ID3D11Texture2D>& aTexture) { 140 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); 141 MOZ_ASSERT(aTexture); 142 143 RefPtr<ID3D11Device> device; 144 aTexture->GetDevice(getter_AddRefs(device)); 145 146 D3D11_TEXTURE2D_DESC desc; 147 aTexture->GetDesc(&desc); 148 149 { 150 MutexAutoLock lock(mMutex); 151 if (device != mDevice || desc.Format != DXGI_FORMAT_NV12 || 152 desc.Width != static_cast<UINT>(mSize.width) || 153 desc.Height != static_cast<UINT>(mSize.height)) { 154 return; 155 } 156 157 const auto kMaxPooledSized = 5; 158 if (mRecycledTextures.size() > kMaxPooledSized) { 159 return; 160 } 161 mRecycledTextures.emplace_back(aTexture); 162 } 163 } 164 165 void TextureWrapperD3D11Allocator::RegisterTextureHostWrapper( 166 const wr::ExternalImageId& aExternalImageId, 167 RefPtr<TextureHost> aTextureHost) { 168 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); 169 170 auto it = mTextureHostWrappers.find(wr::AsUint64(aExternalImageId)); 171 if (it != mTextureHostWrappers.end()) { 172 MOZ_ASSERT_UNREACHABLE("unexpected to be called"); 173 return; 174 } 175 mTextureHostWrappers.emplace(wr::AsUint64(aExternalImageId), aTextureHost); 176 } 177 178 void TextureWrapperD3D11Allocator::UnregisterTextureHostWrapper( 179 const wr::ExternalImageId& aExternalImageId) { 180 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); 181 182 auto it = mTextureHostWrappers.find(wr::AsUint64(aExternalImageId)); 183 if (it == mTextureHostWrappers.end()) { 184 MOZ_ASSERT_UNREACHABLE("unexpected to be called"); 185 return; 186 } 187 mTextureHostWrappers.erase(it); 188 } 189 190 RefPtr<TextureHost> TextureWrapperD3D11Allocator::GetTextureHostWrapper( 191 const wr::ExternalImageId& aExternalImageId) { 192 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); 193 194 auto it = mTextureHostWrappers.find(wr::AsUint64(aExternalImageId)); 195 if (it == mTextureHostWrappers.end()) { 196 return nullptr; 197 } 198 return it->second; 199 } 200 201 // static 202 RefPtr<TextureHost> TextureHostWrapperD3D11::CreateFromBufferTexture( 203 const RefPtr<TextureWrapperD3D11Allocator>& aAllocator, 204 TextureHost* aTextureHost) { 205 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); 206 MOZ_ASSERT(aAllocator); 207 MOZ_ASSERT(aTextureHost); 208 209 if (!XRE_IsGPUProcess()) { 210 return nullptr; 211 } 212 213 auto* bufferTexture = aTextureHost->AsBufferTextureHost(); 214 if (!bufferTexture || 215 bufferTexture->GetFormat() != gfx::SurfaceFormat::YUV420) { 216 MOZ_ASSERT_UNREACHABLE("unexpected to be called"); 217 return nullptr; 218 } 219 220 auto extId = aTextureHost->GetMaybeExternalImageId(); 221 MOZ_RELEASE_ASSERT(extId.isSome()); 222 223 // Reuse TextureHostWrapperD3D11 if it is still valid. 224 RefPtr<TextureHost> textureHost = 225 aAllocator->GetTextureHostWrapper(extId.ref()); 226 if (textureHost) { 227 return textureHost; 228 } 229 230 auto size = bufferTexture->GetSize(); 231 auto colorDepth = bufferTexture->GetColorDepth(); 232 auto colorRange = bufferTexture->GetColorRange(); 233 auto chromaSubsampling = bufferTexture->GetChromaSubsampling(); 234 235 // Check if data could be used with NV12 236 // XXX support gfx::ColorRange::FULL 237 if (size.width % 2 != 0 || size.height % 2 != 0 || 238 colorDepth != gfx::ColorDepth::COLOR_8 || 239 colorRange != gfx::ColorRange::LIMITED || 240 chromaSubsampling != gfx::ChromaSubsampling::HALF_WIDTH_AND_HEIGHT) { 241 if (profiler_thread_is_being_profiled_for_markers()) { 242 nsPrintfCString str( 243 "Unsupported size(%dx%d) colorDepth %hhu colorRange %hhu " 244 "chromaSubsampling %hhu", 245 size.width, size.height, uint8_t(colorDepth), uint8_t(colorRange), 246 uint8_t(chromaSubsampling)); 247 PROFILER_MARKER_TEXT("TextureHostWrapperD3D11", GRAPHICS, {}, str); 248 } 249 return nullptr; 250 } 251 252 auto id = GpuProcessD3D11TextureMap::GetNextTextureId(); 253 auto flags = aTextureHost->GetFlags() | TextureFlags::SOFTWARE_DECODED_VIDEO; 254 255 auto colorSpace = ToColorSpace2(bufferTexture->GetYUVColorSpace()); 256 257 auto descD3D10 = SurfaceDescriptorD3D10( 258 nullptr, Some(id), 259 /* arrayIndex */ 0, gfx::SurfaceFormat::NV12, size, colorSpace, 260 colorRange, /* hasKeyedMutex */ false, /* fencesHolderId */ Nothing()); 261 262 RefPtr<DXGITextureHostD3D11> textureHostD3D11 = 263 new DXGITextureHostD3D11(flags, descD3D10); 264 265 RefPtr<TextureHostWrapperD3D11> textureHostWrapper = 266 new TextureHostWrapperD3D11(flags, aAllocator, id, textureHostD3D11, 267 aTextureHost, extId.ref()); 268 textureHostWrapper->PostTask(); 269 270 auto externalImageId = AsyncImagePipelineManager::GetNextExternalImageId(); 271 272 textureHost = 273 new WebRenderTextureHost(flags, textureHostWrapper, externalImageId); 274 aAllocator->RegisterTextureHostWrapper(extId.ref(), textureHost); 275 276 return textureHost; 277 } 278 279 TextureHostWrapperD3D11::TextureHostWrapperD3D11( 280 TextureFlags aFlags, const RefPtr<TextureWrapperD3D11Allocator>& aAllocator, 281 const GpuProcessTextureId aTextureId, 282 DXGITextureHostD3D11* aTextureHostD3D11, TextureHost* aWrappedTextureHost, 283 const wr::ExternalImageId aWrappedExternalImageId) 284 : TextureHost(TextureHostType::DXGI, aFlags), 285 mAllocator(aAllocator), 286 mTextureId(aTextureId), 287 mTextureHostD3D11(aTextureHostD3D11), 288 mWrappedTextureHost(aWrappedTextureHost), 289 mWrappedExternalImageId(aWrappedExternalImageId) { 290 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); 291 MOZ_ASSERT(mAllocator); 292 MOZ_ASSERT(mTextureHostD3D11); 293 MOZ_ASSERT(mWrappedTextureHost); 294 295 MOZ_COUNT_CTOR(TextureHostWrapperD3D11); 296 } 297 298 TextureHostWrapperD3D11::~TextureHostWrapperD3D11() { 299 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); 300 MOZ_COUNT_DTOR(TextureHostWrapperD3D11); 301 302 auto* textureMap = GpuProcessD3D11TextureMap::Get(); 303 if (textureMap) { 304 RefPtr<ID3D11Texture2D> texture = textureMap->GetTexture(mTextureId); 305 if (texture) { 306 mAllocator->RecycleTexture(texture); 307 textureMap->Unregister(mTextureId); 308 } 309 } else { 310 gfxCriticalNoteOnce << "GpuProcessD3D11TextureMap does not exist"; 311 } 312 } 313 314 void TextureHostWrapperD3D11::PostTask() { 315 GpuProcessD3D11TextureMap::Get()->PostUpdateTextureDataTask( 316 mTextureId, this, mWrappedTextureHost, mAllocator); 317 } 318 319 bool TextureHostWrapperD3D11::IsValid() { return true; } 320 321 gfx::ColorRange TextureHostWrapperD3D11::GetColorRange() const { 322 return mTextureHostD3D11->GetColorRange(); 323 } 324 325 gfx::IntSize TextureHostWrapperD3D11::GetSize() const { 326 return mTextureHostD3D11->GetSize(); 327 } 328 329 gfx::SurfaceFormat TextureHostWrapperD3D11::GetFormat() const { 330 return mTextureHostD3D11->GetFormat(); 331 } 332 333 void TextureHostWrapperD3D11::CreateRenderTexture( 334 const wr::ExternalImageId& aExternalImageId) { 335 MOZ_ASSERT(mExternalImageId.isSome()); 336 337 mTextureHostD3D11->EnsureRenderTexture(mExternalImageId); 338 } 339 340 void TextureHostWrapperD3D11::MaybeDestroyRenderTexture() { 341 // TextureHostWrapperD3D11 does not create RenderTexture, then 342 // TextureHostWrapperD3D11 does not need to destroy RenderTexture. 343 mExternalImageId = Nothing(); 344 } 345 346 uint32_t TextureHostWrapperD3D11::NumSubTextures() { 347 return mTextureHostD3D11->NumSubTextures(); 348 } 349 350 void TextureHostWrapperD3D11::PushResourceUpdates( 351 wr::TransactionBuilder& aResources, ResourceUpdateOp aOp, 352 const Range<wr::ImageKey>& aImageKeys, const wr::ExternalImageId& aExtID) { 353 mTextureHostD3D11->PushResourceUpdates(aResources, aOp, aImageKeys, aExtID); 354 } 355 356 void TextureHostWrapperD3D11::PushDisplayItems( 357 wr::DisplayListBuilder& aBuilder, const wr::LayoutRect& aBounds, 358 const wr::LayoutRect& aClip, wr::ImageRendering aFilter, 359 const Range<wr::ImageKey>& aImageKeys, PushDisplayItemFlagSet aFlags) { 360 MOZ_ASSERT(aImageKeys.length() > 0); 361 362 mTextureHostD3D11->PushDisplayItems(aBuilder, aBounds, aClip, aFilter, 363 aImageKeys, aFlags); 364 } 365 366 bool TextureHostWrapperD3D11::SupportsExternalCompositing( 367 WebRenderBackend aBackend) { 368 return mTextureHostD3D11->SupportsExternalCompositing(aBackend); 369 } 370 371 void TextureHostWrapperD3D11::UnbindTextureSource() { 372 mTextureHostD3D11->UnbindTextureSource(); 373 // Handle read unlock 374 TextureHost::UnbindTextureSource(); 375 } 376 377 void TextureHostWrapperD3D11::NotifyNotUsed() { 378 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); 379 380 mAllocator->UnregisterTextureHostWrapper(mWrappedExternalImageId); 381 382 MOZ_ASSERT(mWrappedTextureHost); 383 if (mWrappedTextureHost) { 384 mWrappedTextureHost = nullptr; 385 } 386 mTextureHostD3D11->NotifyNotUsed(); 387 TextureHost::NotifyNotUsed(); 388 } 389 390 BufferTextureHost* TextureHostWrapperD3D11::AsBufferTextureHost() { 391 return nullptr; 392 } 393 394 bool TextureHostWrapperD3D11::IsWrappingSurfaceTextureHost() { return false; } 395 396 TextureHostType TextureHostWrapperD3D11::GetTextureHostType() { 397 return mTextureHostD3D11->GetTextureHostType(); 398 } 399 400 bool TextureHostWrapperD3D11::NeedsDeferredDeletion() const { 401 return mTextureHostD3D11->NeedsDeferredDeletion(); 402 } 403 404 } // namespace layers 405 } // namespace mozilla