Skip to main content

moq_vaapi/
config.rs

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