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