// Copyright 2022 The ChromiumOS Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. use std::rc::Rc; use crate::bindings; use crate::va_check; use crate::Display; use crate::Surface; use crate::SurfaceMemoryDescriptor; use crate::VaError; /// Wrapper around `VAImage` that is tied to the lifetime of a given `Picture`. /// /// An image is used to either get the surface data to client memory, or to copy image data in /// client memory to a surface. pub struct Image<'a> { /// The display from which the image was created, so we can unmap it upon destruction. display: Rc, /// The `VAImage` returned by libva. image: bindings::VAImage, /// The mapped surface data. /// /// The lifetime also allows us to ensure that the `Surface` we have been created from /// does not drop or get changed while we exist. data: &'a mut [u8], /// Whether the image was derived using the `vaDeriveImage` API or created using the /// `vaCreateImage` API. derived: bool, /// The display resolution requested by the client. The implementation is /// free to enlarge this value as needed. In any case, we guarantee that an /// image at least as large is returned. display_resolution: (u32, u32), /// Tracks whether the underlying data has possibly been written to, i.e. an encoder will create /// an image and map its buffer in order to write to it, so we must writeback later. dirty: bool, /// The ID of the `Surface` we have been created from. surface_id: u32, } impl<'a> Image<'a> { /// Helper method to map a `VAImage` using `vaMapBuffer` and return an `Image`. /// /// Returns an error if the mapping failed. fn new( surface: &'a Surface, image: bindings::VAImage, derived: bool, display_resolution: (u32, u32), ) -> Result { let mut addr = std::ptr::null_mut(); // Safe since `picture.inner.context` represents a valid `VAContext` and `image` has been // successfully created at this point. match va_check(unsafe { bindings::vaMapBuffer(surface.display().handle(), image.buf, &mut addr) }) { Ok(_) => { // Assert that libva provided us with a coded resolution that is // at least as large as `display_resolution`. assert!(u32::from(image.width) >= display_resolution.0); assert!(u32::from(image.height) >= display_resolution.1); // Safe since `addr` points to data mapped onto our address space since we called // `vaMapBuffer` above, which also guarantees that the data is valid for // `image.data_size`. let data = unsafe { std::slice::from_raw_parts_mut(addr as _, image.data_size as usize) }; Ok(Image { display: Rc::clone(surface.display()), image, data, derived, display_resolution, dirty: false, surface_id: surface.id(), }) } Err(e) => { // Safe because `picture.inner.context` represents a valid `VAContext` and `image` // represents a valid `VAImage`. unsafe { bindings::vaDestroyImage(surface.display().handle(), image.image_id); } Err(e) } } } /// Create a new derived image from this `surface` using `vaDeriveImage`. /// /// Derived images are a direct view (i.e. without any copy) on the buffer content of /// `surface`. On the other hand, not all `Surface`s can be derived. /// /// `visible_rect` is the visible rectangle inside `surface` that we want to access. pub fn derive_from( surface: &'a Surface, visible_rect: (u32, u32), ) -> Result { // An all-zero byte-pattern is a valid initial value for `VAImage`. let mut image: bindings::VAImage = Default::default(); // Safe because `self` has a valid display handle and ID. va_check(unsafe { bindings::vaDeriveImage(surface.display().handle(), surface.id(), &mut image) })?; Self::new(surface, image, true, visible_rect) } /// Create new image from `surface` using `vaCreateImage` and `vaGetImage`. /// /// `visible_rect` is the visible rectangle inside `surface` that we want to access. /// /// The image will contain a copy of `surface`'s data' in the desired `format` and /// `coded_resolution`, meaning the data can be scaled if `coded_resolution` and `visible_rect` /// differ. pub fn create_from( surface: &'a Surface, mut format: bindings::VAImageFormat, coded_resolution: (u32, u32), visible_rect: (u32, u32), ) -> Result { // An all-zero byte-pattern is a valid initial value for `VAImage`. let mut image: bindings::VAImage = Default::default(); let dpy = surface.display().handle(); // Safe because `dpy` is a valid display handle. va_check(unsafe { bindings::vaCreateImage( dpy, &mut format, coded_resolution.0 as i32, coded_resolution.1 as i32, &mut image, ) })?; // Safe because `dpy` is a valid display handle, `picture.surface` is a valid VASurface and // `image` is a valid `VAImage`. match va_check(unsafe { bindings::vaGetImage( dpy, surface.id(), 0, 0, coded_resolution.0, coded_resolution.1, image.image_id, ) }) { Ok(()) => Self::new(surface, image, false, visible_rect), Err(e) => { // Safe because `image` is a valid `VAImage`. unsafe { bindings::vaDestroyImage(dpy, image.image_id); } Err(e) } } } /// Get a reference to the underlying `VAImage` that describes this image. pub fn image(&self) -> &bindings::VAImage { &self.image } /// Returns whether this image is directly derived from its underlying `Picture`, as opposed to /// being a view/copy of said `Picture` in a guaranteed pixel format. pub fn is_derived(&self) -> bool { self.derived } /// Returns the display resolution as passed in by the client. This is a /// value that is less than or equal to the coded resolution. pub fn display_resolution(&self) -> (u32, u32) { self.display_resolution } /// Returns the coded resolution. This value can be larger than the value /// passed in when the image was created if the driver needs to. pub fn coded_resolution(&self) -> (u32, u32) { (self.image.width.into(), self.image.height.into()) } } impl<'a> AsRef<[u8]> for Image<'a> { fn as_ref(&self) -> &[u8] { self.data } } impl<'a> AsMut<[u8]> for Image<'a> { fn as_mut(&mut self) -> &mut [u8] { self.dirty = true; self.data } } impl<'a> Drop for Image<'a> { fn drop(&mut self) { if !self.derived && self.dirty { // Safe because `picture.inner.context` represents a valid `VAContext`, // `picture.surface` represents a valid `VASurface` and `image` represents a valid // `VAImage`. unsafe { bindings::vaPutImage( self.display.handle(), self.surface_id, self.image.image_id, 0, 0, self.image.width as u32, self.image.height as u32, 0, 0, self.image.width as u32, self.image.height as u32, ); } } unsafe { // Safe since the buffer is mapped in `Image::new`, so `self.image.buf` points to a // valid `VABufferID`. bindings::vaUnmapBuffer(self.display.handle(), self.image.buf); // Safe since `self.image` represents a valid `VAImage`. bindings::vaDestroyImage(self.display.handle(), self.image.image_id); } } }