1use std::fmt;
8use std::os::raw::c_char;
9use std::os::raw::c_void;
10use std::path::PathBuf;
11use std::sync::Arc;
12
13use mesa3d_util::MesaError;
14use remain::sorted;
15use serde::Deserialize;
16use serde::Serialize;
17use serde_json::Error as SerdeJsonError;
18use thiserror::Error;
19#[cfg(feature = "vulkano")]
20use vulkano::device::DeviceCreationError;
21#[cfg(feature = "vulkano")]
22use vulkano::image::ImageError;
23#[cfg(feature = "vulkano")]
24use vulkano::instance::InstanceCreationError;
25#[cfg(feature = "vulkano")]
26use vulkano::memory::DeviceMemoryError;
27#[cfg(feature = "vulkano")]
28use vulkano::memory::MemoryMapError;
29#[cfg(feature = "vulkano")]
30use vulkano::LoadingError;
31#[cfg(feature = "vulkano")]
32use vulkano::VulkanError;
33use zerocopy::FromBytes;
34use zerocopy::Immutable;
35use zerocopy::IntoBytes;
36
37#[repr(C)]
40#[derive(Copy, Clone)]
41pub struct RutabagaIovec {
42 pub base: *mut c_void,
43 pub len: usize,
44}
45
46unsafe impl Send for RutabagaIovec {}
48
49unsafe impl Sync for RutabagaIovec {}
51
52pub const RUTABAGA_PIPE_TEXTURE_2D: u32 = 2;
56pub const RUTABAGA_PIPE_BIND_RENDER_TARGET: u32 = 2;
57#[repr(C)]
58#[derive(Copy, Clone, Debug, Deserialize, Serialize)]
59pub struct ResourceCreate3D {
60 pub target: u32,
61 pub format: u32,
62 pub bind: u32,
63 pub width: u32,
64 pub height: u32,
65 pub depth: u32,
66 pub array_size: u32,
67 pub last_level: u32,
68 pub nr_samples: u32,
69 pub flags: u32,
70}
71
72pub const RUTABAGA_BLOB_MEM_GUEST: u32 = 0x0001;
74pub const RUTABAGA_BLOB_MEM_HOST3D: u32 = 0x0002;
75pub const RUTABAGA_BLOB_MEM_HOST3D_GUEST: u32 = 0x0003;
76
77pub const RUTABAGA_BLOB_FLAG_USE_MAPPABLE: u32 = 0x0001;
78pub const RUTABAGA_BLOB_FLAG_USE_SHAREABLE: u32 = 0x0002;
79pub const RUTABAGA_BLOB_FLAG_USE_CROSS_DEVICE: u32 = 0x0004;
80#[repr(C)]
81#[derive(Copy, Clone, Debug)]
82pub struct ResourceCreateBlob {
83 pub blob_mem: u32,
84 pub blob_flags: u32,
85 pub blob_id: u64,
86 pub size: u64,
87}
88
89#[repr(C)]
91#[derive(Default, Copy, Clone, Debug, Deserialize, Serialize)]
92pub struct Resource3DInfo {
93 pub width: u32,
94 pub height: u32,
95 pub drm_fourcc: u32,
96 pub strides: [u32; 4],
97 pub offsets: [u32; 4],
98 pub modifier: u64,
99}
100
101#[derive(
103 Copy,
104 Clone,
105 Debug,
106 Default,
107 PartialEq,
108 Eq,
109 PartialOrd,
110 Ord,
111 Hash,
112 FromBytes,
113 IntoBytes,
114 Immutable,
115)]
116#[repr(C)]
117#[derive(Deserialize, Serialize)]
118pub struct DeviceId {
119 pub device_uuid: [u8; 16],
120 pub driver_uuid: [u8; 16],
121}
122
123#[derive(
125 Copy,
126 Clone,
127 Debug,
128 Default,
129 PartialEq,
130 Eq,
131 PartialOrd,
132 Ord,
133 Hash,
134 FromBytes,
135 IntoBytes,
136 Immutable,
137)]
138#[repr(C)]
139#[derive(Deserialize, Serialize)]
140pub struct VulkanInfo {
141 pub memory_idx: u32,
142 pub device_id: DeviceId,
143}
144
145pub const RUTABAGA_CONTEXT_INIT_CAPSET_ID_MASK: u32 = 0x00ff;
147
148pub const RUTABAGA_FLAG_FENCE: u32 = 1 << 0;
150pub const RUTABAGA_FLAG_INFO_RING_IDX: u32 = 1 << 1;
151pub const RUTABAGA_FLAG_FENCE_HOST_SHAREABLE: u32 = 1 << 2;
152
153#[repr(C)]
155#[derive(Copy, Clone)]
156pub struct RutabagaFence {
157 pub flags: u32,
158 pub fence_id: u64,
159 pub ctx_id: u32,
160 pub ring_idx: u8,
161}
162
163pub const RUTABAGA_DEBUG_ERROR: u32 = 0x01;
165pub const RUTABAGA_DEBUG_WARNING: u32 = 0x02;
166pub const RUTABAGA_DEBUG_INFO: u32 = 0x03;
167
168#[repr(C)]
170#[derive(Copy, Clone)]
171pub struct RutabagaDebug {
172 pub debug_type: u32,
173 pub message: *const c_char,
174}
175
176pub const RUTABAGA_IMPORT_FLAG_3D_INFO: u32 = 1 << 0;
178pub const RUTABAGA_IMPORT_FLAG_VULKAN_INFO: u32 = 1 << 1;
179pub const RUTABAGA_IMPORT_FLAG_RESOURCE_EXISTS: u32 = 1 << 30;
180pub const RUTABAGA_IMPORT_FLAG_PRESERVE_CONTENT: u32 = 1 << 31;
181
182#[repr(C)]
184#[derive(Copy, Clone)]
185pub struct RutabagaImportData {
186 pub flags: u32,
187 pub info_3d: Resource3DInfo,
188}
189
190unsafe impl Send for RutabagaDebug {}
195unsafe impl Sync for RutabagaDebug {}
200
201pub const RUTABAGA_MAP_CACHE_MASK: u32 = 0x0f;
203pub const RUTABAGA_MAP_CACHE_CACHED: u32 = 0x01;
204pub const RUTABAGA_MAP_CACHE_UNCACHED: u32 = 0x02;
205pub const RUTABAGA_MAP_CACHE_WC: u32 = 0x03;
206pub const RUTABAGA_MAP_ACCESS_MASK: u32 = 0xf0;
208pub const RUTABAGA_MAP_ACCESS_READ: u32 = 0x10;
209pub const RUTABAGA_MAP_ACCESS_WRITE: u32 = 0x20;
210pub const RUTABAGA_MAP_ACCESS_RW: u32 = 0x30;
211
212pub const RUTABAGA_CAPSET_VIRGL: u32 = 1;
214pub const RUTABAGA_CAPSET_VIRGL2: u32 = 2;
215pub const RUTABAGA_CAPSET_GFXSTREAM_VULKAN: u32 = 3;
216pub const RUTABAGA_CAPSET_VENUS: u32 = 4;
217pub const RUTABAGA_CAPSET_CROSS_DOMAIN: u32 = 5;
218pub const RUTABAGA_CAPSET_DRM: u32 = 6;
219pub const RUTABAGA_CAPSET_MAGMA: u32 = 7;
220pub const RUTABAGA_CAPSET_GFXSTREAM_GLES: u32 = 8;
221pub const RUTABAGA_CAPSET_GFXSTREAM_COMPOSER: u32 = 9;
222
223#[sorted]
230#[non_exhaustive]
231#[derive(Error, Debug)]
232pub enum RutabagaError {
233 #[error("attempted to use a rutabaga asset already in use")]
236 AlreadyInUse,
237 #[error("arithmetic failed: {}({}) {op} {}({})", .field1.0, .field1.1, .field2.0, .field2.1)]
239 CheckedArithmetic {
240 field1: (&'static str, usize),
241 field2: (&'static str, usize),
242 op: &'static str,
243 },
244 #[error("range check failed: {}({}) vs {}({})", .field1.0, .field1.1, .field2.0, .field2.1)]
246 CheckedRange {
247 field1: (&'static str, usize),
248 field2: (&'static str, usize),
249 },
250 #[error("rutabaga component failed with error {0}")]
252 ComponentError(i32),
253 #[error("invalid 2D info")]
255 Invalid2DInfo,
256 #[error("invalid capset")]
258 InvalidCapset,
259 #[error("invalid command buffer submitted")]
261 InvalidCommandBuffer,
262 #[error("command buffer submitted with invalid size: {0}")]
264 InvalidCommandSize(usize),
265 #[error("invalid rutabaga component")]
267 InvalidComponent,
268 #[error("invalid context id")]
270 InvalidContextId,
271 #[error("invalid cross domain channel")]
273 InvalidCrossDomainChannel,
274 #[error("invalid cross domain item id")]
276 InvalidCrossDomainItemId,
277 #[error("invalid cross domain item type")]
279 InvalidCrossDomainItemType,
280 #[error("invalid cross domain state")]
282 InvalidCrossDomainState,
283 #[error("invalid gralloc backend")]
285 InvalidGrallocBackend,
286 #[error("invalid gralloc dimensions")]
288 InvalidGrallocDimensions,
289 #[error("invalid gralloc DRM format")]
291 InvalidGrallocDrmFormat,
292 #[error("invalid GPU type for gralloc")]
294 InvalidGrallocGpuType,
295 #[error("invalid number of YUV planes")]
297 InvalidGrallocNumberOfPlanes,
298 #[error("an iovec is outside of guest memory's range")]
300 InvalidIovec,
301 #[error("invalid resource id")]
303 InvalidResourceId,
304 #[error("invalid rutabaga build parameters")]
306 InvalidRutabagaBuild,
307 #[error("invalid vulkan info")]
309 InvalidVulkanInfo,
310 #[error("The mapping failed with library error: {0}")]
312 MappingFailed(i32),
313 #[error("An mesa error was returned {0}")]
315 MesaError(MesaError),
316 #[error("An serde json snapshot error was returned {0}")]
318 SerdeJsonError(SerdeJsonError),
319 #[error("An snapshot error was returned")]
321 SnapshotError,
322 #[cfg(feature = "vulkano")]
324 #[error("vulkano device creation failure {0}")]
325 VkDeviceCreationError(DeviceCreationError),
326 #[cfg(feature = "vulkano")]
328 #[error("vulkano device memory failure {0}")]
329 VkDeviceMemoryError(DeviceMemoryError),
330 #[cfg(feature = "vulkano")]
332 #[error("vulkano failure {0}")]
333 VkError(VulkanError),
334 #[cfg(feature = "vulkano")]
336 #[error("vulkano image creation failure {0}")]
337 VkImageCreationError(ImageError),
338 #[cfg(feature = "vulkano")]
340 #[error("vulkano instance creation failure {0}")]
341 VkInstanceCreationError(InstanceCreationError),
342 #[cfg(feature = "vulkano")]
344 #[error("vulkano loading failure {0}")]
345 VkLoadingError(LoadingError),
346 #[cfg(feature = "vulkano")]
348 #[error("vulkano memory map failure {0}")]
349 VkMemoryMapError(MemoryMapError),
350}
351
352impl From<MesaError> for RutabagaError {
353 fn from(e: MesaError) -> RutabagaError {
354 RutabagaError::MesaError(e)
355 }
356}
357
358impl From<SerdeJsonError> for RutabagaError {
359 fn from(e: SerdeJsonError) -> RutabagaError {
360 RutabagaError::SerdeJsonError(e)
361 }
362}
363
364pub type RutabagaResult<T> = std::result::Result<T, RutabagaError>;
366
367const VIRGLRENDERER_USE_EGL: u32 = 1 << 0;
369const VIRGLRENDERER_THREAD_SYNC: u32 = 1 << 1;
370#[allow(dead_code)]
371const VIRGLRENDERER_USE_GLX: u32 = 1 << 2;
372const VIRGLRENDERER_USE_SURFACELESS: u32 = 1 << 3;
373const VIRGLRENDERER_USE_GLES: u32 = 1 << 4;
374const VIRGLRENDERER_USE_EXTERNAL_BLOB: u32 = 1 << 5;
375const VIRGLRENDERER_VENUS: u32 = 1 << 6;
376const VIRGLRENDERER_NO_VIRGL: u32 = 1 << 7;
377const VIRGLRENDERER_USE_ASYNC_FENCE_CB: u32 = 1 << 8;
378const VIRGLRENDERER_RENDER_SERVER: u32 = 1 << 9;
379const VIRGLRENDERER_DRM: u32 = 1 << 10;
380
381#[derive(Copy, Clone)]
383pub struct VirglRendererFlags(u32);
384
385impl Default for VirglRendererFlags {
386 fn default() -> VirglRendererFlags {
387 VirglRendererFlags::new()
388 .use_virgl(true)
389 .use_venus(false)
390 .use_egl(true)
391 .use_surfaceless(true)
392 .use_gles(true)
393 .use_render_server(false)
394 }
395}
396
397impl From<VirglRendererFlags> for u32 {
398 fn from(flags: VirglRendererFlags) -> u32 {
399 flags.0
400 }
401}
402
403impl From<VirglRendererFlags> for i32 {
404 fn from(flags: VirglRendererFlags) -> i32 {
405 flags.0 as i32
406 }
407}
408
409impl VirglRendererFlags {
410 pub fn new() -> VirglRendererFlags {
412 VirglRendererFlags(0)
413 }
414
415 fn set_flag(self, bitmask: u32, set: bool) -> VirglRendererFlags {
416 if set {
417 VirglRendererFlags(self.0 | bitmask)
418 } else {
419 VirglRendererFlags(self.0 & (!bitmask))
420 }
421 }
422
423 pub fn use_virgl(self, v: bool) -> VirglRendererFlags {
425 self.set_flag(VIRGLRENDERER_NO_VIRGL, !v)
426 }
427
428 pub fn use_venus(self, v: bool) -> VirglRendererFlags {
430 self.set_flag(VIRGLRENDERER_VENUS, v)
431 }
432
433 pub fn use_drm(self, v: bool) -> VirglRendererFlags {
435 self.set_flag(VIRGLRENDERER_DRM, v)
436 }
437
438 pub fn use_egl(self, v: bool) -> VirglRendererFlags {
440 self.set_flag(VIRGLRENDERER_USE_EGL, v)
441 }
442
443 pub fn use_thread_sync(self, v: bool) -> VirglRendererFlags {
445 self.set_flag(VIRGLRENDERER_THREAD_SYNC, v)
446 }
447
448 pub fn use_surfaceless(self, v: bool) -> VirglRendererFlags {
450 self.set_flag(VIRGLRENDERER_USE_SURFACELESS, v)
451 }
452
453 pub fn use_gles(self, v: bool) -> VirglRendererFlags {
455 self.set_flag(VIRGLRENDERER_USE_GLES, v)
456 }
457
458 pub fn use_external_blob(self, v: bool) -> VirglRendererFlags {
460 self.set_flag(VIRGLRENDERER_USE_EXTERNAL_BLOB, v)
461 }
462
463 pub fn use_async_fence_cb(self, v: bool) -> VirglRendererFlags {
465 self.set_flag(VIRGLRENDERER_USE_ASYNC_FENCE_CB, v)
466 }
467
468 pub fn use_render_server(self, v: bool) -> VirglRendererFlags {
469 self.set_flag(VIRGLRENDERER_RENDER_SERVER, v)
470 }
471}
472
473const STREAM_RENDERER_FLAGS_USE_EGL: u32 = 1 << 0;
475#[allow(dead_code)]
476const STREAM_RENDERER_FLAGS_THREAD_SYNC: u32 = 1 << 1;
477#[allow(dead_code)]
478const STREAM_RENDERER_FLAGS_USE_GLX: u32 = 1 << 2;
479const STREAM_RENDERER_FLAGS_USE_SURFACELESS: u32 = 1 << 3;
480const STREAM_RENDERER_FLAGS_USE_GLES: u32 = 1 << 4;
481const STREAM_RENDERER_FLAGS_USE_VK_BIT: u32 = 1 << 5;
482const STREAM_RENDERER_FLAGS_USE_EXTERNAL_BLOB: u32 = 1 << 6;
483const STREAM_RENDERER_FLAGS_USE_SYSTEM_BLOB: u32 = 1 << 7;
484const STREAM_RENDERER_FLAGS_VULKAN_NATIVE_SWAPCHAIN_BIT: u32 = 1 << 8;
485
486#[derive(Copy, Clone, Default)]
488pub struct GfxstreamFlags(u32);
489
490#[derive(Clone, Debug)]
491pub enum RutabagaWsi {
492 Surfaceless,
493 VulkanSwapchain,
494}
495
496impl GfxstreamFlags {
497 pub fn new() -> GfxstreamFlags {
499 GfxstreamFlags(0)
500 }
501
502 fn set_flag(self, bitmask: u32, set: bool) -> GfxstreamFlags {
503 if set {
504 GfxstreamFlags(self.0 | bitmask)
505 } else {
506 GfxstreamFlags(self.0 & (!bitmask))
507 }
508 }
509
510 pub fn use_egl(self, v: bool) -> GfxstreamFlags {
512 self.set_flag(STREAM_RENDERER_FLAGS_USE_EGL, v)
513 }
514
515 pub fn use_surfaceless(self, v: bool) -> GfxstreamFlags {
517 self.set_flag(STREAM_RENDERER_FLAGS_USE_SURFACELESS, v)
518 }
519
520 pub fn use_gles(self, v: bool) -> GfxstreamFlags {
522 self.set_flag(STREAM_RENDERER_FLAGS_USE_GLES, v)
523 }
524
525 pub fn use_vulkan(self, v: bool) -> GfxstreamFlags {
527 self.set_flag(STREAM_RENDERER_FLAGS_USE_VK_BIT, v)
528 }
529
530 pub fn set_wsi(self, v: RutabagaWsi) -> GfxstreamFlags {
532 let use_vulkan_swapchain = matches!(v, RutabagaWsi::VulkanSwapchain);
533 self.set_flag(
534 STREAM_RENDERER_FLAGS_VULKAN_NATIVE_SWAPCHAIN_BIT,
535 use_vulkan_swapchain,
536 )
537 }
538
539 pub fn use_external_blob(self, v: bool) -> GfxstreamFlags {
541 self.set_flag(STREAM_RENDERER_FLAGS_USE_EXTERNAL_BLOB, v)
542 }
543
544 pub fn use_system_blob(self, v: bool) -> GfxstreamFlags {
546 self.set_flag(STREAM_RENDERER_FLAGS_USE_SYSTEM_BLOB, v)
547 }
548}
549
550impl From<GfxstreamFlags> for u32 {
551 fn from(flags: GfxstreamFlags) -> u32 {
552 flags.0
553 }
554}
555
556impl From<GfxstreamFlags> for i32 {
557 fn from(flags: GfxstreamFlags) -> i32 {
558 flags.0 as i32
559 }
560}
561
562impl From<GfxstreamFlags> for u64 {
563 fn from(flags: GfxstreamFlags) -> u64 {
564 flags.0 as u64
565 }
566}
567
568#[repr(C)]
570#[derive(Copy, Clone, Debug)]
571pub struct Transfer3D {
572 pub x: u32,
573 pub y: u32,
574 pub z: u32,
575 pub w: u32,
576 pub h: u32,
577 pub d: u32,
578 pub level: u32,
579 pub stride: u32,
580 pub layer_stride: u32,
581 pub offset: u64,
582}
583
584impl Transfer3D {
585 pub fn new_2d(x: u32, y: u32, w: u32, h: u32, offset: u64) -> Transfer3D {
588 Transfer3D {
589 x,
590 y,
591 z: 0,
592 w,
593 h,
594 d: 1,
595 level: 0,
596 stride: 0,
597 layer_stride: 0,
598 offset,
599 }
600 }
601
602 pub fn is_empty(&self) -> bool {
604 self.w == 0 || self.h == 0 || self.d == 0
605 }
606}
607
608pub const RUTABAGA_PATH_TYPE_WAYLAND: u32 = 0x0001;
610pub const RUTABAGA_PATH_TYPE_GPU: u32 = 0x0002;
611
612pub type RutabagaPaths = Vec<RutabagaPath>;
613
614#[derive(Clone)]
617pub struct RutabagaPath {
618 pub path: PathBuf,
619 pub path_type: u32,
620}
621
622#[repr(u8)]
624#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord)]
625pub enum RutabagaComponentType {
626 NoneSelected,
627 Rutabaga2D,
628 VirglRenderer,
629 Gfxstream,
630 CrossDomain,
631 Magma,
632}
633
634impl RutabagaComponentType {
635 pub fn as_str(&self) -> &'static str {
636 match self {
637 RutabagaComponentType::NoneSelected => "none_selected",
638 RutabagaComponentType::CrossDomain => "cross_domain",
639 RutabagaComponentType::Gfxstream => "gfxstream",
640 RutabagaComponentType::Magma => "magma",
641 RutabagaComponentType::Rutabaga2D => "rutabaga_2d",
642 RutabagaComponentType::VirglRenderer => "virgl_renderer",
643 }
644 }
645}
646
647pub const RUTABAGA_HANDLE_TYPE_PLATFORM_SCREEN_BUFFER_QNX: u32 = 0x01000000;
649pub const RUTABAGA_HANDLE_TYPE_PLATFORM_EGL_NATIVE_PIXMAP: u32 = 0x02000000;
650
651#[derive(Clone)]
652pub struct RutabagaHandler<S> {
653 closure: Arc<dyn Fn(S) + Send + Sync>,
654}
655
656impl<S> RutabagaHandler<S>
657where
658 S: Send + Sync + Clone + 'static,
659{
660 pub fn new(closure: impl Fn(S) + Send + Sync + 'static) -> RutabagaHandler<S> {
661 RutabagaHandler {
662 closure: Arc::new(closure),
663 }
664 }
665
666 pub fn call(&self, data: S) {
667 (self.closure)(data)
668 }
669}
670
671impl<S> fmt::Debug for RutabagaHandler<S> {
672 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
673 f.debug_struct("Closure debug").finish()
674 }
675}
676
677pub type RutabagaFenceHandler = RutabagaHandler<RutabagaFence>;
678pub type RutabagaDebugHandler = RutabagaHandler<RutabagaDebug>;