chromium/media/gpu/windows/d3d12_helpers.cc

// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "media/gpu/windows/d3d12_helpers.h"

#include "base/check_is_test.h"
#include "base/logging.h"
#include "media/base/video_codecs.h"
#include "media/gpu/windows/format_utils.h"
#include "media/gpu/windows/supported_profile_helpers.h"
#include "third_party/microsoft_dxheaders/src/include/directx/d3dx12_core.h"

namespace media {

D3D12ReferenceFrameList::D3D12ReferenceFrameList(ComD3D12VideoDecoderHeap heap)
    : heap_(std::move(heap)) {
  std::fill(heaps_.begin(), heaps_.end(), heap_.Get());
}

D3D12ReferenceFrameList::~D3D12ReferenceFrameList() = default;

void D3D12ReferenceFrameList::WriteTo(
    D3D12_VIDEO_DECODE_REFERENCE_FRAMES* dest) {
  dest->NumTexture2Ds = static_cast<UINT>(size_);
  dest->ppTexture2Ds = resources_.data();
  dest->pSubresources = subresources_.data();
  dest->ppHeaps = heaps_.data();
}

void D3D12ReferenceFrameList::emplace(size_t index,
                                      ID3D12Resource* resource,
                                      UINT subresource) {
  if (index >= size_) {
    size_ = index + 1;
    CHECK_LE(size_, kMaxSize);
  }
  resources_[index] = resource;
  subresources_[index] = subresource;
}

ComD3D12Device CreateD3D12Device(IDXGIAdapter* adapter) {
  if (!adapter) {
    // We've had at least a couple of scenarios where two calls to EnumAdapters
    // return different default adapters on multi-adapter systems due to race
    // conditions. These result in hard to repro bugs for end users.
    // Allowing using a default adapter only in tests.
    CHECK_IS_TEST();
  }

  ComD3D12Device device;
  HRESULT hr =
      D3D12CreateDevice(adapter, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&device));
  if (FAILED(hr)) {
    LOG(ERROR) << "D3D12CreateDevice failed: "
               << logging::SystemErrorCodeToString(hr);
    return nullptr;
  }

  return device;
}

absl::InlinedVector<D3D12_RESOURCE_BARRIER, 2>
CreateD3D12TransitionBarriersForAllPlanes(ID3D12Resource* resource,
                                          UINT subresource,
                                          D3D12_RESOURCE_STATES state_before,
                                          D3D12_RESOURCE_STATES state_after) {
  CHECK(resource);
  D3D12_RESOURCE_DESC desc = resource->GetDesc();
  absl::InlinedVector<D3D12_RESOURCE_BARRIER, 2> barriers;
  for (size_t i = 0; i < GetFormatPlaneCount(desc.Format); i++) {
    barriers.push_back({.Transition = {.pResource = resource,
                                       .Subresource = D3D12CalcSubresource(
                                           subresource, 0, i, desc.MipLevels,
                                           desc.DepthOrArraySize),
                                       .StateBefore = state_before,
                                       .StateAfter = state_after}});
  }
  return barriers;
}

GUID GetD3D12VideoDecodeGUID(VideoCodecProfile profile,
                             uint8_t bitdepth,
                             VideoChromaSampling chroma_sampling) {
  switch (profile) {
    case H264PROFILE_BASELINE:
    case H264PROFILE_MAIN:
    case H264PROFILE_EXTENDED:
    case H264PROFILE_HIGH:
    case H264PROFILE_HIGH10PROFILE:
    case H264PROFILE_HIGH422PROFILE:
    case H264PROFILE_HIGH444PREDICTIVEPROFILE:
    case H264PROFILE_SCALABLEBASELINE:
    case H264PROFILE_SCALABLEHIGH:
    case H264PROFILE_STEREOHIGH:
    case H264PROFILE_MULTIVIEWHIGH:
      return D3D12_VIDEO_DECODE_PROFILE_H264;
    case VP9PROFILE_PROFILE0:
      return D3D12_VIDEO_DECODE_PROFILE_VP9;
    case VP9PROFILE_PROFILE2:
      return D3D12_VIDEO_DECODE_PROFILE_VP9_10BIT_PROFILE2;
#if BUILDFLAG(ENABLE_HEVC_PARSER_AND_HW_DECODER)
    // Per DirectX Video Acceleration Specification for High Efficiency Video
    // Coding - 7.4, DXVA_ModeHEVC_VLD_Main GUID can be used for both main and
    // main still picture profile.
    case HEVCPROFILE_MAIN:
    case HEVCPROFILE_MAIN_STILL_PICTURE:
      return D3D12_VIDEO_DECODE_PROFILE_HEVC_MAIN;
    case HEVCPROFILE_MAIN10:
      return D3D12_VIDEO_DECODE_PROFILE_HEVC_MAIN10;
    case HEVCPROFILE_REXT:
      return GetHEVCRangeExtensionPrivateGUID(bitdepth, chroma_sampling);
#endif  // BUILDFLAG(ENABLE_HEVC_PARSER_AND_HW_DECODER)
    case AV1PROFILE_PROFILE_MAIN:
      return D3D12_VIDEO_DECODE_PROFILE_AV1_PROFILE0;
    case AV1PROFILE_PROFILE_HIGH:
      return D3D12_VIDEO_DECODE_PROFILE_AV1_PROFILE1;
    case AV1PROFILE_PROFILE_PRO:
      return D3D12_VIDEO_DECODE_PROFILE_AV1_PROFILE2;
    default:
      return {};
  }
}

}  // namespace media