• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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