• 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 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     #[cfg(libva_1_20_or_higher)]
105     Reset = bindings::VADecodeErrorType::VADecodeReset,
106 }
107 
108 /// Decode error details extracted from `VASurfaceDecodeMBErrors`, result of vaQuerySurfaceError.
109 #[derive(Debug)]
110 pub struct SurfaceDecodeMBError {
111     /// Start mb address with errors
112     pub start_mb: u32,
113 
114     /// End mb address with errors
115     pub end_mb: u32,
116 
117     pub decode_error_type: DecodeErrorType,
118 
119     /// Number of mbs with errors
120     pub num_mb: u32,
121 }
122 
123 /// An owned VA surface that is tied to a particular `Display`.
124 pub struct Surface<D: SurfaceMemoryDescriptor> {
125     display: Rc<Display>,
126     id: bindings::VASurfaceID,
127     descriptor: D,
128     width: u32,
129     height: u32,
130 }
131 
132 impl From<i32> for bindings::VAGenericValue {
from(i: i32) -> Self133     fn from(i: i32) -> Self {
134         Self {
135             type_: bindings::VAGenericValueType::VAGenericValueTypeInteger,
136             value: bindings::_VAGenericValue__bindgen_ty_1 { i },
137         }
138     }
139 }
140 
141 impl From<f32> for bindings::VAGenericValue {
from(f: f32) -> Self142     fn from(f: f32) -> Self {
143         Self {
144             type_: bindings::VAGenericValueType::VAGenericValueTypeFloat,
145             value: bindings::_VAGenericValue__bindgen_ty_1 { f },
146         }
147     }
148 }
149 
150 impl From<*mut c_void> for bindings::VAGenericValue {
from(p: *mut c_void) -> Self151     fn from(p: *mut c_void) -> Self {
152         Self {
153             type_: bindings::VAGenericValueType::VAGenericValueTypePointer,
154             value: bindings::_VAGenericValue__bindgen_ty_1 { p },
155         }
156     }
157 }
158 
159 /// Helpers to build valid `VASurfaceAttrib`s.
160 impl bindings::VASurfaceAttrib {
new_pixel_format(fourcc: u32) -> Self161     pub fn new_pixel_format(fourcc: u32) -> Self {
162         Self {
163             type_: bindings::VASurfaceAttribType::VASurfaceAttribPixelFormat,
164             flags: bindings::VA_SURFACE_ATTRIB_SETTABLE,
165             value: bindings::VAGenericValue::from(fourcc as i32),
166         }
167     }
168 
new_usage_hint(usage_hint: UsageHint) -> Self169     pub fn new_usage_hint(usage_hint: UsageHint) -> Self {
170         Self {
171             type_: bindings::VASurfaceAttribType::VASurfaceAttribUsageHint,
172             flags: bindings::VA_SURFACE_ATTRIB_SETTABLE,
173             value: bindings::VAGenericValue::from(usage_hint.bits() as i32),
174         }
175     }
176 
new_memory_type(mem_type: MemoryType) -> Self177     pub fn new_memory_type(mem_type: MemoryType) -> Self {
178         Self {
179             type_: bindings::VASurfaceAttribType::VASurfaceAttribMemoryType,
180             flags: bindings::VA_SURFACE_ATTRIB_SETTABLE,
181             value: bindings::VAGenericValue::from(mem_type as i32),
182         }
183     }
184 
new_buffer_descriptor<T: SurfaceExternalDescriptor>(desc: &mut T) -> Self185     pub fn new_buffer_descriptor<T: SurfaceExternalDescriptor>(desc: &mut T) -> Self {
186         Self {
187             type_: bindings::VASurfaceAttribType::VASurfaceAttribExternalBufferDescriptor,
188             flags: bindings::VA_SURFACE_ATTRIB_SETTABLE,
189             value: bindings::VAGenericValue::from(desc as *mut _ as *mut c_void),
190         }
191     }
192 }
193 
194 impl<D: SurfaceMemoryDescriptor> Surface<D> {
195     /// Create `Surfaces` by wrapping around a `vaCreateSurfaces` call. This is just a helper for
196     /// [`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>197     pub(crate) fn new(
198         display: Rc<Display>,
199         rt_format: u32,
200         va_fourcc: Option<u32>,
201         width: u32,
202         height: u32,
203         usage_hint: Option<UsageHint>,
204         descriptors: Vec<D>,
205     ) -> Result<Vec<Self>, VaError> {
206         let mut surfaces = vec![];
207 
208         for mut descriptor in descriptors {
209             let mut attrs = vec![];
210 
211             if let Some(usage_hint) = usage_hint {
212                 attrs.push(bindings::VASurfaceAttrib::new_usage_hint(usage_hint));
213             }
214 
215             if let Some(fourcc) = va_fourcc {
216                 attrs.push(bindings::VASurfaceAttrib::new_pixel_format(fourcc));
217             }
218 
219             // Just to be kept alive until we call `vaCreateSurfaces`...
220             let mut _va_desc = descriptor.add_attrs(&mut attrs);
221             let mut surface_id: VASurfaceID = 0;
222 
223             // Safe because `self` represents a valid VADisplay. The `surface` and `attrs` vectors are
224             // properly initialized and valid sizes are passed to the C function, so it is impossible to
225             // write past the end of their storage by mistake.
226             //
227             // Also all the pointers in `attrs` are pointing to valid objects that haven't been
228             // moved or destroyed.
229             match va_check(unsafe {
230                 bindings::vaCreateSurfaces(
231                     display.handle(),
232                     rt_format,
233                     width,
234                     height,
235                     &mut surface_id,
236                     1,
237                     attrs.as_mut_ptr(),
238                     attrs.len() as u32,
239                 )
240             }) {
241                 Ok(()) => surfaces.push(Self {
242                     display: Rc::clone(&display),
243                     id: surface_id,
244                     descriptor,
245                     width,
246                     height,
247                 }),
248                 Err(e) => return Err(e),
249             }
250         }
251 
252         Ok(surfaces)
253     }
254 
display(&self) -> &Rc<Display>255     pub(crate) fn display(&self) -> &Rc<Display> {
256         &self.display
257     }
258 
259     /// Wrapper around `vaSyncSurface` that blocks until all pending operations on the render
260     /// target have been completed.
261     ///
262     /// Upon return it
263     /// is safe to use the render target for a different picture.
sync(&self) -> Result<(), VaError>264     pub fn sync(&self) -> Result<(), VaError> {
265         // Safe because `self` represents a valid VASurface.
266         va_check(unsafe { bindings::vaSyncSurface(self.display.handle(), self.id) })
267     }
268 
269     /// Convenience function to return a VASurfaceID vector. Useful to interface with the C API
270     /// where a surface array might be needed.
as_id_vec(surfaces: &[Self]) -> Vec<bindings::VASurfaceID>271     pub fn as_id_vec(surfaces: &[Self]) -> Vec<bindings::VASurfaceID> {
272         surfaces.iter().map(|surface| surface.id).collect()
273     }
274 
275     /// Wrapper over `vaQuerySurfaceStatus` to find out any pending ops on the render target.
query_status(&self) -> Result<bindings::VASurfaceStatus::Type, VaError>276     pub fn query_status(&self) -> Result<bindings::VASurfaceStatus::Type, VaError> {
277         let mut status: bindings::VASurfaceStatus::Type = 0;
278         // Safe because `self` represents a valid VASurface.
279         va_check(unsafe {
280             bindings::vaQuerySurfaceStatus(self.display.handle(), self.id, &mut status)
281         })?;
282 
283         Ok(status)
284     }
285 
query_error(&self) -> Result<Vec<SurfaceDecodeMBError>, VaError>286     pub fn query_error(&self) -> Result<Vec<SurfaceDecodeMBError>, VaError> {
287         let mut raw: *const bindings::VASurfaceDecodeMBErrors = std::ptr::null();
288 
289         // Safe because `self` represents a valid VASurface.
290         va_check(unsafe {
291             bindings::vaQuerySurfaceError(
292                 self.display.handle(),
293                 self.id,
294                 bindings::VA_STATUS_ERROR_DECODING_ERROR as i32,
295                 (&mut raw) as *mut _ as *mut _,
296             )
297         })?;
298 
299         let mut errors = vec![];
300 
301         while !raw.is_null() {
302             // Safe because raw is a valid pointer
303             let error = unsafe { *raw };
304             if error.status == -1 {
305                 break;
306             }
307 
308             let type_ = match error.decode_error_type {
309                 bindings::VADecodeErrorType::VADecodeSliceMissing => DecodeErrorType::SliceMissing,
310                 bindings::VADecodeErrorType::VADecodeMBError => DecodeErrorType::MBError,
311                 #[cfg(libva_1_20_or_higher)]
312                 bindings::VADecodeErrorType::VADecodeReset => DecodeErrorType::Reset,
313                 _ => {
314                     log::warn!(
315                         "Unrecognized `decode_error_type` value ({})",
316                         error.decode_error_type
317                     );
318 
319                     // Safe because status != -1
320                     raw = unsafe { raw.offset(1) };
321                     continue;
322                 }
323             };
324 
325             errors.push(SurfaceDecodeMBError {
326                 start_mb: error.start_mb,
327                 end_mb: error.end_mb,
328                 decode_error_type: type_,
329                 num_mb: error.num_mb,
330             });
331 
332             // Safe because status != -1
333             raw = unsafe { raw.offset(1) };
334         }
335 
336         Ok(errors)
337     }
338 
339     /// Returns the ID of this surface.
id(&self) -> bindings::VASurfaceID340     pub fn id(&self) -> bindings::VASurfaceID {
341         self.id
342     }
343 
344     /// Returns the dimensions of this surface.
size(&self) -> (u32, u32)345     pub fn size(&self) -> (u32, u32) {
346         (self.width, self.height)
347     }
348 
349     /// Returns a PRIME descriptor for this surface.
export_prime(&self) -> Result<DrmPrimeSurfaceDescriptor, VaError>350     pub fn export_prime(&self) -> Result<DrmPrimeSurfaceDescriptor, VaError> {
351         let mut desc: bindings::VADRMPRIMESurfaceDescriptor = Default::default();
352 
353         va_check(unsafe {
354             bindings::vaExportSurfaceHandle(
355                 self.display.handle(),
356                 self.id(),
357                 bindings::VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2,
358                 bindings::VA_EXPORT_SURFACE_READ_ONLY | bindings::VA_EXPORT_SURFACE_COMPOSED_LAYERS,
359                 &mut desc as *mut _ as *mut c_void,
360             )
361         })?;
362 
363         // We do not use a `From<VADRMPRIMESurfaceDescriptor>` implementation as this would allow
364         // to create "safe" descriptors outside of this method and thus from made up values,
365         // violating the safety guarantee that our FDs are legit.
366 
367         let objects = (0..desc.num_objects as usize)
368             // Make sure we don't go out of bounds.
369             .take(4)
370             .map(|i| desc.objects[i])
371             .map(|o| {
372                 DrmPrimeSurfaceDescriptorObject {
373                     // Safe because `o.fd` is a valid file descriptor returned by
374                     // `vaExportSurfaceHandle`.
375                     fd: unsafe { OwnedFd::from_raw_fd(o.fd) },
376                     size: o.size,
377                     drm_format_modifier: o.drm_format_modifier,
378                 }
379             })
380             .collect();
381 
382         let layers = (0..desc.num_layers as usize)
383             // Make sure we don't go out of bounds.
384             .take(4)
385             .map(|i| desc.layers[i])
386             .map(|l| DrmPrimeSurfaceDescriptorLayer {
387                 drm_format: l.drm_format,
388                 num_planes: l.num_planes,
389                 object_index: [
390                     l.object_index[0] as u8,
391                     l.object_index[1] as u8,
392                     l.object_index[2] as u8,
393                     l.object_index[3] as u8,
394                 ],
395                 offset: l.offset,
396                 pitch: l.pitch,
397             })
398             .collect();
399 
400         Ok(DrmPrimeSurfaceDescriptor {
401             fourcc: desc.fourcc,
402             width: desc.width,
403             height: desc.height,
404             objects,
405             layers,
406         })
407     }
408 }
409 
410 impl<D: SurfaceMemoryDescriptor> AsRef<D> for Surface<D> {
as_ref(&self) -> &D411     fn as_ref(&self) -> &D {
412         &self.descriptor
413     }
414 }
415 
416 impl<D: SurfaceMemoryDescriptor> AsMut<D> for Surface<D> {
as_mut(&mut self) -> &mut D417     fn as_mut(&mut self) -> &mut D {
418         &mut self.descriptor
419     }
420 }
421 
422 impl<D: SurfaceMemoryDescriptor> Drop for Surface<D> {
drop(&mut self)423     fn drop(&mut self) {
424         // Safe because `self` represents a valid VASurface.
425         unsafe { bindings::vaDestroySurfaces(self.display.handle(), &mut self.id, 1) };
426     }
427 }
428 
429 /// Safe wrapper for the `object` member of `VADRMPRIMESurfaceDescriptor`.
430 pub struct DrmPrimeSurfaceDescriptorObject {
431     pub fd: OwnedFd,
432     pub size: u32,
433     pub drm_format_modifier: u64,
434 }
435 
436 /// Safe wrapper for the `layers` member of `VADRMPRIMESurfaceDescriptor`.
437 pub struct DrmPrimeSurfaceDescriptorLayer {
438     pub drm_format: u32,
439     pub num_planes: u32,
440     pub object_index: [u8; 4],
441     pub offset: [u32; 4],
442     pub pitch: [u32; 4],
443 }
444 
445 /// Safe wrapper around `VADRMPRIMESurfaceDescriptor`.
446 pub struct DrmPrimeSurfaceDescriptor {
447     pub fourcc: u32,
448     pub width: u32,
449     pub height: u32,
450     pub objects: Vec<DrmPrimeSurfaceDescriptorObject>,
451     pub layers: Vec<DrmPrimeSurfaceDescriptorLayer>,
452 }
453