Skip to main content

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}