use std::any::Any;
use std::os::fd::FromRawFd;
use std::os::fd::OwnedFd;
use std::os::raw::c_void;
use std::sync::Arc;
use crate::bindings;
use crate::display::Display;
use crate::va_check;
use crate::UsageHint;
use crate::VASurfaceID;
use crate::VaError;
pub trait SurfaceMemoryDescriptor {
fn add_attrs(&mut self, attrs: &mut Vec<bindings::VASurfaceAttrib>) -> Option<Box<dyn Any>>;
}
#[repr(u32)]
pub enum MemoryType {
Va = bindings::VA_SURFACE_ATTRIB_MEM_TYPE_VA,
V4L2 = bindings::VA_SURFACE_ATTRIB_MEM_TYPE_V4L2,
UserPtr = bindings::VA_SURFACE_ATTRIB_MEM_TYPE_USER_PTR,
DrmPrime2 = bindings::VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2,
}
impl SurfaceMemoryDescriptor for () {
fn add_attrs(&mut self, _: &mut Vec<bindings::VASurfaceAttrib>) -> Option<Box<dyn Any>> {
None
}
}
mod private {
pub trait Sealed {}
}
pub trait SurfaceExternalDescriptor: private::Sealed {}
impl private::Sealed for bindings::VASurfaceAttribExternalBuffers {}
impl SurfaceExternalDescriptor for bindings::VASurfaceAttribExternalBuffers {}
impl private::Sealed for bindings::VADRMPRIMESurfaceDescriptor {}
impl SurfaceExternalDescriptor for bindings::VADRMPRIMESurfaceDescriptor {}
pub trait ExternalBufferDescriptor {
const MEMORY_TYPE: MemoryType;
type DescriptorAttribute: SurfaceExternalDescriptor;
fn va_surface_attribute(&mut self) -> Self::DescriptorAttribute;
}
impl<T> SurfaceMemoryDescriptor for T
where
T: ExternalBufferDescriptor,
<T as ExternalBufferDescriptor>::DescriptorAttribute: 'static,
{
fn add_attrs(&mut self, attrs: &mut Vec<bindings::VASurfaceAttrib>) -> Option<Box<dyn Any>> {
let mut desc = Box::new(self.va_surface_attribute());
attrs.push(bindings::VASurfaceAttrib::new_memory_type(Self::MEMORY_TYPE));
attrs.push(bindings::VASurfaceAttrib::new_buffer_descriptor(desc.as_mut()));
Some(desc)
}
}
#[repr(u32)]
#[derive(Debug)]
pub enum DecodeErrorType {
SliceMissing = bindings::VADecodeErrorType::VADecodeSliceMissing,
MBError = bindings::VADecodeErrorType::VADecodeMBError,
#[cfg(libva_1_20_or_higher)]
Reset = bindings::VADecodeErrorType::VADecodeReset,
}
#[derive(Debug)]
pub struct SurfaceDecodeMBError {
pub start_mb: u32,
pub end_mb: u32,
pub decode_error_type: DecodeErrorType,
pub num_mb: u32,
}
pub struct Surface<D: SurfaceMemoryDescriptor> {
display: Arc<Display>,
id: bindings::VASurfaceID,
descriptor: D,
width: u32,
height: u32,
}
impl From<i32> for bindings::VAGenericValue {
fn from(i: i32) -> Self {
Self {
type_: bindings::VAGenericValueType::VAGenericValueTypeInteger,
value: bindings::_VAGenericValue__bindgen_ty_1 { i },
}
}
}
impl From<f32> for bindings::VAGenericValue {
fn from(f: f32) -> Self {
Self {
type_: bindings::VAGenericValueType::VAGenericValueTypeFloat,
value: bindings::_VAGenericValue__bindgen_ty_1 { f },
}
}
}
impl From<*mut c_void> for bindings::VAGenericValue {
fn from(p: *mut c_void) -> Self {
Self {
type_: bindings::VAGenericValueType::VAGenericValueTypePointer,
value: bindings::_VAGenericValue__bindgen_ty_1 { p },
}
}
}
impl bindings::VASurfaceAttrib {
pub fn new_pixel_format(fourcc: u32) -> Self {
Self {
type_: bindings::VASurfaceAttribType::VASurfaceAttribPixelFormat,
flags: bindings::VA_SURFACE_ATTRIB_SETTABLE,
value: bindings::VAGenericValue::from(fourcc as i32),
}
}
pub fn new_usage_hint(usage_hint: UsageHint) -> Self {
Self {
type_: bindings::VASurfaceAttribType::VASurfaceAttribUsageHint,
flags: bindings::VA_SURFACE_ATTRIB_SETTABLE,
value: bindings::VAGenericValue::from(usage_hint.bits() as i32),
}
}
pub fn new_memory_type(mem_type: MemoryType) -> Self {
Self {
type_: bindings::VASurfaceAttribType::VASurfaceAttribMemoryType,
flags: bindings::VA_SURFACE_ATTRIB_SETTABLE,
value: bindings::VAGenericValue::from(mem_type as i32),
}
}
pub fn new_buffer_descriptor<T: SurfaceExternalDescriptor>(desc: &mut T) -> Self {
Self {
type_: bindings::VASurfaceAttribType::VASurfaceAttribExternalBufferDescriptor,
flags: bindings::VA_SURFACE_ATTRIB_SETTABLE,
value: bindings::VAGenericValue::from(desc as *mut _ as *mut c_void),
}
}
}
impl<D: SurfaceMemoryDescriptor> Surface<D> {
pub(crate) fn new(
display: Arc<Display>,
rt_format: u32,
va_fourcc: Option<u32>,
width: u32,
height: u32,
usage_hint: Option<UsageHint>,
descriptors: Vec<D>,
) -> Result<Vec<Self>, VaError> {
let mut surfaces = vec![];
for mut descriptor in descriptors {
let mut attrs = vec![];
if let Some(usage_hint) = usage_hint {
attrs.push(bindings::VASurfaceAttrib::new_usage_hint(usage_hint));
}
if let Some(fourcc) = va_fourcc {
attrs.push(bindings::VASurfaceAttrib::new_pixel_format(fourcc));
}
let mut _va_desc = descriptor.add_attrs(&mut attrs);
let mut surface_id: VASurfaceID = 0;
match va_check(unsafe {
bindings::vaCreateSurfaces(
display.handle(),
rt_format,
width,
height,
&mut surface_id,
1,
attrs.as_mut_ptr(),
attrs.len() as u32,
)
}) {
Ok(()) => surfaces.push(Self {
display: Arc::clone(&display),
id: surface_id,
descriptor,
width,
height,
}),
Err(e) => return Err(e),
}
}
Ok(surfaces)
}
pub fn display(&self) -> &Arc<Display> {
&self.display
}
pub fn sync(&self) -> Result<(), VaError> {
va_check(unsafe { bindings::vaSyncSurface(self.display.handle(), self.id) })
}
pub fn as_id_vec(surfaces: &[Self]) -> Vec<bindings::VASurfaceID> {
surfaces.iter().map(|surface| surface.id).collect()
}
pub fn query_status(&self) -> Result<bindings::VASurfaceStatus::Type, VaError> {
let mut status: bindings::VASurfaceStatus::Type = 0;
va_check(unsafe { bindings::vaQuerySurfaceStatus(self.display.handle(), self.id, &mut status) })?;
Ok(status)
}
pub fn query_error(&self) -> Result<Vec<SurfaceDecodeMBError>, VaError> {
let mut raw: *const bindings::VASurfaceDecodeMBErrors = std::ptr::null();
va_check(unsafe {
bindings::vaQuerySurfaceError(
self.display.handle(),
self.id,
bindings::VA_STATUS_ERROR_DECODING_ERROR as i32,
(&mut raw) as *mut _ as *mut _,
)
})?;
let mut errors = vec![];
while !raw.is_null() {
let error = unsafe { *raw };
if error.status == -1 {
break;
}
let type_ = match error.decode_error_type {
bindings::VADecodeErrorType::VADecodeSliceMissing => DecodeErrorType::SliceMissing,
bindings::VADecodeErrorType::VADecodeMBError => DecodeErrorType::MBError,
#[cfg(libva_1_20_or_higher)]
bindings::VADecodeErrorType::VADecodeReset => DecodeErrorType::Reset,
_ => {
log::warn!("Unrecognized `decode_error_type` value ({})", error.decode_error_type);
raw = unsafe { raw.offset(1) };
continue;
}
};
errors.push(SurfaceDecodeMBError {
start_mb: error.start_mb,
end_mb: error.end_mb,
decode_error_type: type_,
num_mb: error.num_mb,
});
raw = unsafe { raw.offset(1) };
}
Ok(errors)
}
pub fn id(&self) -> bindings::VASurfaceID {
self.id
}
pub fn size(&self) -> (u32, u32) {
(self.width, self.height)
}
pub fn export_prime(&self) -> Result<DrmPrimeSurfaceDescriptor, VaError> {
let mut desc: bindings::VADRMPRIMESurfaceDescriptor = Default::default();
va_check(unsafe {
bindings::vaExportSurfaceHandle(
self.display.handle(),
self.id(),
bindings::VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2,
bindings::VA_EXPORT_SURFACE_READ_ONLY | bindings::VA_EXPORT_SURFACE_COMPOSED_LAYERS,
&mut desc as *mut _ as *mut c_void,
)
})?;
let objects = (0..desc.num_objects as usize)
.take(4)
.map(|i| desc.objects[i])
.map(|o| {
DrmPrimeSurfaceDescriptorObject {
fd: unsafe { OwnedFd::from_raw_fd(o.fd) },
size: o.size,
drm_format_modifier: o.drm_format_modifier,
}
})
.collect();
let layers = (0..desc.num_layers as usize)
.take(4)
.map(|i| desc.layers[i])
.map(|l| DrmPrimeSurfaceDescriptorLayer {
drm_format: l.drm_format,
num_planes: l.num_planes,
object_index: [
l.object_index[0] as u8,
l.object_index[1] as u8,
l.object_index[2] as u8,
l.object_index[3] as u8,
],
offset: l.offset,
pitch: l.pitch,
})
.collect();
Ok(DrmPrimeSurfaceDescriptor {
fourcc: desc.fourcc,
width: desc.width,
height: desc.height,
objects,
layers,
})
}
}
impl<D: SurfaceMemoryDescriptor> AsRef<D> for Surface<D> {
fn as_ref(&self) -> &D {
&self.descriptor
}
}
impl<D: SurfaceMemoryDescriptor> AsMut<D> for Surface<D> {
fn as_mut(&mut self) -> &mut D {
&mut self.descriptor
}
}
impl<D: SurfaceMemoryDescriptor> Drop for Surface<D> {
fn drop(&mut self) {
unsafe { bindings::vaDestroySurfaces(self.display.handle(), &mut self.id, 1) };
}
}
pub struct DrmPrimeSurfaceDescriptorObject {
pub fd: OwnedFd,
pub size: u32,
pub drm_format_modifier: u64,
}
pub struct DrmPrimeSurfaceDescriptorLayer {
pub drm_format: u32,
pub num_planes: u32,
pub object_index: [u8; 4],
pub offset: [u32; 4],
pub pitch: [u32; 4],
}
pub struct DrmPrimeSurfaceDescriptor {
pub fourcc: u32,
pub width: u32,
pub height: u32,
pub objects: Vec<DrmPrimeSurfaceDescriptorObject>,
pub layers: Vec<DrmPrimeSurfaceDescriptorLayer>,
}