tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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