]>
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::cell::Ref; | |
6 | use std::cell::RefCell; | |
7 | use std::cell::RefMut; | |
8 | use std::marker::PhantomData; | |
9 | use std::rc::Rc; | |
10 | ||
11 | use crate::bindings; | |
12 | use crate::buffer::Buffer; | |
13 | use crate::context::Context; | |
14 | use crate::display::Display; | |
15 | use crate::drmprime::*; | |
16 | use crate::status::*; | |
17 | use crate::surface::Surface; | |
18 | ||
19 | // Use the sealed trait pattern to make sure that new states are not created in caller code. More | |
20 | // information about the sealed trait pattern can be found at | |
21 | // <https://rust-lang.github.io/api-guidelines/future-proofing.html#sealed-traits-protect-against-downstream-implementations-c-sealed> | |
22 | mod private { | |
23 | pub trait Sealed {} | |
24 | } | |
25 | ||
26 | /// A `Picture` will only have valid YUV data after a sequence of operations are performed in a | |
27 | /// particular order. This order correspond to the following VA-API calls: `vaBeginPicture`, | |
28 | /// `vaRenderPicture`, `vaEndPicture` and `vaSyncSurface`. This trait enforces this ordering by | |
29 | /// implementing the Typestate pattern to constrain what operations are available in what particular | |
30 | /// states. | |
31 | /// | |
32 | /// The states for the state machine are: | |
33 | /// | |
34 | /// * PictureNew -> PictureBegin | |
35 | /// * PictureBegin -> PictureRender | |
36 | /// * PictureRender ->PictureEnd | |
37 | /// * PictureEnd -> PictureSync | |
38 | /// | |
39 | /// Where the surface can be reclaimed in both `PictureNew` and `PictureSync`, as either no | |
40 | /// operation took place (as in `PictureNew`), or it is guaranteed that the operation has already | |
41 | /// completed (as in `PictureSync`). | |
42 | /// | |
43 | /// More information about the Typestate pattern can be found at | |
44 | /// <http://cliffle.com/blog/rust-typestate/> | |
45 | pub trait PictureState: private::Sealed {} | |
46 | ||
47 | /// Represents a `Picture` that has just been created. | |
48 | pub enum PictureNew {} | |
49 | impl PictureState for PictureNew {} | |
50 | impl private::Sealed for PictureNew {} | |
51 | ||
52 | /// Represents a `Picture` after `vaBeginPicture` has been called. | |
53 | pub enum PictureBegin {} | |
54 | impl PictureState for PictureBegin {} | |
55 | impl private::Sealed for PictureBegin {} | |
56 | ||
57 | /// Represents a `Picture` after `vaRenderPicture` has been called. | |
58 | pub enum PictureRender {} | |
59 | impl PictureState for PictureRender {} | |
60 | impl private::Sealed for PictureRender {} | |
61 | ||
62 | /// Represents a `Picture` after `vaEndPicture` has been called. | |
63 | pub enum PictureEnd {} | |
64 | impl PictureState for PictureEnd {} | |
65 | impl private::Sealed for PictureEnd {} | |
66 | ||
67 | /// Represents a `Picture` after `vaSyncSurface` has been called on the underlying surface. | |
68 | pub enum PictureSync {} | |
69 | impl PictureState for PictureSync {} | |
70 | impl private::Sealed for PictureSync {} | |
71 | ||
72 | /// Represents a state where one can reclaim the underlying `Surface` for this `Picture`. This is | |
73 | /// true when either no decoding has been initiated or, alternatively, when the decoding operation | |
74 | /// has completed for the underlying `vaSurface` | |
75 | pub trait PictureReclaimableSurface: PictureState + private::Sealed {} | |
76 | impl PictureReclaimableSurface for PictureNew {} | |
77 | impl PictureReclaimableSurface for PictureSync {} | |
78 | ||
79 | struct PictureInner { | |
80 | /// Timestamp of the picture. | |
81 | timestamp: u64, | |
82 | /// A context associated with this picture. | |
83 | context: Rc<Context>, | |
84 | /// Contains the buffers used to decode the data. | |
85 | buffers: Vec<Buffer>, | |
86 | /// Contains the actual decoded data. Note that the surface may be shared in | |
87 | /// interlaced decoding. | |
88 | surface: Rc<RefCell<Surface>>, | |
89 | } | |
90 | ||
91 | /// A `Surface` that is being rendered into. | |
92 | /// | |
93 | /// This struct abstracts the decoding flow using `vaBeginPicture`, `vaRenderPicture`, | |
94 | /// `vaEndPicture` and `vaSyncSurface` in a type-safe way. | |
95 | /// | |
96 | /// The surface will have valid picture data after all the stages of decoding are called. | |
97 | pub struct Picture<S: PictureState> { | |
98 | inner: Box<PictureInner>, | |
99 | phantom: std::marker::PhantomData<S>, | |
100 | } | |
101 | ||
102 | impl Picture<PictureNew> { | |
103 | /// Creates a new Picture with a given `timestamp`. `surface` is the underlying surface that | |
104 | /// libva will render to. | |
105 | pub fn new(timestamp: u64, context: Rc<Context>, surface: Surface) -> Self { | |
106 | Self { | |
107 | inner: Box::new(PictureInner { | |
108 | timestamp, | |
109 | context, | |
110 | buffers: Default::default(), | |
111 | surface: Rc::new(RefCell::new(surface)), | |
112 | }), | |
113 | ||
114 | phantom: PhantomData, | |
115 | } | |
116 | } | |
117 | ||
118 | /// Creates a new Picture with a given `frame_number` to identify it, | |
119 | /// reusing the Surface from `picture`. This is useful for interlaced | |
120 | /// decoding as one can render both fields to the same underlying surface. | |
121 | pub fn new_from_same_surface<T: PictureReclaimableSurface, S: PictureReclaimableSurface>( | |
122 | timestamp: u64, | |
123 | picture: &Picture<S>, | |
124 | ) -> Picture<T> { | |
125 | let context = Rc::clone(&picture.inner.context); | |
126 | Picture { | |
127 | inner: Box::new(PictureInner { | |
128 | timestamp, | |
129 | context, | |
130 | buffers: Default::default(), | |
131 | surface: Rc::clone(&picture.inner.surface), | |
132 | }), | |
133 | ||
134 | phantom: PhantomData, | |
135 | } | |
136 | } | |
137 | ||
138 | /// Add `buffer` to the picture. | |
139 | pub fn add_buffer(&mut self, buffer: Buffer) { | |
140 | self.inner.buffers.push(buffer); | |
141 | } | |
142 | ||
143 | /// Wrapper around `vaBeginPicture`. | |
144 | pub fn begin(self) -> VAResult<Picture<PictureBegin>> { | |
145 | // Safe because `self.inner.context` represents a valid VAContext and | |
146 | // `self.inner.surface` represents a valid VASurface. | |
147 | (unsafe { | |
148 | bindings::vaBeginPicture( | |
149 | self.inner.context.display().handle(), | |
150 | self.inner.context.id(), | |
151 | self.inner.surface.borrow().id(), | |
152 | ) | |
153 | }) | |
154 | .check()?; | |
155 | ||
156 | Ok(Picture { | |
157 | inner: self.inner, | |
158 | phantom: PhantomData, | |
159 | }) | |
160 | } | |
161 | } | |
162 | ||
163 | impl Picture<PictureBegin> { | |
164 | /// Wrapper around `vaRenderPicture`. | |
165 | pub fn render(self) -> VAResult<Picture<PictureRender>> { | |
166 | // Safe because `self.inner.context` represents a valid `VAContext` and `self.inner.surface` | |
167 | // represents a valid `VASurface`. `buffers` point to a Rust struct and the vector length is | |
168 | // passed to the C function, so it is impossible to write past the end of the vector's | |
169 | // storage by mistake. | |
170 | (unsafe { | |
171 | bindings::vaRenderPicture( | |
172 | self.inner.context.display().handle(), | |
173 | self.inner.context.id(), | |
174 | Buffer::as_id_vec(&self.inner.buffers).as_mut_ptr(), | |
175 | self.inner.buffers.len() as i32, | |
176 | ) | |
177 | }) | |
178 | .check()?; | |
179 | ||
180 | Ok(Picture { | |
181 | inner: self.inner, | |
182 | phantom: PhantomData, | |
183 | }) | |
184 | } | |
185 | } | |
186 | ||
187 | impl Picture<PictureRender> { | |
188 | /// Wrapper around `vaEndPicture`. | |
189 | pub fn end(self) -> VAResult<Picture<PictureEnd>> { | |
190 | // Safe because `self.inner.context` represents a valid `VAContext`. | |
191 | (unsafe { | |
192 | bindings::vaEndPicture( | |
193 | self.inner.context.display().handle(), | |
194 | self.inner.context.id(), | |
195 | ) | |
196 | }) | |
197 | .check()?; | |
198 | Ok(Picture { | |
199 | inner: self.inner, | |
200 | phantom: PhantomData, | |
201 | }) | |
202 | } | |
203 | } | |
204 | ||
205 | impl Picture<PictureEnd> { | |
206 | /// Syncs the picture, ensuring that all pending operations are complete when this call returns. | |
207 | pub fn sync(self) -> std::result::Result<Picture<PictureSync>, (VAError, Self)> { | |
208 | let res = self.inner.surface.borrow().sync(); | |
209 | ||
210 | match res { | |
211 | Ok(()) => Ok(Picture { | |
212 | inner: self.inner, | |
213 | phantom: PhantomData, | |
214 | }), | |
215 | Err(e) => Err((e, self)), | |
216 | } | |
217 | } | |
218 | ||
219 | /// Queries the status of the underlying surface. | |
220 | /// | |
221 | /// This call can be used to implement a non-blocking path, wherein a decoder queries the status | |
222 | /// of the surface after each decode operation instead of blocking on it. | |
223 | pub fn query_status(&self) -> VAResult<VASurfaceStatus> { | |
224 | self.inner.surface.borrow_mut().query_status() | |
225 | } | |
226 | } | |
227 | ||
228 | impl<S: PictureState> Picture<S> { | |
229 | /// Returns the timestamp of this picture. | |
230 | pub fn timestamp(&self) -> u64 { | |
231 | self.inner.timestamp | |
232 | } | |
233 | ||
234 | /// Returns the ID of the underlying surface. | |
235 | pub fn surface_id(&self) -> bindings::VASurfaceID { | |
236 | self.inner.surface.borrow().id() | |
237 | } | |
238 | ||
239 | /// Returns a reference to the display owning this `Picture`. | |
240 | pub(crate) fn display(&self) -> &Rc<Display> { | |
241 | self.inner.context.display() | |
242 | } | |
243 | ||
244 | /// Returns the size of the surface being rendered to by this `Picture`. | |
245 | pub fn surface_size(&self) -> (u32, u32) { | |
246 | self.inner.surface.borrow().size() | |
247 | } | |
248 | ||
249 | /// Returns DRM Prime surface descriptor. | |
250 | pub fn surface_descriptor(&self) -> Option<VADRMPRIMESurfaceDescriptor> { | |
251 | unsafe { | |
252 | let mut desc = VADRMPRIMESurfaceDescriptor::default(); | |
253 | let display = self.inner.context.display().handle(); | |
254 | let handle = self.inner.surface.borrow().id(); | |
255 | let ret = crate::bindings::vaExportSurfaceHandle(display, handle, VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2, crate::constants::VA_EXPORT_SURFACE_READ_ONLY, &mut desc as *mut VADRMPRIMESurfaceDescriptor as *mut ::std::os::raw::c_void); | |
256 | if ret == 0 { | |
257 | Some(desc) | |
258 | } else { | |
259 | None | |
260 | } | |
261 | } | |
262 | } | |
263 | } | |
264 | ||
265 | impl<S: PictureReclaimableSurface> Picture<S> { | |
266 | /// Reclaim ownership of the Surface this picture has been created from, consuming the picture | |
267 | /// in the process. Useful if the Surface is part of a pool. | |
268 | pub fn take_surface(self) -> VAResult<Surface> { | |
269 | match Rc::try_unwrap(self.inner.surface) { | |
270 | Ok(surface) => Ok(surface.into_inner()), | |
271 | Err(_) => Err(VAError::SurfaceBusy), | |
272 | } | |
273 | } | |
274 | ||
275 | /// Returns a reference to the underlying `Surface` for this `Picture` | |
276 | pub fn surface(&self) -> Ref<Surface> { | |
277 | self.inner.surface.borrow() | |
278 | } | |
279 | ||
280 | /// Returns a mutable reference to the underlying `Surface` for this `Picture` | |
281 | pub fn surface_mut(&mut self) -> RefMut<Surface> { | |
282 | self.inner.surface.borrow_mut() | |
283 | } | |
284 | } |