]>
Commit | Line | Data |
---|---|---|
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 | } |