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