mirror of
https://github.com/Alex313031/thorium.git
synced 2025-01-10 03:47:44 -03:00
Update vaapi_wrapper.cc
This commit is contained in:
parent
b65026de0a
commit
7a3a84e7ee
1 changed files with 192 additions and 75 deletions
|
@ -5,6 +5,7 @@
|
|||
#include "media/gpu/vaapi/vaapi_wrapper.h"
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <drm_fourcc.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
@ -54,6 +55,7 @@
|
|||
#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"
|
||||
|
@ -243,7 +245,7 @@ media::VAImplementation VendorStringToImplementationType(
|
|||
} else if (base::StartsWith(va_vendor_string, "Intel iHD driver",
|
||||
base::CompareCase::SENSITIVE)) {
|
||||
return media::VAImplementation::kIntelIHD;
|
||||
} else if (base::StartsWith(va_vendor_string, "Nvidia VDPAU",
|
||||
} else if (base::StartsWith(va_vendor_string, "Splitted-Desktop Systems VDPAU",
|
||||
base::CompareCase::SENSITIVE)) {
|
||||
return media::VAImplementation::kNVIDIAVDPAU;
|
||||
}
|
||||
|
@ -262,6 +264,152 @@ bool UseGlobalVaapiLock(media::VAImplementation implementation_type) {
|
|||
base::FeatureList::IsEnabled(media::kGlobalVaapiLock);
|
||||
}
|
||||
|
||||
bool FillVADRMPRIMESurfaceDescriptor(const gfx::NativePixmap& pixmap,
|
||||
VADRMPRIMESurfaceDescriptor& descriptor) {
|
||||
memset(&descriptor, 0, sizeof(VADRMPRIMESurfaceDescriptor));
|
||||
|
||||
const gfx::BufferFormat buffer_format = pixmap.GetBufferFormat();
|
||||
const uint32_t va_fourcc = BufferFormatToVAFourCC(buffer_format);
|
||||
DCHECK(va_fourcc);
|
||||
|
||||
const gfx::Size size = pixmap.GetBufferSize();
|
||||
const size_t num_planes = pixmap.GetNumberOfPlanes();
|
||||
const int drm_fourcc = ui::GetFourCCFormatFromBufferFormat(buffer_format);
|
||||
if (drm_fourcc == DRM_FORMAT_INVALID) {
|
||||
LOG(ERROR) << "Failed to get the DRM format from the buffer format";
|
||||
return false;
|
||||
}
|
||||
if (num_planes > std::size(descriptor.objects)) {
|
||||
LOG(ERROR) << "Too many planes in the NativePixmap; got " << num_planes
|
||||
<< " but the maximum number is "
|
||||
<< std::size(descriptor.objects);
|
||||
return false;
|
||||
}
|
||||
static_assert(std::size(VADRMPRIMESurfaceDescriptor{}.layers) ==
|
||||
std::size(VADRMPRIMESurfaceDescriptor{}.objects));
|
||||
static_assert(
|
||||
std::size(VADRMPRIMESurfaceDescriptor{}.layers[0].object_index) ==
|
||||
std::size(VADRMPRIMESurfaceDescriptor{}.objects));
|
||||
static_assert(std::size(VADRMPRIMESurfaceDescriptor{}.layers[0].offset) ==
|
||||
std::size(VADRMPRIMESurfaceDescriptor{}.objects));
|
||||
static_assert(std::size(VADRMPRIMESurfaceDescriptor{}.layers[0].pitch) ==
|
||||
std::size(VADRMPRIMESurfaceDescriptor{}.objects));
|
||||
|
||||
descriptor.fourcc = va_fourcc;
|
||||
descriptor.width = base::checked_cast<uint32_t>(size.width());
|
||||
descriptor.height = base::checked_cast<uint32_t>(size.height());
|
||||
|
||||
// We can pass the planes as separate layers or all in one layer. The choice
|
||||
// of doing the latter was arbitrary.
|
||||
descriptor.num_layers = 1u;
|
||||
descriptor.layers[0].drm_format = base::checked_cast<uint32_t>(drm_fourcc);
|
||||
descriptor.layers[0].num_planes = base::checked_cast<uint32_t>(num_planes);
|
||||
|
||||
descriptor.num_objects = base::checked_cast<uint32_t>(num_planes);
|
||||
for (size_t i = 0u; i < num_planes; i++) {
|
||||
const int dma_buf_fd = pixmap.GetDmaBufFd(i);
|
||||
if (dma_buf_fd < 0) {
|
||||
LOG(ERROR) << "Failed to get dmabuf from an Ozone NativePixmap";
|
||||
return false;
|
||||
}
|
||||
const off_t data_size = lseek(dma_buf_fd, /*offset=*/0, SEEK_END);
|
||||
if (data_size == static_cast<off_t>(-1)) {
|
||||
PLOG(ERROR) << "Failed to get the size of the dma-buf";
|
||||
return false;
|
||||
}
|
||||
if (lseek(dma_buf_fd, /*offset=*/0, SEEK_SET) == static_cast<off_t>(-1)) {
|
||||
PLOG(ERROR) << "Failed to reset the file offset of the dma-buf";
|
||||
return false;
|
||||
}
|
||||
|
||||
descriptor.objects[i].fd = dma_buf_fd;
|
||||
descriptor.objects[i].size = base::checked_cast<uint32_t>(data_size);
|
||||
descriptor.objects[i].drm_format_modifier =
|
||||
pixmap.GetBufferFormatModifier();
|
||||
|
||||
descriptor.layers[0].object_index[i] = base::checked_cast<uint32_t>(i);
|
||||
if (!base::IsValueInRangeForNumericType<uint32_t>(
|
||||
pixmap.GetDmaBufOffset(i))) {
|
||||
LOG(ERROR) << "The offset for plane " << i << " is out-of-range";
|
||||
return false;
|
||||
}
|
||||
descriptor.layers[0].offset[i] =
|
||||
base::checked_cast<uint32_t>(pixmap.GetDmaBufOffset(i));
|
||||
descriptor.layers[0].pitch[i] = pixmap.GetDmaBufPitch(i);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
struct VASurfaceAttribExternalBuffersAndFD {
|
||||
VASurfaceAttribExternalBuffers va_attrib_extbuf;
|
||||
uintptr_t fd;
|
||||
};
|
||||
|
||||
bool FillVASurfaceAttribExternalBuffers(
|
||||
const gfx::NativePixmap& pixmap,
|
||||
VASurfaceAttribExternalBuffersAndFD& va_attrib_extbuf_and_fd) {
|
||||
VASurfaceAttribExternalBuffers& va_attrib_extbuf =
|
||||
va_attrib_extbuf_and_fd.va_attrib_extbuf;
|
||||
memset(&va_attrib_extbuf_and_fd, 0,
|
||||
sizeof(VASurfaceAttribExternalBuffersAndFD));
|
||||
|
||||
const uint32_t va_fourcc = BufferFormatToVAFourCC(pixmap.GetBufferFormat());
|
||||
DCHECK(va_fourcc);
|
||||
|
||||
const gfx::Size size = pixmap.GetBufferSize();
|
||||
const size_t num_planes = pixmap.GetNumberOfPlanes();
|
||||
|
||||
va_attrib_extbuf.pixel_format = va_fourcc;
|
||||
va_attrib_extbuf.width = base::checked_cast<uint32_t>(size.width());
|
||||
va_attrib_extbuf.height = base::checked_cast<uint32_t>(size.height());
|
||||
|
||||
static_assert(std::size(VASurfaceAttribExternalBuffers{}.pitches) ==
|
||||
std::size(VASurfaceAttribExternalBuffers{}.offsets));
|
||||
if (num_planes > std::size(va_attrib_extbuf.pitches)) {
|
||||
LOG(ERROR) << "Too many planes in the NativePixmap; got " << num_planes
|
||||
<< " but the maximum number is "
|
||||
<< std::size(va_attrib_extbuf.pitches);
|
||||
return false;
|
||||
}
|
||||
for (size_t i = 0; i < num_planes; ++i) {
|
||||
va_attrib_extbuf.pitches[i] = pixmap.GetDmaBufPitch(i);
|
||||
va_attrib_extbuf.offsets[i] =
|
||||
base::checked_cast<uint32_t>(pixmap.GetDmaBufOffset(i));
|
||||
DVLOG(4) << "plane " << i << ": pitch: " << va_attrib_extbuf.pitches[i]
|
||||
<< " offset: " << va_attrib_extbuf.offsets[i];
|
||||
}
|
||||
va_attrib_extbuf.num_planes = base::checked_cast<uint32_t>(num_planes);
|
||||
|
||||
const int dma_buf_fd = pixmap.GetDmaBufFd(0);
|
||||
if (dma_buf_fd < 0) {
|
||||
LOG(ERROR) << "Failed to get dmabuf from an Ozone NativePixmap";
|
||||
return false;
|
||||
}
|
||||
const off_t data_size = lseek(dma_buf_fd, /*offset=*/0, SEEK_END);
|
||||
if (data_size == static_cast<off_t>(-1)) {
|
||||
PLOG(ERROR) << "Failed to get the size of the dma-buf";
|
||||
return false;
|
||||
}
|
||||
if (lseek(dma_buf_fd, /*offset=*/0, SEEK_SET) == static_cast<off_t>(-1)) {
|
||||
PLOG(ERROR) << "Failed to reset the file offset of the dma-buf";
|
||||
return false;
|
||||
}
|
||||
// If the data size doesn't fit in a uint32_t, we probably have bigger
|
||||
// problems.
|
||||
va_attrib_extbuf.data_size = base::checked_cast<uint32_t>(data_size);
|
||||
|
||||
// We only have to pass the first file descriptor to a driver. A VA-API driver
|
||||
// shall create a VASurface from the single fd correctly.
|
||||
va_attrib_extbuf_and_fd.fd = base::checked_cast<uintptr_t>(dma_buf_fd);
|
||||
va_attrib_extbuf.buffers = &va_attrib_extbuf_and_fd.fd;
|
||||
va_attrib_extbuf.num_buffers = 1u;
|
||||
|
||||
DCHECK_EQ(va_attrib_extbuf.flags, 0u);
|
||||
DCHECK_EQ(va_attrib_extbuf.private_data, nullptr);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace media {
|
||||
|
@ -981,6 +1129,10 @@ class VASupportedProfiles {
|
|||
// Determines if |mode| supports |va_profile| (and |va_entrypoint| if defined
|
||||
// and valid). If so, returns a const pointer to its ProfileInfo, otherwise
|
||||
// returns nullptr.
|
||||
// TODO(hiroh): If VAEntrypoint is kVAEntrypointInvalid, the default entry
|
||||
// point acquired by GetDefaultVaEntryPoint() is used. If the default entry
|
||||
// point is not supported, the earlier supported entrypoint in
|
||||
// |kAllowedEntryPopints| is used.
|
||||
const ProfileInfo* IsProfileSupported(
|
||||
VaapiWrapper::CodecMode mode,
|
||||
VAProfile va_profile,
|
||||
|
@ -1641,26 +1793,18 @@ bool VaapiWrapper::IsDecodingSupportedForInternalFormat(
|
|||
}
|
||||
|
||||
// static
|
||||
bool VaapiWrapper::GetDecodeMinResolution(VAProfile va_profile,
|
||||
gfx::Size* min_size) {
|
||||
bool VaapiWrapper::GetSupportedResolutions(VAProfile va_profile,
|
||||
CodecMode codec_mode,
|
||||
gfx::Size& min_size,
|
||||
gfx::Size& max_size) {
|
||||
const VASupportedProfiles::ProfileInfo* profile_info =
|
||||
VASupportedProfiles::Get().IsProfileSupported(kDecode, va_profile);
|
||||
if (!profile_info)
|
||||
return false;
|
||||
*min_size = gfx::Size(std::max(1, profile_info->min_resolution.width()),
|
||||
std::max(1, profile_info->min_resolution.height()));
|
||||
return true;
|
||||
}
|
||||
|
||||
// static
|
||||
bool VaapiWrapper::GetDecodeMaxResolution(VAProfile va_profile,
|
||||
gfx::Size* max_size) {
|
||||
const VASupportedProfiles::ProfileInfo* profile_info =
|
||||
VASupportedProfiles::Get().IsProfileSupported(kDecode, va_profile);
|
||||
if (!profile_info)
|
||||
VASupportedProfiles::Get().IsProfileSupported(codec_mode, va_profile);
|
||||
if (!profile_info || profile_info->max_resolution.IsEmpty())
|
||||
return false;
|
||||
|
||||
*max_size = profile_info->max_resolution;
|
||||
min_size = gfx::Size(std::max(1, profile_info->min_resolution.width()),
|
||||
std::max(1, profile_info->min_resolution.height()));
|
||||
max_size = profile_info->max_resolution;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -2178,65 +2322,31 @@ scoped_refptr<VASurface> VaapiWrapper::CreateVASurfaceForPixmap(
|
|||
CHECK(!enforce_sequence_affinity_ ||
|
||||
sequence_checker_.CalledOnValidSequence());
|
||||
const gfx::BufferFormat buffer_format = pixmap->GetBufferFormat();
|
||||
|
||||
const uint32_t va_fourcc = BufferFormatToVAFourCC(buffer_format);
|
||||
if (!va_fourcc) {
|
||||
if (!BufferFormatToVAFourCC(buffer_format)) {
|
||||
LOG(ERROR) << "Failed to get the VA fourcc from the buffer format";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const size_t num_planes = pixmap->GetNumberOfPlanes();
|
||||
// TODO(b/233894465): use the DRM_PRIME_2 API with the Mesa Gallium driver
|
||||
// when AMD supports it.
|
||||
// TODO(b/233924862): use the DRM_PRIME_2 API with protected content.
|
||||
// TODO(b/233929647): use the DRM_PRIME_2 API with the i965 driver.
|
||||
const bool use_drm_prime_2 =
|
||||
GetImplementationType() == VAImplementation::kIntelIHD &&
|
||||
!protected_content;
|
||||
|
||||
// Create a VASurface for a NativePixmap by importing the underlying dmabufs.
|
||||
const gfx::Size size = pixmap->GetBufferSize();
|
||||
VASurfaceAttribExternalBuffers va_attrib_extbuf{};
|
||||
va_attrib_extbuf.pixel_format = va_fourcc;
|
||||
va_attrib_extbuf.width = base::checked_cast<uint32_t>(size.width());
|
||||
va_attrib_extbuf.height = base::checked_cast<uint32_t>(size.height());
|
||||
union {
|
||||
VADRMPRIMESurfaceDescriptor descriptor;
|
||||
VASurfaceAttribExternalBuffersAndFD va_attrib_extbuf_and_fd;
|
||||
};
|
||||
|
||||
static_assert(std::size(va_attrib_extbuf.pitches) ==
|
||||
std::size(va_attrib_extbuf.offsets));
|
||||
if (num_planes > std::size(va_attrib_extbuf.pitches)) {
|
||||
LOG(ERROR) << "Too many planes in the NativePixmap; got " << num_planes
|
||||
<< " but the maximum number is "
|
||||
<< std::size(va_attrib_extbuf.pitches);
|
||||
return nullptr;
|
||||
if (use_drm_prime_2) {
|
||||
if (!FillVADRMPRIMESurfaceDescriptor(*pixmap, descriptor))
|
||||
return nullptr;
|
||||
} else {
|
||||
if (!FillVASurfaceAttribExternalBuffers(*pixmap, va_attrib_extbuf_and_fd))
|
||||
return nullptr;
|
||||
}
|
||||
for (size_t i = 0; i < num_planes; ++i) {
|
||||
va_attrib_extbuf.pitches[i] = pixmap->GetDmaBufPitch(i);
|
||||
va_attrib_extbuf.offsets[i] =
|
||||
base::checked_cast<uint32_t>(pixmap->GetDmaBufOffset(i));
|
||||
DVLOG(4) << "plane " << i << ": pitch: " << va_attrib_extbuf.pitches[i]
|
||||
<< " offset: " << va_attrib_extbuf.offsets[i];
|
||||
}
|
||||
va_attrib_extbuf.num_planes = base::checked_cast<uint32_t>(num_planes);
|
||||
|
||||
const int dma_buf_fd = pixmap->GetDmaBufFd(0);
|
||||
if (dma_buf_fd < 0) {
|
||||
LOG(ERROR) << "Failed to get dmabuf from an Ozone NativePixmap";
|
||||
return nullptr;
|
||||
}
|
||||
const off_t data_size = lseek(dma_buf_fd, /*offset=*/0, SEEK_END);
|
||||
if (data_size == static_cast<off_t>(-1)) {
|
||||
PLOG(ERROR) << "Failed to get the size of the dma-buf";
|
||||
return nullptr;
|
||||
}
|
||||
if (lseek(dma_buf_fd, /*offset=*/0, SEEK_SET) == static_cast<off_t>(-1)) {
|
||||
PLOG(ERROR) << "Failed to reset the file offset of the dma-buf";
|
||||
return nullptr;
|
||||
}
|
||||
// If the data size doesn't fit in a uint32_t, we probably have bigger
|
||||
// problems.
|
||||
va_attrib_extbuf.data_size = base::checked_cast<uint32_t>(data_size);
|
||||
|
||||
// We only have to pass the first file descriptor to a driver. A VA-API driver
|
||||
// shall create a VASurface from the single fd correctly.
|
||||
uintptr_t fd = base::checked_cast<uintptr_t>(dma_buf_fd);
|
||||
va_attrib_extbuf.buffers = &fd;
|
||||
va_attrib_extbuf.num_buffers = 1u;
|
||||
|
||||
DCHECK_EQ(va_attrib_extbuf.flags, 0u);
|
||||
DCHECK_EQ(va_attrib_extbuf.private_data, nullptr);
|
||||
|
||||
unsigned int va_format =
|
||||
base::strict_cast<unsigned int>(BufferFormatToVARTFormat(buffer_format));
|
||||
|
@ -2246,10 +2356,12 @@ scoped_refptr<VASurface> VaapiWrapper::CreateVASurfaceForPixmap(
|
|||
}
|
||||
|
||||
if (protected_content) {
|
||||
if (GetImplementationType() == VAImplementation::kMesaGallium)
|
||||
if (GetImplementationType() == VAImplementation::kMesaGallium) {
|
||||
va_format |= VA_RT_FORMAT_PROTECTED;
|
||||
else
|
||||
va_attrib_extbuf.flags = VA_SURFACE_EXTBUF_DESC_PROTECTED;
|
||||
} else {
|
||||
va_attrib_extbuf_and_fd.va_attrib_extbuf.flags =
|
||||
VA_SURFACE_EXTBUF_DESC_PROTECTED;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<VASurfaceAttrib> va_attribs(2);
|
||||
|
@ -2257,13 +2369,18 @@ scoped_refptr<VASurface> VaapiWrapper::CreateVASurfaceForPixmap(
|
|||
va_attribs[0].type = VASurfaceAttribMemoryType;
|
||||
va_attribs[0].flags = VA_SURFACE_ATTRIB_SETTABLE;
|
||||
va_attribs[0].value.type = VAGenericValueTypeInteger;
|
||||
va_attribs[0].value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME;
|
||||
va_attribs[0].value.value.i = use_drm_prime_2
|
||||
? VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2
|
||||
: VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME;
|
||||
|
||||
va_attribs[1].type = VASurfaceAttribExternalBufferDescriptor;
|
||||
va_attribs[1].flags = VA_SURFACE_ATTRIB_SETTABLE;
|
||||
va_attribs[1].value.type = VAGenericValueTypePointer;
|
||||
va_attribs[1].value.value.p = &va_attrib_extbuf;
|
||||
va_attribs[1].value.value.p = use_drm_prime_2
|
||||
? static_cast<void*>(&descriptor)
|
||||
: &va_attrib_extbuf_and_fd.va_attrib_extbuf;
|
||||
|
||||
const gfx::Size size = pixmap->GetBufferSize();
|
||||
VASurfaceID va_surface_id = VA_INVALID_ID;
|
||||
{
|
||||
base::AutoLockMaybe auto_lock(va_lock_);
|
||||
|
|
Loading…
Reference in a new issue