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