tor-browser

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

VideoProcessorD3D11.cpp (8278B)


      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 "VideoProcessorD3D11.h"
      8 
      9 #include <d3d11.h>
     10 #include <d3d11_1.h>
     11 
     12 #include "mozilla/gfx/Logging.h"
     13 #include "mozilla/gfx/Types.h"
     14 #include "mozilla/layers/TextureD3D11.h"
     15 #include "mozilla/Maybe.h"
     16 
     17 namespace mozilla {
     18 namespace layers {
     19 
     20 // TODO: Replace with YUVRangedColorSpace
     21 static Maybe<DXGI_COLOR_SPACE_TYPE> GetSourceDXGIColorSpace(
     22    const gfx::YUVColorSpace aYUVColorSpace, const gfx::ColorRange aColorRange,
     23    const bool aContentIsHDR) {
     24  if (aYUVColorSpace == gfx::YUVColorSpace::BT601) {
     25    if (aColorRange == gfx::ColorRange::FULL) {
     26      return Some(DXGI_COLOR_SPACE_YCBCR_FULL_G22_LEFT_P601);
     27    } else {
     28      return Some(DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P601);
     29    }
     30  } else if (aYUVColorSpace == gfx::YUVColorSpace::BT709) {
     31    if (aColorRange == gfx::ColorRange::FULL) {
     32      return Some(DXGI_COLOR_SPACE_YCBCR_FULL_G22_LEFT_P709);
     33    } else {
     34      return Some(DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P709);
     35    }
     36  } else if (aYUVColorSpace == gfx::YUVColorSpace::BT2020) {
     37    if (aColorRange == gfx::ColorRange::FULL) {
     38      if (aContentIsHDR) {
     39        // DXGI doesn't have a full range PQ YCbCr format, hopefully we won't
     40        // have to deal with this case.
     41        gfxCriticalNoteOnce
     42            << "GetSourceDXGIColorSpace: DXGI has no full range "
     43               "BT2020 PQ YCbCr format, using studio range instead";
     44        return Some(DXGI_COLOR_SPACE_YCBCR_STUDIO_G2084_LEFT_P2020);
     45      } else {
     46        return Some(DXGI_COLOR_SPACE_YCBCR_FULL_G22_LEFT_P2020);
     47      }
     48    } else {
     49      if (aContentIsHDR) {
     50        return Some(DXGI_COLOR_SPACE_YCBCR_STUDIO_G2084_LEFT_P2020);
     51      } else {
     52        return Some(DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P2020);
     53      }
     54    }
     55  }
     56 
     57  return Nothing();
     58 }
     59 
     60 static Maybe<DXGI_COLOR_SPACE_TYPE> GetSourceDXGIColorSpace(
     61    const gfx::YUVRangedColorSpace aYUVColorSpace, const bool aContentIsHDR) {
     62  const auto info = FromYUVRangedColorSpace(aYUVColorSpace);
     63  return GetSourceDXGIColorSpace(info.space, info.range, aContentIsHDR);
     64 }
     65 
     66 /* static */
     67 RefPtr<VideoProcessorD3D11> VideoProcessorD3D11::Create(ID3D11Device* aDevice) {
     68  MOZ_ASSERT(aDevice);
     69 
     70  if (!aDevice) {
     71    return nullptr;
     72  }
     73 
     74  RefPtr<ID3D11DeviceContext> context;
     75  aDevice->GetImmediateContext(getter_AddRefs(context));
     76  if (!context) {
     77    return nullptr;
     78  }
     79 
     80  HRESULT hr;
     81  RefPtr<ID3D11VideoDevice> videoDevice;
     82  hr =
     83      aDevice->QueryInterface((ID3D11VideoDevice**)getter_AddRefs(videoDevice));
     84  if (FAILED(hr)) {
     85    gfxCriticalNoteOnce << "Failed to get D3D11VideoDevice: " << gfx::hexa(hr);
     86    return nullptr;
     87  }
     88 
     89  RefPtr<ID3D11VideoContext> videoContext;
     90  hr = context->QueryInterface(
     91      (ID3D11VideoContext**)getter_AddRefs(videoContext));
     92  if (FAILED(hr)) {
     93    gfxCriticalNoteOnce << "Failed to get D3D11VideoContext: " << gfx::hexa(hr);
     94    return nullptr;
     95  }
     96 
     97  RefPtr<ID3D11VideoContext1> videoContext1;
     98  hr = videoContext->QueryInterface(
     99      (ID3D11VideoContext1**)getter_AddRefs(videoContext1));
    100  if (FAILED(hr)) {
    101    gfxCriticalNoteOnce << "Failed to get D3D11VideoContext1: "
    102                        << gfx::hexa(hr);
    103    return nullptr;
    104  }
    105 
    106  RefPtr<VideoProcessorD3D11> videoProcessor = new VideoProcessorD3D11(
    107      aDevice, context, videoDevice, videoContext, videoContext1);
    108 
    109  return videoProcessor;
    110 }
    111 
    112 VideoProcessorD3D11::VideoProcessorD3D11(ID3D11Device* aDevice,
    113                                         ID3D11DeviceContext* aDeviceContext,
    114                                         ID3D11VideoDevice* aVideoDevice,
    115                                         ID3D11VideoContext* aVideoContext,
    116                                         ID3D11VideoContext1* aVideoContext1)
    117    : mDevice(aDevice),
    118      mDeviceContext(aDeviceContext),
    119      mVideoDevice(aVideoDevice),
    120      mVideoContext(aVideoContext),
    121      mVideoContext1(aVideoContext1) {}
    122 
    123 VideoProcessorD3D11::~VideoProcessorD3D11() {}
    124 
    125 HRESULT VideoProcessorD3D11::Init(const gfx::IntSize& aSize) {
    126  if (mSize == aSize) {
    127    return S_OK;
    128  }
    129 
    130  mVideoProcessorEnumerator = nullptr;
    131  mVideoProcessor = nullptr;
    132  mSize = gfx::IntSize();
    133 
    134  D3D11_VIDEO_PROCESSOR_CONTENT_DESC desc;
    135  desc.InputFrameFormat = D3D11_VIDEO_FRAME_FORMAT_PROGRESSIVE;
    136  desc.InputFrameRate.Numerator = 60;
    137  desc.InputFrameRate.Denominator = 1;
    138  desc.InputWidth = aSize.width;
    139  desc.InputHeight = aSize.height;
    140  desc.OutputFrameRate.Numerator = 60;
    141  desc.OutputFrameRate.Denominator = 1;
    142  desc.OutputWidth = aSize.width;
    143  desc.OutputHeight = aSize.height;
    144  desc.Usage = D3D11_VIDEO_USAGE_PLAYBACK_NORMAL;
    145 
    146  HRESULT hr = mVideoDevice->CreateVideoProcessorEnumerator(
    147      &desc, getter_AddRefs(mVideoProcessorEnumerator));
    148  if (FAILED(hr)) {
    149    gfxCriticalNoteOnce << "Failed to create VideoProcessorEnumerator: "
    150                        << gfx::hexa(hr);
    151    return hr;
    152  }
    153 
    154  hr = mVideoDevice->CreateVideoProcessor(mVideoProcessorEnumerator, 0,
    155                                          getter_AddRefs(mVideoProcessor));
    156  if (FAILED(hr)) {
    157    gfxCriticalNoteOnce << "Failed to create VideoProcessor: " << gfx::hexa(hr);
    158    return hr;
    159  }
    160 
    161  // Turn off auto stream processing (the default) that will hurt power
    162  // consumption.
    163  mVideoContext->VideoProcessorSetStreamAutoProcessingMode(mVideoProcessor, 0,
    164                                                           FALSE);
    165 
    166  mSize = aSize;
    167 
    168  return S_OK;
    169 }
    170 
    171 bool VideoProcessorD3D11::CallVideoProcessorBlt(
    172    InputTextureInfo& aTextureInfo, ID3D11Texture2D* aOutputTexture) {
    173  MOZ_ASSERT(mVideoProcessorEnumerator);
    174  MOZ_ASSERT(mVideoProcessor);
    175  MOZ_ASSERT(aTextureInfo.mTexture);
    176  MOZ_ASSERT(aOutputTexture);
    177 
    178  HRESULT hr;
    179 
    180  auto yuvRangedColorSpace = gfx::ToYUVRangedColorSpace(
    181      gfx::ToYUVColorSpace(aTextureInfo.mColorSpace), aTextureInfo.mColorRange);
    182  auto sourceColorSpace =
    183      GetSourceDXGIColorSpace(yuvRangedColorSpace, mContentIsHDR);
    184  if (sourceColorSpace.isNothing()) {
    185    gfxCriticalNoteOnce << "Unsupported color space";
    186    return false;
    187  }
    188 
    189  DXGI_COLOR_SPACE_TYPE inputColorSpace = sourceColorSpace.ref();
    190  mVideoContext1->VideoProcessorSetStreamColorSpace1(mVideoProcessor, 0,
    191                                                     inputColorSpace);
    192 
    193  const DXGI_COLOR_SPACE_TYPE outputColorSpace =
    194      DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709;
    195 
    196  mVideoContext1->VideoProcessorSetOutputColorSpace1(mVideoProcessor,
    197                                                     outputColorSpace);
    198 
    199  D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC inputDesc = {};
    200  inputDesc.ViewDimension = D3D11_VPIV_DIMENSION_TEXTURE2D;
    201  inputDesc.Texture2D.ArraySlice = aTextureInfo.mIndex;
    202 
    203  RefPtr<ID3D11VideoProcessorInputView> inputView;
    204  hr = mVideoDevice->CreateVideoProcessorInputView(
    205      aTextureInfo.mTexture, mVideoProcessorEnumerator, &inputDesc,
    206      getter_AddRefs(inputView));
    207  if (FAILED(hr)) {
    208    gfxCriticalNoteOnce << "ID3D11VideoProcessorInputView creation failed: "
    209                        << gfx::hexa(hr);
    210    return false;
    211  }
    212 
    213  D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC outputDesc = {};
    214  outputDesc.ViewDimension = D3D11_VPOV_DIMENSION_TEXTURE2D;
    215  outputDesc.Texture2D.MipSlice = 0;
    216 
    217  RefPtr<ID3D11VideoProcessorOutputView> outputView;
    218  hr = mVideoDevice->CreateVideoProcessorOutputView(
    219      aOutputTexture, mVideoProcessorEnumerator, &outputDesc,
    220      getter_AddRefs(outputView));
    221  if (FAILED(hr)) {
    222    gfxCriticalNoteOnce << "ID3D11VideoProcessorOutputView creation failed: "
    223                        << gfx::hexa(hr);
    224    return false;
    225  }
    226 
    227  D3D11_VIDEO_PROCESSOR_STREAM stream = {};
    228  stream.Enable = true;
    229  stream.pInputSurface = inputView.get();
    230 
    231  hr = mVideoContext->VideoProcessorBlt(mVideoProcessor, outputView, 0, 1,
    232                                        &stream);
    233  if (FAILED(hr)) {
    234    gfxCriticalNoteOnce << "VideoProcessorBlt failed: " << gfx::hexa(hr);
    235    return false;
    236  }
    237 
    238  return true;
    239 }
    240 
    241 }  // namespace layers
    242 }  // namespace mozilla