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