#ifdef UNSAFE_BUFFERS_BUILD
#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"
#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 {
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 = …;
const char* VaapiFunctionName(VaapiFunctions function) { … }
class VADisplayStateSingleton { … };
}
#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 media {
namespace {
constexpr VAEntrypoint kVAEntrypointInvalid = …;
bool IsGen8Gpu() { … }
bool IsGen9Gpu() { … }
bool IsGen95Gpu() { … }
bool IsGen11Gpu() { … }
bool IsUsingHybridDriverForDecoding(VAProfile va_profile) { … }
bool IsLowPowerIntelProcessor() { … }
bool IsModeDecoding(VaapiWrapper::CodecMode mode) { … }
bool IsModeEncoding(VaapiWrapper::CodecMode mode) { … }
void FillNV12Padding(const VAImage& image,
const gfx::Size& visible_size,
uint8_t* data) { … }
std::optional<base::AutoLock> AutoLockOnlyIfNeeded(base::Lock* lock) { … }
ProfileCodecMap;
const ProfileCodecMap& GetProfileCodecMap() { … }
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) { … }
std::vector<VAProfile> GetSupportedVAProfiles(const base::Lock* va_lock,
VADisplay va_display) { … }
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) { … }
bool AreAttribsSupported(const base::Lock* va_lock,
VADisplay va_display,
VAProfile va_profile,
VAEntrypoint entrypoint,
const std::vector<VAConfigAttrib>& required_attribs) { … }
class VASupportedProfiles { … };
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) { … }
class VASupportedImageFormats { … };
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) { … }
}
VADisplayStateSingleton& VADisplayStateSingleton::GetInstance() { … }
void VADisplayStateSingleton::PreSandboxInitialization() { … }
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;
VAImplementation VaapiWrapper::GetImplementationType() { … }
int VaapiWrapper::GetMaxNumDecoderInstances() { … }
base::expected<scoped_refptr<VaapiWrapper>, DecoderStatus> VaapiWrapper::Create(
CodecMode mode,
VAProfile va_profile,
EncryptionScheme encryption_scheme,
const ReportErrorToUMACB& report_error_to_uma_cb) { … }
base::AtomicRefCount VaapiWrapper::num_decoder_instances_(0);
base::expected<scoped_refptr<VaapiWrapper>, DecoderStatus>
VaapiWrapper::CreateForVideoCodec(
CodecMode mode,
VideoCodecProfile profile,
EncryptionScheme encryption_scheme,
const ReportErrorToUMACB& report_error_to_uma_cb) { … }
std::vector<SVCScalabilityMode> VaapiWrapper::GetSupportedScalabilityModes(
VideoCodecProfile media_profile,
VAProfile va_profile) { … }
VideoEncodeAccelerator::SupportedProfiles
VaapiWrapper::GetSupportedEncodeProfiles() { … }
VideoDecodeAccelerator::SupportedProfiles
VaapiWrapper::GetSupportedDecodeProfiles() { … }
bool VaapiWrapper::IsDecodeSupported(VAProfile va_profile) { … }
VaapiWrapper::InternalFormats VaapiWrapper::GetDecodeSupportedInternalFormats(
VAProfile va_profile) { … }
bool VaapiWrapper::IsDecodingSupportedForInternalFormat(
VAProfile va_profile,
unsigned int rt_format) { … }
bool VaapiWrapper::GetSupportedResolutions(VAProfile va_profile,
CodecMode codec_mode,
gfx::Size& min_size,
gfx::Size& max_size) { … }
bool VaapiWrapper::GetJpegDecodeSuitableImageFourCC(unsigned int rt_format,
uint32_t preferred_fourcc,
uint32_t* suitable_fourcc) { … }
bool VaapiWrapper::IsVppResolutionAllowed(const gfx::Size& size) { … }
bool VaapiWrapper::IsVppFormatSupported(uint32_t va_fourcc) { … }
std::vector<Fourcc> VaapiWrapper::GetVppSupportedFormats() { … }
bool VaapiWrapper::IsVppSupportedForJpegDecodedSurfaceToFourCC(
unsigned int rt_format,
uint32_t fourcc) { … }
bool VaapiWrapper::IsJpegEncodeSupported() { … }
bool VaapiWrapper::IsImageFormatSupported(const VAImageFormat& format) { … }
const std::vector<VAImageFormat>&
VaapiWrapper::GetSupportedImageFormatsForTesting() { … }
std::map<VAProfile, std::vector<VAEntrypoint>>
VaapiWrapper::GetSupportedConfigurationsForCodecModeForTesting(CodecMode mode) { … }
VAEntrypoint VaapiWrapper::GetDefaultVaEntryPoint(CodecMode mode,
VAProfile profile) { … }
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);
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
) { … }
bool VaapiWrapper::allow_disabling_global_lock_ = …;
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() { … }
}