chromium/media/gpu/vaapi/vaapi_wrapper.cc

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

#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
#pragma allow_unsafe_buffers
#endif

#include "media/gpu/vaapi/vaapi_wrapper.h"

#include <dlfcn.h>
#include <drm_fourcc.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <va/va.h>
#include <va/va_drm.h>
#include <va/va_drmcommon.h>
#include <va/va_str.h>
#include <va/va_version.h>
#include <xf86drm.h>

#include <optional>
#include <string>
#include <type_traits>
#include <utility>
#include <vector>

#include "base/containers/contains.h"
#include "base/containers/fixed_flat_set.h"
#include "base/cpu.h"
#include "base/environment.h"
#include "base/feature_list.h"
#include "base/files/scoped_file.h"
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/logging.h"
#include "base/metrics/histogram_macros.h"
#include "base/numerics/checked_math.h"
#include "base/numerics/safe_conversions.h"
#include "base/posix/eintr_wrapper.h"
#include "base/ranges/algorithm.h"
#include "base/strings/pattern.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/synchronization/lock.h"
#include "base/system/sys_info.h"
#include "base/trace_event/trace_event.h"
#include "base/version.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "media/base/limits.h"
#include "media/base/media_switches.h"
#include "media/base/platform_features.h"
#include "media/base/video_codecs.h"
#include "media/base/video_frame.h"
#include "media/base/video_types.h"
#include "media/gpu/chromeos/frame_resource.h"
#include "media/gpu/macros.h"
// Auto-generated for dlopen libva libraries
#include "media/gpu/vaapi/va_stubs.h"
#include "media/media_buildflags.h"
#include "third_party/abseil-cpp/absl/cleanup/cleanup.h"
#include "third_party/libva_protected_content/va_protected_content.h"
#include "third_party/libyuv/include/libyuv.h"
#include "ui/gfx/buffer_format_util.h"
#include "ui/gfx/buffer_types.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/linux/drm_util_linux.h"
#include "ui/gfx/linux/native_pixmap_dmabuf.h"
#include "ui/gfx/native_pixmap.h"
#include "ui/gfx/native_pixmap_handle.h"

#if BUILDFLAG(IS_CHROMEOS_ASH)
#include <va/va_prot.h>
using media_gpu_vaapi::kModuleVa_prot;
#endif

#if BUILDFLAG(IS_LINUX)
#include "base/files/file_util.h"
#include "base/strings/string_split.h"
#endif

InitializeStubs;
IsVa_drmInitialized;
IsVaInitialized;
kModuleVa;
kModuleVa_drm;
StubPathMap;

namespace media {

// These values are logged to UMA. Entries should not be renumbered and numeric
// values should never be reused. Please keep in sync with
// "VaapiFunctions" in src/tools/metrics/histograms/enums.xml.
enum class VaapiFunctions {};

void ReportVaapiErrorToUMA(const std::string& histogram_name,
                           VaapiFunctions value) {}

constexpr std::array<const char*,
                     static_cast<size_t>(VaapiFunctions::kMaxValue) + 1>
    kVaapiFunctionNames =;

// Translates |function| into a human readable string for logging.
const char* VaapiFunctionName(VaapiFunctions function) {}

// This class is a wrapper around its |va_display_| (and its associated
// |va_lock_|) to guarantee mutual exclusion and singleton behaviour.
//
// Users of this class should hold onto a non-null VADisplayStateHandle for as
// long as they need to access any of the VADisplayStateSingleton methods. This
// guarantees that the VADisplayStateSingleton is properly initialized.
//
// Details:
//
// A VADisplayStateSingleton is immutable from the point of view of its users.
// That is, as long as a non-null VADisplayStateHandle exists, the va_display(),
// implementation_type(), and vendor_string() methods always return the same
// values.
//
// It's not strictly necessary to acquire the lock returned by va_lock() before
// calling va_display(), implementation_type(), or vendor_string(). However, on
// older drivers, it maybe necessary to acquire that lock before using the
// VADisplay returned by va_display() on any libva calls. That's because older
// drivers may not guarantee that it's safe to use the same VADisplay
// concurrently.
class VADisplayStateSingleton {};

}  // namespace media

#define LOG_VA_ERROR_AND_REPORT(va_error, function)

#define VA_LOG_ON_ERROR(va_res, function)

#define VA_SUCCESS_OR_RETURN(va_res, function, ret)

namespace {

uint32_t BufferFormatToVAFourCC(gfx::BufferFormat fmt) {}

media::VAImplementation VendorStringToImplementationType(
    const std::string& va_vendor_string) {}

bool IsThreadSafeDriver(media::VAImplementation implementation_type) {}

bool UseGlobalVaapiLock(media::VAImplementation implementation_type) {}

bool FillVADRMPRIMESurfaceDescriptor(const gfx::NativePixmap& pixmap,
                                     VADRMPRIMESurfaceDescriptor& descriptor) {}

struct VASurfaceAttribExternalBuffersAndFD {};

bool FillVASurfaceAttribExternalBuffers(
    const gfx::NativePixmap& pixmap,
    VASurfaceAttribExternalBuffersAndFD& va_attrib_extbuf_and_fd) {}

}  // namespace

namespace media {

namespace {
// VAEntrypoint is an enumeration starting from 1, but has no "invalid" value.
constexpr VAEntrypoint kVAEntrypointInvalid =;

// Returns true if the SoC has a Gen8 GPU. CPU model ID's are referenced from
// the following file in the kernel source: arch/x86/include/asm/intel-family.h.
bool IsGen8Gpu() {}

// Returns true if the SoC has a Gen9 GPU. CPU model ID's are referenced from
// the following file in the kernel source: arch/x86/include/asm/intel-family.h.
bool IsGen9Gpu() {}

// Returns true if the SoC has a Gen9.5 GPU. CPU model IDs are referenced from
// the following file in the kernel source: arch/x86/include/asm/intel-family.h.
bool IsGen95Gpu() {}

// Returns true if the SoC has a Gen11 GPU. CPU model IDs are referenced from
// the following file in the kernel source: arch/x86/include/asm/intel-family.h.
bool IsGen11Gpu() {}

// Returns true if the intel hybrid driver is used for decoding |va_profile|.
// https://github.com/intel/intel-hybrid-driver
// Note that since the hybrid driver runs as a part of the i965 driver,
// vaQueryVendorString() returns "Intel i965 driver".
bool IsUsingHybridDriverForDecoding(VAProfile va_profile) {}

// Returns true if the SoC is considered a low power one, i.e. it's an Intel
// Pentium, Celeron, or a Core Y-series. See go/intel-socs-101 or
// https://www.intel.com/content/www/us/en/processors/processor-numbers.html.
bool IsLowPowerIntelProcessor() {}

bool IsModeDecoding(VaapiWrapper::CodecMode mode) {}

bool IsModeEncoding(VaapiWrapper::CodecMode mode) {}

// Fill VAImage's non-visible area with 0s.
void FillNV12Padding(const VAImage& image,
                     const gfx::Size& visible_size,
                     uint8_t* data) {}

// Creates an AutoLock iff |va_lock_| is not null and the libva backend is
// thread-safe.
std::optional<base::AutoLock> AutoLockOnlyIfNeeded(base::Lock* lock) {}

// Can't statically initialize the profile map:
// https://google.github.io/styleguide/cppguide.html#Static_and_Global_Variables
ProfileCodecMap;
const ProfileCodecMap& GetProfileCodecMap() {}

// Maps a VideoCodecProfile |profile| to a VAProfile, or VAProfileNone.
VAProfile ProfileToVAProfile(VideoCodecProfile profile) {}

bool IsVAProfileSupported(VAProfile va_profile, bool is_encoding) {}

bool IsBlockedDriver(VaapiWrapper::CodecMode mode,
                     VAProfile va_profile,
                     const std::string& va_vendor_string) {}

// Returns all the VAProfiles that the driver lists as supported, regardless of
// what Chrome supports or not.
std::vector<VAProfile> GetSupportedVAProfiles(const base::Lock* va_lock,
                                              VADisplay va_display) {}

// Queries the driver for the supported entrypoints for |va_profile|, then
// returns those allowed for |mode|.
std::vector<VAEntrypoint> GetEntryPointsForProfile(const base::Lock* va_lock,
                                                   VADisplay va_display,
                                                   VaapiWrapper::CodecMode mode,
                                                   VAProfile va_profile) {}

bool GetRequiredAttribs(const base::Lock* va_lock,
                        VADisplay va_display,
                        VaapiWrapper::CodecMode mode,
                        VAProfile profile,
                        VAEntrypoint entrypoint,
                        std::vector<VAConfigAttrib>* required_attribs) {}

// Returns true if |va_profile| for |entrypoint| with |required_attribs| is
// supported.
bool AreAttribsSupported(const base::Lock* va_lock,
                         VADisplay va_display,
                         VAProfile va_profile,
                         VAEntrypoint entrypoint,
                         const std::vector<VAConfigAttrib>& required_attribs) {}

// This class encapsulates reading and giving access to the list of supported
// ProfileInfo entries, in a singleton way.
class VASupportedProfiles {};

// static
const VASupportedProfiles& VASupportedProfiles::Get() {}

const VASupportedProfiles::ProfileInfo* VASupportedProfiles::IsProfileSupported(
    VaapiWrapper::CodecMode mode,
    VAProfile va_profile,
    VAEntrypoint va_entrypoint) const {}

VASupportedProfiles::VASupportedProfiles()
    :{}

void VASupportedProfiles::FillSupportedProfileInfos(
    base::Lock* va_lock,
    VADisplay va_display,
    const std::string& va_vendor_string) {}

bool VASupportedProfiles::FillProfileInfo_Locked(
    const base::Lock* va_lock,
    VADisplay va_display,
    VAProfile va_profile,
    VAEntrypoint entrypoint,
    std::vector<VAConfigAttrib>& required_attribs,
    ProfileInfo* profile_info) const {}

void DestroyVAImage(VADisplay va_display, const VAImage& image) {}

// This class encapsulates fetching the list of supported output image formats
// from the VAAPI driver, in a singleton way.
class VASupportedImageFormats {};

// static
const VASupportedImageFormats& VASupportedImageFormats::Get() {}

bool VASupportedImageFormats::IsImageFormatSupported(
    const VAImageFormat& va_image_format) const {}

const std::vector<VAImageFormat>&
VASupportedImageFormats::GetSupportedImageFormats() const {}

VASupportedImageFormats::VASupportedImageFormats()
    :{}

bool VASupportedImageFormats::InitSupportedImageFormats_Locked(
    const base::Lock* va_lock,
    VADisplay va_display) {}

bool IsLowPowerEncSupported(VAProfile va_profile) {}

bool IsVBREncodingSupported(VAProfile va_profile) {}

bool IsLibVACompatible(const base::Version& runtime,
                       const base::Version& build_time) {}

}  // namespace

// static
VADisplayStateSingleton& VADisplayStateSingleton::GetInstance() {}

// static
void VADisplayStateSingleton::PreSandboxInitialization() {}

// static
VADisplayStateHandle VADisplayStateSingleton::GetHandle() {}

bool VADisplayStateSingleton::Initialize() {}

void VADisplayStateSingleton::OnRefDestroyed() {}

VADisplayStateHandle::VADisplayStateHandle() :{}

VADisplayStateHandle::VADisplayStateHandle(
    VADisplayStateSingleton* va_display_state)
    :{}

VADisplayStateHandle::~VADisplayStateHandle() {}

NativePixmapAndSizeInfo::NativePixmapAndSizeInfo() = default;

NativePixmapAndSizeInfo::~NativePixmapAndSizeInfo() = default;

// static
VAImplementation VaapiWrapper::GetImplementationType() {}

// static
int VaapiWrapper::GetMaxNumDecoderInstances() {}

// static
base::expected<scoped_refptr<VaapiWrapper>, DecoderStatus> VaapiWrapper::Create(
    CodecMode mode,
    VAProfile va_profile,
    EncryptionScheme encryption_scheme,
    const ReportErrorToUMACB& report_error_to_uma_cb) {}

// static
base::AtomicRefCount VaapiWrapper::num_decoder_instances_(0);

// static
base::expected<scoped_refptr<VaapiWrapper>, DecoderStatus>
VaapiWrapper::CreateForVideoCodec(
    CodecMode mode,
    VideoCodecProfile profile,
    EncryptionScheme encryption_scheme,
    const ReportErrorToUMACB& report_error_to_uma_cb) {}

// static
std::vector<SVCScalabilityMode> VaapiWrapper::GetSupportedScalabilityModes(
    VideoCodecProfile media_profile,
    VAProfile va_profile) {}

// static
VideoEncodeAccelerator::SupportedProfiles
VaapiWrapper::GetSupportedEncodeProfiles() {}

// static
VideoDecodeAccelerator::SupportedProfiles
VaapiWrapper::GetSupportedDecodeProfiles() {}

// static
bool VaapiWrapper::IsDecodeSupported(VAProfile va_profile) {}

// static
VaapiWrapper::InternalFormats VaapiWrapper::GetDecodeSupportedInternalFormats(
    VAProfile va_profile) {}

// static
bool VaapiWrapper::IsDecodingSupportedForInternalFormat(
    VAProfile va_profile,
    unsigned int rt_format) {}

// static
bool VaapiWrapper::GetSupportedResolutions(VAProfile va_profile,
                                           CodecMode codec_mode,
                                           gfx::Size& min_size,
                                           gfx::Size& max_size) {}

// static
bool VaapiWrapper::GetJpegDecodeSuitableImageFourCC(unsigned int rt_format,
                                                    uint32_t preferred_fourcc,
                                                    uint32_t* suitable_fourcc) {}

// static
bool VaapiWrapper::IsVppResolutionAllowed(const gfx::Size& size) {}

// static
bool VaapiWrapper::IsVppFormatSupported(uint32_t va_fourcc) {}

// static
std::vector<Fourcc> VaapiWrapper::GetVppSupportedFormats() {}

// static
bool VaapiWrapper::IsVppSupportedForJpegDecodedSurfaceToFourCC(
    unsigned int rt_format,
    uint32_t fourcc) {}

// static
bool VaapiWrapper::IsJpegEncodeSupported() {}

// static
bool VaapiWrapper::IsImageFormatSupported(const VAImageFormat& format) {}

// static
const std::vector<VAImageFormat>&
VaapiWrapper::GetSupportedImageFormatsForTesting() {}

// static
std::map<VAProfile, std::vector<VAEntrypoint>>
VaapiWrapper::GetSupportedConfigurationsForCodecModeForTesting(CodecMode mode) {}

// static
VAEntrypoint VaapiWrapper::GetDefaultVaEntryPoint(CodecMode mode,
                                                  VAProfile profile) {}

// static
uint32_t VaapiWrapper::BufferFormatToVARTFormat(gfx::BufferFormat fmt) {}

bool VaapiWrapper::CreateContextAndSurfaces(
    unsigned int va_format,
    const gfx::Size& size,
    const std::vector<SurfaceUsageHint>& surface_usage_hints,
    size_t num_surfaces,
    std::vector<VASurfaceID>* va_surfaces) {}

std::vector<std::unique_ptr<ScopedVASurface>>
VaapiWrapper::CreateContextAndScopedVASurfaces(
    unsigned int va_format,
    const gfx::Size& size,
    const std::vector<SurfaceUsageHint>& usage_hints,
    size_t num_surfaces,
    const std::optional<gfx::Size>& visible_size) {}

bool VaapiWrapper::CreateProtectedSession(
    EncryptionScheme encryption,
    const std::vector<uint8_t>& hw_config,
    std::vector<uint8_t>* hw_identifier_out) {}

bool VaapiWrapper::IsProtectedSessionDead() {}

#if BUILDFLAG(IS_CHROMEOS_ASH)
bool VaapiWrapper::IsProtectedSessionDead(
    VAProtectedSessionID va_protected_session_id) {
  VAAPI_CHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  if (va_protected_session_id == VA_INVALID_ID)
    return false;

  uint8_t alive;
  VAProtectedSessionExecuteBuffer tee_exec_buf = {};
  tee_exec_buf.function_id = VA_TEE_EXEC_TEE_FUNCID_IS_SESSION_ALIVE;
  tee_exec_buf.input.data_size = 0;
  tee_exec_buf.input.data = nullptr;
  tee_exec_buf.output.data_size = sizeof(alive);
  tee_exec_buf.output.data = &alive;

  base::AutoLockMaybe auto_lock(va_lock_.get());
  VABufferID buf_id;
  VAStatus va_res = vaCreateBuffer(
      va_display_, va_protected_session_id, VAProtectedSessionExecuteBufferType,
      sizeof(tee_exec_buf), 1, &tee_exec_buf, &buf_id);
  // Failure here is valid if the protected session has been closed.
  if (va_res != VA_STATUS_SUCCESS)
    return true;

  va_res =
      vaProtectedSessionExecute(va_display_, va_protected_session_id, buf_id);
  vaDestroyBuffer(va_display_, buf_id);
  if (va_res != VA_STATUS_SUCCESS)
    return true;

  return !alive;
}
#endif

#if BUILDFLAG(IS_CHROMEOS_ASH)
VAProtectedSessionID VaapiWrapper::GetProtectedSessionID() const {
  VAAPI_CHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  return va_protected_session_id_;
}
#endif

void VaapiWrapper::DestroyProtectedSession() {}

void VaapiWrapper::DestroyContextAndSurfaces(
    std::vector<VASurfaceID> va_surfaces) {}

bool VaapiWrapper::CreateContext(const gfx::Size& size) {}

std::unique_ptr<ScopedVASurface> VaapiWrapper::CreateVASurfaceForFrameResource(
    const FrameResource& frame,
    bool protected_content) {}

std::unique_ptr<ScopedVASurface> VaapiWrapper::CreateVASurfaceForPixmap(
    scoped_refptr<const gfx::NativePixmap> pixmap,
    bool protected_content) {}

std::unique_ptr<ScopedVASurface> VaapiWrapper::CreateVASurfaceForUserPtr(
    const gfx::Size& size,
    uintptr_t* buffers,
    size_t buffer_size) {}

std::unique_ptr<ScopedVASurface> VaapiWrapper::CreateVASurfaceWithUsageHints(
    unsigned int va_rt_format,
    const gfx::Size& size,
    const std::vector<SurfaceUsageHint>& usage_hints) {}

std::unique_ptr<NativePixmapAndSizeInfo>
VaapiWrapper::ExportVASurfaceAsNativePixmapDmaBufUnwrapped(
    VASurfaceID va_surface_id,
    const gfx::Size& va_surface_size) {}

std::unique_ptr<NativePixmapAndSizeInfo>
VaapiWrapper::ExportVASurfaceAsNativePixmapDmaBuf(
    const ScopedVASurface& scoped_va_surface) {}

bool VaapiWrapper::SyncSurface(VASurfaceID va_surface_id) {}

bool VaapiWrapper::SubmitBuffer(VABufferType va_buffer_type,
                                size_t size,
                                const void* data) {}

bool VaapiWrapper::SubmitBuffers(
    const std::vector<VABufferDescriptor>& va_buffers) {}

void VaapiWrapper::DestroyPendingBuffers() {}

void VaapiWrapper::DestroyPendingBuffers_Locked() {}

bool VaapiWrapper::ExecuteAndDestroyPendingBuffers(VASurfaceID va_surface_id) {}

bool VaapiWrapper::MapAndCopyAndExecute(
    VASurfaceID va_surface_id,
    const std::vector<std::pair<VABufferID, VABufferDescriptor>>& va_buffers) {}

std::unique_ptr<ScopedVAImage> VaapiWrapper::CreateVaImage(
    VASurfaceID va_surface_id,
    const VAImageFormat& format,
    const gfx::Size& size) {}

bool VaapiWrapper::UploadVideoFrameToSurface(const VideoFrame& frame,
                                             VASurfaceID va_surface_id,
                                             const gfx::Size& va_surface_size)
    NO_THREAD_SAFETY_ANALYSIS {}

std::unique_ptr<ScopedVABuffer> VaapiWrapper::CreateVABuffer(VABufferType type,
                                                             size_t size) {}

uint64_t VaapiWrapper::GetEncodedChunkSize(VABufferID buffer_id,
                                           VASurfaceID sync_surface_id)
    NO_THREAD_SAFETY_ANALYSIS {}

bool VaapiWrapper::DownloadFromVABuffer(
    VABufferID buffer_id,
    std::optional<VASurfaceID> sync_surface_id,
    uint8_t* target_ptr,
    size_t target_size,
    size_t* coded_data_size) NO_THREAD_SAFETY_ANALYSIS {}

bool VaapiWrapper::GetVAEncMaxNumOfRefFrames(VideoCodecProfile profile,
                                             size_t* max_ref_frames) {}

bool VaapiWrapper::GetSupportedPackedHeaders(VideoCodecProfile profile,
                                             bool& packed_sps,
                                             bool& packed_pps,
                                             bool& packed_slice) {}

bool VaapiWrapper::GetMinAV1SegmentSize(VideoCodecProfile profile,
                                        uint32_t& min_seg_size) {}

bool VaapiWrapper::BlitSurface(VASurfaceID va_surface_src_id,
                               const gfx::Size& va_surface_src_size,
                               VASurfaceID va_surface_dst_id,
                               const gfx::Size& va_surface_dst_size,
                               std::optional<gfx::Rect> src_rect,
                               std::optional<gfx::Rect> dest_rect
#if BUILDFLAG(IS_CHROMEOS_ASH)
                               ,
                               VAProtectedSessionID va_protected_session_id
#endif
) {}

// static
bool VaapiWrapper::allow_disabling_global_lock_ =;

// static
void VaapiWrapper::PreSandboxInitialization(bool allow_disabling_global_lock) {}

VaapiWrapper::VaapiWrapper(VADisplayStateHandle va_display_state_handle,
                           CodecMode mode)
    :{}

VaapiWrapper::~VaapiWrapper() {}

bool VaapiWrapper::Initialize(VAProfile va_profile,
                              EncryptionScheme encryption_scheme) {}

void VaapiWrapper::Deinitialize() {}

void VaapiWrapper::VaInitialize(
    const ReportErrorToUMACB& report_error_to_uma_cb) {}

bool VaapiWrapper::HasContext() const {}

void VaapiWrapper::DestroyContext() {}

bool VaapiWrapper::CreateSurfaces(
    unsigned int va_format,
    const gfx::Size& size,
    const std::vector<SurfaceUsageHint>& usage_hints,
    size_t num_surfaces,
    std::vector<VASurfaceID>* va_surfaces) {}

std::vector<std::unique_ptr<ScopedVASurface>>
VaapiWrapper::CreateScopedVASurfaces(
    unsigned int va_rt_format,
    const gfx::Size& size,
    const std::vector<SurfaceUsageHint>& usage_hints,
    size_t num_surfaces,
    const std::optional<gfx::Size>& visible_size,
    const std::optional<uint32_t>& va_fourcc) {}

void VaapiWrapper::DestroySurfaces(std::vector<VASurfaceID> va_surfaces) {}

void VaapiWrapper::DestroySurface(VASurfaceID va_surface_id) {}

bool VaapiWrapper::Execute_Locked(VASurfaceID va_surface_id,
                                  const std::vector<VABufferID>& va_buffers) {}

bool VaapiWrapper::SubmitBuffer_Locked(const VABufferDescriptor& va_buffer) {}

bool VaapiWrapper::MapAndCopy_Locked(VABufferID va_buffer_id,
                                     const VABufferDescriptor& va_buffer) {}

void VaapiWrapper::MaybeSetLowQualityEncoding_Locked() {}

bool VaapiWrapper::MaybeAttachProtectedSession_Locked() {}

}  // namespace media