1 // Copyright 2020 The Chromium OS Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 //! rutabaga_utils: Utility enums, structs, and implementations needed by the rest of the crate. 6 7 use std::fmt::{self, Display}; 8 use std::io::Error as IoError; 9 use std::num::TryFromIntError; 10 use std::os::raw::c_void; 11 use std::path::PathBuf; 12 use std::str::Utf8Error; 13 14 use base::{Error as SysError, ExternalMappingError, SafeDescriptor}; 15 use data_model::VolatileMemoryError; 16 17 #[cfg(feature = "vulkano")] 18 use vulkano::device::DeviceCreationError; 19 #[cfg(feature = "vulkano")] 20 use vulkano::image::ImageCreationError; 21 #[cfg(feature = "vulkano")] 22 use vulkano::instance::InstanceCreationError; 23 #[cfg(feature = "vulkano")] 24 use vulkano::memory::DeviceMemoryAllocError; 25 26 /// Represents a buffer. `base` contains the address of a buffer, while `len` contains the length 27 /// of the buffer. 28 #[derive(Copy, Clone)] 29 pub struct RutabagaIovec { 30 pub base: *mut c_void, 31 pub len: usize, 32 } 33 34 /// 3D resource creation parameters. Also used to create 2D resource. Constants based on Mesa's 35 /// (internal) Gallium interface. Not in the virtio-gpu spec, but should be since dumb resources 36 /// can't work with gfxstream/virglrenderer without this. 37 pub const RUTABAGA_PIPE_TEXTURE_2D: u32 = 2; 38 pub const RUTABAGA_PIPE_BIND_RENDER_TARGET: u32 = 2; 39 #[derive(Copy, Clone, Debug)] 40 pub struct ResourceCreate3D { 41 pub target: u32, 42 pub format: u32, 43 pub bind: u32, 44 pub width: u32, 45 pub height: u32, 46 pub depth: u32, 47 pub array_size: u32, 48 pub last_level: u32, 49 pub nr_samples: u32, 50 pub flags: u32, 51 } 52 53 /// Blob resource creation parameters. 54 pub const RUTABAGA_BLOB_MEM_GUEST: u32 = 0x0001; 55 pub const RUTABAGA_BLOB_MEM_HOST3D: u32 = 0x0002; 56 pub const RUTABAGA_BLOB_MEM_HOST3D_GUEST: u32 = 0x0003; 57 58 pub const RUTABAGA_BLOB_FLAG_USE_MAPPABLE: u32 = 0x0001; 59 pub const RUTABAGA_BLOB_FLAG_USE_SHAREABLE: u32 = 0x0002; 60 pub const RUTABAGA_BLOB_FLAG_USE_CROSS_DEVICE: u32 = 0x0004; 61 #[derive(Copy, Clone, Debug)] 62 pub struct ResourceCreateBlob { 63 pub blob_mem: u32, 64 pub blob_flags: u32, 65 pub blob_id: u64, 66 pub size: u64, 67 } 68 69 /// Metadata associated with a swapchain, video or camera image. 70 #[derive(Default, Copy, Clone, Debug)] 71 pub struct Resource3DInfo { 72 pub width: u32, 73 pub height: u32, 74 pub drm_fourcc: u32, 75 pub strides: [u32; 4], 76 pub offsets: [u32; 4], 77 pub modifier: u64, 78 } 79 80 /// Memory index and physical device index of the associated VkDeviceMemory. 81 #[derive(Copy, Clone, Default)] 82 pub struct VulkanInfo { 83 pub memory_idx: u32, 84 pub physical_device_idx: u32, 85 } 86 87 /// Rutabaga context init capset id mask (not upstreamed). 88 pub const RUTABAGA_CONTEXT_INIT_CAPSET_ID_MASK: u32 = 0x00ff; 89 90 /// Rutabaga flags for creating fences (fence ctx idx info not upstreamed). 91 pub const RUTABAGA_FLAG_FENCE: u32 = 1 << 0; 92 pub const RUTABAGA_FLAG_INFO_FENCE_CTX_IDX: u32 = 1 << 1; 93 94 /// Convenience struct for Rutabaga fences 95 pub struct RutabagaFenceData { 96 pub flags: u32, 97 pub fence_id: u64, 98 pub ctx_id: u32, 99 pub fence_ctx_idx: u32, 100 } 101 102 /// Mapped memory caching flags (see virtio_gpu spec) 103 pub const RUTABAGA_MAP_CACHE_CACHED: u32 = 0x01; 104 pub const RUTABAGA_MAP_CACHE_UNCACHED: u32 = 0x02; 105 pub const RUTABAGA_MAP_CACHE_WC: u32 = 0x03; 106 107 /// Rutabaga capsets. 108 pub const RUTABAGA_CAPSET_VIRGL: u32 = 1; 109 pub const RUTABAGA_CAPSET_VIRGL2: u32 = 2; 110 /// The following capsets are not upstreamed. 111 pub const RUTABAGA_CAPSET_GFXSTREAM: u32 = 3; 112 pub const RUTABAGA_CAPSET_VENUS: u32 = 4; 113 pub const RUTABAGA_CAPSET_CROSS_DOMAIN: u32 = 5; 114 115 /// An error generated while using this crate. 116 #[derive(Debug)] 117 pub enum RutabagaError { 118 /// Indicates `Rutabaga` was already initialized since only one Rutabaga instance per process 119 /// is allowed. 120 AlreadyInUse, 121 /// Checked Arithmetic error 122 CheckedArithmetic { 123 field1: (&'static str, usize), 124 field2: (&'static str, usize), 125 op: &'static str, 126 }, 127 /// Checked Range error 128 CheckedRange { 129 field1: (&'static str, usize), 130 field2: (&'static str, usize), 131 }, 132 /// The Rutabaga component failed to export a RutabagaHandle. 133 ExportedRutabagaHandle, 134 /// Invalid Capset 135 InvalidCapset, 136 /// A command size was submitted that was invalid. 137 InvalidCommandSize(usize), 138 /// Invalid RutabagaComponent 139 InvalidComponent, 140 /// Invalid Context ID 141 InvalidContextId, 142 /// The indicated region of guest memory is invalid. 143 InvalidIovec, 144 /// Invalid Resource ID. 145 InvalidResourceId, 146 /// Indicates an error in the RutabagaBuilder. 147 InvalidRutabagaBuild, 148 /// An input/output error occured. 149 IoError(IoError), 150 /// The mapping failed. 151 MappingFailed(ExternalMappingError), 152 /// An internal Rutabaga component error was returned. 153 ComponentError(i32), 154 /// Violation of the Rutabaga spec occured. 155 SpecViolation, 156 /// System error returned as a result of rutabaga library operation. 157 SysError(SysError), 158 /// An attempted integer conversion failed. 159 TryFromIntError(TryFromIntError), 160 /// The command is unsupported. 161 Unsupported, 162 /// Utf8 error. 163 Utf8Error(Utf8Error), 164 /// Volatile memory error 165 VolatileMemoryError(VolatileMemoryError), 166 /// Image creation error 167 #[cfg(feature = "vulkano")] 168 VkImageCreationError(ImageCreationError), 169 /// Instance creation error 170 #[cfg(feature = "vulkano")] 171 VkInstanceCreationError(InstanceCreationError), 172 /// Device creation error 173 #[cfg(feature = "vulkano")] 174 VkDeviceCreationError(DeviceCreationError), 175 /// Device memory allocation error 176 #[cfg(feature = "vulkano")] 177 VkDeviceMemoryAllocError(DeviceMemoryAllocError), 178 } 179 180 impl Display for RutabagaError { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result181 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 182 use self::RutabagaError::*; 183 match self { 184 AlreadyInUse => write!(f, "attempted to use a rutabaga asset already in use"), 185 CheckedArithmetic { 186 field1: (label1, value1), 187 field2: (label2, value2), 188 op, 189 } => write!( 190 f, 191 "arithmetic failed: {}({}) {} {}({})", 192 label1, value1, op, label2, value2 193 ), 194 CheckedRange { 195 field1: (label1, value1), 196 field2: (label2, value2), 197 } => write!( 198 f, 199 "range check failed: {}({}) vs {}({})", 200 label1, value1, label2, value2 201 ), 202 ExportedRutabagaHandle => write!(f, "failed to export Rutabaga handle"), 203 InvalidCapset => write!(f, "invalid capset"), 204 InvalidCommandSize(s) => write!(f, "command buffer submitted with invalid size: {}", s), 205 InvalidComponent => write!(f, "invalid rutabaga component"), 206 InvalidContextId => write!(f, "invalid context id"), 207 InvalidIovec => write!(f, "an iovec is outside of guest memory's range"), 208 InvalidResourceId => write!(f, "invalid resource id"), 209 InvalidRutabagaBuild => write!(f, "invalid rutabaga build parameters"), 210 IoError(e) => write!(f, "an input/output error occur: {}", e), 211 MappingFailed(s) => write!(f, "The mapping failed for the following reason: {}", s), 212 ComponentError(ret) => write!(f, "rutabaga component failed with error {}", ret), 213 SpecViolation => write!(f, "violation of the rutabaga spec"), 214 SysError(e) => write!(f, "rutabaga received a system error: {}", e), 215 TryFromIntError(e) => write!(f, "int conversion failed: {}", e), 216 Unsupported => write!(f, "feature or function unsupported"), 217 Utf8Error(e) => write!(f, "an utf8 error occured: {}", e), 218 VolatileMemoryError(e) => write!(f, "noticed a volatile memory error {}", e), 219 #[cfg(feature = "vulkano")] 220 VkDeviceCreationError(e) => write!(f, "vulkano device creation failure {}", e), 221 #[cfg(feature = "vulkano")] 222 VkDeviceMemoryAllocError(e) => { 223 write!(f, "vulkano device memory allocation failure {}", e) 224 } 225 #[cfg(feature = "vulkano")] 226 VkImageCreationError(e) => write!(f, "vulkano image creation failure {}", e), 227 #[cfg(feature = "vulkano")] 228 VkInstanceCreationError(e) => write!(f, "vulkano instance creation failure {}", e), 229 } 230 } 231 } 232 233 impl From<IoError> for RutabagaError { from(e: IoError) -> RutabagaError234 fn from(e: IoError) -> RutabagaError { 235 RutabagaError::IoError(e) 236 } 237 } 238 239 impl From<SysError> for RutabagaError { from(e: SysError) -> RutabagaError240 fn from(e: SysError) -> RutabagaError { 241 RutabagaError::SysError(e) 242 } 243 } 244 245 impl From<TryFromIntError> for RutabagaError { from(e: TryFromIntError) -> RutabagaError246 fn from(e: TryFromIntError) -> RutabagaError { 247 RutabagaError::TryFromIntError(e) 248 } 249 } 250 251 impl From<Utf8Error> for RutabagaError { from(e: Utf8Error) -> RutabagaError252 fn from(e: Utf8Error) -> RutabagaError { 253 RutabagaError::Utf8Error(e) 254 } 255 } 256 257 impl From<VolatileMemoryError> for RutabagaError { from(e: VolatileMemoryError) -> RutabagaError258 fn from(e: VolatileMemoryError) -> RutabagaError { 259 RutabagaError::VolatileMemoryError(e) 260 } 261 } 262 263 /// The result of an operation in this crate. 264 pub type RutabagaResult<T> = std::result::Result<T, RutabagaError>; 265 266 /// Flags for virglrenderer. Copied from virglrenderer bindings. 267 const VIRGLRENDERER_USE_EGL: u32 = 1 << 0; 268 #[allow(dead_code)] 269 const VIRGLRENDERER_THREAD_SYNC: u32 = 1 << 1; 270 const VIRGLRENDERER_USE_GLX: u32 = 1 << 2; 271 const VIRGLRENDERER_USE_SURFACELESS: u32 = 1 << 3; 272 const VIRGLRENDERER_USE_GLES: u32 = 1 << 4; 273 const VIRGLRENDERER_USE_EXTERNAL_BLOB: u32 = 1 << 5; 274 const VIRGLRENDERER_VENUS: u32 = 1 << 6; 275 const VIRGLRENDERER_NO_VIRGL: u32 = 1 << 7; 276 277 /// virglrenderer flag struct. 278 #[derive(Copy, Clone)] 279 pub struct VirglRendererFlags(u32); 280 281 impl Default for VirglRendererFlags { default() -> VirglRendererFlags282 fn default() -> VirglRendererFlags { 283 VirglRendererFlags::new() 284 .use_virgl(true) 285 .use_venus(false) 286 .use_egl(true) 287 .use_surfaceless(true) 288 .use_gles(true) 289 } 290 } 291 292 impl From<VirglRendererFlags> for i32 { from(flags: VirglRendererFlags) -> i32293 fn from(flags: VirglRendererFlags) -> i32 { 294 flags.0 as i32 295 } 296 } 297 298 impl VirglRendererFlags { 299 /// Create new virglrenderer flags. new() -> VirglRendererFlags300 pub fn new() -> VirglRendererFlags { 301 VirglRendererFlags(0) 302 } 303 set_flag(self, bitmask: u32, set: bool) -> VirglRendererFlags304 fn set_flag(self, bitmask: u32, set: bool) -> VirglRendererFlags { 305 if set { 306 VirglRendererFlags(self.0 | bitmask) 307 } else { 308 VirglRendererFlags(self.0 & (!bitmask)) 309 } 310 } 311 312 /// Enable virgl support use_virgl(self, v: bool) -> VirglRendererFlags313 pub fn use_virgl(self, v: bool) -> VirglRendererFlags { 314 self.set_flag(VIRGLRENDERER_NO_VIRGL, !v) 315 } 316 317 /// Enable venus support use_venus(self, v: bool) -> VirglRendererFlags318 pub fn use_venus(self, v: bool) -> VirglRendererFlags { 319 self.set_flag(VIRGLRENDERER_VENUS, v) 320 } 321 322 /// Use EGL for context creation. use_egl(self, v: bool) -> VirglRendererFlags323 pub fn use_egl(self, v: bool) -> VirglRendererFlags { 324 self.set_flag(VIRGLRENDERER_USE_EGL, v) 325 } 326 327 /// Use GLX for context creation. use_glx(self, v: bool) -> VirglRendererFlags328 pub fn use_glx(self, v: bool) -> VirglRendererFlags { 329 self.set_flag(VIRGLRENDERER_USE_GLX, v) 330 } 331 332 /// No surfaces required when creating context. use_surfaceless(self, v: bool) -> VirglRendererFlags333 pub fn use_surfaceless(self, v: bool) -> VirglRendererFlags { 334 self.set_flag(VIRGLRENDERER_USE_SURFACELESS, v) 335 } 336 337 /// Use GLES drivers. use_gles(self, v: bool) -> VirglRendererFlags338 pub fn use_gles(self, v: bool) -> VirglRendererFlags { 339 self.set_flag(VIRGLRENDERER_USE_GLES, v) 340 } 341 342 /// Use external memory when creating blob resources. use_external_blob(self, v: bool) -> VirglRendererFlags343 pub fn use_external_blob(self, v: bool) -> VirglRendererFlags { 344 self.set_flag(VIRGLRENDERER_USE_EXTERNAL_BLOB, v) 345 } 346 } 347 348 /// Flags for the gfxstream renderer. 349 const GFXSTREAM_RENDERER_FLAGS_USE_EGL: u32 = 1 << 0; 350 #[allow(dead_code)] 351 const GFXSTREAM_RENDERER_FLAGS_THREAD_SYNC: u32 = 1 << 1; 352 const GFXSTREAM_RENDERER_FLAGS_USE_GLX: u32 = 1 << 2; 353 const GFXSTREAM_RENDERER_FLAGS_USE_SURFACELESS: u32 = 1 << 3; 354 const GFXSTREAM_RENDERER_FLAGS_USE_GLES: u32 = 1 << 4; 355 const GFXSTREAM_RENDERER_FLAGS_NO_VK_BIT: u32 = 1 << 5; 356 const GFXSTREAM_RENDERER_FLAGS_NO_SYNCFD_BIT: u32 = 1 << 20; 357 const GFXSTREAM_RENDERER_FLAGS_GUEST_USES_ANGLE: u32 = 1 << 21; 358 359 /// gfxstream flag struct. 360 #[derive(Copy, Clone, Default)] 361 pub struct GfxstreamFlags(u32); 362 363 impl GfxstreamFlags { 364 /// Create new gfxstream flags. new() -> GfxstreamFlags365 pub fn new() -> GfxstreamFlags { 366 GfxstreamFlags(0) 367 } 368 set_flag(self, bitmask: u32, set: bool) -> GfxstreamFlags369 fn set_flag(self, bitmask: u32, set: bool) -> GfxstreamFlags { 370 if set { 371 GfxstreamFlags(self.0 | bitmask) 372 } else { 373 GfxstreamFlags(self.0 & (!bitmask)) 374 } 375 } 376 377 /// Use EGL for context creation. use_egl(self, v: bool) -> GfxstreamFlags378 pub fn use_egl(self, v: bool) -> GfxstreamFlags { 379 self.set_flag(GFXSTREAM_RENDERER_FLAGS_USE_EGL, v) 380 } 381 382 /// Use GLX for context creation. use_glx(self, v: bool) -> GfxstreamFlags383 pub fn use_glx(self, v: bool) -> GfxstreamFlags { 384 self.set_flag(GFXSTREAM_RENDERER_FLAGS_USE_GLX, v) 385 } 386 387 /// No surfaces required when creating context. use_surfaceless(self, v: bool) -> GfxstreamFlags388 pub fn use_surfaceless(self, v: bool) -> GfxstreamFlags { 389 self.set_flag(GFXSTREAM_RENDERER_FLAGS_USE_SURFACELESS, v) 390 } 391 392 /// Use GLES drivers. use_gles(self, v: bool) -> GfxstreamFlags393 pub fn use_gles(self, v: bool) -> GfxstreamFlags { 394 self.set_flag(GFXSTREAM_RENDERER_FLAGS_USE_GLES, v) 395 } 396 397 /// Use external synchronization. use_syncfd(self, v: bool) -> GfxstreamFlags398 pub fn use_syncfd(self, v: bool) -> GfxstreamFlags { 399 self.set_flag(GFXSTREAM_RENDERER_FLAGS_NO_SYNCFD_BIT, !v) 400 } 401 402 /// Support using Vulkan. use_vulkan(self, v: bool) -> GfxstreamFlags403 pub fn use_vulkan(self, v: bool) -> GfxstreamFlags { 404 self.set_flag(GFXSTREAM_RENDERER_FLAGS_NO_VK_BIT, !v) 405 } 406 407 /// Use ANGLE as the guest GLES driver. use_guest_angle(self, v: bool) -> GfxstreamFlags408 pub fn use_guest_angle(self, v: bool) -> GfxstreamFlags { 409 self.set_flag(GFXSTREAM_RENDERER_FLAGS_GUEST_USES_ANGLE, v) 410 } 411 } 412 413 impl From<GfxstreamFlags> for i32 { from(flags: GfxstreamFlags) -> i32414 fn from(flags: GfxstreamFlags) -> i32 { 415 flags.0 as i32 416 } 417 } 418 419 /// Transfers {to, from} 1D buffers, 2D textures, 3D textures, and cubemaps. 420 #[derive(Debug)] 421 pub struct Transfer3D { 422 pub x: u32, 423 pub y: u32, 424 pub z: u32, 425 pub w: u32, 426 pub h: u32, 427 pub d: u32, 428 pub level: u32, 429 pub stride: u32, 430 pub layer_stride: u32, 431 pub offset: u64, 432 } 433 434 impl Transfer3D { 435 /// Constructs a 2 dimensional XY box in 3 dimensional space with unit depth and zero 436 /// displacement on the Z axis. new_2d(x: u32, y: u32, w: u32, h: u32) -> Transfer3D437 pub fn new_2d(x: u32, y: u32, w: u32, h: u32) -> Transfer3D { 438 Transfer3D { 439 x, 440 y, 441 z: 0, 442 w, 443 h, 444 d: 1, 445 level: 0, 446 stride: 0, 447 layer_stride: 0, 448 offset: 0, 449 } 450 } 451 452 /// Returns true if this box represents a volume of zero. is_empty(&self) -> bool453 pub fn is_empty(&self) -> bool { 454 self.w == 0 || self.h == 0 || self.d == 0 455 } 456 } 457 458 /// Rutabaga channel types 459 pub const RUTABAGA_CHANNEL_TYPE_WAYLAND: u32 = 0x0001; 460 pub const RUTABAGA_CHANNEL_TYPE_CAMERA: u32 = 0x0002; 461 462 /// Information needed to open an OS-specific RutabagaConnection (TBD). Only Linux hosts are 463 /// considered at the moment. 464 #[derive(Clone)] 465 pub struct RutabagaChannel { 466 pub base_channel: PathBuf, 467 pub channel_type: u32, 468 } 469 470 /// Enumeration of possible rutabaga components. 471 #[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord)] 472 pub enum RutabagaComponentType { 473 Rutabaga2D, 474 VirglRenderer, 475 Gfxstream, 476 CrossDomain, 477 } 478 479 /// Rutabaga handle types (memory and sync in same namespace) 480 pub const RUTABAGA_MEM_HANDLE_TYPE_OPAQUE_FD: u32 = 0x0001; 481 pub const RUTABAGA_MEM_HANDLE_TYPE_DMABUF: u32 = 0x0002; 482 pub const RUTABAGE_MEM_HANDLE_TYPE_OPAQUE_WIN32: u32 = 0x0003; 483 pub const RUTABAGA_FENCE_HANDLE_TYPE_OPAQUE_FD: u32 = 0x0004; 484 pub const RUTABAGA_FENCE_HANDLE_TYPE_SYNC_FD: u32 = 0x0005; 485 pub const RUTABAGE_FENCE_HANDLE_TYPE_OPAQUE_WIN32: u32 = 0x0006; 486 487 /// Handle to OS-specific memory or synchronization objects. 488 pub struct RutabagaHandle { 489 pub os_handle: SafeDescriptor, 490 pub handle_type: u32, 491 } 492 493 impl RutabagaHandle { 494 /// Clones an existing rutabaga handle, by using OS specific mechanisms. try_clone(&self) -> RutabagaResult<RutabagaHandle>495 pub fn try_clone(&self) -> RutabagaResult<RutabagaHandle> { 496 let clone = self 497 .os_handle 498 .try_clone() 499 .map_err(|_| RutabagaError::Unsupported)?; 500 Ok(RutabagaHandle { 501 os_handle: clone, 502 handle_type: self.handle_type, 503 }) 504 } 505 } 506