Skip to main content

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}