• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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