nihed-cros-libva: use simple error enum instead of anyhow crate
[nihav-player.git] / nihed-cros-libva / src / image.rs
CommitLineData
68362724
KS
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
68362724
KS
5use crate::bindings;
6use crate::picture::Picture;
7use crate::picture::PictureSync;
69e6ce02 8use crate::status::*;
68362724
KS
9
10/// Wrapper around `VAImage` that is tied to the lifetime of a given `Picture`.
11///
12/// An image is used to either get the surface data to client memory, or to copy image data in
13/// client memory to a surface.
14pub struct Image<'a> {
15 /// The picture whose `Surface` we use as the source of pixel data.
16 picture: &'a Picture<PictureSync>,
17 /// The `VAImage` returned by libva.
18 image: bindings::VAImage,
19 /// The mapped surface data.
20 data: &'a mut [u8],
21 /// Whether the image was derived using the `vaDeriveImage` API or created using the
22 /// `vaCreateImage` API.
23 derived: bool,
24 /// Tracks whether the underlying data has possibly been written to, i.e. an encoder will create
25 /// an image and map its buffer in order to write to it, so we must writeback later.
26 dirty: bool,
27}
28
29impl<'a> Image<'a> {
30 /// Creates a new `Image` either by calling `vaCreateImage` or
31 /// `vaDeriveImage`. Creating an Image depends on acquiring a ready Surface
32 /// from an underlying Picture. Note that Image has a borrowed Picture, so
33 /// it will be dropped before the underlying Surface is dropped, as mandated
34 /// by VAAPI.
35 ///
36 /// # Arguments
37 ///
38 /// * `picture` - The [`Picture`] that owns the Surface this image will be created from.
39 /// * `format` - A `VAImageFormat` returned by [`crate::Display::query_image_formats`].
40 /// * `width` - The image's desired width.
41 /// * `height` - The image's desired height.
42 /// * `derive` - Whether to try deriving the image from `picture`, which allows zero-copy access
43 /// to the surface data. Deriving may fail, in which case vaCreateImage will be used instead,
44 /// incurring an extra data copy.
45 pub fn new(
46 picture: &'a Picture<PictureSync>,
47 mut format: bindings::VAImageFormat,
48 width: u32,
49 height: u32,
50 derive: bool,
69e6ce02 51 ) -> VAResult<Self> {
68362724
KS
52 // An all-zero byte-pattern is a valid initial value for `VAImage`.
53 let mut image: bindings::VAImage = Default::default();
54 let mut addr = std::ptr::null_mut();
55 let mut derived = false;
56
57 if derive {
58 derived = Image::derive_image(picture, &mut image)?;
59 }
60
61 if !derived {
62 Image::create_image(picture, &mut image, &mut format, width, height)?;
63 }
64
65 // Safe since `picture.inner.context` represents a valid `VAContext` and `image` has been
66 // successfully created at this point.
69e6ce02 67 match (unsafe {
68362724
KS
68 bindings::vaMapBuffer(picture.display().handle(), image.buf, &mut addr)
69 })
70 .check()
71 {
72 Ok(_) => {
73 // Safe since `addr` points to data mapped onto our address space since we called
74 // `vaMapBuffer` above, which also guarantees that the data is valid for
75 // `image.data_size`.
76 let data =
77 unsafe { std::slice::from_raw_parts_mut(addr as _, image.data_size as usize) };
78 Ok(Self {
79 picture,
80 image,
81 data,
82 derived,
83 dirty: false,
84 })
85 }
86 Err(e) => {
87 // Safe because `picture.inner.context` represents a valid `VAContext` and `image`
88 // represents a valid `VAImage`.
89 unsafe {
90 bindings::vaDestroyImage(picture.display().handle(), image.image_id);
91 }
92 Err(e)
93 }
94 }
95 }
96
97 /// Creates `image` from `picture` using `vaCreateImage` and `vaGetImage` in order to copy the
98 /// surface data into the image buffer.
99 fn create_image(
100 picture: &'a Picture<PictureSync>,
101 image: &mut bindings::VAImage,
102 format: &mut bindings::VAImageFormat,
103 width: u32,
104 height: u32,
69e6ce02 105 ) -> VAResult<()> {
68362724
KS
106 let dpy = picture.display().handle();
107
108 // Safe because `picture.inner.context` represents a valid
109 // VAContext.
69e6ce02 110 (unsafe { bindings::vaCreateImage(dpy, format, width as i32, height as i32, image) })
68362724
KS
111 .check()?;
112
113 // Safe because `picture.inner.context` represents a valid VAContext,
114 // `picture.surface` represents a valid VASurface and `image` represents
115 // a valid `VAImage`.
69e6ce02 116 if let Err(e) = (unsafe {
68362724
KS
117 bindings::vaGetImage(
118 dpy,
119 picture.surface().id(),
120 0,
121 0,
122 width,
123 height,
124 image.image_id,
125 )
126 })
127 .check()
128 {
129 // Safe since `image` represents a valid `VAImage`.
130 unsafe {
131 bindings::vaDestroyImage(dpy, image.image_id);
132 }
133 return Err(e);
134 }
135
136 Ok(())
137 }
138
139 /// Tries to derive `image` from `picture` to access the raw surface data without copy.
140 ///
141 /// Returns `Ok(true)` if the image has been successfully derived, `Ok(false)` if deriving is
142 /// not possible and `create_image` should be used as a fallback, or an error if an error
143 /// occurred.
144 fn derive_image(
145 picture: &'a Picture<PictureSync>,
146 image: &mut bindings::VAImage,
69e6ce02
KS
147 ) -> VAResult<bool> {
148 let status = unsafe {
68362724 149 bindings::vaDeriveImage(picture.display().handle(), picture.surface().id(), image)
69e6ce02 150 };
68362724 151
69e6ce02 152 if status == bindings::constants::VA_STATUS_ERROR_OPERATION_FAILED as i32 {
68362724
KS
153 // The implementation can't derive, try the create API instead.
154 Ok(false)
155 } else {
156 status.check()?;
157 Ok(true)
158 }
159 }
160
161 /// Get a reference to the underlying `VAImage` that describes this image.
162 pub fn image(&self) -> &bindings::VAImage {
163 &self.image
164 }
165}
166
167impl<'a> AsRef<[u8]> for Image<'a> {
168 fn as_ref(&self) -> &[u8] {
169 self.data
170 }
171}
172
173impl<'a> AsMut<[u8]> for Image<'a> {
174 fn as_mut(&mut self) -> &mut [u8] {
175 self.dirty = true;
176 self.data
177 }
178}
179
180impl<'a> Drop for Image<'a> {
181 fn drop(&mut self) {
182 if !self.derived && self.dirty {
183 // Safe because `picture.inner.context` represents a valid `VAContext`,
184 // `picture.surface` represents a valid `VASurface` and `image` represents a valid
185 // `VAImage`.
186 unsafe {
187 bindings::vaPutImage(
188 self.picture.display().handle(),
189 self.picture.surface().id(),
190 self.image.image_id,
191 0,
192 0,
193 self.image.width as u32,
194 self.image.height as u32,
195 0,
196 0,
197 self.image.width as u32,
198 self.image.height as u32,
199 );
200 }
201 }
202 unsafe {
203 // Safe since the buffer is mapped in `Image::new`, so `self.image.buf` points to a
204 // valid `VABufferID`.
205 bindings::vaUnmapBuffer(self.picture.display().handle(), self.image.buf);
206 // Safe since `self.image` represents a valid `VAImage`.
207 bindings::vaDestroyImage(self.picture.display().handle(), self.image.image_id);
208 }
209 }
210}