nihed-cros-libva: use simple error enum instead of anyhow crate
[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
68362724
KS
11use crate::bindings;
12use crate::buffer::Buffer;
13use crate::context::Context;
14use crate::display::Display;
69e6ce02 15use crate::status::*;
68362724
KS
16use crate::surface::Surface;
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
78struct PictureInner {
79 /// Timestamp of the picture.
80 timestamp: u64,
81 /// A context associated with this picture.
82 context: Rc<Context>,
83 /// Contains the buffers used to decode the data.
84 buffers: Vec<Buffer>,
85 /// Contains the actual decoded data. Note that the surface may be shared in
86 /// interlaced decoding.
87 surface: Rc<RefCell<Surface>>,
88}
89
90/// A `Surface` that is being rendered into.
91///
92/// This struct abstracts the decoding flow using `vaBeginPicture`, `vaRenderPicture`,
93/// `vaEndPicture` and `vaSyncSurface` in a type-safe way.
94///
95/// The surface will have valid picture data after all the stages of decoding are called.
96pub struct Picture<S: PictureState> {
97 inner: Box<PictureInner>,
98 phantom: std::marker::PhantomData<S>,
99}
100
101impl 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 {
105 Self {
106 inner: Box::new(PictureInner {
107 timestamp,
108 context,
109 buffers: Default::default(),
110 surface: Rc::new(RefCell::new(surface)),
111 }),
112
113 phantom: PhantomData,
114 }
115 }
116
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>(
121 timestamp: u64,
122 picture: &Picture<S>,
123 ) -> Picture<T> {
124 let context = Rc::clone(&picture.inner.context);
125 Picture {
126 inner: Box::new(PictureInner {
127 timestamp,
128 context,
129 buffers: Default::default(),
130 surface: Rc::clone(&picture.inner.surface),
131 }),
132
133 phantom: PhantomData,
134 }
135 }
136
137 /// Add `buffer` to the picture.
138 pub fn add_buffer(&mut self, buffer: Buffer) {
139 self.inner.buffers.push(buffer);
140 }
141
142 /// Wrapper around `vaBeginPicture`.
69e6ce02 143 pub fn begin(self) -> VAResult<Picture<PictureBegin>> {
68362724
KS
144 // Safe because `self.inner.context` represents a valid VAContext and
145 // `self.inner.surface` represents a valid VASurface.
69e6ce02 146 (unsafe {
68362724
KS
147 bindings::vaBeginPicture(
148 self.inner.context.display().handle(),
149 self.inner.context.id(),
150 self.inner.surface.borrow().id(),
151 )
152 })
153 .check()?;
154
155 Ok(Picture {
156 inner: self.inner,
157 phantom: PhantomData,
158 })
159 }
160}
161
162impl Picture<PictureBegin> {
163 /// Wrapper around `vaRenderPicture`.
69e6ce02 164 pub fn render(self) -> VAResult<Picture<PictureRender>> {
68362724
KS
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.
69e6ce02 169 (unsafe {
68362724
KS
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,
175 )
176 })
177 .check()?;
178
179 Ok(Picture {
180 inner: self.inner,
181 phantom: PhantomData,
182 })
183 }
184}
185
186impl Picture<PictureRender> {
187 /// Wrapper around `vaEndPicture`.
69e6ce02 188 pub fn end(self) -> VAResult<Picture<PictureEnd>> {
68362724 189 // Safe because `self.inner.context` represents a valid `VAContext`.
69e6ce02 190 (unsafe {
68362724
KS
191 bindings::vaEndPicture(
192 self.inner.context.display().handle(),
193 self.inner.context.id(),
194 )
195 })
196 .check()?;
197 Ok(Picture {
198 inner: self.inner,
199 phantom: PhantomData,
200 })
201 }
202}
203
204impl Picture<PictureEnd> {
205 /// Syncs the picture, ensuring that all pending operations are complete when this call returns.
69e6ce02 206 pub fn sync(self) -> std::result::Result<Picture<PictureSync>, (VAError, Self)> {
68362724
KS
207 let res = self.inner.surface.borrow().sync();
208
209 match res {
210 Ok(()) => Ok(Picture {
211 inner: self.inner,
212 phantom: PhantomData,
213 }),
214 Err(e) => Err((e, self)),
215 }
216 }
217
218 /// Queries the status of the underlying surface.
219 ///
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.
69e6ce02 222 pub fn query_status(&self) -> VAResult<bindings::VASurfaceStatus::Type> {
68362724
KS
223 self.inner.surface.borrow_mut().query_status()
224 }
225}
226
227impl<S: PictureState> Picture<S> {
228 /// Returns the timestamp of this picture.
229 pub fn timestamp(&self) -> u64 {
230 self.inner.timestamp
231 }
232
233 /// Returns the ID of the underlying surface.
234 pub fn surface_id(&self) -> bindings::VASurfaceID {
235 self.inner.surface.borrow().id()
236 }
237
238 /// Returns a reference to the display owning this `Picture`.
239 pub(crate) fn display(&self) -> &Rc<Display> {
240 self.inner.context.display()
241 }
242
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()
246 }
247}
248
249impl<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.
69e6ce02 252 pub fn take_surface(self) -> VAResult<Surface> {
68362724
KS
253 match Rc::try_unwrap(self.inner.surface) {
254 Ok(surface) => Ok(surface.into_inner()),
69e6ce02 255 Err(_) => Err(VAError::SurfaceBusy),
68362724
KS
256 }
257 }
258
259 /// Returns a reference to the underlying `Surface` for this `Picture`
260 pub fn surface(&self) -> Ref<Surface> {
261 self.inner.surface.borrow()
262 }
263
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()
267 }
268}