moq_vaapi/image.rs
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
5use std::sync::Arc;
6
7use crate::bindings;
8use crate::va_check;
9use crate::Display;
10use crate::Surface;
11use crate::SurfaceMemoryDescriptor;
12use 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.
18pub struct Image<'a> {
19 /// The display from which the image was created, so we can unmap it upon destruction.
20 display: Arc<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
42impl<'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.
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 { bindings::vaMapBuffer(surface.display().handle(), image.buf, &mut addr) }) {
57 Ok(_) => {
58 // Assert that libva provided us with a coded resolution that is
59 // at least as large as `display_resolution`.
60 assert!(u32::from(image.width) >= display_resolution.0);
61 assert!(u32::from(image.height) >= display_resolution.1);
62
63 // Safe since `addr` points to data mapped onto our address space since we called
64 // `vaMapBuffer` above, which also guarantees that the data is valid for
65 // `image.data_size`.
66 let data = unsafe { std::slice::from_raw_parts_mut(addr as _, image.data_size as usize) };
67 Ok(Image {
68 display: Arc::clone(surface.display()),
69 image,
70 data,
71 derived,
72 display_resolution,
73 dirty: false,
74 surface_id: surface.id(),
75 })
76 }
77 Err(e) => {
78 // Safe because `picture.inner.context` represents a valid `VAContext` and `image`
79 // represents a valid `VAImage`.
80 unsafe {
81 bindings::vaDestroyImage(surface.display().handle(), image.image_id);
82 }
83
84 Err(e)
85 }
86 }
87 }
88
89 /// Create a new derived image from this `surface` using `vaDeriveImage`.
90 ///
91 /// Derived images are a direct view (i.e. without any copy) on the buffer content of
92 /// `surface`. On the other hand, not all `Surface`s can be derived.
93 ///
94 /// `visible_rect` is the visible rectangle inside `surface` that we want to access.
95 pub fn derive_from<D: SurfaceMemoryDescriptor>(
96 surface: &'a Surface<D>,
97 visible_rect: (u32, u32),
98 ) -> Result<Self, VaError> {
99 // An all-zero byte-pattern is a valid initial value for `VAImage`.
100 let mut image: bindings::VAImage = Default::default();
101
102 // Safe because `self` has a valid display handle and ID.
103 va_check(unsafe { bindings::vaDeriveImage(surface.display().handle(), surface.id(), &mut image) })?;
104
105 Self::new(surface, image, true, visible_rect)
106 }
107
108 /// Create new image from `surface` using `vaCreateImage` and `vaGetImage`.
109 ///
110 /// `visible_rect` is the visible rectangle inside `surface` that we want to access.
111 ///
112 /// The image will contain a copy of `surface`'s data' in the desired `format` and
113 /// `coded_resolution`, meaning the data can be scaled if `coded_resolution` and `visible_rect`
114 /// differ.
115 pub fn create_from<D: SurfaceMemoryDescriptor>(
116 surface: &'a Surface<D>,
117 mut format: bindings::VAImageFormat,
118 coded_resolution: (u32, u32),
119 visible_rect: (u32, u32),
120 ) -> Result<Image<'a>, VaError> {
121 // An all-zero byte-pattern is a valid initial value for `VAImage`.
122 let mut image: bindings::VAImage = Default::default();
123 let dpy = surface.display().handle();
124
125 // Safe because `dpy` is a valid display handle.
126 va_check(unsafe {
127 bindings::vaCreateImage(
128 dpy,
129 &mut format,
130 coded_resolution.0 as i32,
131 coded_resolution.1 as i32,
132 &mut image,
133 )
134 })?;
135
136 // Safe because `dpy` is a valid display handle, `picture.surface` is a valid VASurface and
137 // `image` is a valid `VAImage`.
138 match va_check(unsafe {
139 bindings::vaGetImage(
140 dpy,
141 surface.id(),
142 0,
143 0,
144 coded_resolution.0,
145 coded_resolution.1,
146 image.image_id,
147 )
148 }) {
149 Ok(()) => Self::new(surface, image, false, visible_rect),
150
151 Err(e) => {
152 // Safe because `image` is a valid `VAImage`.
153 unsafe {
154 bindings::vaDestroyImage(dpy, image.image_id);
155 }
156
157 Err(e)
158 }
159 }
160 }
161
162 /// Get a reference to the underlying `VAImage` that describes this image.
163 pub fn image(&self) -> &bindings::VAImage {
164 &self.image
165 }
166
167 /// Returns whether this image is directly derived from its underlying `Picture`, as opposed to
168 /// being a view/copy of said `Picture` in a guaranteed pixel format.
169 pub fn is_derived(&self) -> bool {
170 self.derived
171 }
172
173 /// Returns the display resolution as passed in by the client. This is a
174 /// value that is less than or equal to the coded resolution.
175 pub fn display_resolution(&self) -> (u32, u32) {
176 self.display_resolution
177 }
178
179 /// Returns the coded resolution. This value can be larger than the value
180 /// passed in when the image was created if the driver needs to.
181 pub fn coded_resolution(&self) -> (u32, u32) {
182 (self.image.width.into(), self.image.height.into())
183 }
184}
185
186impl<'a> AsRef<[u8]> for Image<'a> {
187 fn as_ref(&self) -> &[u8] {
188 self.data
189 }
190}
191
192impl<'a> AsMut<[u8]> for Image<'a> {
193 fn as_mut(&mut self) -> &mut [u8] {
194 self.dirty = true;
195 self.data
196 }
197}
198
199impl<'a> Drop for Image<'a> {
200 fn drop(&mut self) {
201 if !self.derived && self.dirty {
202 // Safe because `picture.inner.context` represents a valid `VAContext`,
203 // `picture.surface` represents a valid `VASurface` and `image` represents a valid
204 // `VAImage`.
205 unsafe {
206 bindings::vaPutImage(
207 self.display.handle(),
208 self.surface_id,
209 self.image.image_id,
210 0,
211 0,
212 self.image.width as u32,
213 self.image.height as u32,
214 0,
215 0,
216 self.image.width as u32,
217 self.image.height as u32,
218 );
219 }
220 }
221
222 unsafe {
223 // Safe since the buffer is mapped in `Image::new`, so `self.image.buf` points to a
224 // valid `VABufferID`.
225 bindings::vaUnmapBuffer(self.display.handle(), self.image.buf);
226 // Safe since `self.image` represents a valid `VAImage`.
227 bindings::vaDestroyImage(self.display.handle(), self.image.image_id);
228 }
229 }
230}