start work on nihed-cros-libva
[nihav-player.git] / nihed-cros-libva / src / picture.rs
CommitLineData
68362724
KS
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::cell::Ref;
6use std::cell::RefCell;
7use std::cell::RefMut;
8use std::marker::PhantomData;
9use std::rc::Rc;
10
11use anyhow::anyhow;
12use anyhow::Result;
13
14use crate::bindings;
15use crate::buffer::Buffer;
16use crate::context::Context;
17use crate::display::Display;
18use crate::status::Status;
19use crate::surface::Surface;
20
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>
24mod private {
25 pub trait Sealed {}
26}
27
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
32/// states.
33///
34/// The states for the state machine are:
35///
36/// * PictureNew -> PictureBegin
37/// * PictureBegin -> PictureRender
38/// * PictureRender ->PictureEnd
39/// * PictureEnd -> PictureSync
40///
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`).
44///
45/// More information about the Typestate pattern can be found at
46/// <http://cliffle.com/blog/rust-typestate/>
47pub trait PictureState: private::Sealed {}
48
49/// Represents a `Picture` that has just been created.
50pub enum PictureNew {}
51impl PictureState for PictureNew {}
52impl private::Sealed for PictureNew {}
53
54/// Represents a `Picture` after `vaBeginPicture` has been called.
55pub enum PictureBegin {}
56impl PictureState for PictureBegin {}
57impl private::Sealed for PictureBegin {}
58
59/// Represents a `Picture` after `vaRenderPicture` has been called.
60pub enum PictureRender {}
61impl PictureState for PictureRender {}
62impl private::Sealed for PictureRender {}
63
64/// Represents a `Picture` after `vaEndPicture` has been called.
65pub enum PictureEnd {}
66impl PictureState for PictureEnd {}
67impl private::Sealed for PictureEnd {}
68
69/// Represents a `Picture` after `vaSyncSurface` has been called on the underlying surface.
70pub enum PictureSync {}
71impl PictureState for PictureSync {}
72impl private::Sealed for PictureSync {}
73
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`
77pub trait PictureReclaimableSurface: PictureState + private::Sealed {}
78impl PictureReclaimableSurface for PictureNew {}
79impl PictureReclaimableSurface for PictureSync {}
80
81struct PictureInner {
82 /// Timestamp of the picture.
83 timestamp: u64,
84 /// A context associated with this picture.
85 context: Rc<Context>,
86 /// Contains the buffers used to decode the data.
87 buffers: Vec<Buffer>,
88 /// Contains the actual decoded data. Note that the surface may be shared in
89 /// interlaced decoding.
90 surface: Rc<RefCell<Surface>>,
91}
92
93/// A `Surface` that is being rendered into.
94///
95/// This struct abstracts the decoding flow using `vaBeginPicture`, `vaRenderPicture`,
96/// `vaEndPicture` and `vaSyncSurface` in a type-safe way.
97///
98/// The surface will have valid picture data after all the stages of decoding are called.
99pub struct Picture<S: PictureState> {
100 inner: Box<PictureInner>,
101 phantom: std::marker::PhantomData<S>,
102}
103
104impl 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 {
108 Self {
109 inner: Box::new(PictureInner {
110 timestamp,
111 context,
112 buffers: Default::default(),
113 surface: Rc::new(RefCell::new(surface)),
114 }),
115
116 phantom: PhantomData,
117 }
118 }
119
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>(
124 timestamp: u64,
125 picture: &Picture<S>,
126 ) -> Picture<T> {
127 let context = Rc::clone(&picture.inner.context);
128 Picture {
129 inner: Box::new(PictureInner {
130 timestamp,
131 context,
132 buffers: Default::default(),
133 surface: Rc::clone(&picture.inner.surface),
134 }),
135
136 phantom: PhantomData,
137 }
138 }
139
140 /// Add `buffer` to the picture.
141 pub fn add_buffer(&mut self, buffer: Buffer) {
142 self.inner.buffers.push(buffer);
143 }
144
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.
149 Status(unsafe {
150 bindings::vaBeginPicture(
151 self.inner.context.display().handle(),
152 self.inner.context.id(),
153 self.inner.surface.borrow().id(),
154 )
155 })
156 .check()?;
157
158 Ok(Picture {
159 inner: self.inner,
160 phantom: PhantomData,
161 })
162 }
163}
164
165impl 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.
172 Status(unsafe {
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,
178 )
179 })
180 .check()?;
181
182 Ok(Picture {
183 inner: self.inner,
184 phantom: PhantomData,
185 })
186 }
187}
188
189impl Picture<PictureRender> {
190 /// Wrapper around `vaEndPicture`.
191 pub fn end(self) -> Result<Picture<PictureEnd>> {
192 // Safe because `self.inner.context` represents a valid `VAContext`.
193 Status(unsafe {
194 bindings::vaEndPicture(
195 self.inner.context.display().handle(),
196 self.inner.context.id(),
197 )
198 })
199 .check()?;
200 Ok(Picture {
201 inner: self.inner,
202 phantom: PhantomData,
203 })
204 }
205}
206
207impl 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();
211
212 match res {
213 Ok(()) => Ok(Picture {
214 inner: self.inner,
215 phantom: PhantomData,
216 }),
217 Err(e) => Err((e, self)),
218 }
219 }
220
221 /// Queries the status of the underlying surface.
222 ///
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()
227 }
228}
229
230impl<S: PictureState> Picture<S> {
231 /// Returns the timestamp of this picture.
232 pub fn timestamp(&self) -> u64 {
233 self.inner.timestamp
234 }
235
236 /// Returns the ID of the underlying surface.
237 pub fn surface_id(&self) -> bindings::VASurfaceID {
238 self.inner.surface.borrow().id()
239 }
240
241 /// Returns a reference to the display owning this `Picture`.
242 pub(crate) fn display(&self) -> &Rc<Display> {
243 self.inner.context.display()
244 }
245
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()
249 }
250}
251
252impl<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")),
259 }
260 }
261
262 /// Returns a reference to the underlying `Surface` for this `Picture`
263 pub fn surface(&self) -> Ref<Surface> {
264 self.inner.surface.borrow()
265 }
266
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()
270 }
271}