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 
5 use std::rc::Rc;
6 
7 use log::error;
8 use thiserror::Error;
9 
10 use crate::bindings;
11 use crate::display::Display;
12 use crate::generic_value::GenericValue;
13 use crate::va_check;
14 use crate::GenericValueError;
15 use crate::VaError;
16 
17 /// A configuration for a given [`Display`].
18 pub struct Config {
19     display: Rc<Display>,
20     id: bindings::VAConfigID,
21 }
22 
23 #[derive(Debug, Error)]
24 pub 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 
31 impl Config {
32     /// Creates a Config by wrapping around the `vaCreateConfig` call. This is just a helper for
33     /// [`Display::create_config`].
new( display: Rc<Display>, mut attrs: Vec<bindings::VAConfigAttrib>, profile: bindings::VAProfile::Type, entrypoint: bindings::VAEntrypoint::Type, ) -> Result<Self, VaError>34     pub(crate) fn new(
35         display: Rc<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 {
58             display,
59             id: config_id,
60         })
61     }
62 
63     /// Returns the ID of this config.
id(&self) -> bindings::VAConfigID64     pub(crate) fn id(&self) -> bindings::VAConfigID {
65         self.id
66     }
67 
68     // Queries surface attributes for this config.
69     //
70     // This function queries for all supported attributes for this configuration. In particular, if
71     // the underlying hardware supports the creation of VA surfaces in various formats, then this
72     // function will enumerate all pixel formats that are supported.
query_surface_attributes(&mut self) -> Result<Vec<bindings::VASurfaceAttrib>, VaError>73     fn query_surface_attributes(&mut self) -> Result<Vec<bindings::VASurfaceAttrib>, VaError> {
74         // Safe because `self` represents a valid VAConfig. We first query how
75         // much space is needed by the C API by passing in NULL in the first
76         // call to `vaQuerySurfaceAttributes`.
77         let attrs_len: std::os::raw::c_uint = 0;
78         va_check(unsafe {
79             bindings::vaQuerySurfaceAttributes(
80                 self.display.handle(),
81                 self.id,
82                 std::ptr::null_mut(),
83                 &attrs_len as *const _ as *mut std::os::raw::c_uint,
84             )
85         })?;
86 
87         let mut attrs = Vec::with_capacity(attrs_len as usize);
88         // Safe because we allocate a vector with the required capacity as
89         // returned by the initial call to vaQuerySurfaceAttributes. We then
90         // pass a valid pointer to it.
91         va_check(unsafe {
92             bindings::vaQuerySurfaceAttributes(
93                 self.display.handle(),
94                 self.id,
95                 attrs.as_mut_ptr(),
96                 &attrs_len as *const _ as *mut std::os::raw::c_uint,
97             )
98         })?;
99 
100         // Safe because vaQuerySurfaceAttributes will have written to
101         // exactly attrs_len entries in the vector.
102         unsafe {
103             attrs.set_len(attrs_len as usize);
104         }
105 
106         Ok(attrs)
107     }
108 
109     /// Query the surface attributes of type `attr_type`. The attribute may or may not be defined by
110     /// the driver.
query_surface_attributes_by_type( &mut self, attr_type: bindings::VASurfaceAttribType::Type, ) -> Result<Vec<GenericValue>, QuerySurfaceAttributesError>111     pub fn query_surface_attributes_by_type(
112         &mut self,
113         attr_type: bindings::VASurfaceAttribType::Type,
114     ) -> Result<Vec<GenericValue>, QuerySurfaceAttributesError> {
115         let surface_attributes = self.query_surface_attributes()?;
116 
117         surface_attributes
118             .into_iter()
119             .filter(|attr| attr.type_ == attr_type)
120             .map(|attr| {
121                 GenericValue::try_from(attr.value)
122                     .map_err(QuerySurfaceAttributesError::GenericValueError)
123             })
124             .collect()
125     }
126 }
127 
128 impl Drop for Config {
drop(&mut self)129     fn drop(&mut self) {
130         // Safe because `self` represents a valid Config.
131         let status = va_check(unsafe { bindings::vaDestroyConfig(self.display.handle(), self.id) });
132 
133         if status.is_err() {
134             error!("vaDestroyConfig failed: {}", status.unwrap_err());
135         }
136     }
137 }
138