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