tor-browser

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

D3D11ShareHandleImage.cpp (10286B)


      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 "D3D11ShareHandleImage.h"
      8 #include "DXVA2Manager.h"
      9 #include "WMF.h"
     10 #include "d3d11.h"
     11 #include "gfxImageSurface.h"
     12 #include "gfxWindowsPlatform.h"
     13 #include "libyuv.h"
     14 #include "mozilla/StaticPrefs_media.h"
     15 #include "mozilla/gfx/DeviceManagerDx.h"
     16 #include "mozilla/layers/CompositableClient.h"
     17 #include "mozilla/layers/CompositableForwarder.h"
     18 #include "mozilla/layers/CompositeProcessD3D11FencesHolderMap.h"
     19 #include "mozilla/layers/FenceD3D11.h"
     20 #include "mozilla/layers/TextureClient.h"
     21 #include "mozilla/layers/TextureD3D11.h"
     22 
     23 namespace mozilla {
     24 namespace layers {
     25 
     26 using namespace gfx;
     27 
     28 D3D11ShareHandleImage::D3D11ShareHandleImage(const gfx::IntSize& aSize,
     29                                             const gfx::IntRect& aRect,
     30                                             gfx::ColorSpace2 aColorSpace,
     31                                             gfx::ColorRange aColorRange,
     32                                             gfx::ColorDepth aColorDepth)
     33    : Image(nullptr, ImageFormat::D3D11_SHARE_HANDLE_TEXTURE),
     34      mSize(aSize),
     35      mPictureRect(aRect),
     36      mColorSpace(aColorSpace),
     37      mColorRange(aColorRange),
     38      mColorDepth(aColorDepth) {}
     39 
     40 bool D3D11ShareHandleImage::AllocateTexture(D3D11RecycleAllocator* aAllocator,
     41                                            ID3D11Device* aDevice) {
     42  if (aAllocator) {
     43    mTextureClient =
     44        aAllocator->CreateOrRecycleClient(mColorSpace, mColorRange, mSize);
     45    if (mTextureClient) {
     46      D3D11TextureData* textureData = GetData();
     47      MOZ_DIAGNOSTIC_ASSERT(textureData, "Wrong TextureDataType");
     48      mTexture = textureData->GetD3D11Texture();
     49      return true;
     50    }
     51    return false;
     52  } else {
     53    MOZ_ASSERT(aDevice);
     54    auto format = mColorDepth > gfx::ColorDepth::COLOR_8
     55                      ? DXGI_FORMAT_R16G16B16A16_FLOAT
     56                      : DXGI_FORMAT_B8G8R8A8_UNORM;
     57    CD3D11_TEXTURE2D_DESC newDesc(
     58        format, mSize.width, mSize.height, 1, 1,
     59        D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE);
     60    newDesc.MiscFlags =
     61        D3D11_RESOURCE_MISC_SHARED_NTHANDLE | D3D11_RESOURCE_MISC_SHARED;
     62 
     63    HRESULT hr =
     64        aDevice->CreateTexture2D(&newDesc, nullptr, getter_AddRefs(mTexture));
     65    return SUCCEEDED(hr);
     66  }
     67 }
     68 
     69 gfx::IntSize D3D11ShareHandleImage::GetSize() const { return mSize; }
     70 
     71 TextureClient* D3D11ShareHandleImage::GetTextureClient(
     72    KnowsCompositor* aKnowsCompositor) {
     73  return mTextureClient;
     74 }
     75 
     76 already_AddRefed<gfx::SourceSurface>
     77 D3D11ShareHandleImage::GetAsSourceSurface() {
     78  RefPtr<ID3D11Texture2D> src = GetTexture();
     79  if (!src) {
     80    gfxWarning() << "Cannot readback from shared texture because no texture is "
     81                    "available.";
     82    return nullptr;
     83  }
     84 
     85  return gfx::Factory::CreateBGRA8DataSourceSurfaceForD3D11Texture(
     86      src, 0, mColorSpace, mColorRange);
     87 }
     88 
     89 nsresult D3D11ShareHandleImage::BuildSurfaceDescriptorBuffer(
     90    SurfaceDescriptorBuffer& aSdBuffer, BuildSdbFlags aFlags,
     91    const std::function<MemoryOrShmem(uint32_t)>& aAllocate) {
     92  RefPtr<ID3D11Texture2D> src = GetTexture();
     93  if (!src) {
     94    gfxWarning() << "Cannot readback from shared texture because no texture is "
     95                    "available.";
     96    return NS_ERROR_FAILURE;
     97  }
     98 
     99  nsresult rv =
    100      gfx::Factory::CreateSdbForD3D11Texture(src, mSize, aSdBuffer, aAllocate);
    101  if (rv != NS_ERROR_NOT_IMPLEMENTED) {
    102    // TODO(aosmond): We only support BGRA on this path, but depending on
    103    // aFlags, we may be able to return a YCbCr format without conversion.
    104    return rv;
    105  }
    106 
    107  return Image::BuildSurfaceDescriptorBuffer(aSdBuffer, aFlags, aAllocate);
    108 }
    109 
    110 ID3D11Texture2D* D3D11ShareHandleImage::GetTexture() const { return mTexture; }
    111 
    112 class MOZ_RAII D3D11TextureClientAllocationHelper
    113    : public ITextureClientAllocationHelper {
    114 public:
    115  D3D11TextureClientAllocationHelper(gfx::SurfaceFormat aFormat,
    116                                     gfx::ColorSpace2 aColorSpace,
    117                                     gfx::ColorRange aColorRange,
    118                                     const gfx::IntSize& aSize,
    119                                     TextureAllocationFlags aAllocFlags,
    120                                     ID3D11Device* aDevice,
    121                                     TextureFlags aTextureFlags)
    122      : ITextureClientAllocationHelper(aFormat, aSize, BackendSelector::Content,
    123                                       aTextureFlags, aAllocFlags),
    124        mColorSpace(aColorSpace),
    125        mColorRange(aColorRange),
    126        mDevice(aDevice) {}
    127 
    128  bool IsCompatible(TextureClient* aTextureClient) override {
    129    D3D11TextureData* textureData =
    130        aTextureClient->GetInternalData()->AsD3D11TextureData();
    131    if (!textureData || aTextureClient->GetFormat() != mFormat ||
    132        aTextureClient->GetSize() != mSize) {
    133      return false;
    134    }
    135    // TODO: Should we also check for change in the allocation flags if RGBA?
    136    return (aTextureClient->GetFormat() != gfx::SurfaceFormat::NV12 &&
    137            aTextureClient->GetFormat() != gfx::SurfaceFormat::P010 &&
    138            aTextureClient->GetFormat() != gfx::SurfaceFormat::P016) ||
    139           (textureData->mColorSpace == mColorSpace &&
    140            textureData->GetColorRange() == mColorRange &&
    141            textureData->GetTextureAllocationFlags() == mAllocationFlags);
    142  }
    143 
    144  already_AddRefed<TextureClient> Allocate(
    145      KnowsCompositor* aAllocator) override {
    146    D3D11TextureData* data =
    147        D3D11TextureData::Create(mSize, mFormat, mAllocationFlags, mDevice);
    148    if (!data) {
    149      return nullptr;
    150    }
    151    data->mColorSpace = mColorSpace;
    152    data->SetColorRange(mColorRange);
    153    return MakeAndAddRef<TextureClient>(data, mTextureFlags,
    154                                        aAllocator->GetTextureForwarder());
    155  }
    156 
    157 private:
    158  const gfx::ColorSpace2 mColorSpace;
    159  const gfx::ColorRange mColorRange;
    160  const RefPtr<ID3D11Device> mDevice;
    161 };
    162 
    163 D3D11RecycleAllocator::D3D11RecycleAllocator(
    164    KnowsCompositor* aAllocator, ID3D11Device* aDevice,
    165    gfx::SurfaceFormat aPreferredFormat)
    166    : TextureClientRecycleAllocator(aAllocator),
    167      mDevice(aDevice),
    168      mCanUseNV12(StaticPrefs::media_wmf_use_nv12_format() &&
    169                  gfx::DeviceManagerDx::Get()->CanUseNV12()),
    170      mCanUseP010(StaticPrefs::media_wmf_use_nv12_format() &&
    171                  gfx::DeviceManagerDx::Get()->CanUseP010()),
    172      mCanUseP016(StaticPrefs::media_wmf_use_nv12_format() &&
    173                  gfx::DeviceManagerDx::Get()->CanUseP016()) {
    174  SetPreferredSurfaceFormat(aPreferredFormat);
    175 }
    176 
    177 void D3D11RecycleAllocator::SetPreferredSurfaceFormat(
    178    gfx::SurfaceFormat aPreferredFormat) {
    179  if ((aPreferredFormat == gfx::SurfaceFormat::NV12 && mCanUseNV12) ||
    180      (aPreferredFormat == gfx::SurfaceFormat::P010 && mCanUseP010) ||
    181      (aPreferredFormat == gfx::SurfaceFormat::P016 && mCanUseP016) ||
    182      (aPreferredFormat == gfx::SurfaceFormat::R10G10B10A2_UINT32) ||
    183      (aPreferredFormat == gfx::SurfaceFormat::R10G10B10X2_UINT32) ||
    184      (aPreferredFormat == gfx::SurfaceFormat::R16G16B16A16F)) {
    185    mUsableSurfaceFormat = aPreferredFormat;
    186    return;
    187  }
    188  // We can't handle the native source format, set it to BGRA which will
    189  // force the caller to convert it later.
    190  mUsableSurfaceFormat = gfx::SurfaceFormat::B8G8R8A8;
    191 }
    192 
    193 already_AddRefed<TextureClient> D3D11RecycleAllocator::CreateOrRecycleClient(
    194    gfx::ColorSpace2 aColorSpace, gfx::ColorRange aColorRange,
    195    const gfx::IntSize& aSize) {
    196  // When CompositorDevice or ContentDevice is updated,
    197  // we could not reuse old D3D11Textures. It could cause video flickering.
    198  RefPtr<ID3D11Device> device = gfx::DeviceManagerDx::Get()->GetImageDevice();
    199  if (!!mImageDevice && mImageDevice != device) {
    200    ShrinkToMinimumSize();
    201  }
    202  mImageDevice = device;
    203 
    204  auto* fencesHolderMap = CompositeProcessD3D11FencesHolderMap::Get();
    205  const bool useFence =
    206      fencesHolderMap && FenceD3D11::IsSupported(mImageDevice);
    207  TextureAllocationFlags allocFlags = TextureAllocationFlags::ALLOC_DEFAULT;
    208  if (!useFence && (StaticPrefs::media_wmf_use_sync_texture_AtStartup() ||
    209                    mDevice == DeviceManagerDx::Get()->GetCompositorDevice())) {
    210    // If our device is the compositor device, we don't need any synchronization
    211    // in practice.
    212    allocFlags = TextureAllocationFlags::ALLOC_MANUAL_SYNCHRONIZATION;
    213  }
    214 
    215  D3D11TextureClientAllocationHelper helper(
    216      mUsableSurfaceFormat, aColorSpace, aColorRange, aSize, allocFlags,
    217      mDevice, layers::TextureFlags::DEFAULT);
    218 
    219  RefPtr<TextureClient> textureClient =
    220      CreateOrRecycle(helper).unwrapOr(nullptr);
    221 
    222  if (textureClient) {
    223    auto* textureData = textureClient->GetInternalData()->AsD3D11TextureData();
    224    MOZ_ASSERT(textureData);
    225    if (textureData && textureData->mFencesHolderId.isSome() &&
    226        fencesHolderMap) {
    227      fencesHolderMap->WaitAllFencesAndForget(
    228          textureData->mFencesHolderId.ref(), mDevice);
    229    }
    230  }
    231  return textureClient.forget();
    232 }
    233 
    234 RefPtr<ID3D11Texture2D> D3D11RecycleAllocator::GetStagingTextureNV12(
    235    gfx::IntSize aSize) {
    236  if (!mStagingTexture || mStagingTextureSize != aSize) {
    237    mStagingTexture = nullptr;
    238 
    239    D3D11_TEXTURE2D_DESC desc = {};
    240    desc.Width = aSize.width;
    241    desc.Height = aSize.height;
    242    desc.Format = DXGI_FORMAT_NV12;
    243    desc.MipLevels = 1;
    244    desc.ArraySize = 1;
    245    desc.Usage = D3D11_USAGE_STAGING;
    246    desc.BindFlags = 0;
    247    desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
    248    desc.MiscFlags = 0;
    249    desc.SampleDesc.Count = 1;
    250 
    251    HRESULT hr = mDevice->CreateTexture2D(&desc, nullptr,
    252                                          getter_AddRefs(mStagingTexture));
    253    if (FAILED(hr)) {
    254      gfxCriticalNoteOnce << "allocating D3D11 NV12 staging texture failed: "
    255                          << gfx::hexa(hr);
    256      return nullptr;
    257    }
    258    MOZ_ASSERT(mStagingTexture);
    259    mStagingTextureSize = aSize;
    260  }
    261 
    262  return mStagingTexture;
    263 }
    264 
    265 }  // namespace layers
    266 }  // namespace mozilla