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 anyhow::Result; 6 7 use crate::bindings; 8 use crate::picture::Picture; 9 use crate::picture::PictureSync; 10 use crate::status::Status; 11 12 /// Wrapper around `VAImage` that is tied to the lifetime of a given `Picture`. 13 /// 14 /// An image is used to either get the surface data to client memory, or to copy image data in 15 /// client memory to a surface. 16 pub struct Image<'a> { 17 /// The picture whose `Surface` we use as the source of pixel data. 18 picture: &'a Picture<PictureSync>, 19 /// The `VAImage` returned by libva. 20 image: bindings::VAImage, 21 /// The mapped surface data. 22 data: &'a mut [u8], 23 /// Whether the image was derived using the `vaDeriveImage` API or created using the 24 /// `vaCreateImage` API. 25 derived: bool, 26 /// Tracks whether the underlying data has possibly been written to, i.e. an encoder will create 27 /// an image and map its buffer in order to write to it, so we must writeback later. 28 dirty: bool, 29 } 30 31 impl<'a> Image<'a> { 32 /// Creates a new `Image` either by calling `vaCreateImage` or 33 /// `vaDeriveImage`. Creating an Image depends on acquiring a ready Surface 34 /// from an underlying Picture. Note that Image has a borrowed Picture, so 35 /// it will be dropped before the underlying Surface is dropped, as mandated 36 /// by VAAPI. 37 /// 38 /// # Arguments 39 /// 40 /// * `picture` - The [`Picture`] that owns the Surface this image will be created from. 41 /// * `format` - A `VAImageFormat` returned by [`crate::Display::query_image_formats`]. 42 /// * `width` - The image's desired width. 43 /// * `height` - The image's desired height. 44 /// * `derive` - Whether to try deriving the image from `picture`, which allows zero-copy access 45 /// to the surface data. Deriving may fail, in which case vaCreateImage will be used instead, 46 /// incurring an extra data copy. new( picture: &'a mut Picture<PictureSync>, mut format: bindings::VAImageFormat, width: u32, height: u32, derive: bool, ) -> Result<Self>47 pub fn new( 48 picture: &'a mut Picture<PictureSync>, 49 mut format: bindings::VAImageFormat, 50 width: u32, 51 height: u32, 52 derive: bool, 53 ) -> Result<Self> { 54 // An all-zero byte-pattern is a valid initial value for `VAImage`. 55 let mut image: bindings::VAImage = Default::default(); 56 let mut addr = std::ptr::null_mut(); 57 let mut derived = false; 58 59 if derive { 60 derived = Image::derive_image(picture, &mut image)?; 61 } 62 63 if !derived { 64 Image::create_image(picture, &mut image, &mut format, width, height)?; 65 } 66 67 // Safe since `picture.inner.context` represents a valid `VAContext` and `image` has been 68 // successfully created at this point. 69 match Status(unsafe { 70 bindings::vaMapBuffer( 71 picture.inner().context().display().handle(), 72 image.buf, 73 &mut addr, 74 ) 75 }) 76 .check() 77 { 78 Ok(_) => { 79 // Safe since `addr` points to data mapped onto our address space since we called 80 // `vaMapBuffer` above, which also guarantees that the data is valid for 81 // `image.data_size`. 82 let data = 83 unsafe { std::slice::from_raw_parts_mut(addr as _, image.data_size as usize) }; 84 Ok(Self { 85 picture, 86 image, 87 data, 88 derived, 89 dirty: false, 90 }) 91 } 92 Err(e) => { 93 // Safe because `picture.inner.context` represents a valid `VAContext` and `image` 94 // represents a valid `VAImage`. 95 unsafe { 96 bindings::vaDestroyImage( 97 picture.inner().context().display().handle(), 98 image.image_id, 99 ); 100 } 101 Err(e) 102 } 103 } 104 } 105 106 /// Creates `image` from `picture` using `vaCreateImage` and `vaGetImage` in order to copy the 107 /// surface data into the image buffer. create_image( picture: &'a mut Picture<PictureSync>, image: &mut bindings::VAImage, format: &mut bindings::VAImageFormat, width: u32, height: u32, ) -> Result<()>108 fn create_image( 109 picture: &'a mut Picture<PictureSync>, 110 image: &mut bindings::VAImage, 111 format: &mut bindings::VAImageFormat, 112 width: u32, 113 height: u32, 114 ) -> Result<()> { 115 let dpy = picture.inner().context().display().handle(); 116 117 // Safe because `picture.inner.context` represents a valid 118 // VAContext. 119 Status(unsafe { bindings::vaCreateImage(dpy, format, width as i32, height as i32, image) }) 120 .check()?; 121 122 // Safe because `picture.inner.context` represents a valid VAContext, 123 // `picture.surface` represents a valid VASurface and `image` represents 124 // a valid `VAImage`. 125 if let Err(e) = Status(unsafe { 126 bindings::vaGetImage( 127 dpy, 128 picture.surface_mut().id(), 129 0, 130 0, 131 width, 132 height, 133 image.image_id, 134 ) 135 }) 136 .check() 137 { 138 // Safe since `image` represents a valid `VAImage`. 139 unsafe { 140 bindings::vaDestroyImage(dpy, image.image_id); 141 } 142 return Err(e); 143 } 144 145 Ok(()) 146 } 147 148 /// Tries to derive `image` from `picture` to access the raw surface data without copy. 149 /// 150 /// Returns `Ok(true)` if the image has been successfully derived, `Ok(false)` if deriving is 151 /// not possible and `create_image` should be used as a fallback, or an error if an error 152 /// occurred. derive_image( picture: &'a mut Picture<PictureSync>, image: &mut bindings::VAImage, ) -> Result<bool>153 fn derive_image( 154 picture: &'a mut Picture<PictureSync>, 155 image: &mut bindings::VAImage, 156 ) -> Result<bool> { 157 let status = Status(unsafe { 158 bindings::vaDeriveImage( 159 picture.inner().context().display().handle(), 160 picture.surface_mut().id(), 161 image, 162 ) 163 }); 164 165 if status.0 == bindings::constants::VA_STATUS_ERROR_OPERATION_FAILED as i32 { 166 // The implementation can't derive, try the create API instead. 167 Ok(false) 168 } else { 169 status.check()?; 170 Ok(true) 171 } 172 } 173 174 /// Get a reference to the underlying `VAImage` that describes this image. image(&self) -> &bindings::VAImage175 pub fn image(&self) -> &bindings::VAImage { 176 &self.image 177 } 178 } 179 180 impl<'a> AsRef<[u8]> for Image<'a> { as_ref(&self) -> &[u8]181 fn as_ref(&self) -> &[u8] { 182 self.data 183 } 184 } 185 186 impl<'a> AsMut<[u8]> for Image<'a> { as_mut(&mut self) -> &mut [u8]187 fn as_mut(&mut self) -> &mut [u8] { 188 self.dirty = true; 189 self.data 190 } 191 } 192 193 impl<'a> Drop for Image<'a> { drop(&mut self)194 fn drop(&mut self) { 195 if !self.derived && self.dirty { 196 // Safe because `picture.inner.context` represents a valid `VAContext`, 197 // `picture.surface` represents a valid `VASurface` and `image` represents a valid 198 // `VAImage`. 199 unsafe { 200 bindings::vaPutImage( 201 self.picture.inner().context().display().handle(), 202 self.picture.surface().id(), 203 self.image.image_id, 204 0, 205 0, 206 self.image.width as u32, 207 self.image.height as u32, 208 0, 209 0, 210 self.image.width as u32, 211 self.image.height as u32, 212 ); 213 } 214 } 215 unsafe { 216 // Safe since the buffer is mapped in `Image::new`, so `self.image.buf` points to a 217 // valid `VABufferID`. 218 bindings::vaUnmapBuffer( 219 self.picture.inner().context().display().handle(), 220 self.image.buf, 221 ); 222 // Safe since `self.image` represents a valid `VAImage`. 223 bindings::vaDestroyImage( 224 self.picture.inner().context().display().handle(), 225 self.image.image_id, 226 ); 227 } 228 } 229 } 230