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::io::Error as IoError; 8 use std::num::TryFromIntError; 9 use std::os::raw::c_void; 10 use std::path::PathBuf; 11 use std::str::Utf8Error; 12 13 use base::{Error as BaseError, ExternalMappingError, SafeDescriptor}; 14 use data_model::VolatileMemoryError; 15 use remain::sorted; 16 use thiserror::Error; 17 18 #[cfg(feature = "vulkano")] 19 use vulkano::device::DeviceCreationError; 20 #[cfg(feature = "vulkano")] 21 use vulkano::image::ImageCreationError; 22 #[cfg(feature = "vulkano")] 23 use vulkano::instance::InstanceCreationError; 24 #[cfg(feature = "vulkano")] 25 use vulkano::memory::DeviceMemoryAllocationError; 26 #[cfg(feature = "vulkano")] 27 use vulkano::memory::DeviceMemoryExportError; 28 #[cfg(feature = "vulkano")] 29 use vulkano::memory::MemoryMapError; 30 31 /// Represents a buffer. `base` contains the address of a buffer, while `len` contains the length 32 /// of the buffer. 33 #[repr(C)] 34 #[derive(Copy, Clone)] 35 pub struct RutabagaIovec { 36 pub base: *mut c_void, 37 pub len: usize, 38 } 39 40 unsafe impl Send for RutabagaIovec {} 41 unsafe impl Sync for RutabagaIovec {} 42 43 /// 3D resource creation parameters. Also used to create 2D resource. Constants based on Mesa's 44 /// (internal) Gallium interface. Not in the virtio-gpu spec, but should be since dumb resources 45 /// can't work with gfxstream/virglrenderer without this. 46 pub const RUTABAGA_PIPE_TEXTURE_2D: u32 = 2; 47 pub const RUTABAGA_PIPE_BIND_RENDER_TARGET: u32 = 2; 48 #[repr(C)] 49 #[derive(Copy, Clone, Debug)] 50 pub struct ResourceCreate3D { 51 pub target: u32, 52 pub format: u32, 53 pub bind: u32, 54 pub width: u32, 55 pub height: u32, 56 pub depth: u32, 57 pub array_size: u32, 58 pub last_level: u32, 59 pub nr_samples: u32, 60 pub flags: u32, 61 } 62 63 /// Blob resource creation parameters. 64 pub const RUTABAGA_BLOB_MEM_GUEST: u32 = 0x0001; 65 pub const RUTABAGA_BLOB_MEM_HOST3D: u32 = 0x0002; 66 pub const RUTABAGA_BLOB_MEM_HOST3D_GUEST: u32 = 0x0003; 67 68 pub const RUTABAGA_BLOB_FLAG_USE_MAPPABLE: u32 = 0x0001; 69 pub const RUTABAGA_BLOB_FLAG_USE_SHAREABLE: u32 = 0x0002; 70 pub const RUTABAGA_BLOB_FLAG_USE_CROSS_DEVICE: u32 = 0x0004; 71 #[repr(C)] 72 #[derive(Copy, Clone, Debug)] 73 pub struct ResourceCreateBlob { 74 pub blob_mem: u32, 75 pub blob_flags: u32, 76 pub blob_id: u64, 77 pub size: u64, 78 } 79 80 /// Metadata associated with a swapchain, video or camera image. 81 #[derive(Default, Copy, Clone, Debug)] 82 pub struct Resource3DInfo { 83 pub width: u32, 84 pub height: u32, 85 pub drm_fourcc: u32, 86 pub strides: [u32; 4], 87 pub offsets: [u32; 4], 88 pub modifier: u64, 89 } 90 91 /// Memory index and physical device index of the associated VkDeviceMemory. 92 #[derive(Copy, Clone, Default)] 93 pub struct VulkanInfo { 94 pub memory_idx: u32, 95 pub physical_device_idx: u32, 96 } 97 98 /// Rutabaga context init capset id mask. 99 pub const RUTABAGA_CONTEXT_INIT_CAPSET_ID_MASK: u32 = 0x00ff; 100 101 /// Rutabaga flags for creating fences. 102 pub const RUTABAGA_FLAG_FENCE: u32 = 1 << 0; 103 pub const RUTABAGA_FLAG_INFO_RING_IDX: u32 = 1 << 1; 104 105 /// Convenience struct for Rutabaga fences 106 #[repr(C)] 107 #[derive(Copy, Clone)] 108 pub struct RutabagaFence { 109 pub flags: u32, 110 pub fence_id: u64, 111 pub ctx_id: u32, 112 pub ring_idx: u8, 113 } 114 115 /// Mapped memory caching flags (see virtio_gpu spec) 116 pub const RUTABAGA_MAP_CACHE_CACHED: u32 = 0x01; 117 pub const RUTABAGA_MAP_CACHE_UNCACHED: u32 = 0x02; 118 pub const RUTABAGA_MAP_CACHE_WC: u32 = 0x03; 119 120 /// Rutabaga capsets. 121 pub const RUTABAGA_CAPSET_VIRGL: u32 = 1; 122 pub const RUTABAGA_CAPSET_VIRGL2: u32 = 2; 123 pub const RUTABAGA_CAPSET_GFXSTREAM: u32 = 3; 124 pub const RUTABAGA_CAPSET_VENUS: u32 = 4; 125 pub const RUTABAGA_CAPSET_CROSS_DOMAIN: u32 = 5; 126 127 /// An error generated while using this crate. 128 #[sorted] 129 #[derive(Error, Debug)] 130 pub enum RutabagaError { 131 /// Indicates `Rutabaga` was already initialized since only one Rutabaga instance per process 132 /// is allowed. 133 #[error("attempted to use a rutabaga asset already in use")] 134 AlreadyInUse, 135 /// Base error returned as a result of rutabaga library operation. 136 #[error("rutabaga received a base error: {0}")] 137 BaseError(BaseError), 138 /// Checked Arithmetic error 139 #[error("arithmetic failed: {}({}) {op} {}({})", .field1.0, .field1.1, .field2.0, .field2.1)] 140 CheckedArithmetic { 141 field1: (&'static str, usize), 142 field2: (&'static str, usize), 143 op: &'static str, 144 }, 145 /// Checked Range error 146 #[error("range check failed: {}({}) vs {}({})", .field1.0, .field1.1, .field2.0, .field2.1)] 147 CheckedRange { 148 field1: (&'static str, usize), 149 field2: (&'static str, usize), 150 }, 151 /// An internal Rutabaga component error was returned. 152 #[error("rutabaga component failed with error {0}")] 153 ComponentError(i32), 154 /// Invalid 2D info 155 #[error("invalid 2D info")] 156 Invalid2DInfo, 157 /// Invalid Capset 158 #[error("invalid capset")] 159 InvalidCapset, 160 /// A command size was submitted that was invalid. 161 #[error("command buffer submitted with invalid size: {0}")] 162 InvalidCommandSize(usize), 163 /// Invalid RutabagaComponent 164 #[error("invalid rutabaga component")] 165 InvalidComponent, 166 /// Invalid Context ID 167 #[error("invalid context id")] 168 InvalidContextId, 169 /// Invalid cross domain channel 170 #[error("invalid cross domain channel")] 171 InvalidCrossDomainChannel, 172 /// Invalid cross domain item ID 173 #[error("invalid cross domain item id")] 174 InvalidCrossDomainItemId, 175 /// Invalid cross domain item type 176 #[error("invalid cross domain item type")] 177 InvalidCrossDomainItemType, 178 /// Invalid cross domain state 179 #[error("invalid cross domain state")] 180 InvalidCrossDomainState, 181 /// Invalid gralloc backend. 182 #[error("invalid gralloc backend")] 183 InvalidGrallocBackend, 184 /// Invalid gralloc dimensions. 185 #[error("invalid gralloc dimensions")] 186 InvalidGrallocDimensions, 187 /// Invalid gralloc DRM format. 188 #[error("invalid gralloc DRM format")] 189 InvalidGrallocDrmFormat, 190 /// Invalid GPU type. 191 #[error("invalid GPU type for gralloc")] 192 InvalidGrallocGpuType, 193 /// Invalid number of YUV planes. 194 #[error("invalid number of YUV planes")] 195 InvalidGrallocNumberOfPlanes, 196 /// The indicated region of guest memory is invalid. 197 #[error("an iovec is outside of guest memory's range")] 198 InvalidIovec, 199 /// Invalid Resource ID. 200 #[error("invalid resource id")] 201 InvalidResourceId, 202 /// Indicates an error in the RutabagaBuilder. 203 #[error("invalid rutabaga build parameters: {0}")] 204 InvalidRutabagaBuild(&'static str), 205 /// An error with the RutabagaHandle 206 #[error("invalid rutabaga handle")] 207 InvalidRutabagaHandle, 208 /// Invalid Vulkan info 209 #[error("invalid vulkan info")] 210 InvalidVulkanInfo, 211 /// An input/output error occured. 212 #[error("an input/output error occur: {0}")] 213 IoError(IoError), 214 /// The mapping failed. 215 #[error("The mapping failed for the following reason: {0}")] 216 MappingFailed(ExternalMappingError), 217 /// Violation of the Rutabaga spec occured. 218 #[error("violation of the rutabaga spec: {0}")] 219 SpecViolation(&'static str), 220 /// An attempted integer conversion failed. 221 #[error("int conversion failed: {0}")] 222 TryFromIntError(TryFromIntError), 223 /// The command is unsupported. 224 #[error("the requested function is not implemented")] 225 Unsupported, 226 /// Utf8 error. 227 #[error("an utf8 error occured: {0}")] 228 Utf8Error(Utf8Error), 229 /// Device creation error 230 #[cfg(feature = "vulkano")] 231 #[error("vulkano device creation failure {0}")] 232 VkDeviceCreationError(DeviceCreationError), 233 /// Device memory allocation error 234 #[cfg(feature = "vulkano")] 235 #[error("vulkano device memory allocation failure {0}")] 236 VkDeviceMemoryAllocationError(DeviceMemoryAllocationError), 237 /// Device memory export error 238 #[cfg(feature = "vulkano")] 239 #[error("vulkano device memory export failure {0}")] 240 VkDeviceMemoryExportError(DeviceMemoryExportError), 241 /// Image creation error 242 #[cfg(feature = "vulkano")] 243 #[error("vulkano image creation failure {0}")] 244 VkImageCreationError(ImageCreationError), 245 /// Instance creation error 246 #[cfg(feature = "vulkano")] 247 #[error("vulkano instance creation failure {0}")] 248 VkInstanceCreationError(InstanceCreationError), 249 /// Memory map error 250 #[cfg(feature = "vulkano")] 251 #[error("vullano memory map failure {0}")] 252 VkMemoryMapError(MemoryMapError), 253 /// Volatile memory error 254 #[error("noticed a volatile memory error {0}")] 255 VolatileMemoryError(VolatileMemoryError), 256 } 257 258 impl From<IoError> for RutabagaError { from(e: IoError) -> RutabagaError259 fn from(e: IoError) -> RutabagaError { 260 RutabagaError::IoError(e) 261 } 262 } 263 264 impl From<BaseError> for RutabagaError { from(e: BaseError) -> RutabagaError265 fn from(e: BaseError) -> RutabagaError { 266 RutabagaError::BaseError(e) 267 } 268 } 269 270 impl From<TryFromIntError> for RutabagaError { from(e: TryFromIntError) -> RutabagaError271 fn from(e: TryFromIntError) -> RutabagaError { 272 RutabagaError::TryFromIntError(e) 273 } 274 } 275 276 impl From<Utf8Error> for RutabagaError { from(e: Utf8Error) -> RutabagaError277 fn from(e: Utf8Error) -> RutabagaError { 278 RutabagaError::Utf8Error(e) 279 } 280 } 281 282 impl From<VolatileMemoryError> for RutabagaError { from(e: VolatileMemoryError) -> RutabagaError283 fn from(e: VolatileMemoryError) -> RutabagaError { 284 RutabagaError::VolatileMemoryError(e) 285 } 286 } 287 288 /// The result of an operation in this crate. 289 pub type RutabagaResult<T> = std::result::Result<T, RutabagaError>; 290 291 /// Flags for virglrenderer. Copied from virglrenderer bindings. 292 const VIRGLRENDERER_USE_EGL: u32 = 1 << 0; 293 const VIRGLRENDERER_THREAD_SYNC: u32 = 1 << 1; 294 const VIRGLRENDERER_USE_GLX: u32 = 1 << 2; 295 const VIRGLRENDERER_USE_SURFACELESS: u32 = 1 << 3; 296 const VIRGLRENDERER_USE_GLES: u32 = 1 << 4; 297 const VIRGLRENDERER_USE_EXTERNAL_BLOB: u32 = 1 << 5; 298 const VIRGLRENDERER_VENUS: u32 = 1 << 6; 299 const VIRGLRENDERER_NO_VIRGL: u32 = 1 << 7; 300 const VIRGLRENDERER_USE_ASYNC_FENCE_CB: u32 = 1 << 8; 301 const VIRGLRENDERER_RENDER_SERVER: u32 = 1 << 9; 302 303 /// virglrenderer flag struct. 304 #[derive(Copy, Clone)] 305 pub struct VirglRendererFlags(u32); 306 307 impl Default for VirglRendererFlags { default() -> VirglRendererFlags308 fn default() -> VirglRendererFlags { 309 VirglRendererFlags::new() 310 .use_virgl(true) 311 .use_venus(false) 312 .use_egl(true) 313 .use_surfaceless(true) 314 .use_gles(true) 315 .use_render_server(false) 316 } 317 } 318 319 impl From<VirglRendererFlags> for i32 { from(flags: VirglRendererFlags) -> i32320 fn from(flags: VirglRendererFlags) -> i32 { 321 flags.0 as i32 322 } 323 } 324 325 impl VirglRendererFlags { 326 /// Create new virglrenderer flags. new() -> VirglRendererFlags327 pub fn new() -> VirglRendererFlags { 328 VirglRendererFlags(0) 329 } 330 set_flag(self, bitmask: u32, set: bool) -> VirglRendererFlags331 fn set_flag(self, bitmask: u32, set: bool) -> VirglRendererFlags { 332 if set { 333 VirglRendererFlags(self.0 | bitmask) 334 } else { 335 VirglRendererFlags(self.0 & (!bitmask)) 336 } 337 } 338 339 /// Enable virgl support use_virgl(self, v: bool) -> VirglRendererFlags340 pub fn use_virgl(self, v: bool) -> VirglRendererFlags { 341 self.set_flag(VIRGLRENDERER_NO_VIRGL, !v) 342 } 343 344 /// Enable venus support use_venus(self, v: bool) -> VirglRendererFlags345 pub fn use_venus(self, v: bool) -> VirglRendererFlags { 346 self.set_flag(VIRGLRENDERER_VENUS, v) 347 } 348 349 /// Use EGL for context creation. use_egl(self, v: bool) -> VirglRendererFlags350 pub fn use_egl(self, v: bool) -> VirglRendererFlags { 351 self.set_flag(VIRGLRENDERER_USE_EGL, v) 352 } 353 354 /// Use a dedicated thread for fence synchronization. use_thread_sync(self, v: bool) -> VirglRendererFlags355 pub fn use_thread_sync(self, v: bool) -> VirglRendererFlags { 356 self.set_flag(VIRGLRENDERER_THREAD_SYNC, v) 357 } 358 359 /// Use GLX for context creation. use_glx(self, v: bool) -> VirglRendererFlags360 pub fn use_glx(self, v: bool) -> VirglRendererFlags { 361 self.set_flag(VIRGLRENDERER_USE_GLX, v) 362 } 363 364 /// No surfaces required when creating context. use_surfaceless(self, v: bool) -> VirglRendererFlags365 pub fn use_surfaceless(self, v: bool) -> VirglRendererFlags { 366 self.set_flag(VIRGLRENDERER_USE_SURFACELESS, v) 367 } 368 369 /// Use GLES drivers. use_gles(self, v: bool) -> VirglRendererFlags370 pub fn use_gles(self, v: bool) -> VirglRendererFlags { 371 self.set_flag(VIRGLRENDERER_USE_GLES, v) 372 } 373 374 /// Use external memory when creating blob resources. use_external_blob(self, v: bool) -> VirglRendererFlags375 pub fn use_external_blob(self, v: bool) -> VirglRendererFlags { 376 self.set_flag(VIRGLRENDERER_USE_EXTERNAL_BLOB, v) 377 } 378 379 /// Retire fence directly from sync thread. use_async_fence_cb(self, v: bool) -> VirglRendererFlags380 pub fn use_async_fence_cb(self, v: bool) -> VirglRendererFlags { 381 self.set_flag(VIRGLRENDERER_USE_ASYNC_FENCE_CB, v) 382 } 383 use_render_server(self, v: bool) -> VirglRendererFlags384 pub fn use_render_server(self, v: bool) -> VirglRendererFlags { 385 self.set_flag(VIRGLRENDERER_RENDER_SERVER, v) 386 } 387 } 388 389 /// Flags for the gfxstream renderer. 390 const GFXSTREAM_RENDERER_FLAGS_USE_EGL: u32 = 1 << 0; 391 #[allow(dead_code)] 392 const GFXSTREAM_RENDERER_FLAGS_THREAD_SYNC: u32 = 1 << 1; 393 const GFXSTREAM_RENDERER_FLAGS_USE_GLX: u32 = 1 << 2; 394 const GFXSTREAM_RENDERER_FLAGS_USE_SURFACELESS: u32 = 1 << 3; 395 const GFXSTREAM_RENDERER_FLAGS_USE_GLES: u32 = 1 << 4; 396 const GFXSTREAM_RENDERER_FLAGS_NO_VK_BIT: u32 = 1 << 5; 397 const GFXSTREAM_RENDERER_FLAGS_NO_SYNCFD_BIT: u32 = 1 << 20; 398 const GFXSTREAM_RENDERER_FLAGS_GUEST_USES_ANGLE: u32 = 1 << 21; 399 const GFXSTREAM_RENDERER_FLAGS_ASYNC_FENCE_CB: u32 = 1 << 23; 400 401 /// gfxstream flag struct. 402 #[derive(Copy, Clone, Default)] 403 pub struct GfxstreamFlags(u32); 404 405 impl GfxstreamFlags { 406 /// Create new gfxstream flags. new() -> GfxstreamFlags407 pub fn new() -> GfxstreamFlags { 408 GfxstreamFlags(0) 409 } 410 set_flag(self, bitmask: u32, set: bool) -> GfxstreamFlags411 fn set_flag(self, bitmask: u32, set: bool) -> GfxstreamFlags { 412 if set { 413 GfxstreamFlags(self.0 | bitmask) 414 } else { 415 GfxstreamFlags(self.0 & (!bitmask)) 416 } 417 } 418 419 /// Use EGL for context creation. use_egl(self, v: bool) -> GfxstreamFlags420 pub fn use_egl(self, v: bool) -> GfxstreamFlags { 421 self.set_flag(GFXSTREAM_RENDERER_FLAGS_USE_EGL, v) 422 } 423 424 /// Use GLX for context creation. use_glx(self, v: bool) -> GfxstreamFlags425 pub fn use_glx(self, v: bool) -> GfxstreamFlags { 426 self.set_flag(GFXSTREAM_RENDERER_FLAGS_USE_GLX, v) 427 } 428 429 /// No surfaces required when creating context. use_surfaceless(self, v: bool) -> GfxstreamFlags430 pub fn use_surfaceless(self, v: bool) -> GfxstreamFlags { 431 self.set_flag(GFXSTREAM_RENDERER_FLAGS_USE_SURFACELESS, v) 432 } 433 434 /// Use GLES drivers. use_gles(self, v: bool) -> GfxstreamFlags435 pub fn use_gles(self, v: bool) -> GfxstreamFlags { 436 self.set_flag(GFXSTREAM_RENDERER_FLAGS_USE_GLES, v) 437 } 438 439 /// Use external synchronization. use_syncfd(self, v: bool) -> GfxstreamFlags440 pub fn use_syncfd(self, v: bool) -> GfxstreamFlags { 441 self.set_flag(GFXSTREAM_RENDERER_FLAGS_NO_SYNCFD_BIT, !v) 442 } 443 444 /// Support using Vulkan. use_vulkan(self, v: bool) -> GfxstreamFlags445 pub fn use_vulkan(self, v: bool) -> GfxstreamFlags { 446 self.set_flag(GFXSTREAM_RENDERER_FLAGS_NO_VK_BIT, !v) 447 } 448 449 /// Use ANGLE as the guest GLES driver. use_guest_angle(self, v: bool) -> GfxstreamFlags450 pub fn use_guest_angle(self, v: bool) -> GfxstreamFlags { 451 self.set_flag(GFXSTREAM_RENDERER_FLAGS_GUEST_USES_ANGLE, v) 452 } 453 454 /// Use async fence completion callback. use_async_fence_cb(self, v: bool) -> GfxstreamFlags455 pub fn use_async_fence_cb(self, v: bool) -> GfxstreamFlags { 456 self.set_flag(GFXSTREAM_RENDERER_FLAGS_ASYNC_FENCE_CB, v) 457 } 458 } 459 460 impl From<GfxstreamFlags> for i32 { from(flags: GfxstreamFlags) -> i32461 fn from(flags: GfxstreamFlags) -> i32 { 462 flags.0 as i32 463 } 464 } 465 466 /// Transfers {to, from} 1D buffers, 2D textures, 3D textures, and cubemaps. 467 #[repr(C)] 468 #[derive(Copy, Clone, Debug)] 469 pub struct Transfer3D { 470 pub x: u32, 471 pub y: u32, 472 pub z: u32, 473 pub w: u32, 474 pub h: u32, 475 pub d: u32, 476 pub level: u32, 477 pub stride: u32, 478 pub layer_stride: u32, 479 pub offset: u64, 480 } 481 482 impl Transfer3D { 483 /// Constructs a 2 dimensional XY box in 3 dimensional space with unit depth and zero 484 /// displacement on the Z axis. new_2d(x: u32, y: u32, w: u32, h: u32) -> Transfer3D485 pub fn new_2d(x: u32, y: u32, w: u32, h: u32) -> Transfer3D { 486 Transfer3D { 487 x, 488 y, 489 z: 0, 490 w, 491 h, 492 d: 1, 493 level: 0, 494 stride: 0, 495 layer_stride: 0, 496 offset: 0, 497 } 498 } 499 500 /// Returns true if this box represents a volume of zero. is_empty(&self) -> bool501 pub fn is_empty(&self) -> bool { 502 self.w == 0 || self.h == 0 || self.d == 0 503 } 504 } 505 506 /// Rutabaga channel types 507 pub const RUTABAGA_CHANNEL_TYPE_WAYLAND: u32 = 0x0001; 508 pub const RUTABAGA_CHANNEL_TYPE_CAMERA: u32 = 0x0002; 509 510 /// Information needed to open an OS-specific RutabagaConnection (TBD). Only Linux hosts are 511 /// considered at the moment. 512 #[derive(Clone)] 513 pub struct RutabagaChannel { 514 pub base_channel: PathBuf, 515 pub channel_type: u32, 516 } 517 518 /// Enumeration of possible rutabaga components. 519 #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] 520 pub enum RutabagaComponentType { 521 Rutabaga2D, 522 VirglRenderer, 523 Gfxstream, 524 CrossDomain, 525 } 526 527 /// Rutabaga handle types (memory and sync in same namespace) 528 pub const RUTABAGA_MEM_HANDLE_TYPE_OPAQUE_FD: u32 = 0x0001; 529 pub const RUTABAGA_MEM_HANDLE_TYPE_DMABUF: u32 = 0x0002; 530 pub const RUTABAGE_MEM_HANDLE_TYPE_OPAQUE_WIN32: u32 = 0x0003; 531 pub const RUTABAGA_MEM_HANDLE_TYPE_SHM: u32 = 0x0004; 532 pub const RUTABAGA_FENCE_HANDLE_TYPE_OPAQUE_FD: u32 = 0x0010; 533 pub const RUTABAGA_FENCE_HANDLE_TYPE_SYNC_FD: u32 = 0x0011; 534 pub const RUTABAGE_FENCE_HANDLE_TYPE_OPAQUE_WIN32: u32 = 0x0012; 535 536 /// Handle to OS-specific memory or synchronization objects. 537 pub struct RutabagaHandle { 538 pub os_handle: SafeDescriptor, 539 pub handle_type: u32, 540 } 541 542 impl RutabagaHandle { 543 /// Clones an existing rutabaga handle, by using OS specific mechanisms. try_clone(&self) -> RutabagaResult<RutabagaHandle>544 pub fn try_clone(&self) -> RutabagaResult<RutabagaHandle> { 545 let clone = self 546 .os_handle 547 .try_clone() 548 .map_err(|_| RutabagaError::InvalidRutabagaHandle)?; 549 Ok(RutabagaHandle { 550 os_handle: clone, 551 handle_type: self.handle_type, 552 }) 553 } 554 } 555 556 /// Trait for fence completion handlers 557 pub trait RutabagaFenceCallback: Send { call(&self, data: RutabagaFence)558 fn call(&self, data: RutabagaFence); clone_box(&self) -> RutabagaFenceHandler559 fn clone_box(&self) -> RutabagaFenceHandler; 560 } 561 562 /// Wrapper type to allow cloning while respecting object-safety 563 pub type RutabagaFenceHandler = Box<dyn RutabagaFenceCallback>; 564 565 impl Clone for RutabagaFenceHandler { clone(&self) -> Self566 fn clone(&self) -> Self { 567 self.clone_box() 568 } 569 } 570 571 /// Fence handler implementation that wraps a closure 572 #[derive(Clone)] 573 pub struct RutabagaFenceClosure<T> { 574 closure: T, 575 } 576 577 impl<T> RutabagaFenceClosure<T> 578 where 579 T: Fn(RutabagaFence) + Clone + Send + 'static, 580 { new(closure: T) -> RutabagaFenceHandler581 pub fn new(closure: T) -> RutabagaFenceHandler { 582 Box::new(RutabagaFenceClosure { closure }) 583 } 584 } 585 586 impl<T> RutabagaFenceCallback for RutabagaFenceClosure<T> 587 where 588 T: Fn(RutabagaFence) + Clone + Send + 'static, 589 { call(&self, data: RutabagaFence)590 fn call(&self, data: RutabagaFence) { 591 (self.closure)(data) 592 } 593 clone_box(&self) -> RutabagaFenceHandler594 fn clone_box(&self) -> RutabagaFenceHandler { 595 Box::new(self.clone()) 596 } 597 } 598