1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
// Copyright 2022 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use std::rc::Rc;
use log::error;
use thiserror::Error;
use crate::bindings;
use crate::display::Display;
use crate::generic_value::GenericValue;
use crate::va_check;
use crate::GenericValueError;
use crate::VaError;
/// A configuration for a given [`Display`].
pub struct Config {
display: Rc<Display>,
id: bindings::VAConfigID,
}
#[derive(Debug, Error)]
pub enum QuerySurfaceAttributesError {
#[error("error while calling vaQuerySurfaceAttributes: {0}")]
VaError(#[from] VaError),
#[error("error while converting attribute: {0}")]
GenericValueError(#[from] GenericValueError),
}
impl Config {
/// Creates a Config by wrapping around the `vaCreateConfig` call. This is just a helper for
/// [`Display::create_config`].
pub(crate) fn new(
display: Rc<Display>,
mut attrs: Vec<bindings::VAConfigAttrib>,
profile: bindings::VAProfile::Type,
entrypoint: bindings::VAEntrypoint::Type,
) -> Result<Self, VaError> {
let mut config_id = 0u32;
// Safe because `self` represents a valid `VADisplay`.
//
// The `attrs` vector is also properly initialized and its actual size is passed to
// `vaCreateConfig`, so it is impossible to write past the end of its storage by mistake.
va_check(unsafe {
bindings::vaCreateConfig(
display.handle(),
profile,
entrypoint,
attrs.as_mut_ptr(),
attrs.len() as i32,
&mut config_id,
)
})?;
Ok(Self {
display,
id: config_id,
})
}
/// Returns the ID of this config.
pub(crate) fn id(&self) -> bindings::VAConfigID {
self.id
}
// Queries surface attributes for this config.
//
// This function queries for all supported attributes for this configuration. In particular, if
// the underlying hardware supports the creation of VA surfaces in various formats, then this
// function will enumerate all pixel formats that are supported.
fn query_surface_attributes(&mut self) -> Result<Vec<bindings::VASurfaceAttrib>, VaError> {
// Safe because `self` represents a valid VAConfig. We first query how
// much space is needed by the C API by passing in NULL in the first
// call to `vaQuerySurfaceAttributes`.
let attrs_len: std::os::raw::c_uint = 0;
va_check(unsafe {
bindings::vaQuerySurfaceAttributes(
self.display.handle(),
self.id,
std::ptr::null_mut(),
&attrs_len as *const _ as *mut std::os::raw::c_uint,
)
})?;
let mut attrs = Vec::with_capacity(attrs_len as usize);
// Safe because we allocate a vector with the required capacity as
// returned by the initial call to vaQuerySurfaceAttributes. We then
// pass a valid pointer to it.
va_check(unsafe {
bindings::vaQuerySurfaceAttributes(
self.display.handle(),
self.id,
attrs.as_mut_ptr(),
&attrs_len as *const _ as *mut std::os::raw::c_uint,
)
})?;
// Safe because vaQuerySurfaceAttributes will have written to
// exactly attrs_len entries in the vector.
unsafe {
attrs.set_len(attrs_len as usize);
}
Ok(attrs)
}
/// Query the surface attributes of type `attr_type`. The attribute may or may not be defined by
/// the driver.
pub fn query_surface_attributes_by_type(
&mut self,
attr_type: bindings::VASurfaceAttribType::Type,
) -> Result<Vec<GenericValue>, QuerySurfaceAttributesError> {
let surface_attributes = self.query_surface_attributes()?;
surface_attributes
.into_iter()
.filter(|attr| attr.type_ == attr_type)
.map(|attr| {
GenericValue::try_from(attr.value)
.map_err(QuerySurfaceAttributesError::GenericValueError)
})
.collect()
}
}
impl Drop for Config {
fn drop(&mut self) {
// Safe because `self` represents a valid Config.
let status = va_check(unsafe { bindings::vaDestroyConfig(self.display.handle(), self.id) });
if status.is_err() {
error!("vaDestroyConfig failed: {}", status.unwrap_err());
}
}
}