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