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