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 5 use std::cell::Ref; 6 use std::cell::RefCell; 7 use std::cell::RefMut; 8 use std::marker::PhantomData; 9 use std::rc::Rc; 10 11 use anyhow::anyhow; 12 use anyhow::Result; 13 14 use crate::bindings; 15 use crate::buffer::Buffer; 16 use crate::context::Context; 17 use crate::status::Status; 18 use crate::surface::Surface; 19 20 // Use the sealed trait pattern to make sure that new states are not created in caller code. More 21 // information about the sealed trait pattern can be found at 22 // <https://rust-lang.github.io/api-guidelines/future-proofing.html#sealed-traits-protect-against-downstream-implementations-c-sealed> 23 mod private { 24 pub trait Sealed {} 25 } 26 27 /// A `Picture` will only have valid YUV data after a sequence of operations are performed in a 28 /// particular order. This order correspond to the following VA-API calls: `vaBeginPicture`, 29 /// `vaRenderPicture`, `vaEndPicture` and `vaSyncSurface`. This trait enforces this ordering by 30 /// implementing the Typestate pattern to constrain what operations are available in what particular 31 /// states. 32 /// 33 /// The states for the state machine are: 34 /// 35 /// * PictureNew -> PictureBegin 36 /// * PictureBegin -> PictureRender 37 /// * PictureRender ->PictureEnd 38 /// * PictureEnd -> PictureSync 39 /// 40 /// Where the surface can be reclaimed in both `PictureNew` and `PictureSync`, as either no 41 /// operation took place (as in `PictureNew`), or it is guaranteed that the operation has already 42 /// completed (as in `PictureSync`). 43 /// 44 /// More information about the Typestate pattern can be found at 45 /// <http://cliffle.com/blog/rust-typestate/> 46 pub trait PictureState: private::Sealed {} 47 48 /// Represents a `Picture` that has just been created. 49 pub enum PictureNew {} 50 impl PictureState for PictureNew {} 51 impl private::Sealed for PictureNew {} 52 53 /// Represents a `Picture` after `vaBeginPicture` has been called. 54 pub enum PictureBegin {} 55 impl PictureState for PictureBegin {} 56 impl private::Sealed for PictureBegin {} 57 58 /// Represents a `Picture` after `vaRenderPicture` has been called. 59 pub enum PictureRender {} 60 impl PictureState for PictureRender {} 61 impl private::Sealed for PictureRender {} 62 63 /// Represents a `Picture` after `vaEndPicture` has been called. 64 pub enum PictureEnd {} 65 impl PictureState for PictureEnd {} 66 impl private::Sealed for PictureEnd {} 67 68 /// Represents a `Picture` after `vaSyncSurface` has been called on the underlying surface. 69 pub enum PictureSync {} 70 impl PictureState for PictureSync {} 71 impl private::Sealed for PictureSync {} 72 73 /// Represents a state where one can reclaim the underlying `Surface` for this `Picture`. This is 74 /// true when either no decoding has been initiated or, alternatively, when the decoding operation 75 /// has completed for the underlying `vaSurface` 76 pub trait PictureReclaimableSurface: PictureState + private::Sealed {} 77 impl PictureReclaimableSurface for PictureNew {} 78 impl PictureReclaimableSurface for PictureSync {} 79 80 pub(crate) struct PictureInner { 81 /// Timestamp of the picture. 82 timestamp: u64, 83 /// A context associated with this picture. 84 context: Rc<Context>, 85 /// Contains the buffers used to decode the data. 86 buffers: Vec<Buffer>, 87 /// Contains the actual decoded data. Note that the surface may be shared in 88 /// interlaced decoding. 89 surface: Rc<RefCell<Surface>>, 90 } 91 92 impl PictureInner { 93 /// Returns a reference to the Context used by the Picture context(&self) -> Rc<Context>94 pub(crate) fn context(&self) -> Rc<Context> { 95 Rc::clone(&self.context) 96 } 97 } 98 99 /// A `Surface` that is being rendered into. 100 /// 101 /// This struct abstracts the decoding flow using `vaBeginPicture`, `vaRenderPicture`, 102 /// `vaEndPicture` and `vaSyncSurface` in a type-safe way. 103 /// 104 /// The surface will have valid picture data after all the stages of decoding are called. 105 pub struct Picture<S: PictureState> { 106 inner: Box<PictureInner>, 107 phantom: std::marker::PhantomData<S>, 108 } 109 110 impl Picture<PictureNew> { 111 /// Creates a new Picture with a given `timestamp`. `surface` is the underlying surface that 112 /// libva will render to. new(timestamp: u64, context: Rc<Context>, surface: Surface) -> Self113 pub fn new(timestamp: u64, context: Rc<Context>, surface: Surface) -> Self { 114 Self { 115 inner: Box::new(PictureInner { 116 timestamp, 117 context, 118 buffers: Default::default(), 119 surface: Rc::new(RefCell::new(surface)), 120 }), 121 122 phantom: PhantomData, 123 } 124 } 125 126 /// Creates a new Picture with a given `frame_number` to identify it, 127 /// reusing the Surface from `picture`. This is useful for interlaced 128 /// decoding as one can render both fields to the same underlying surface. new_from_same_surface<T: PictureReclaimableSurface, S: PictureReclaimableSurface>( timestamp: u64, picture: &Picture<S>, ) -> Picture<T>129 pub fn new_from_same_surface<T: PictureReclaimableSurface, S: PictureReclaimableSurface>( 130 timestamp: u64, 131 picture: &Picture<S>, 132 ) -> Picture<T> { 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. add_buffer(&mut self, buffer: Buffer)147 pub fn add_buffer(&mut self, buffer: Buffer) { 148 self.inner.buffers.push(buffer); 149 } 150 151 /// Wrapper around `vaBeginPicture`. begin(self) -> Result<Picture<PictureBegin>>152 pub fn begin(self) -> Result<Picture<PictureBegin>> { 153 // Safe because `self.inner.context` represents a valid VAContext and 154 // `self.inner.surface` represents a valid VASurface. 155 Status(unsafe { 156 bindings::vaBeginPicture( 157 self.inner.context.display().handle(), 158 self.inner.context.id(), 159 self.inner.surface.borrow().id(), 160 ) 161 }) 162 .check()?; 163 164 Ok(Picture { 165 inner: self.inner, 166 phantom: PhantomData, 167 }) 168 } 169 } 170 171 impl Picture<PictureBegin> { 172 /// Wrapper around `vaRenderPicture`. render(self) -> Result<Picture<PictureRender>>173 pub fn render(self) -> Result<Picture<PictureRender>> { 174 // Safe because `self.inner.context` represents a valid `VAContext` and `self.inner.surface` 175 // represents a valid `VASurface`. `buffers` point to a Rust struct and the vector length is 176 // passed to the C function, so it is impossible to write past the end of the vector's 177 // storage by mistake. 178 Status(unsafe { 179 bindings::vaRenderPicture( 180 self.inner.context.display().handle(), 181 self.inner.context.id(), 182 Buffer::as_id_vec(&self.inner.buffers).as_mut_ptr(), 183 self.inner.buffers.len() as i32, 184 ) 185 }) 186 .check()?; 187 188 Ok(Picture { 189 inner: self.inner, 190 phantom: PhantomData, 191 }) 192 } 193 } 194 195 impl Picture<PictureRender> { 196 /// Wrapper around `vaEndPicture`. end(self) -> Result<Picture<PictureEnd>>197 pub fn end(self) -> Result<Picture<PictureEnd>> { 198 // Safe because `self.inner.context` represents a valid `VAContext`. 199 Status(unsafe { 200 bindings::vaEndPicture( 201 self.inner.context.display().handle(), 202 self.inner.context.id(), 203 ) 204 }) 205 .check()?; 206 Ok(Picture { 207 inner: self.inner, 208 phantom: PhantomData, 209 }) 210 } 211 } 212 213 impl Picture<PictureEnd> { 214 /// Syncs the picture, ensuring that all pending operations are complete when this call returns. sync(self) -> Result<Picture<PictureSync>>215 pub fn sync(self) -> Result<Picture<PictureSync>> { 216 self.inner.surface.borrow().sync()?; 217 218 Ok(Picture { 219 inner: self.inner, 220 phantom: PhantomData, 221 }) 222 } 223 224 /// Queries the status of the underlying surface. 225 /// 226 /// This call can be used to implement a non-blocking path, wherein a decoder queries the status 227 /// of the surface after each decode operation instead of blocking on it. query_status(&self) -> Result<bindings::VASurfaceStatus::Type>228 pub fn query_status(&self) -> Result<bindings::VASurfaceStatus::Type> { 229 self.inner.surface.borrow_mut().query_status() 230 } 231 } 232 233 impl<S: PictureState> Picture<S> { 234 /// Returns the timestamp of this picture. timestamp(&self) -> u64235 pub fn timestamp(&self) -> u64 { 236 self.inner.timestamp 237 } 238 239 /// Returns a reference to the `inner` struct. inner(&self) -> &PictureInner240 pub(crate) fn inner(&self) -> &PictureInner { 241 self.inner.as_ref() 242 } 243 } 244 245 impl<S: PictureReclaimableSurface> Picture<S> { 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. take_surface(self) -> Result<Surface>248 pub fn take_surface(self) -> Result<Surface> { 249 match Rc::try_unwrap(self.inner.surface) { 250 Ok(surface) => Ok(surface.into_inner()), 251 Err(_) => Err(anyhow!("Surface still in use")), 252 } 253 } 254 255 /// Returns a reference to the underlying `Surface` for this `Picture` surface(&self) -> Ref<Surface>256 pub fn surface(&self) -> Ref<Surface> { 257 self.inner.surface.borrow() 258 } 259 260 /// Returns a mutable reference to the underlying `Surface` for this `Picture` surface_mut(&mut self) -> RefMut<Surface>261 pub fn surface_mut(&mut self) -> RefMut<Surface> { 262 self.inner.surface.borrow_mut() 263 } 264 } 265