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::any::Any;
6 use std::os::fd::FromRawFd;
7 use std::os::fd::OwnedFd;
8 use std::os::raw::c_void;
9 use std::rc::Rc;
10 
11 use crate::bindings;
12 use crate::display::Display;
13 use crate::va_check;
14 use crate::UsageHint;
15 use crate::VASurfaceID;
16 use crate::VaError;
17 
18 /// Trait describing a memory backing for surfaces.
19 ///
20 /// Using external memory for backing a VA surface is done in two steps:
21 ///
22 /// 1. Build the descriptor specific to the memory type we want to use,
23 /// 2. Mention this descriptor as an attribute to be passed to `vaDeriveImage`.
24 ///
25 /// This trait allows to do that in a as-safe-as-possible way, by adding the required attributes
26 /// and returning a heap-allocated object containing the data pointed to by the attributes. That
27 /// way, the caller can keep that object alive until `vaCreateSurfaces` has returned.
28 pub trait SurfaceMemoryDescriptor {
29     /// Add the required attributes to `attr` in order to attach the memory of this descriptor to
30     /// the surface when it is created.
31     ///
32     /// The returned object, if any, is the descriptor pointed to by the attributes. The caller
33     /// must keep it around and unmoved until `vaCreateSurfaces` has returned.
add_attrs(&mut self, attrs: &mut Vec<bindings::VASurfaceAttrib>) -> Option<Box<dyn Any>>34     fn add_attrs(&mut self, attrs: &mut Vec<bindings::VASurfaceAttrib>) -> Option<Box<dyn Any>>;
35 }
36 
37 /// VA memory types, aka `VA_SURFACE_ATTRIB_MEM_TYPE_*`.
38 #[repr(u32)]
39 pub enum MemoryType {
40     Va = bindings::VA_SURFACE_ATTRIB_MEM_TYPE_VA,
41     V4L2 = bindings::VA_SURFACE_ATTRIB_MEM_TYPE_V4L2,
42     UserPtr = bindings::VA_SURFACE_ATTRIB_MEM_TYPE_USER_PTR,
43     DrmPrime2 = bindings::VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2,
44 }
45 
46 /// Used when we want the VA driver to allocate surface memory for us. In this case we don't need
47 /// to add any specific attribute for surface creation.
48 impl SurfaceMemoryDescriptor for () {
add_attrs(&mut self, _: &mut Vec<bindings::VASurfaceAttrib>) -> Option<Box<dyn Any>>49     fn add_attrs(&mut self, _: &mut Vec<bindings::VASurfaceAttrib>) -> Option<Box<dyn Any>> {
50         None
51     }
52 }
53 
54 /// Sealed trait pattern to avoid reimplementation of our local traits.
55 mod private {
56     pub trait Sealed {}
57 }
58 
59 /// Trait for types that can be used as a `VASurfaceAttribExternalBufferDescriptor`.
60 pub trait SurfaceExternalDescriptor: private::Sealed {}
61 impl private::Sealed for bindings::VASurfaceAttribExternalBuffers {}
62 impl SurfaceExternalDescriptor for bindings::VASurfaceAttribExternalBuffers {}
63 impl private::Sealed for bindings::VADRMPRIMESurfaceDescriptor {}
64 impl SurfaceExternalDescriptor for bindings::VADRMPRIMESurfaceDescriptor {}
65 
66 /// Trait allowing to import an external memory source to use with a surface by setting the
67 /// `VASurfaceAttribMemoryType` and `VASurfaceAttribExternalBuffers` attributes.
68 pub trait ExternalBufferDescriptor {
69     /// Memory type to set for `VASurfaceAttribMemoryType`.
70     const MEMORY_TYPE: MemoryType;
71     /// Type of the descriptor to be set with `VASurfaceAttribExternalBuffers`.
72     type DescriptorAttribute: SurfaceExternalDescriptor;
73 
74     /// Returns the `Self::DescriptorAttribute` instance allowing this memory to be imported
75     /// into VAAPI.
va_surface_attribute(&mut self) -> Self::DescriptorAttribute76     fn va_surface_attribute(&mut self) -> Self::DescriptorAttribute;
77 }
78 
79 impl<T> SurfaceMemoryDescriptor for T
80 where
81     T: ExternalBufferDescriptor,
82     <T as ExternalBufferDescriptor>::DescriptorAttribute: 'static,
83 {
add_attrs(&mut self, attrs: &mut Vec<bindings::VASurfaceAttrib>) -> Option<Box<dyn Any>>84     fn add_attrs(&mut self, attrs: &mut Vec<bindings::VASurfaceAttrib>) -> Option<Box<dyn Any>> {
85         let mut desc = Box::new(self.va_surface_attribute());
86 
87         attrs.push(bindings::VASurfaceAttrib::new_memory_type(
88             Self::MEMORY_TYPE,
89         ));
90         attrs.push(bindings::VASurfaceAttrib::new_buffer_descriptor(
91             desc.as_mut(),
92         ));
93 
94         Some(desc)
95     }
96 }
97 
98 /// Decode error type aka `VADecodeErrorType`
99 #[repr(u32)]
100 #[derive(Debug)]
101 pub enum DecodeErrorType {
102     SliceMissing = bindings::VADecodeErrorType::VADecodeSliceMissing,
103     MBError = bindings::VADecodeErrorType::VADecodeMBError,
104     Reset = bindings::VADecodeErrorType::VADecodeReset,
105 }
106 
107 /// Decode error details extracted from `VASurfaceDecodeMBErrors`, result of vaQuerySurfaceError.
108 #[derive(Debug)]
109 pub struct SurfaceDecodeMBError {
110     /// Start mb address with errors
111     pub start_mb: u32,
112 
113     /// End mb address with errors
114     pub end_mb: u32,
115 
116     pub decode_error_type: DecodeErrorType,
117 
118     /// Number of mbs with errors
119     pub num_mb: u32,
120 }
121 
122 /// An owned VA surface that is tied to a particular `Display`.
123 pub struct Surface<D: SurfaceMemoryDescriptor> {
124     display: Rc<Display>,
125     id: bindings::VASurfaceID,
126     descriptor: D,
127     width: u32,
128     height: u32,
129 }
130 
131 impl From<i32> for bindings::VAGenericValue {
from(i: i32) -> Self132     fn from(i: i32) -> Self {
133         Self {
134             type_: bindings::VAGenericValueType::VAGenericValueTypeInteger,
135             value: bindings::_VAGenericValue__bindgen_ty_1 { i },
136         }
137     }
138 }
139 
140 impl From<f32> for bindings::VAGenericValue {
from(f: f32) -> Self141     fn from(f: f32) -> Self {
142         Self {
143             type_: bindings::VAGenericValueType::VAGenericValueTypeFloat,
144             value: bindings::_VAGenericValue__bindgen_ty_1 { f },
145         }
146     }
147 }
148 
149 impl From<*mut c_void> for bindings::VAGenericValue {
from(p: *mut c_void) -> Self150     fn from(p: *mut c_void) -> Self {
151         Self {
152             type_: bindings::VAGenericValueType::VAGenericValueTypePointer,
153             value: bindings::_VAGenericValue__bindgen_ty_1 { p },
154         }
155     }
156 }
157 
158 /// Helpers to build valid `VASurfaceAttrib`s.
159 impl bindings::VASurfaceAttrib {
new_pixel_format(fourcc: u32) -> Self160     pub fn new_pixel_format(fourcc: u32) -> Self {
161         Self {
162             type_: bindings::VASurfaceAttribType::VASurfaceAttribPixelFormat,
163             flags: bindings::VA_SURFACE_ATTRIB_SETTABLE,
164             value: bindings::VAGenericValue::from(fourcc as i32),
165         }
166     }
167 
new_usage_hint(usage_hint: UsageHint) -> Self168     pub fn new_usage_hint(usage_hint: UsageHint) -> Self {
169         Self {
170             type_: bindings::VASurfaceAttribType::VASurfaceAttribUsageHint,
171             flags: bindings::VA_SURFACE_ATTRIB_SETTABLE,
172             value: bindings::VAGenericValue::from(usage_hint.bits() as i32),
173         }
174     }
175 
new_memory_type(mem_type: MemoryType) -> Self176     pub fn new_memory_type(mem_type: MemoryType) -> Self {
177         Self {
178             type_: bindings::VASurfaceAttribType::VASurfaceAttribMemoryType,
179             flags: bindings::VA_SURFACE_ATTRIB_SETTABLE,
180             value: bindings::VAGenericValue::from(mem_type as i32),
181         }
182     }
183 
new_buffer_descriptor<T: SurfaceExternalDescriptor>(desc: &mut T) -> Self184     pub fn new_buffer_descriptor<T: SurfaceExternalDescriptor>(desc: &mut T) -> Self {
185         Self {
186             type_: bindings::VASurfaceAttribType::VASurfaceAttribExternalBufferDescriptor,
187             flags: bindings::VA_SURFACE_ATTRIB_SETTABLE,
188             value: bindings::VAGenericValue::from(desc as *mut _ as *mut c_void),
189         }
190     }
191 }
192 
193 impl<D: SurfaceMemoryDescriptor> Surface<D> {
194     /// Create `Surfaces` by wrapping around a `vaCreateSurfaces` call. This is just a helper for
195     /// [`Display::create_surfaces`].
new( display: Rc<Display>, rt_format: u32, va_fourcc: Option<u32>, width: u32, height: u32, usage_hint: Option<UsageHint>, descriptors: Vec<D>, ) -> Result<Vec<Self>, VaError>196     pub(crate) fn new(
197         display: Rc<Display>,
198         rt_format: u32,
199         va_fourcc: Option<u32>,
200         width: u32,
201         height: u32,
202         usage_hint: Option<UsageHint>,
203         descriptors: Vec<D>,
204     ) -> Result<Vec<Self>, VaError> {
205         let mut surfaces = vec![];
206 
207         for mut descriptor in descriptors {
208             let mut attrs = vec![];
209 
210             if let Some(usage_hint) = usage_hint {
211                 attrs.push(bindings::VASurfaceAttrib::new_usage_hint(usage_hint));
212             }
213 
214             if let Some(fourcc) = va_fourcc {
215                 attrs.push(bindings::VASurfaceAttrib::new_pixel_format(fourcc));
216             }
217 
218             // Just to be kept alive until we call `vaCreateSurfaces`...
219             let mut _va_desc = descriptor.add_attrs(&mut attrs);
220             let mut surface_id: VASurfaceID = 0;
221 
222             // Safe because `self` represents a valid VADisplay. The `surface` and `attrs` vectors are
223             // properly initialized and valid sizes are passed to the C function, so it is impossible to
224             // write past the end of their storage by mistake.
225             //
226             // Also all the pointers in `attrs` are pointing to valid objects that haven't been
227             // moved or destroyed.
228             match va_check(unsafe {
229                 bindings::vaCreateSurfaces(
230                     display.handle(),
231                     rt_format,
232                     width,
233                     height,
234                     &mut surface_id,
235                     1,
236                     attrs.as_mut_ptr(),
237                     attrs.len() as u32,
238                 )
239             }) {
240                 Ok(()) => surfaces.push(Self {
241                     display: Rc::clone(&display),
242                     id: surface_id,
243                     descriptor,
244                     width,
245                     height,
246                 }),
247                 Err(e) => return Err(e),
248             }
249         }
250 
251         Ok(surfaces)
252     }
253 
display(&self) -> &Rc<Display>254     pub(crate) fn display(&self) -> &Rc<Display> {
255         &self.display
256     }
257 
258     /// Wrapper around `vaSyncSurface` that blocks until all pending operations on the render
259     /// target have been completed.
260     ///
261     /// Upon return it
262     /// is safe to use the render target for a different picture.
sync(&self) -> Result<(), VaError>263     pub fn sync(&self) -> Result<(), VaError> {
264         // Safe because `self` represents a valid VASurface.
265         va_check(unsafe { bindings::vaSyncSurface(self.display.handle(), self.id) })
266     }
267 
268     /// Convenience function to return a VASurfaceID vector. Useful to interface with the C API
269     /// where a surface array might be needed.
as_id_vec(surfaces: &[Self]) -> Vec<bindings::VASurfaceID>270     pub fn as_id_vec(surfaces: &[Self]) -> Vec<bindings::VASurfaceID> {
271         surfaces.iter().map(|surface| surface.id).collect()
272     }
273 
274     /// Wrapper over `vaQuerySurfaceStatus` to find out any pending ops on the render target.
query_status(&self) -> Result<bindings::VASurfaceStatus::Type, VaError>275     pub fn query_status(&self) -> Result<bindings::VASurfaceStatus::Type, VaError> {
276         let mut status: bindings::VASurfaceStatus::Type = 0;
277         // Safe because `self` represents a valid VASurface.
278         va_check(unsafe {
279             bindings::vaQuerySurfaceStatus(self.display.handle(), self.id, &mut status)
280         })?;
281 
282         Ok(status)
283     }
284 
query_error(&self) -> Result<Vec<SurfaceDecodeMBError>, VaError>285     pub fn query_error(&self) -> Result<Vec<SurfaceDecodeMBError>, VaError> {
286         let mut raw: *const bindings::VASurfaceDecodeMBErrors = std::ptr::null();
287 
288         // Safe because `self` represents a valid VASurface.
289         va_check(unsafe {
290             bindings::vaQuerySurfaceError(
291                 self.display.handle(),
292                 self.id,
293                 bindings::VA_STATUS_ERROR_DECODING_ERROR as i32,
294                 (&mut raw) as *mut _ as *mut _,
295             )
296         })?;
297 
298         let mut errors = vec![];
299 
300         while !raw.is_null() {
301             // Safe because raw is a valid pointer
302             let error = unsafe { *raw };
303             if error.status == -1 {
304                 break;
305             }
306 
307             let type_ = match error.decode_error_type {
308                 bindings::VADecodeErrorType::VADecodeSliceMissing => DecodeErrorType::SliceMissing,
309                 bindings::VADecodeErrorType::VADecodeMBError => DecodeErrorType::MBError,
310                 bindings::VADecodeErrorType::VADecodeReset => DecodeErrorType::Reset,
311                 _ => {
312                     log::warn!(
313                         "Unrecognized `decode_error_type` value ({})",
314                         error.decode_error_type
315                     );
316 
317                     // Safe because status != -1
318                     raw = unsafe { raw.offset(1) };
319                     continue;
320                 }
321             };
322 
323             errors.push(SurfaceDecodeMBError {
324                 start_mb: error.start_mb,
325                 end_mb: error.end_mb,
326                 decode_error_type: type_,
327                 num_mb: error.num_mb,
328             });
329 
330             // Safe because status != -1
331             raw = unsafe { raw.offset(1) };
332         }
333 
334         Ok(errors)
335     }
336 
337     /// Returns the ID of this surface.
id(&self) -> bindings::VASurfaceID338     pub fn id(&self) -> bindings::VASurfaceID {
339         self.id
340     }
341 
342     /// Returns the dimensions of this surface.
size(&self) -> (u32, u32)343     pub fn size(&self) -> (u32, u32) {
344         (self.width, self.height)
345     }
346 
347     /// Returns a PRIME descriptor for this surface.
export_prime(&self) -> Result<DrmPrimeSurfaceDescriptor, VaError>348     pub fn export_prime(&self) -> Result<DrmPrimeSurfaceDescriptor, VaError> {
349         let mut desc: bindings::VADRMPRIMESurfaceDescriptor = Default::default();
350 
351         va_check(unsafe {
352             bindings::vaExportSurfaceHandle(
353                 self.display.handle(),
354                 self.id(),
355                 bindings::VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2,
356                 bindings::VA_EXPORT_SURFACE_READ_ONLY | bindings::VA_EXPORT_SURFACE_COMPOSED_LAYERS,
357                 &mut desc as *mut _ as *mut c_void,
358             )
359         })?;
360 
361         // We do not use a `From<VADRMPRIMESurfaceDescriptor>` implementation as this would allow
362         // to create "safe" descriptors outside of this method and thus from made up values,
363         // violating the safety guarantee that our FDs are legit.
364 
365         let objects = (0..desc.num_objects as usize)
366             // Make sure we don't go out of bounds.
367             .take(4)
368             .map(|i| desc.objects[i])
369             .map(|o| {
370                 DrmPrimeSurfaceDescriptorObject {
371                     // Safe because `o.fd` is a valid file descriptor returned by
372                     // `vaExportSurfaceHandle`.
373                     fd: unsafe { OwnedFd::from_raw_fd(o.fd) },
374                     size: o.size,
375                     drm_format_modifier: o.drm_format_modifier,
376                 }
377             })
378             .collect();
379 
380         let layers = (0..desc.num_layers as usize)
381             // Make sure we don't go out of bounds.
382             .take(4)
383             .map(|i| desc.layers[i])
384             .map(|l| DrmPrimeSurfaceDescriptorLayer {
385                 drm_format: l.drm_format,
386                 num_planes: l.num_planes,
387                 object_index: [
388                     l.object_index[0] as u8,
389                     l.object_index[1] as u8,
390                     l.object_index[2] as u8,
391                     l.object_index[3] as u8,
392                 ],
393                 offset: l.offset,
394                 pitch: l.pitch,
395             })
396             .collect();
397 
398         Ok(DrmPrimeSurfaceDescriptor {
399             fourcc: desc.fourcc,
400             width: desc.width,
401             height: desc.height,
402             objects,
403             layers,
404         })
405     }
406 }
407 
408 impl<D: SurfaceMemoryDescriptor> AsRef<D> for Surface<D> {
as_ref(&self) -> &D409     fn as_ref(&self) -> &D {
410         &self.descriptor
411     }
412 }
413 
414 impl<D: SurfaceMemoryDescriptor> AsMut<D> for Surface<D> {
as_mut(&mut self) -> &mut D415     fn as_mut(&mut self) -> &mut D {
416         &mut self.descriptor
417     }
418 }
419 
420 impl<D: SurfaceMemoryDescriptor> Drop for Surface<D> {
drop(&mut self)421     fn drop(&mut self) {
422         // Safe because `self` represents a valid VASurface.
423         unsafe { bindings::vaDestroySurfaces(self.display.handle(), &mut self.id, 1) };
424     }
425 }
426 
427 /// Safe wrapper for the `object` member of `VADRMPRIMESurfaceDescriptor`.
428 pub struct DrmPrimeSurfaceDescriptorObject {
429     pub fd: OwnedFd,
430     pub size: u32,
431     pub drm_format_modifier: u64,
432 }
433 
434 /// Safe wrapper for the `layers` member of `VADRMPRIMESurfaceDescriptor`.
435 pub struct DrmPrimeSurfaceDescriptorLayer {
436     pub drm_format: u32,
437     pub num_planes: u32,
438     pub object_index: [u8; 4],
439     pub offset: [u32; 4],
440     pub pitch: [u32; 4],
441 }
442 
443 /// Safe wrapper around `VADRMPRIMESurfaceDescriptor`.
444 pub struct DrmPrimeSurfaceDescriptor {
445     pub fourcc: u32,
446     pub width: u32,
447     pub height: u32,
448     pub objects: Vec<DrmPrimeSurfaceDescriptorObject>,
449     pub layers: Vec<DrmPrimeSurfaceDescriptorLayer>,
450 }
451