tor-browser

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

GpuProcessD3D11TextureMap.cpp (13704B)


      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 "GpuProcessD3D11TextureMap.h"
      8 
      9 #include "libyuv.h"
     10 #include "mozilla/layers/CompositorThread.h"
     11 #include "mozilla/layers/D3D11ZeroCopyTextureImage.h"
     12 #include "mozilla/layers/HelpersD3D11.h"
     13 #include "mozilla/layers/TextureHostWrapperD3D11.h"
     14 #include "mozilla/ProfilerMarkers.h"
     15 #include "mozilla/SharedThreadPool.h"
     16 #include "mozilla/webrender/RenderThread.h"
     17 
     18 namespace mozilla {
     19 
     20 namespace layers {
     21 
     22 StaticAutoPtr<GpuProcessD3D11TextureMap> GpuProcessD3D11TextureMap::sInstance;
     23 
     24 /* static */
     25 void GpuProcessD3D11TextureMap::Init() {
     26  MOZ_ASSERT(XRE_IsGPUProcess());
     27  sInstance = new GpuProcessD3D11TextureMap();
     28 }
     29 
     30 /* static */
     31 void GpuProcessD3D11TextureMap::Shutdown() {
     32  MOZ_ASSERT(XRE_IsGPUProcess());
     33  sInstance = nullptr;
     34 }
     35 
     36 /* static */
     37 GpuProcessTextureId GpuProcessD3D11TextureMap::GetNextTextureId() {
     38  MOZ_ASSERT(XRE_IsGPUProcess());
     39  return GpuProcessTextureId::GetNext();
     40 }
     41 
     42 GpuProcessD3D11TextureMap::GpuProcessD3D11TextureMap()
     43    : mMonitor("GpuProcessD3D11TextureMap::mMonitor") {}
     44 
     45 GpuProcessD3D11TextureMap::~GpuProcessD3D11TextureMap() {}
     46 
     47 void GpuProcessD3D11TextureMap::Register(
     48    GpuProcessTextureId aTextureId, ID3D11Texture2D* aTexture,
     49    uint32_t aArrayIndex, const gfx::IntSize& aSize,
     50    RefPtr<ZeroCopyUsageInfo> aUsageInfo,
     51    RefPtr<gfx::FileHandleWrapper> aSharedHandle) {
     52  MonitorAutoLock lock(mMonitor);
     53  Register(lock, aTextureId, aTexture, aArrayIndex, aSize, aUsageInfo,
     54           aSharedHandle);
     55 }
     56 void GpuProcessD3D11TextureMap::Register(
     57    const MonitorAutoLock& aProofOfLock, GpuProcessTextureId aTextureId,
     58    ID3D11Texture2D* aTexture, uint32_t aArrayIndex, const gfx::IntSize& aSize,
     59    RefPtr<ZeroCopyUsageInfo> aUsageInfo,
     60    RefPtr<gfx::FileHandleWrapper> aSharedHandle) {
     61  MOZ_RELEASE_ASSERT(aTexture);
     62 
     63  auto it = mD3D11TexturesById.find(aTextureId);
     64  if (it != mD3D11TexturesById.end()) {
     65    MOZ_ASSERT_UNREACHABLE("unexpected to be called");
     66    return;
     67  }
     68  mD3D11TexturesById.emplace(
     69      aTextureId,
     70      TextureHolder(aTexture, aArrayIndex, aSize, aUsageInfo, aSharedHandle));
     71 }
     72 
     73 void GpuProcessD3D11TextureMap::Unregister(GpuProcessTextureId aTextureId) {
     74  MonitorAutoLock lock(mMonitor);
     75 
     76  auto it = mD3D11TexturesById.find(aTextureId);
     77  if (it == mD3D11TexturesById.end()) {
     78    return;
     79  }
     80  mD3D11TexturesById.erase(it);
     81 }
     82 
     83 RefPtr<ID3D11Texture2D> GpuProcessD3D11TextureMap::GetTexture(
     84    GpuProcessTextureId aTextureId) {
     85  MonitorAutoLock lock(mMonitor);
     86 
     87  auto it = mD3D11TexturesById.find(aTextureId);
     88  if (it == mD3D11TexturesById.end()) {
     89    return nullptr;
     90  }
     91 
     92  return it->second.mTexture;
     93 }
     94 
     95 Maybe<HANDLE> GpuProcessD3D11TextureMap::GetSharedHandle(
     96    GpuProcessTextureId aTextureId) {
     97  TextureHolder holder;
     98  {
     99    MonitorAutoLock lock(mMonitor);
    100 
    101    auto it = mD3D11TexturesById.find(aTextureId);
    102    if (it == mD3D11TexturesById.end()) {
    103      return Nothing();
    104    }
    105 
    106    if (it->second.mSharedHandle) {
    107      return Some(it->second.mSharedHandle->GetHandle());
    108    }
    109 
    110    if (it->second.mCopiedTextureSharedHandle) {
    111      return Some(it->second.mCopiedTextureSharedHandle->GetHandle());
    112    }
    113 
    114    holder = it->second;
    115  }
    116 
    117  RefPtr<ID3D11Device> device;
    118  holder.mTexture->GetDevice(getter_AddRefs(device));
    119  if (!device) {
    120    return Nothing();
    121  }
    122 
    123  RefPtr<ID3D11DeviceContext> context;
    124  device->GetImmediateContext(getter_AddRefs(context));
    125  if (!context) {
    126    return Nothing();
    127  }
    128 
    129  CD3D11_TEXTURE2D_DESC newDesc(
    130      DXGI_FORMAT_NV12, holder.mSize.width, holder.mSize.height, 1, 1,
    131      D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE);
    132  newDesc.MiscFlags =
    133      D3D11_RESOURCE_MISC_SHARED_NTHANDLE | D3D11_RESOURCE_MISC_SHARED;
    134 
    135  RefPtr<ID3D11Texture2D> copiedTexture;
    136  HRESULT hr =
    137      device->CreateTexture2D(&newDesc, nullptr, getter_AddRefs(copiedTexture));
    138  if (FAILED(hr)) {
    139    return Nothing();
    140  }
    141 
    142  D3D11_TEXTURE2D_DESC inDesc;
    143  holder.mTexture->GetDesc(&inDesc);
    144 
    145  D3D11_TEXTURE2D_DESC outDesc;
    146  copiedTexture->GetDesc(&outDesc);
    147 
    148  UINT height = std::min(inDesc.Height, outDesc.Height);
    149  UINT width = std::min(inDesc.Width, outDesc.Width);
    150  D3D11_BOX srcBox = {0, 0, 0, width, height, 1};
    151 
    152  context->CopySubresourceRegion(copiedTexture, 0, 0, 0, 0, holder.mTexture,
    153                                 holder.mArrayIndex, &srcBox);
    154 
    155  RefPtr<IDXGIResource1> resource;
    156  copiedTexture->QueryInterface((IDXGIResource1**)getter_AddRefs(resource));
    157  if (!resource) {
    158    return Nothing();
    159  }
    160 
    161  HANDLE sharedHandle;
    162  hr = resource->CreateSharedHandle(
    163      nullptr, DXGI_SHARED_RESOURCE_READ | DXGI_SHARED_RESOURCE_WRITE, nullptr,
    164      &sharedHandle);
    165  if (FAILED(hr)) {
    166    return Nothing();
    167  }
    168 
    169  RefPtr<gfx::FileHandleWrapper> handle =
    170      new gfx::FileHandleWrapper(UniqueFileHandle(sharedHandle));
    171 
    172  RefPtr<ID3D11Query> query;
    173  CD3D11_QUERY_DESC desc(D3D11_QUERY_EVENT);
    174  hr = device->CreateQuery(&desc, getter_AddRefs(query));
    175  if (FAILED(hr) || !query) {
    176    gfxWarning() << "Could not create D3D11_QUERY_EVENT: " << gfx::hexa(hr);
    177    return Nothing();
    178  }
    179 
    180  context->End(query);
    181 
    182  BOOL result;
    183  bool ret = WaitForFrameGPUQuery(device, context, query, &result);
    184  if (!ret) {
    185    gfxCriticalNoteOnce << "WaitForFrameGPUQuery() failed";
    186  }
    187 
    188  {
    189    MonitorAutoLock lock(mMonitor);
    190 
    191    auto it = mD3D11TexturesById.find(aTextureId);
    192    if (it == mD3D11TexturesById.end()) {
    193      MOZ_ASSERT_UNREACHABLE("unexpected to be called");
    194      return Nothing();
    195    }
    196 
    197    // Disable no video copy for future decoded video frames. Since
    198    // Get SharedHandle of copied Texture() is slow.
    199    if (it->second.mZeroCopyUsageInfo) {
    200      it->second.mZeroCopyUsageInfo->DisableZeroCopyNV12Texture();
    201    }
    202 
    203    it->second.mCopiedTexture = copiedTexture;
    204    it->second.mCopiedTextureSharedHandle = handle;
    205  }
    206 
    207  return Some(handle->GetHandle());
    208 }
    209 
    210 void GpuProcessD3D11TextureMap::DisableZeroCopyNV12Texture(
    211    GpuProcessTextureId aTextureId) {
    212  MonitorAutoLock lock(mMonitor);
    213 
    214  auto it = mD3D11TexturesById.find(aTextureId);
    215  if (it == mD3D11TexturesById.end()) {
    216    MOZ_ASSERT_UNREACHABLE("unexpected to be called");
    217    return;
    218  }
    219 
    220  if (!it->second.mZeroCopyUsageInfo) {
    221    return;
    222  }
    223 
    224  // Disable no video copy for future decoded video frames. Since
    225  // Get SharedHandle of copied Texture() is slow.
    226  it->second.mZeroCopyUsageInfo->DisableZeroCopyNV12Texture();
    227 }
    228 
    229 size_t GpuProcessD3D11TextureMap::GetWaitingTextureCount() const {
    230  MonitorAutoLock lock(mMonitor);
    231  return mWaitingTextures.size();
    232 }
    233 
    234 bool GpuProcessD3D11TextureMap::WaitTextureReady(
    235    const GpuProcessTextureId aTextureId) {
    236  MOZ_ASSERT(wr::RenderThread::IsInRenderThread());
    237 
    238  MonitorAutoLock lock(mMonitor);
    239  auto it = mWaitingTextures.find(aTextureId);
    240  if (it == mWaitingTextures.end()) {
    241    return true;
    242  }
    243 
    244  auto start = TimeStamp::Now();
    245  const TimeDuration timeout = TimeDuration::FromMilliseconds(1000);
    246  while (1) {
    247    CVStatus status = mMonitor.Wait(timeout);
    248    if (status == CVStatus::Timeout) {
    249      MOZ_ASSERT_UNREACHABLE("unexpected to be called");
    250      gfxCriticalNoteOnce << "GpuProcessTextureI wait time out id:"
    251                          << uint64_t(aTextureId);
    252      return false;
    253    }
    254 
    255    auto it = mWaitingTextures.find(aTextureId);
    256    if (it == mWaitingTextures.end()) {
    257      break;
    258    }
    259  }
    260 
    261  auto end = TimeStamp::Now();
    262  const auto durationMs = static_cast<uint32_t>((end - start).ToMilliseconds());
    263  nsPrintfCString marker("TextureReadyWait %ums ", durationMs);
    264  PROFILER_MARKER_TEXT("PresentWait", GRAPHICS, {}, marker);
    265 
    266  return true;
    267 }
    268 
    269 void GpuProcessD3D11TextureMap::PostUpdateTextureDataTask(
    270    const GpuProcessTextureId aTextureId, TextureHost* aTextureHost,
    271    TextureHost* aWrappedTextureHost,
    272    TextureWrapperD3D11Allocator* aAllocator) {
    273  {
    274    MonitorAutoLock lock(mMonitor);
    275 
    276    auto it = mWaitingTextures.find(aTextureId);
    277    if (it != mWaitingTextures.end()) {
    278      MOZ_ASSERT_UNREACHABLE("unexpected to be called");
    279      return;
    280    }
    281 
    282    auto updatingTexture = MakeUnique<UpdatingTextureHolder>(
    283        aTextureId, aTextureHost, aWrappedTextureHost, aAllocator);
    284 
    285    mWaitingTextures.emplace(aTextureId);
    286    mWaitingTextureQueue.push_back(std::move(updatingTexture));
    287  }
    288 
    289  RefPtr<Runnable> runnable = NS_NewRunnableFunction(
    290      "GpuProcessD3D11TextureMap::PostUpdateTextureDataTaskRunnable", []() {
    291        GpuProcessD3D11TextureMap::Get()->HandleInTextureUpdateThread();
    292      });
    293  nsCOMPtr<nsIEventTarget> thread = aAllocator->mThread;
    294  thread->Dispatch(runnable.forget());
    295 }
    296 
    297 void GpuProcessD3D11TextureMap::HandleInTextureUpdateThread() {
    298  UniquePtr<UpdatingTextureHolder> textureHolder;
    299  {
    300    MonitorAutoLock lock(mMonitor);
    301 
    302    if (mWaitingTextureQueue.empty()) {
    303      return;
    304    }
    305    textureHolder = std::move(mWaitingTextureQueue.front());
    306    mWaitingTextureQueue.pop_front();
    307  }
    308 
    309  RefPtr<ID3D11Texture2D> texture = UpdateTextureData(textureHolder.get());
    310 
    311  {
    312    MonitorAutoLock lock(mMonitor);
    313    if (texture) {
    314      auto size = textureHolder->mWrappedTextureHost->GetSize();
    315      Register(lock, textureHolder->mTextureId, texture, /* aArrayIndex */ 0,
    316               size, /* aUsageInfo */ nullptr, /* aSharedHandle */ nullptr);
    317    }
    318    mWaitingTextures.erase(textureHolder->mTextureId);
    319    MOZ_ASSERT(mWaitingTextures.size() == mWaitingTextureQueue.size());
    320    mMonitor.Notify();
    321  }
    322 
    323  // Release UpdatingTextureHolder in CompositorThread
    324  RefPtr<Runnable> runnable = NS_NewRunnableFunction(
    325      "GpuProcessD3D11TextureMap::HandleInTextureUpdateThread::Runnable",
    326      [textureHolder = std::move(textureHolder)]() mutable {
    327        textureHolder = nullptr;
    328      });
    329  CompositorThread()->Dispatch(runnable.forget());
    330 }
    331 
    332 RefPtr<ID3D11Texture2D> GpuProcessD3D11TextureMap::UpdateTextureData(
    333    UpdatingTextureHolder* aHolder) {
    334  MOZ_ASSERT(aHolder);
    335  MOZ_ASSERT(aHolder->mAllocator->mThread->IsOnCurrentThread());
    336 
    337  auto* bufferTexture = aHolder->mWrappedTextureHost->AsBufferTextureHost();
    338  MOZ_ASSERT(bufferTexture);
    339  if (!bufferTexture) {
    340    MOZ_ASSERT_UNREACHABLE("unexpected to be called");
    341    return nullptr;
    342  }
    343 
    344  auto size = bufferTexture->GetSize();
    345 
    346  RefPtr<ID3D11Texture2D> texture2D =
    347      aHolder->mAllocator->CreateOrRecycle(gfx::SurfaceFormat::NV12, size);
    348  if (!texture2D) {
    349    return nullptr;
    350  }
    351 
    352  RefPtr<ID3D11Texture2D> stagingTexture =
    353      aHolder->mAllocator->GetStagingTextureNV12();
    354  if (!stagingTexture) {
    355    return nullptr;
    356  }
    357 
    358  RefPtr<ID3D11DeviceContext> context;
    359  RefPtr<ID3D11Device> device = aHolder->mAllocator->GetDevice();
    360  device->GetImmediateContext(getter_AddRefs(context));
    361  if (!context) {
    362    return nullptr;
    363  }
    364 
    365  RefPtr<ID3D10Multithread> mt;
    366  HRESULT hr = device->QueryInterface((ID3D10Multithread**)getter_AddRefs(mt));
    367  if (FAILED(hr) || !mt) {
    368    gfxCriticalError() << "Multithread safety interface not supported. " << hr;
    369    return nullptr;
    370  }
    371 
    372  if (!mt->GetMultithreadProtected()) {
    373    gfxCriticalError() << "Device used not marked as multithread-safe.";
    374    return nullptr;
    375  }
    376 
    377  D3D11MTAutoEnter mtAutoEnter(mt.forget());
    378 
    379  AutoLockD3D11Texture lockSt(stagingTexture);
    380 
    381  D3D11_MAP mapType = D3D11_MAP_WRITE;
    382  D3D11_MAPPED_SUBRESOURCE mappedResource;
    383 
    384  hr = context->Map(stagingTexture, 0, mapType, 0, &mappedResource);
    385  if (FAILED(hr)) {
    386    gfxCriticalNoteOnce << "Mapping D3D11 staging texture failed: "
    387                        << gfx::hexa(hr);
    388    return nullptr;
    389  }
    390 
    391  const size_t destStride = mappedResource.RowPitch;
    392  uint8_t* yDestPlaneStart = reinterpret_cast<uint8_t*>(mappedResource.pData);
    393  uint8_t* uvDestPlaneStart = reinterpret_cast<uint8_t*>(mappedResource.pData) +
    394                              destStride * size.height;
    395  // Convert I420 to NV12,
    396  const uint8_t* yChannel = bufferTexture->GetYChannel();
    397  const uint8_t* cbChannel = bufferTexture->GetCbChannel();
    398  const uint8_t* crChannel = bufferTexture->GetCrChannel();
    399  int32_t yStride = bufferTexture->GetYStride();
    400  int32_t cbCrStride = bufferTexture->GetCbCrStride();
    401 
    402  libyuv::I420ToNV12(yChannel, yStride, cbChannel, cbCrStride, crChannel,
    403                     cbCrStride, yDestPlaneStart, destStride, uvDestPlaneStart,
    404                     destStride, size.width, size.height);
    405 
    406  context->Unmap(stagingTexture, 0);
    407 
    408  context->CopyResource(texture2D, stagingTexture);
    409 
    410  return texture2D;
    411 }
    412 
    413 GpuProcessD3D11TextureMap::TextureHolder::TextureHolder(
    414    ID3D11Texture2D* aTexture, uint32_t aArrayIndex, const gfx::IntSize& aSize,
    415    RefPtr<ZeroCopyUsageInfo> aUsageInfo,
    416    RefPtr<gfx::FileHandleWrapper> aSharedHandle)
    417    : mTexture(aTexture),
    418      mArrayIndex(aArrayIndex),
    419      mSize(aSize),
    420      mZeroCopyUsageInfo(aUsageInfo),
    421      mSharedHandle(aSharedHandle) {}
    422 
    423 GpuProcessD3D11TextureMap::UpdatingTextureHolder::UpdatingTextureHolder(
    424    const GpuProcessTextureId aTextureId, TextureHost* aTextureHost,
    425    TextureHost* aWrappedTextureHost, TextureWrapperD3D11Allocator* aAllocator)
    426    : mTextureId(aTextureId),
    427      mTextureHost(aTextureHost),
    428      mWrappedTextureHost(aWrappedTextureHost),
    429      mAllocator(aAllocator) {
    430  MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
    431 }
    432 
    433 GpuProcessD3D11TextureMap::UpdatingTextureHolder::~UpdatingTextureHolder() {
    434  MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
    435 }
    436 
    437 }  // namespace layers
    438 }  // namespace mozilla