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;
15 use crate::buffer::Buffer;
16 use crate::context::Context;
17 use crate::display::Display;
18 use crate::status::Status;
19 use crate::surface::Surface;
21 // Use the sealed trait pattern to make sure that new states are not created in caller code. More
22 // information about the sealed trait pattern can be found at
23 // <https://rust-lang.github.io/api-guidelines/future-proofing.html#sealed-traits-protect-against-downstream-implementations-c-sealed>
28 /// A `Picture` will only have valid YUV data after a sequence of operations are performed in a
29 /// particular order. This order correspond to the following VA-API calls: `vaBeginPicture`,
30 /// `vaRenderPicture`, `vaEndPicture` and `vaSyncSurface`. This trait enforces this ordering by
31 /// implementing the Typestate pattern to constrain what operations are available in what particular
34 /// The states for the state machine are:
36 /// * PictureNew -> PictureBegin
37 /// * PictureBegin -> PictureRender
38 /// * PictureRender ->PictureEnd
39 /// * PictureEnd -> PictureSync
41 /// Where the surface can be reclaimed in both `PictureNew` and `PictureSync`, as either no
42 /// operation took place (as in `PictureNew`), or it is guaranteed that the operation has already
43 /// completed (as in `PictureSync`).
45 /// More information about the Typestate pattern can be found at
46 /// <http://cliffle.com/blog/rust-typestate/>
47 pub trait PictureState: private::Sealed {}
49 /// Represents a `Picture` that has just been created.
50 pub enum PictureNew {}
51 impl PictureState for PictureNew {}
52 impl private::Sealed for PictureNew {}
54 /// Represents a `Picture` after `vaBeginPicture` has been called.
55 pub enum PictureBegin {}
56 impl PictureState for PictureBegin {}
57 impl private::Sealed for PictureBegin {}
59 /// Represents a `Picture` after `vaRenderPicture` has been called.
60 pub enum PictureRender {}
61 impl PictureState for PictureRender {}
62 impl private::Sealed for PictureRender {}
64 /// Represents a `Picture` after `vaEndPicture` has been called.
65 pub enum PictureEnd {}
66 impl PictureState for PictureEnd {}
67 impl private::Sealed for PictureEnd {}
69 /// Represents a `Picture` after `vaSyncSurface` has been called on the underlying surface.
70 pub enum PictureSync {}
71 impl PictureState for PictureSync {}
72 impl private::Sealed for PictureSync {}
74 /// Represents a state where one can reclaim the underlying `Surface` for this `Picture`. This is
75 /// true when either no decoding has been initiated or, alternatively, when the decoding operation
76 /// has completed for the underlying `vaSurface`
77 pub trait PictureReclaimableSurface: PictureState + private::Sealed {}
78 impl PictureReclaimableSurface for PictureNew {}
79 impl PictureReclaimableSurface for PictureSync {}
82 /// Timestamp of the picture.
84 /// A context associated with this picture.
86 /// Contains the buffers used to decode the data.
88 /// Contains the actual decoded data. Note that the surface may be shared in
89 /// interlaced decoding.
90 surface: Rc<RefCell<Surface>>,
93 /// A `Surface` that is being rendered into.
95 /// This struct abstracts the decoding flow using `vaBeginPicture`, `vaRenderPicture`,
96 /// `vaEndPicture` and `vaSyncSurface` in a type-safe way.
98 /// The surface will have valid picture data after all the stages of decoding are called.
99 pub struct Picture<S: PictureState> {
100 inner: Box<PictureInner>,
101 phantom: std::marker::PhantomData<S>,
104 impl Picture<PictureNew> {
105 /// Creates a new Picture with a given `timestamp`. `surface` is the underlying surface that
106 /// libva will render to.
107 pub fn new(timestamp: u64, context: Rc<Context>, surface: Surface) -> Self {
109 inner: Box::new(PictureInner {
112 buffers: Default::default(),
113 surface: Rc::new(RefCell::new(surface)),
116 phantom: PhantomData,
120 /// Creates a new Picture with a given `frame_number` to identify it,
121 /// reusing the Surface from `picture`. This is useful for interlaced
122 /// decoding as one can render both fields to the same underlying surface.
123 pub fn new_from_same_surface<T: PictureReclaimableSurface, S: PictureReclaimableSurface>(
125 picture: &Picture<S>,
127 let context = Rc::clone(&picture.inner.context);
129 inner: Box::new(PictureInner {
132 buffers: Default::default(),
133 surface: Rc::clone(&picture.inner.surface),
136 phantom: PhantomData,
140 /// Add `buffer` to the picture.
141 pub fn add_buffer(&mut self, buffer: Buffer) {
142 self.inner.buffers.push(buffer);
145 /// Wrapper around `vaBeginPicture`.
146 pub fn begin(self) -> Result<Picture<PictureBegin>> {
147 // Safe because `self.inner.context` represents a valid VAContext and
148 // `self.inner.surface` represents a valid VASurface.
150 bindings::vaBeginPicture(
151 self.inner.context.display().handle(),
152 self.inner.context.id(),
153 self.inner.surface.borrow().id(),
160 phantom: PhantomData,
165 impl Picture<PictureBegin> {
166 /// Wrapper around `vaRenderPicture`.
167 pub fn render(self) -> Result<Picture<PictureRender>> {
168 // Safe because `self.inner.context` represents a valid `VAContext` and `self.inner.surface`
169 // represents a valid `VASurface`. `buffers` point to a Rust struct and the vector length is
170 // passed to the C function, so it is impossible to write past the end of the vector's
171 // storage by mistake.
173 bindings::vaRenderPicture(
174 self.inner.context.display().handle(),
175 self.inner.context.id(),
176 Buffer::as_id_vec(&self.inner.buffers).as_mut_ptr(),
177 self.inner.buffers.len() as i32,
184 phantom: PhantomData,
189 impl Picture<PictureRender> {
190 /// Wrapper around `vaEndPicture`.
191 pub fn end(self) -> Result<Picture<PictureEnd>> {
192 // Safe because `self.inner.context` represents a valid `VAContext`.
194 bindings::vaEndPicture(
195 self.inner.context.display().handle(),
196 self.inner.context.id(),
202 phantom: PhantomData,
207 impl Picture<PictureEnd> {
208 /// Syncs the picture, ensuring that all pending operations are complete when this call returns.
209 pub fn sync(self) -> std::result::Result<Picture<PictureSync>, (anyhow::Error, Self)> {
210 let res = self.inner.surface.borrow().sync();
213 Ok(()) => Ok(Picture {
215 phantom: PhantomData,
217 Err(e) => Err((e, self)),
221 /// Queries the status of the underlying surface.
223 /// This call can be used to implement a non-blocking path, wherein a decoder queries the status
224 /// of the surface after each decode operation instead of blocking on it.
225 pub fn query_status(&self) -> Result<bindings::VASurfaceStatus::Type> {
226 self.inner.surface.borrow_mut().query_status()
230 impl<S: PictureState> Picture<S> {
231 /// Returns the timestamp of this picture.
232 pub fn timestamp(&self) -> u64 {
236 /// Returns the ID of the underlying surface.
237 pub fn surface_id(&self) -> bindings::VASurfaceID {
238 self.inner.surface.borrow().id()
241 /// Returns a reference to the display owning this `Picture`.
242 pub(crate) fn display(&self) -> &Rc<Display> {
243 self.inner.context.display()
246 /// Returns the size of the surface being rendered to by this `Picture`.
247 pub fn surface_size(&self) -> (u32, u32) {
248 self.inner.surface.borrow().size()
252 impl<S: PictureReclaimableSurface> Picture<S> {
253 /// Reclaim ownership of the Surface this picture has been created from, consuming the picture
254 /// in the process. Useful if the Surface is part of a pool.
255 pub fn take_surface(self) -> Result<Surface> {
256 match Rc::try_unwrap(self.inner.surface) {
257 Ok(surface) => Ok(surface.into_inner()),
258 Err(_) => Err(anyhow!("Surface still in use")),
262 /// Returns a reference to the underlying `Surface` for this `Picture`
263 pub fn surface(&self) -> Ref<Surface> {
264 self.inner.surface.borrow()
267 /// Returns a mutable reference to the underlying `Surface` for this `Picture`
268 pub fn surface_mut(&mut self) -> RefMut<Surface> {
269 self.inner.surface.borrow_mut()