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.
6 use std::cell::RefCell;
8 use std::marker::PhantomData;
12 use crate::buffer::Buffer;
13 use crate::context::Context;
14 use crate::display::Display;
16 use crate::surface::Surface;
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>
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
31 /// The states for the state machine are:
33 /// * PictureNew -> PictureBegin
34 /// * PictureBegin -> PictureRender
35 /// * PictureRender ->PictureEnd
36 /// * PictureEnd -> PictureSync
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`).
42 /// More information about the Typestate pattern can be found at
43 /// <http://cliffle.com/blog/rust-typestate/>
44 pub trait PictureState: private::Sealed {}
46 /// Represents a `Picture` that has just been created.
47 pub enum PictureNew {}
48 impl PictureState for PictureNew {}
49 impl private::Sealed for PictureNew {}
51 /// Represents a `Picture` after `vaBeginPicture` has been called.
52 pub enum PictureBegin {}
53 impl PictureState for PictureBegin {}
54 impl private::Sealed for PictureBegin {}
56 /// Represents a `Picture` after `vaRenderPicture` has been called.
57 pub enum PictureRender {}
58 impl PictureState for PictureRender {}
59 impl private::Sealed for PictureRender {}
61 /// Represents a `Picture` after `vaEndPicture` has been called.
62 pub enum PictureEnd {}
63 impl PictureState for PictureEnd {}
64 impl private::Sealed for PictureEnd {}
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 {}
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 {}
79 /// Timestamp of the picture.
81 /// A context associated with this picture.
83 /// Contains the buffers used to decode the data.
85 /// Contains the actual decoded data. Note that the surface may be shared in
86 /// interlaced decoding.
87 surface: Rc<RefCell<Surface>>,
90 /// A `Surface` that is being rendered into.
92 /// This struct abstracts the decoding flow using `vaBeginPicture`, `vaRenderPicture`,
93 /// `vaEndPicture` and `vaSyncSurface` in a type-safe way.
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>,
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 {
106 inner: Box::new(PictureInner {
109 buffers: Default::default(),
110 surface: Rc::new(RefCell::new(surface)),
113 phantom: PhantomData,
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>(
122 picture: &Picture<S>,
124 let context = Rc::clone(&picture.inner.context);
126 inner: Box::new(PictureInner {
129 buffers: Default::default(),
130 surface: Rc::clone(&picture.inner.surface),
133 phantom: PhantomData,
137 /// Add `buffer` to the picture.
138 pub fn add_buffer(&mut self, buffer: Buffer) {
139 self.inner.buffers.push(buffer);
142 /// Wrapper around `vaBeginPicture`.
143 pub fn begin(self) -> VAResult<Picture<PictureBegin>> {
144 // Safe because `self.inner.context` represents a valid VAContext and
145 // `self.inner.surface` represents a valid VASurface.
147 bindings::vaBeginPicture(
148 self.inner.context.display().handle(),
149 self.inner.context.id(),
150 self.inner.surface.borrow().id(),
157 phantom: PhantomData,
162 impl Picture<PictureBegin> {
163 /// Wrapper around `vaRenderPicture`.
164 pub fn render(self) -> VAResult<Picture<PictureRender>> {
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.
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,
181 phantom: PhantomData,
186 impl Picture<PictureRender> {
187 /// Wrapper around `vaEndPicture`.
188 pub fn end(self) -> VAResult<Picture<PictureEnd>> {
189 // Safe because `self.inner.context` represents a valid `VAContext`.
191 bindings::vaEndPicture(
192 self.inner.context.display().handle(),
193 self.inner.context.id(),
199 phantom: PhantomData,
204 impl Picture<PictureEnd> {
205 /// Syncs the picture, ensuring that all pending operations are complete when this call returns.
206 pub fn sync(self) -> std::result::Result<Picture<PictureSync>, (VAError, Self)> {
207 let res = self.inner.surface.borrow().sync();
210 Ok(()) => Ok(Picture {
212 phantom: PhantomData,
214 Err(e) => Err((e, self)),
218 /// Queries the status of the underlying surface.
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.
222 pub fn query_status(&self) -> VAResult<VASurfaceStatus> {
223 self.inner.surface.borrow_mut().query_status()
227 impl<S: PictureState> Picture<S> {
228 /// Returns the timestamp of this picture.
229 pub fn timestamp(&self) -> u64 {
233 /// Returns the ID of the underlying surface.
234 pub fn surface_id(&self) -> bindings::VASurfaceID {
235 self.inner.surface.borrow().id()
238 /// Returns a reference to the display owning this `Picture`.
239 pub(crate) fn display(&self) -> &Rc<Display> {
240 self.inner.context.display()
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()
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.
252 pub fn take_surface(self) -> VAResult<Surface> {
253 match Rc::try_unwrap(self.inner.surface) {
254 Ok(surface) => Ok(surface.into_inner()),
255 Err(_) => Err(VAError::SurfaceBusy),
259 /// Returns a reference to the underlying `Surface` for this `Picture`
260 pub fn surface(&self) -> Ref<Surface> {
261 self.inner.surface.borrow()
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()