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::borrow::Borrow;
6 use std::marker::PhantomData;
7 use std::rc::Rc;
8 
9 use crate::bindings;
10 use crate::buffer::Buffer;
11 use crate::context::Context;
12 use crate::surface::Surface;
13 use crate::va_check;
14 use crate::Image;
15 use crate::SurfaceMemoryDescriptor;
16 use crate::VaError;
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 /// Inner type for [`Picture`], that is, the part that exists in all states.
79 struct PictureInner<T> {
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<T>,
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 ///
98 /// The `T` generic parameter must be `Borrow<Surface<_>>`, i.e. it can be [`Surface`] directly or
99 /// some other type that contains one.
100 ///
101 /// No constraint on `T` is specified in this declaration because specifying it here would force us
102 /// to add the generic argument of [`Surface`] to this type as well, turning it into a type with 3
103 /// generics, one of which is redundant. To avoid that we leave `T` unconstrained and instead
104 /// constrain the methods that require to act on it as a [`Surface`].
105 pub struct Picture<S: PictureState, T> {
106     inner: Box<PictureInner<T>>,
107     phantom: std::marker::PhantomData<S>,
108 }
109 
110 impl<T> Picture<PictureNew, T> {
111     /// Creates a new Picture with a given `timestamp`. `surface` is the underlying surface that
112     /// libva will render to.
new<D: SurfaceMemoryDescriptor>(timestamp: u64, context: Rc<Context>, surface: T) -> Self where T: Borrow<Surface<D>>,113     pub fn new<D: SurfaceMemoryDescriptor>(timestamp: u64, context: Rc<Context>, surface: T) -> Self
114     where
115         T: Borrow<Surface<D>>,
116     {
117         Self {
118             inner: Box::new(PictureInner {
119                 timestamp,
120                 context,
121                 buffers: Default::default(),
122                 surface: Rc::new(surface),
123             }),
124 
125             phantom: PhantomData,
126         }
127     }
128 
129     /// Creates a new Picture with a given `timestamp` to identify it,
130     /// reusing the Surface from `picture`. This is useful for interlaced
131     /// decoding as one can render both fields to the same underlying surface.
new_from_same_surface<S: PictureState>(timestamp: u64, picture: &Picture<S, T>) -> Self132     pub fn new_from_same_surface<S: PictureState>(timestamp: u64, picture: &Picture<S, T>) -> Self {
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<D: SurfaceMemoryDescriptor>(self) -> Result<Picture<PictureBegin, T>, VaError> where T: Borrow<Surface<D>>,152     pub fn begin<D: SurfaceMemoryDescriptor>(self) -> Result<Picture<PictureBegin, T>, VaError>
153     where
154         T: Borrow<Surface<D>>,
155     {
156         // Safe because `self.inner.context` represents a valid VAContext and
157         // `self.inner.surface` represents a valid VASurface.
158         let res = va_check(unsafe {
159             bindings::vaBeginPicture(
160                 self.inner.context.display().handle(),
161                 self.inner.context.id(),
162                 self.surface().id(),
163             )
164         });
165 
166         res.map(|()| Picture {
167             inner: self.inner,
168             phantom: PhantomData,
169         })
170     }
171 }
172 
173 impl<T> Picture<PictureBegin, T> {
174     /// Wrapper around `vaRenderPicture`.
render(self) -> Result<Picture<PictureRender, T>, VaError>175     pub fn render(self) -> Result<Picture<PictureRender, T>, VaError> {
176         // Safe because `self.inner.context` represents a valid `VAContext` and `self.inner.surface`
177         // represents a valid `VASurface`. `buffers` point to a Rust struct and the vector length is
178         // passed to the C function, so it is impossible to write past the end of the vector's
179         // storage by mistake.
180         va_check(unsafe {
181             bindings::vaRenderPicture(
182                 self.inner.context.display().handle(),
183                 self.inner.context.id(),
184                 Buffer::as_id_vec(&self.inner.buffers).as_mut_ptr(),
185                 self.inner.buffers.len() as i32,
186             )
187         })
188         .map(|()| Picture {
189             inner: self.inner,
190             phantom: PhantomData,
191         })
192     }
193 }
194 
195 impl<T> Picture<PictureRender, T> {
196     /// Wrapper around `vaEndPicture`.
end(self) -> Result<Picture<PictureEnd, T>, VaError>197     pub fn end(self) -> Result<Picture<PictureEnd, T>, VaError> {
198         // Safe because `self.inner.context` represents a valid `VAContext`.
199         va_check(unsafe {
200             bindings::vaEndPicture(
201                 self.inner.context.display().handle(),
202                 self.inner.context.id(),
203             )
204         })
205         .map(|()| Picture {
206             inner: self.inner,
207             phantom: PhantomData,
208         })
209     }
210 }
211 
212 impl<T> Picture<PictureEnd, T> {
213     /// Syncs the picture, ensuring that all pending operations are complete when this call returns.
sync<D: SurfaceMemoryDescriptor>( self, ) -> Result<Picture<PictureSync, T>, (VaError, Self)> where T: Borrow<Surface<D>>,214     pub fn sync<D: SurfaceMemoryDescriptor>(
215         self,
216     ) -> Result<Picture<PictureSync, T>, (VaError, Self)>
217     where
218         T: Borrow<Surface<D>>,
219     {
220         let res = self.surface().sync();
221 
222         match res {
223             Ok(()) => Ok(Picture {
224                 inner: self.inner,
225                 phantom: PhantomData,
226             }),
227             Err(e) => Err((e, self)),
228         }
229     }
230 }
231 
232 impl<S: PictureState, T> Picture<S, T> {
233     /// Returns the timestamp of this picture.
timestamp(&self) -> u64234     pub fn timestamp(&self) -> u64 {
235         self.inner.timestamp
236     }
237 
238     /// Returns a reference to the underlying `Surface`.
239     ///
240     /// If you are interested in obtaining the container of the `Surface`, use `as_ref()` instead.
241     /// This is a convenience method to avoid having to call `borrow()` every time the surface is
242     /// needed.
surface<D: SurfaceMemoryDescriptor>(&self) -> &Surface<D> where T: Borrow<Surface<D>>,243     pub fn surface<D: SurfaceMemoryDescriptor>(&self) -> &Surface<D>
244     where
245         T: Borrow<Surface<D>>,
246     {
247         self.as_ref().borrow()
248     }
249 }
250 
251 impl<S: PictureReclaimableSurface, T> Picture<S, T> {
252     /// Reclaim ownership of the Surface this picture has been created from, consuming the picture
253     /// in the process. Useful if the Surface is part of a pool.
254     ///
255     /// This will fail and return the passed object if there are more than one reference to the
256     /// underlying surface.
take_surface(self) -> Result<T, Self>257     pub fn take_surface(self) -> Result<T, Self> {
258         let inner = self.inner;
259         match Rc::try_unwrap(inner.surface) {
260             Ok(surface) => Ok(surface),
261             Err(surface) => Err(Self {
262                 inner: Box::new(PictureInner {
263                     surface,
264                     context: inner.context,
265                     buffers: inner.buffers,
266                     timestamp: inner.timestamp,
267                 }),
268                 phantom: PhantomData,
269             }),
270         }
271     }
272 
273     /// Create a new derived image from this `Picture` using `vaDeriveImage`.
274     ///
275     /// Derived images are a direct view (i.e. without any copy) on the buffer content of the
276     /// `Picture`. On the other hand, not all `Pictures` can be derived.
derive_image<'a, D: SurfaceMemoryDescriptor + 'a>( &'a self, visible_rect: (u32, u32), ) -> Result<Image, VaError> where T: Borrow<Surface<D>>,277     pub fn derive_image<'a, D: SurfaceMemoryDescriptor + 'a>(
278         &'a self,
279         visible_rect: (u32, u32),
280     ) -> Result<Image, VaError>
281     where
282         T: Borrow<Surface<D>>,
283     {
284         Image::derive_from(self.surface(), visible_rect)
285     }
286 
287     /// Create new image from the `Picture` using `vaCreateImage` and `vaGetImage`.
288     ///
289     /// The image will contain a copy of the `Picture` in the desired `format` and `coded_resolution`.
create_image<'a, D: SurfaceMemoryDescriptor + 'a>( &'a self, format: bindings::VAImageFormat, coded_resolution: (u32, u32), visible_rect: (u32, u32), ) -> Result<Image, VaError> where T: Borrow<Surface<D>>,290     pub fn create_image<'a, D: SurfaceMemoryDescriptor + 'a>(
291         &'a self,
292         format: bindings::VAImageFormat,
293         coded_resolution: (u32, u32),
294         visible_rect: (u32, u32),
295     ) -> Result<Image, VaError>
296     where
297         T: Borrow<Surface<D>>,
298     {
299         Image::create_from(self.surface(), format, coded_resolution, visible_rect)
300     }
301 }
302 
303 impl<S: PictureState, T> AsRef<T> for Picture<S, T> {
as_ref(&self) -> &T304     fn as_ref(&self) -> &T {
305         (*self.inner.surface).borrow()
306     }
307 }
308