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::rc::Rc; 6 7 use crate::bindings; 8 use crate::va_check; 9 use crate::Display; 10 use crate::Surface; 11 use crate::SurfaceMemoryDescriptor; 12 use crate::VaError; 13 14 /// Wrapper around `VAImage` that is tied to the lifetime of a given `Picture`. 15 /// 16 /// An image is used to either get the surface data to client memory, or to copy image data in 17 /// client memory to a surface. 18 pub struct Image<'a> { 19 /// The display from which the image was created, so we can unmap it upon destruction. 20 display: Rc<Display>, 21 /// The `VAImage` returned by libva. 22 image: bindings::VAImage, 23 /// The mapped surface data. 24 /// 25 /// The lifetime also allows us to ensure that the `Surface` we have been created from 26 /// does not drop or get changed while we exist. 27 data: &'a mut [u8], 28 /// Whether the image was derived using the `vaDeriveImage` API or created using the 29 /// `vaCreateImage` API. 30 derived: bool, 31 /// The display resolution requested by the client. The implementation is 32 /// free to enlarge this value as needed. In any case, we guarantee that an 33 /// image at least as large is returned. 34 display_resolution: (u32, u32), 35 /// Tracks whether the underlying data has possibly been written to, i.e. an encoder will create 36 /// an image and map its buffer in order to write to it, so we must writeback later. 37 dirty: bool, 38 /// The ID of the `Surface` we have been created from. 39 surface_id: u32, 40 } 41 42 impl<'a> Image<'a> { 43 /// Helper method to map a `VAImage` using `vaMapBuffer` and return an `Image`. 44 /// 45 /// Returns an error if the mapping failed. new<D: SurfaceMemoryDescriptor>( surface: &'a Surface<D>, image: bindings::VAImage, derived: bool, display_resolution: (u32, u32), ) -> Result<Self, VaError>46 fn new<D: SurfaceMemoryDescriptor>( 47 surface: &'a Surface<D>, 48 image: bindings::VAImage, 49 derived: bool, 50 display_resolution: (u32, u32), 51 ) -> Result<Self, VaError> { 52 let mut addr = std::ptr::null_mut(); 53 54 // Safe since `picture.inner.context` represents a valid `VAContext` and `image` has been 55 // successfully created at this point. 56 match va_check(unsafe { 57 bindings::vaMapBuffer(surface.display().handle(), image.buf, &mut addr) 58 }) { 59 Ok(_) => { 60 // Assert that libva provided us with a coded resolution that is 61 // at least as large as `display_resolution`. 62 assert!(u32::from(image.width) >= display_resolution.0); 63 assert!(u32::from(image.height) >= display_resolution.1); 64 65 // Safe since `addr` points to data mapped onto our address space since we called 66 // `vaMapBuffer` above, which also guarantees that the data is valid for 67 // `image.data_size`. 68 let data = 69 unsafe { std::slice::from_raw_parts_mut(addr as _, image.data_size as usize) }; 70 Ok(Image { 71 display: Rc::clone(surface.display()), 72 image, 73 data, 74 derived, 75 display_resolution, 76 dirty: false, 77 surface_id: surface.id(), 78 }) 79 } 80 Err(e) => { 81 // Safe because `picture.inner.context` represents a valid `VAContext` and `image` 82 // represents a valid `VAImage`. 83 unsafe { 84 bindings::vaDestroyImage(surface.display().handle(), image.image_id); 85 } 86 87 Err(e) 88 } 89 } 90 } 91 92 /// Create a new derived image from this `surface` using `vaDeriveImage`. 93 /// 94 /// Derived images are a direct view (i.e. without any copy) on the buffer content of 95 /// `surface`. On the other hand, not all `Surface`s can be derived. 96 /// 97 /// `visible_rect` is the visible rectangle inside `surface` that we want to access. derive_from<D: SurfaceMemoryDescriptor>( surface: &'a Surface<D>, visible_rect: (u32, u32), ) -> Result<Self, VaError>98 pub fn derive_from<D: SurfaceMemoryDescriptor>( 99 surface: &'a Surface<D>, 100 visible_rect: (u32, u32), 101 ) -> Result<Self, VaError> { 102 // An all-zero byte-pattern is a valid initial value for `VAImage`. 103 let mut image: bindings::VAImage = Default::default(); 104 105 // Safe because `self` has a valid display handle and ID. 106 va_check(unsafe { 107 bindings::vaDeriveImage(surface.display().handle(), surface.id(), &mut image) 108 })?; 109 110 Self::new(surface, image, true, visible_rect) 111 } 112 113 /// Create new image from `surface` using `vaCreateImage` and `vaGetImage`. 114 /// 115 /// `visible_rect` is the visible rectangle inside `surface` that we want to access. 116 /// 117 /// The image will contain a copy of `surface`'s data' in the desired `format` and 118 /// `coded_resolution`, meaning the data can be scaled if `coded_resolution` and `visible_rect` 119 /// differ. create_from<D: SurfaceMemoryDescriptor>( surface: &'a Surface<D>, mut format: bindings::VAImageFormat, coded_resolution: (u32, u32), visible_rect: (u32, u32), ) -> Result<Image, VaError>120 pub fn create_from<D: SurfaceMemoryDescriptor>( 121 surface: &'a Surface<D>, 122 mut format: bindings::VAImageFormat, 123 coded_resolution: (u32, u32), 124 visible_rect: (u32, u32), 125 ) -> Result<Image, VaError> { 126 // An all-zero byte-pattern is a valid initial value for `VAImage`. 127 let mut image: bindings::VAImage = Default::default(); 128 let dpy = surface.display().handle(); 129 130 // Safe because `dpy` is a valid display handle. 131 va_check(unsafe { 132 bindings::vaCreateImage( 133 dpy, 134 &mut format, 135 coded_resolution.0 as i32, 136 coded_resolution.1 as i32, 137 &mut image, 138 ) 139 })?; 140 141 // Safe because `dpy` is a valid display handle, `picture.surface` is a valid VASurface and 142 // `image` is a valid `VAImage`. 143 match va_check(unsafe { 144 bindings::vaGetImage( 145 dpy, 146 surface.id(), 147 0, 148 0, 149 coded_resolution.0, 150 coded_resolution.1, 151 image.image_id, 152 ) 153 }) { 154 Ok(()) => Self::new(surface, image, false, visible_rect), 155 156 Err(e) => { 157 // Safe because `image` is a valid `VAImage`. 158 unsafe { 159 bindings::vaDestroyImage(dpy, image.image_id); 160 } 161 162 Err(e) 163 } 164 } 165 } 166 167 /// Get a reference to the underlying `VAImage` that describes this image. image(&self) -> &bindings::VAImage168 pub fn image(&self) -> &bindings::VAImage { 169 &self.image 170 } 171 172 /// Returns whether this image is directly derived from its underlying `Picture`, as opposed to 173 /// being a view/copy of said `Picture` in a guaranteed pixel format. is_derived(&self) -> bool174 pub fn is_derived(&self) -> bool { 175 self.derived 176 } 177 178 /// Returns the display resolution as passed in by the client. This is a 179 /// value that is less than or equal to the coded resolution. display_resolution(&self) -> (u32, u32)180 pub fn display_resolution(&self) -> (u32, u32) { 181 self.display_resolution 182 } 183 184 /// Returns the coded resolution. This value can be larger than the value 185 /// passed in when the image was created if the driver needs to. coded_resolution(&self) -> (u32, u32)186 pub fn coded_resolution(&self) -> (u32, u32) { 187 (self.image.width.into(), self.image.height.into()) 188 } 189 } 190 191 impl<'a> AsRef<[u8]> for Image<'a> { as_ref(&self) -> &[u8]192 fn as_ref(&self) -> &[u8] { 193 self.data 194 } 195 } 196 197 impl<'a> AsMut<[u8]> for Image<'a> { as_mut(&mut self) -> &mut [u8]198 fn as_mut(&mut self) -> &mut [u8] { 199 self.dirty = true; 200 self.data 201 } 202 } 203 204 impl<'a> Drop for Image<'a> { drop(&mut self)205 fn drop(&mut self) { 206 if !self.derived && self.dirty { 207 // Safe because `picture.inner.context` represents a valid `VAContext`, 208 // `picture.surface` represents a valid `VASurface` and `image` represents a valid 209 // `VAImage`. 210 unsafe { 211 bindings::vaPutImage( 212 self.display.handle(), 213 self.surface_id, 214 self.image.image_id, 215 0, 216 0, 217 self.image.width as u32, 218 self.image.height as u32, 219 0, 220 0, 221 self.image.width as u32, 222 self.image.height as u32, 223 ); 224 } 225 } 226 227 unsafe { 228 // Safe since the buffer is mapped in `Image::new`, so `self.image.buf` points to a 229 // valid `VABufferID`. 230 bindings::vaUnmapBuffer(self.display.handle(), self.image.buf); 231 // Safe since `self.image` represents a valid `VAImage`. 232 bindings::vaDestroyImage(self.display.handle(), self.image.image_id); 233 } 234 } 235 } 236