]>
Commit | Line | Data |
---|---|---|
68362724 KS |
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 anyhow::Result; | |
8 | ||
9 | use crate::bindings; | |
10 | use crate::display::Display; | |
11 | use crate::status::Status; | |
12 | use crate::UsageHint; | |
13 | ||
14 | /// An owned VA surface that is tied to the lifetime of a particular VADisplay | |
15 | pub struct Surface { | |
16 | display: Rc<Display>, | |
17 | id: bindings::VASurfaceID, | |
18 | width: u32, | |
19 | height: u32, | |
20 | } | |
21 | ||
22 | impl Surface { | |
23 | /// Create `Surfaces` by wrapping around a `vaCreateSurfaces` call. This is just a helper for | |
24 | /// [`Display::create_surfaces`]. | |
25 | pub(crate) fn new( | |
26 | display: Rc<Display>, | |
27 | rt_format: u32, | |
28 | va_fourcc: Option<u32>, | |
29 | width: u32, | |
30 | height: u32, | |
31 | usage_hint: Option<UsageHint>, | |
32 | num_surfaces: u32, | |
33 | ) -> Result<Vec<Self>> { | |
34 | let mut attrs = vec![]; | |
35 | ||
36 | if let Some(usage_hint) = usage_hint { | |
37 | let attr = bindings::VASurfaceAttrib { | |
38 | type_: bindings::VASurfaceAttribType::VASurfaceAttribUsageHint, | |
39 | flags: bindings::constants::VA_SURFACE_ATTRIB_SETTABLE, | |
40 | value: bindings::VAGenericValue { | |
41 | type_: bindings::VAGenericValueType::VAGenericValueTypeInteger, | |
42 | value: bindings::_VAGenericValue__bindgen_ty_1 { | |
43 | i: usage_hint.bits() as i32, | |
44 | }, | |
45 | }, | |
46 | }; | |
47 | ||
48 | attrs.push(attr); | |
49 | } | |
50 | ||
51 | if let Some(fourcc) = va_fourcc { | |
52 | let attr = bindings::VASurfaceAttrib { | |
53 | type_: bindings::VASurfaceAttribType::VASurfaceAttribPixelFormat, | |
54 | flags: bindings::constants::VA_DISPLAY_ATTRIB_SETTABLE, | |
55 | value: bindings::VAGenericValue { | |
56 | type_: bindings::VAGenericValueType::VAGenericValueTypeInteger, | |
57 | value: bindings::_VAGenericValue__bindgen_ty_1 { i: fourcc as i32 }, | |
58 | }, | |
59 | }; | |
60 | ||
61 | attrs.push(attr); | |
62 | } | |
63 | ||
64 | let mut surfaces = Vec::with_capacity(num_surfaces as usize); | |
65 | ||
66 | // Safe because `self` represents a valid VADisplay. The `surface` and `attrs` vectors are | |
67 | // properly initialized and valid sizes are passed to the C function, so it is impossible to | |
68 | // write past the end of their storage by mistake. | |
69 | Status(unsafe { | |
70 | bindings::vaCreateSurfaces( | |
71 | display.handle(), | |
72 | rt_format, | |
73 | width, | |
74 | height, | |
75 | surfaces.as_mut_ptr(), | |
76 | num_surfaces, | |
77 | attrs.as_mut_ptr(), | |
78 | attrs.len() as u32, | |
79 | ) | |
80 | }) | |
81 | .check()?; | |
82 | ||
83 | // Safe because the C function will have written to exactly `num_surfaces` entries, which is | |
84 | // known to be within the vector's capacity. | |
85 | unsafe { | |
86 | surfaces.set_len(num_surfaces as usize); | |
87 | } | |
88 | ||
89 | let va_surfaces = surfaces | |
90 | .iter() | |
91 | .map(|&id| Self { | |
92 | display: Rc::clone(&display), | |
93 | id, | |
94 | width, | |
95 | height, | |
96 | }) | |
97 | .collect(); | |
98 | ||
99 | Ok(va_surfaces) | |
100 | } | |
101 | ||
102 | /// Blocks until all pending operations on the render target have been completed. Upon return it | |
103 | /// is safe to use the render target for a different picture. | |
104 | pub fn sync(&self) -> Result<()> { | |
105 | // Safe because `self` represents a valid VASurface. | |
106 | Status(unsafe { bindings::vaSyncSurface(self.display.handle(), self.id) }).check() | |
107 | } | |
108 | ||
109 | /// Convenience function to return a VASurfaceID vector. Useful to interface with the C API | |
110 | /// where a surface array might be needed. | |
111 | pub fn as_id_vec(surfaces: &[Self]) -> Vec<bindings::VASurfaceID> { | |
112 | surfaces.iter().map(|surface| surface.id).collect() | |
113 | } | |
114 | ||
115 | /// Wrapper over `vaQuerySurfaceStatus` to find out any pending ops on the render target. | |
116 | pub fn query_status(&self) -> Result<bindings::VASurfaceStatus::Type> { | |
117 | let mut status: bindings::VASurfaceStatus::Type = 0; | |
118 | // Safe because `self` represents a valid VASurface. | |
119 | Status(unsafe { | |
120 | bindings::vaQuerySurfaceStatus(self.display.handle(), self.id, &mut status) | |
121 | }) | |
122 | .check()?; | |
123 | Ok(status) | |
124 | } | |
125 | ||
126 | /// Returns the ID of this surface. | |
127 | pub fn id(&self) -> bindings::VASurfaceID { | |
128 | self.id | |
129 | } | |
130 | ||
131 | /// Returns the dimensions of this surface. | |
132 | pub fn size(&self) -> (u32, u32) { | |
133 | (self.width, self.height) | |
134 | } | |
135 | } | |
136 | ||
137 | impl Drop for Surface { | |
138 | fn drop(&mut self) { | |
139 | // Safe because `self` represents a valid VASurface. | |
140 | unsafe { bindings::vaDestroySurfaces(self.display.handle(), &mut self.id, 1) }; | |
141 | } | |
142 | } |