moq_vaapi/picture.rs
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
5use std::borrow::Borrow;
6use std::marker::PhantomData;
7use std::rc::Rc;
8
9use crate::bindings;
10use crate::buffer::Buffer;
11use crate::context::Context;
12use crate::surface::Surface;
13use crate::va_check;
14use crate::Image;
15use crate::SurfaceMemoryDescriptor;
16use 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>
21mod 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/>
44pub trait PictureState: private::Sealed {}
45
46/// Represents a `Picture` that has just been created.
47pub enum PictureNew {}
48impl PictureState for PictureNew {}
49impl private::Sealed for PictureNew {}
50
51/// Represents a `Picture` after `vaBeginPicture` has been called.
52pub enum PictureBegin {}
53impl PictureState for PictureBegin {}
54impl private::Sealed for PictureBegin {}
55
56/// Represents a `Picture` after `vaRenderPicture` has been called.
57pub enum PictureRender {}
58impl PictureState for PictureRender {}
59impl private::Sealed for PictureRender {}
60
61/// Represents a `Picture` after `vaEndPicture` has been called.
62pub enum PictureEnd {}
63impl PictureState for PictureEnd {}
64impl private::Sealed for PictureEnd {}
65
66/// Represents a `Picture` after `vaSyncSurface` has been called on the underlying surface.
67pub enum PictureSync {}
68impl PictureState for PictureSync {}
69impl 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`
74pub trait PictureReclaimableSurface: PictureState + private::Sealed {}
75impl PictureReclaimableSurface for PictureNew {}
76impl PictureReclaimableSurface for PictureSync {}
77
78/// Inner type for [`Picture`], that is, the part that exists in all states.
79struct 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`].
105pub struct Picture<S: PictureState, T> {
106 inner: Box<PictureInner<T>>,
107 phantom: std::marker::PhantomData<S>,
108}
109
110impl<T> Picture<PictureNew, T> {
111 /// Creates a new Picture with a given `timestamp`. `surface` is the underlying surface that
112 /// libva will render to.
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.
132 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.
147 pub fn add_buffer(&mut self, buffer: Buffer) {
148 self.inner.buffers.push(buffer);
149 }
150
151 /// Wrapper around `vaBeginPicture`.
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
173impl<T> Picture<PictureBegin, T> {
174 /// Wrapper around `vaRenderPicture`.
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
195impl<T> Picture<PictureRender, T> {
196 /// Wrapper around `vaEndPicture`.
197 pub fn end(self) -> Result<Picture<PictureEnd, T>, VaError> {
198 // Safe because `self.inner.context` represents a valid `VAContext`.
199 va_check(unsafe { bindings::vaEndPicture(self.inner.context.display().handle(), self.inner.context.id()) }).map(
200 |()| Picture {
201 inner: self.inner,
202 phantom: PhantomData,
203 },
204 )
205 }
206}
207
208impl<T> Picture<PictureEnd, T> {
209 /// Syncs the picture, ensuring that all pending operations are complete when this call returns.
210 pub fn sync<D: SurfaceMemoryDescriptor>(self) -> Result<Picture<PictureSync, T>, (VaError, Self)>
211 where
212 T: Borrow<Surface<D>>,
213 {
214 let res = self.surface().sync();
215
216 match res {
217 Ok(()) => Ok(Picture {
218 inner: self.inner,
219 phantom: PhantomData,
220 }),
221 Err(e) => Err((e, self)),
222 }
223 }
224}
225
226impl<S: PictureState, T> Picture<S, T> {
227 /// Returns the timestamp of this picture.
228 pub fn timestamp(&self) -> u64 {
229 self.inner.timestamp
230 }
231
232 /// Returns a reference to the underlying `Surface`.
233 ///
234 /// If you are interested in obtaining the container of the `Surface`, use `as_ref()` instead.
235 /// This is a convenience method to avoid having to call `borrow()` every time the surface is
236 /// needed.
237 pub fn surface<D: SurfaceMemoryDescriptor>(&self) -> &Surface<D>
238 where
239 T: Borrow<Surface<D>>,
240 {
241 self.as_ref().borrow()
242 }
243}
244
245impl<S: PictureReclaimableSurface, T> Picture<S, T> {
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.
248 ///
249 /// This will fail and return the passed object if there are more than one reference to the
250 /// underlying surface.
251 pub fn take_surface(self) -> Result<T, Self> {
252 let inner = self.inner;
253 match Rc::try_unwrap(inner.surface) {
254 Ok(surface) => Ok(surface),
255 Err(surface) => Err(Self {
256 inner: Box::new(PictureInner {
257 surface,
258 context: inner.context,
259 buffers: inner.buffers,
260 timestamp: inner.timestamp,
261 }),
262 phantom: PhantomData,
263 }),
264 }
265 }
266
267 /// Create a new derived image from this `Picture` using `vaDeriveImage`.
268 ///
269 /// Derived images are a direct view (i.e. without any copy) on the buffer content of the
270 /// `Picture`. On the other hand, not all `Pictures` can be derived.
271 pub fn derive_image<'a, D: SurfaceMemoryDescriptor + 'a>(
272 &'a self,
273 visible_rect: (u32, u32),
274 ) -> Result<Image<'a>, VaError>
275 where
276 T: Borrow<Surface<D>>,
277 {
278 Image::derive_from(self.surface(), visible_rect)
279 }
280
281 /// Create new image from the `Picture` using `vaCreateImage` and `vaGetImage`.
282 ///
283 /// The image will contain a copy of the `Picture` in the desired `format` and `coded_resolution`.
284 pub fn create_image<'a, D: SurfaceMemoryDescriptor + 'a>(
285 &'a self,
286 format: bindings::VAImageFormat,
287 coded_resolution: (u32, u32),
288 visible_rect: (u32, u32),
289 ) -> Result<Image<'a>, VaError>
290 where
291 T: Borrow<Surface<D>>,
292 {
293 Image::create_from(self.surface(), format, coded_resolution, visible_rect)
294 }
295}
296
297impl<S: PictureState, T> AsRef<T> for Picture<S, T> {
298 fn as_ref(&self) -> &T {
299 (*self.inner.surface).borrow()
300 }
301}