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