1 // Copyright 2021 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 //! C bindings for the rutabaga_gfx crate
6
7 extern crate rutabaga_gfx;
8
9 use std::cell::RefCell;
10 use std::convert::TryInto;
11 use std::ffi::CStr;
12 use std::ffi::CString;
13 use std::fs::File;
14 use std::io::IoSliceMut;
15 use std::os::raw::c_char;
16 use std::os::raw::c_void;
17 use std::panic::catch_unwind;
18 use std::panic::AssertUnwindSafe;
19 use std::path::Path;
20 use std::path::PathBuf;
21 use std::ptr::copy_nonoverlapping;
22 use std::ptr::null_mut;
23 use std::slice::from_raw_parts;
24 use std::slice::from_raw_parts_mut;
25
26 #[cfg(unix)]
27 use libc::iovec;
28 use libc::EINVAL;
29 use libc::ESRCH;
30 use rutabaga_gfx::ResourceCreate3D;
31 use rutabaga_gfx::ResourceCreateBlob;
32 use rutabaga_gfx::Rutabaga;
33 use rutabaga_gfx::RutabagaBuilder;
34 use rutabaga_gfx::RutabagaChannel;
35 use rutabaga_gfx::RutabagaComponentType;
36 use rutabaga_gfx::RutabagaDebug;
37 use rutabaga_gfx::RutabagaDebugHandler;
38 use rutabaga_gfx::RutabagaDescriptor;
39 use rutabaga_gfx::RutabagaFence;
40 use rutabaga_gfx::RutabagaFenceHandler;
41 use rutabaga_gfx::RutabagaFromRawDescriptor;
42 use rutabaga_gfx::RutabagaHandle;
43 use rutabaga_gfx::RutabagaImportData;
44 use rutabaga_gfx::RutabagaIntoRawDescriptor;
45 use rutabaga_gfx::RutabagaIovec;
46 use rutabaga_gfx::RutabagaResult;
47 use rutabaga_gfx::RutabagaWsi;
48 use rutabaga_gfx::Transfer3D;
49 use rutabaga_gfx::RUTABAGA_DEBUG_ERROR;
50
51 #[cfg(not(unix))]
52 #[repr(C)]
53 pub struct iovec {
54 pub iov_base: *mut c_void,
55 pub iov_len: usize,
56 }
57
58 const NO_ERROR: i32 = 0;
59 const RUTABAGA_WSI_SURFACELESS: u64 = 1;
60
61 thread_local! {
62 static S_DEBUG_HANDLER: RefCell<Option<RutabagaDebugHandler>> = const { RefCell::new(None) };
63 }
64
log_error(debug_string: String)65 fn log_error(debug_string: String) {
66 S_DEBUG_HANDLER.with(|handler_cell| {
67 if let Some(handler) = &*handler_cell.borrow() {
68 let cstring = CString::new(debug_string.as_str()).expect("CString creation failed");
69
70 let debug = RutabagaDebug {
71 debug_type: RUTABAGA_DEBUG_ERROR,
72 message: cstring.as_ptr(),
73 };
74
75 handler.call(debug);
76 }
77 });
78 }
79
return_result<T>(result: RutabagaResult<T>) -> i3280 fn return_result<T>(result: RutabagaResult<T>) -> i32 {
81 if let Err(e) = result {
82 log_error(e.to_string());
83 -EINVAL
84 } else {
85 NO_ERROR
86 }
87 }
88
89 macro_rules! return_on_error {
90 ($result:expr) => {
91 match $result {
92 Ok(t) => t,
93 Err(e) => {
94 log_error(e.to_string());
95 return -EINVAL;
96 }
97 }
98 };
99 }
100
101 macro_rules! return_on_io_error {
102 ($result:expr) => {
103 match $result {
104 Ok(t) => t,
105 Err(e) => {
106 log_error(e.to_string());
107 return -e.raw_os_error().unwrap_or(EINVAL);
108 }
109 }
110 };
111 }
112
113 #[allow(non_camel_case_types)]
114 type rutabaga = Rutabaga;
115
116 #[allow(non_camel_case_types)]
117 type rutabaga_create_blob = ResourceCreateBlob;
118
119 #[allow(non_camel_case_types)]
120 type rutabaga_create_3d = ResourceCreate3D;
121
122 #[allow(non_camel_case_types)]
123 type rutabaga_transfer = Transfer3D;
124
125 #[allow(non_camel_case_types)]
126 type rutabaga_fence = RutabagaFence;
127
128 #[allow(non_camel_case_types)]
129 type rutabaga_debug = RutabagaDebug;
130
131 #[repr(C)]
132 #[derive(Copy, Clone)]
133 pub struct rutabaga_iovecs {
134 pub iovecs: *mut iovec,
135 pub num_iovecs: usize,
136 }
137
138 #[repr(C)]
139 #[derive(Copy, Clone)]
140 pub struct rutabaga_handle {
141 pub os_handle: i64,
142 pub handle_type: u32,
143 }
144
145 #[repr(C)]
146 pub struct rutabaga_mapping {
147 pub ptr: *mut c_void,
148 pub size: u64,
149 }
150
151 #[repr(C)]
152 pub struct rutabaga_channel {
153 pub channel_name: *const c_char,
154 pub channel_type: u32,
155 }
156
157 #[repr(C)]
158 pub struct rutabaga_channels {
159 pub channels: *const rutabaga_channel,
160 pub num_channels: usize,
161 }
162
163 #[repr(C)]
164 pub struct rutabaga_command {
165 pub ctx_id: u32,
166 pub cmd_size: u32,
167 pub cmd: *mut u8,
168 pub num_in_fences: u32,
169 pub fence_ids: *mut u64,
170 }
171
172 #[allow(non_camel_case_types)]
173 type rutabaga_import_data = RutabagaImportData;
174
175 #[allow(non_camel_case_types)]
176 pub type rutabaga_fence_callback = extern "C" fn(user_data: u64, fence: &rutabaga_fence);
177
178 #[allow(non_camel_case_types)]
179 pub type rutabaga_debug_callback = extern "C" fn(user_data: u64, debug: &rutabaga_debug);
180
181 #[repr(C)]
182 pub struct rutabaga_builder<'a> {
183 pub user_data: u64,
184 pub capset_mask: u64,
185 pub wsi: u64,
186 pub fence_cb: rutabaga_fence_callback,
187 pub debug_cb: Option<rutabaga_debug_callback>,
188 pub channels: Option<&'a rutabaga_channels>,
189 pub renderer_features: *const c_char,
190 }
191
create_ffi_fence_handler( user_data: u64, fence_cb: rutabaga_fence_callback, ) -> RutabagaFenceHandler192 fn create_ffi_fence_handler(
193 user_data: u64,
194 fence_cb: rutabaga_fence_callback,
195 ) -> RutabagaFenceHandler {
196 RutabagaFenceHandler::new(move |completed_fence| fence_cb(user_data, &completed_fence))
197 }
198
create_ffi_debug_handler( user_data: u64, debug_cb: rutabaga_debug_callback, ) -> RutabagaDebugHandler199 fn create_ffi_debug_handler(
200 user_data: u64,
201 debug_cb: rutabaga_debug_callback,
202 ) -> RutabagaDebugHandler {
203 RutabagaDebugHandler::new(move |rutabaga_debug| debug_cb(user_data, &rutabaga_debug))
204 }
205
206 #[no_mangle]
207 /// # Safety
208 /// - `capset_names` must be a null-terminated C-string.
rutabaga_calculate_capset_mask( capset_names: *const c_char, capset_mask: &mut u64, ) -> i32209 pub unsafe extern "C" fn rutabaga_calculate_capset_mask(
210 capset_names: *const c_char,
211 capset_mask: &mut u64,
212 ) -> i32 {
213 catch_unwind(AssertUnwindSafe(|| {
214 if capset_names.is_null() {
215 return -EINVAL;
216 }
217
218 let c_str_slice = CStr::from_ptr(capset_names);
219 let result = c_str_slice.to_str();
220 let str_slice = return_on_error!(result);
221 *capset_mask = rutabaga_gfx::calculate_capset_mask(str_slice.split(':'));
222 NO_ERROR
223 }))
224 .unwrap_or(-ESRCH)
225 }
226
227 /// # Safety
228 /// - If `(*builder).channels` is not null, the caller must ensure `(*channels).channels` points to
229 /// a valid array of `struct rutabaga_channel` of size `(*channels).num_channels`.
230 /// - The `channel_name` field of `struct rutabaga_channel` must be a null-terminated C-string.
231 #[no_mangle]
rutabaga_init(builder: &rutabaga_builder, ptr: &mut *mut rutabaga) -> i32232 pub unsafe extern "C" fn rutabaga_init(builder: &rutabaga_builder, ptr: &mut *mut rutabaga) -> i32 {
233 catch_unwind(AssertUnwindSafe(|| {
234 let fence_handler = create_ffi_fence_handler(builder.user_data, builder.fence_cb);
235 let mut debug_handler_opt: Option<RutabagaDebugHandler> = None;
236
237 if let Some(func) = builder.debug_cb {
238 let debug_handler = create_ffi_debug_handler(builder.user_data, func);
239 S_DEBUG_HANDLER.with(|handler_cell| {
240 *handler_cell.borrow_mut() = Some(debug_handler.clone());
241 });
242 debug_handler_opt = Some(debug_handler);
243 }
244
245 let mut rutabaga_channels_opt = None;
246 if let Some(channels) = builder.channels {
247 let mut rutabaga_channels: Vec<RutabagaChannel> = Vec::new();
248 let channels_slice = from_raw_parts(channels.channels, channels.num_channels);
249
250 for channel in channels_slice {
251 let c_str_slice = CStr::from_ptr(channel.channel_name);
252 let result = c_str_slice.to_str();
253 let str_slice = return_on_error!(result);
254 let string = str_slice.to_owned();
255 let path = PathBuf::from(&string);
256
257 rutabaga_channels.push(RutabagaChannel {
258 base_channel: path,
259 channel_type: channel.channel_type,
260 });
261 }
262
263 rutabaga_channels_opt = Some(rutabaga_channels);
264 }
265
266 let mut renderer_features_opt = None;
267 let renderer_features_ptr = builder.renderer_features;
268 if !renderer_features_ptr.is_null() {
269 let c_str_slice = CStr::from_ptr(renderer_features_ptr);
270 let result = c_str_slice.to_str();
271 let str_slice = return_on_error!(result);
272 let string = str_slice.to_owned();
273 renderer_features_opt = Some(string);
274 }
275
276 let mut component_type = RutabagaComponentType::CrossDomain;
277 if builder.capset_mask == 0 {
278 component_type = RutabagaComponentType::Rutabaga2D;
279 }
280
281 let rutabaga_wsi = match builder.wsi {
282 RUTABAGA_WSI_SURFACELESS => RutabagaWsi::Surfaceless,
283 _ => return -EINVAL,
284 };
285
286 let result = RutabagaBuilder::new(component_type, builder.capset_mask)
287 .set_use_external_blob(false)
288 .set_use_egl(true)
289 .set_wsi(rutabaga_wsi)
290 .set_debug_handler(debug_handler_opt)
291 .set_rutabaga_channels(rutabaga_channels_opt)
292 .set_renderer_features(renderer_features_opt)
293 .build(fence_handler, None);
294
295 let rtbg = return_on_error!(result);
296 *ptr = Box::into_raw(Box::new(rtbg)) as _;
297 NO_ERROR
298 }))
299 .unwrap_or(-ESRCH)
300 }
301
302 /// # Safety
303 /// - `ptr` must have been created by `rutabaga_init`.
304 #[no_mangle]
rutabaga_finish(ptr: &mut *mut rutabaga) -> i32305 pub extern "C" fn rutabaga_finish(ptr: &mut *mut rutabaga) -> i32 {
306 catch_unwind(AssertUnwindSafe(|| {
307 let _ = unsafe { Box::from_raw(*ptr) };
308 *ptr = null_mut();
309 NO_ERROR
310 }))
311 .unwrap_or(-ESRCH)
312 }
313
314 #[no_mangle]
rutabaga_get_num_capsets(ptr: &mut rutabaga, num_capsets: &mut u32) -> i32315 pub extern "C" fn rutabaga_get_num_capsets(ptr: &mut rutabaga, num_capsets: &mut u32) -> i32 {
316 catch_unwind(AssertUnwindSafe(|| {
317 *num_capsets = ptr.get_num_capsets();
318 NO_ERROR
319 }))
320 .unwrap_or(-ESRCH)
321 }
322
323 #[no_mangle]
rutabaga_get_capset_info( ptr: &mut rutabaga, capset_index: u32, capset_id: &mut u32, capset_version: &mut u32, capset_size: &mut u32, ) -> i32324 pub extern "C" fn rutabaga_get_capset_info(
325 ptr: &mut rutabaga,
326 capset_index: u32,
327 capset_id: &mut u32,
328 capset_version: &mut u32,
329 capset_size: &mut u32,
330 ) -> i32 {
331 catch_unwind(AssertUnwindSafe(|| {
332 let result = ptr.get_capset_info(capset_index);
333 let info = return_on_error!(result);
334 *capset_id = info.0;
335 *capset_version = info.1;
336 *capset_size = info.2;
337 NO_ERROR
338 }))
339 .unwrap_or(-ESRCH)
340 }
341
342 /// # Safety
343 /// - `capset` must point an array of bytes of size `capset_size`.
344 #[no_mangle]
rutabaga_get_capset( ptr: &mut rutabaga, capset_id: u32, version: u32, capset: *mut u8, capset_size: u32, ) -> i32345 pub unsafe extern "C" fn rutabaga_get_capset(
346 ptr: &mut rutabaga,
347 capset_id: u32,
348 version: u32,
349 capset: *mut u8,
350 capset_size: u32,
351 ) -> i32 {
352 catch_unwind(AssertUnwindSafe(|| {
353 let size: usize = capset_size.try_into().map_err(|_e| -EINVAL).unwrap();
354 let result = ptr.get_capset(capset_id, version);
355 let vec = return_on_error!(result);
356 copy_nonoverlapping(vec.as_ptr(), capset, size);
357 NO_ERROR
358 }))
359 .unwrap_or(-ESRCH)
360 }
361
362 #[no_mangle]
rutabaga_context_create( ptr: &mut rutabaga, ctx_id: u32, context_init: u32, context_name: *const c_char, context_name_len: u32, ) -> i32363 pub extern "C" fn rutabaga_context_create(
364 ptr: &mut rutabaga,
365 ctx_id: u32,
366 context_init: u32,
367 context_name: *const c_char,
368 context_name_len: u32,
369 ) -> i32 {
370 let mut name: Option<&str> = None;
371 if !context_name.is_null() && context_name_len > 0 {
372 // Safe because context_name is not NULL and len is a positive integer, so the caller
373 // is expected to provide a valid pointer to an array of bytes at least as long as the
374 // passed length. If the provided byte array doesn't contain valid utf-8, name will be
375 // None.
376 let view = unsafe {
377 std::slice::from_raw_parts(context_name as *const u8, context_name_len as usize)
378 };
379 name = std::str::from_utf8(view).ok();
380 }
381
382 catch_unwind(AssertUnwindSafe(|| {
383 let result = ptr.create_context(ctx_id, context_init, name);
384 return_result(result)
385 }))
386 .unwrap_or(-ESRCH)
387 }
388
389 #[no_mangle]
rutabaga_context_destroy(ptr: &mut rutabaga, ctx_id: u32) -> i32390 pub extern "C" fn rutabaga_context_destroy(ptr: &mut rutabaga, ctx_id: u32) -> i32 {
391 catch_unwind(AssertUnwindSafe(|| {
392 let result = ptr.destroy_context(ctx_id);
393 return_result(result)
394 }))
395 .unwrap_or(-ESRCH)
396 }
397
398 #[no_mangle]
rutabaga_context_attach_resource( ptr: &mut rutabaga, ctx_id: u32, resource_id: u32, ) -> i32399 pub extern "C" fn rutabaga_context_attach_resource(
400 ptr: &mut rutabaga,
401 ctx_id: u32,
402 resource_id: u32,
403 ) -> i32 {
404 catch_unwind(AssertUnwindSafe(|| {
405 let result = ptr.context_attach_resource(ctx_id, resource_id);
406 return_result(result)
407 }))
408 .unwrap_or(-ESRCH)
409 }
410
411 #[no_mangle]
rutabaga_context_detach_resource( ptr: &mut rutabaga, ctx_id: u32, resource_id: u32, ) -> i32412 pub extern "C" fn rutabaga_context_detach_resource(
413 ptr: &mut rutabaga,
414 ctx_id: u32,
415 resource_id: u32,
416 ) -> i32 {
417 catch_unwind(AssertUnwindSafe(|| {
418 let result = ptr.context_detach_resource(ctx_id, resource_id);
419 return_result(result)
420 }))
421 .unwrap_or(-ESRCH)
422 }
423
424 #[no_mangle]
rutabaga_resource_create_3d( ptr: &mut rutabaga, resource_id: u32, create_3d: &rutabaga_create_3d, ) -> i32425 pub extern "C" fn rutabaga_resource_create_3d(
426 ptr: &mut rutabaga,
427 resource_id: u32,
428 create_3d: &rutabaga_create_3d,
429 ) -> i32 {
430 catch_unwind(AssertUnwindSafe(|| {
431 let result = ptr.resource_create_3d(resource_id, *create_3d);
432 return_result(result)
433 }))
434 .unwrap_or(-ESRCH)
435 }
436
437 #[no_mangle]
rutabaga_resource_import( ptr: &mut rutabaga, resource_id: u32, import_handle: &rutabaga_handle, import_data: &rutabaga_import_data, ) -> i32438 pub unsafe extern "C" fn rutabaga_resource_import(
439 ptr: &mut rutabaga,
440 resource_id: u32,
441 import_handle: &rutabaga_handle,
442 import_data: &rutabaga_import_data,
443 ) -> i32 {
444 catch_unwind(AssertUnwindSafe(|| {
445 let internal_handle = RutabagaHandle {
446 os_handle: RutabagaDescriptor::from_raw_descriptor(
447 import_handle.os_handle.try_into().unwrap(),
448 ),
449 handle_type: import_handle.handle_type,
450 };
451
452 let result = ptr.resource_import(resource_id, internal_handle, *import_data);
453 return_result(result)
454 }))
455 .unwrap_or(-ESRCH)
456 }
457
458 /// # Safety
459 /// - If `iovecs` is not null, the caller must ensure `(*iovecs).iovecs` points to a valid array of
460 /// iovecs of size `(*iovecs).num_iovecs`.
461 /// - Each iovec must point to valid memory starting at `iov_base` with length `iov_len`.
462 /// - Each iovec must valid until the resource's backing is explictly detached or the resource is is
463 /// unreferenced.
464 #[no_mangle]
rutabaga_resource_attach_backing( ptr: &mut rutabaga, resource_id: u32, iovecs: &rutabaga_iovecs, ) -> i32465 pub unsafe extern "C" fn rutabaga_resource_attach_backing(
466 ptr: &mut rutabaga,
467 resource_id: u32,
468 iovecs: &rutabaga_iovecs,
469 ) -> i32 {
470 catch_unwind(AssertUnwindSafe(|| {
471 let slice = from_raw_parts(iovecs.iovecs, iovecs.num_iovecs);
472 let vecs = slice
473 .iter()
474 .map(|iov| RutabagaIovec {
475 base: iov.iov_base,
476 len: iov.iov_len,
477 })
478 .collect();
479
480 let result = ptr.attach_backing(resource_id, vecs);
481 return_result(result)
482 }))
483 .unwrap_or(-ESRCH)
484 }
485
486 #[no_mangle]
rutabaga_resource_detach_backing(ptr: &mut rutabaga, resource_id: u32) -> i32487 pub extern "C" fn rutabaga_resource_detach_backing(ptr: &mut rutabaga, resource_id: u32) -> i32 {
488 catch_unwind(AssertUnwindSafe(|| {
489 let result = ptr.detach_backing(resource_id);
490 return_result(result)
491 }))
492 .unwrap_or(-ESRCH)
493 }
494
495 /// # Safety
496 /// - If `iovecs` is not null, the caller must ensure `(*iovecs).iovecs` points to a valid array of
497 /// iovecs of size `(*iovecs).num_iovecs`.
498 #[no_mangle]
rutabaga_resource_transfer_read( ptr: &mut rutabaga, ctx_id: u32, resource_id: u32, transfer: &rutabaga_transfer, buf: Option<&iovec>, ) -> i32499 pub unsafe extern "C" fn rutabaga_resource_transfer_read(
500 ptr: &mut rutabaga,
501 ctx_id: u32,
502 resource_id: u32,
503 transfer: &rutabaga_transfer,
504 buf: Option<&iovec>,
505 ) -> i32 {
506 catch_unwind(AssertUnwindSafe(|| {
507 let mut slice_opt = None;
508 if let Some(iovec) = buf {
509 slice_opt = Some(IoSliceMut::new(std::slice::from_raw_parts_mut(
510 iovec.iov_base as *mut u8,
511 iovec.iov_len,
512 )));
513 }
514
515 let result = ptr.transfer_read(ctx_id, resource_id, *transfer, slice_opt);
516 return_result(result)
517 }))
518 .unwrap_or(-ESRCH)
519 }
520
521 #[no_mangle]
rutabaga_resource_transfer_write( ptr: &mut rutabaga, ctx_id: u32, resource_id: u32, transfer: &rutabaga_transfer, ) -> i32522 pub extern "C" fn rutabaga_resource_transfer_write(
523 ptr: &mut rutabaga,
524 ctx_id: u32,
525 resource_id: u32,
526 transfer: &rutabaga_transfer,
527 ) -> i32 {
528 catch_unwind(AssertUnwindSafe(|| {
529 let result = ptr.transfer_write(ctx_id, resource_id, *transfer);
530 return_result(result)
531 }))
532 .unwrap_or(-ESRCH)
533 }
534
535 /// # Safety
536 /// - If `iovecs` is not null, the caller must ensure `(*iovecs).iovecs` points to a valid array of
537 /// iovecs of size `(*iovecs).num_iovecs`.
538 /// - If `handle` is not null, the caller must ensure it is a valid OS-descriptor. Ownership is
539 /// transfered to rutabaga.
540 /// - Each iovec must valid until the resource's backing is explictly detached or the resource is is
541 /// unreferenced.
542 #[no_mangle]
rutabaga_resource_create_blob( ptr: &mut rutabaga, ctx_id: u32, resource_id: u32, create_blob: &rutabaga_create_blob, iovecs: Option<&rutabaga_iovecs>, handle: Option<&rutabaga_handle>, ) -> i32543 pub unsafe extern "C" fn rutabaga_resource_create_blob(
544 ptr: &mut rutabaga,
545 ctx_id: u32,
546 resource_id: u32,
547 create_blob: &rutabaga_create_blob,
548 iovecs: Option<&rutabaga_iovecs>,
549 handle: Option<&rutabaga_handle>,
550 ) -> i32 {
551 catch_unwind(AssertUnwindSafe(|| {
552 let mut iovecs_opt: Option<Vec<RutabagaIovec>> = None;
553 if let Some(iovs) = iovecs {
554 let slice = if iovs.num_iovecs != 0 {
555 from_raw_parts(iovs.iovecs, iovs.num_iovecs)
556 } else {
557 &[]
558 };
559 let vecs = slice
560 .iter()
561 .map(|iov| RutabagaIovec {
562 base: iov.iov_base,
563 len: iov.iov_len,
564 })
565 .collect();
566 iovecs_opt = Some(vecs);
567 }
568
569 let mut handle_opt: Option<RutabagaHandle> = None;
570
571 // Only needed on Unix, since there is no way to create a handle from guest memory on
572 // Windows.
573 #[cfg(unix)]
574 if let Some(hnd) = handle {
575 handle_opt = Some(RutabagaHandle {
576 os_handle: RutabagaDescriptor::from_raw_descriptor(
577 hnd.os_handle.try_into().unwrap(),
578 ),
579 handle_type: hnd.handle_type,
580 });
581 }
582
583 let result =
584 ptr.resource_create_blob(ctx_id, resource_id, *create_blob, iovecs_opt, handle_opt);
585
586 return_result(result)
587 }))
588 .unwrap_or(-ESRCH)
589 }
590
591 #[no_mangle]
rutabaga_resource_unref(ptr: &mut rutabaga, resource_id: u32) -> i32592 pub extern "C" fn rutabaga_resource_unref(ptr: &mut rutabaga, resource_id: u32) -> i32 {
593 catch_unwind(AssertUnwindSafe(|| {
594 let result = ptr.unref_resource(resource_id);
595 return_result(result)
596 }))
597 .unwrap_or(-ESRCH)
598 }
599
600 /// # Safety
601 /// Caller owns raw descriptor on success and is responsible for closing it.
602 #[no_mangle]
rutabaga_resource_export_blob( ptr: &mut rutabaga, resource_id: u32, handle: &mut rutabaga_handle, ) -> i32603 pub extern "C" fn rutabaga_resource_export_blob(
604 ptr: &mut rutabaga,
605 resource_id: u32,
606 handle: &mut rutabaga_handle,
607 ) -> i32 {
608 catch_unwind(AssertUnwindSafe(|| {
609 let result = ptr.export_blob(resource_id);
610 let hnd = return_on_error!(result);
611
612 handle.handle_type = hnd.handle_type;
613 handle.os_handle = hnd.os_handle.into_raw_descriptor() as i64;
614 NO_ERROR
615 }))
616 .unwrap_or(-ESRCH)
617 }
618
619 #[no_mangle]
rutabaga_resource_map( ptr: &mut rutabaga, resource_id: u32, mapping: &mut rutabaga_mapping, ) -> i32620 pub extern "C" fn rutabaga_resource_map(
621 ptr: &mut rutabaga,
622 resource_id: u32,
623 mapping: &mut rutabaga_mapping,
624 ) -> i32 {
625 catch_unwind(AssertUnwindSafe(|| {
626 let result = ptr.map(resource_id);
627 let internal_map = return_on_error!(result);
628 mapping.ptr = internal_map.ptr as *mut c_void;
629 mapping.size = internal_map.size;
630 NO_ERROR
631 }))
632 .unwrap_or(-ESRCH)
633 }
634
635 #[no_mangle]
rutabaga_resource_unmap(ptr: &mut rutabaga, resource_id: u32) -> i32636 pub extern "C" fn rutabaga_resource_unmap(ptr: &mut rutabaga, resource_id: u32) -> i32 {
637 catch_unwind(AssertUnwindSafe(|| {
638 let result = ptr.unmap(resource_id);
639 return_result(result)
640 }))
641 .unwrap_or(-ESRCH)
642 }
643
644 #[no_mangle]
rutabaga_resource_map_info( ptr: &mut rutabaga, resource_id: u32, map_info: &mut u32, ) -> i32645 pub extern "C" fn rutabaga_resource_map_info(
646 ptr: &mut rutabaga,
647 resource_id: u32,
648 map_info: &mut u32,
649 ) -> i32 {
650 catch_unwind(AssertUnwindSafe(|| {
651 let result = ptr.map_info(resource_id);
652 *map_info = return_on_error!(result);
653 NO_ERROR
654 }))
655 .unwrap_or(-ESRCH)
656 }
657
658 /// # Safety
659 /// - `commands` must point to a contiguous memory region of `size` bytes.
660 #[no_mangle]
rutabaga_submit_command( ptr: &mut rutabaga, cmd: &rutabaga_command, ) -> i32661 pub unsafe extern "C" fn rutabaga_submit_command(
662 ptr: &mut rutabaga,
663 cmd: &rutabaga_command,
664 ) -> i32 {
665 catch_unwind(AssertUnwindSafe(|| {
666 let cmd_slice = if cmd.cmd_size != 0 {
667 from_raw_parts_mut(cmd.cmd, cmd.cmd_size as usize)
668 } else {
669 &mut []
670 };
671 let fence_ids = if cmd.num_in_fences != 0 {
672 from_raw_parts(cmd.fence_ids, cmd.num_in_fences as usize)
673 } else {
674 &mut []
675 };
676
677 let result = ptr.submit_command(cmd.ctx_id, cmd_slice, fence_ids);
678 return_result(result)
679 }))
680 .unwrap_or(-ESRCH)
681 }
682
683 #[no_mangle]
rutabaga_create_fence(ptr: &mut rutabaga, fence: &rutabaga_fence) -> i32684 pub extern "C" fn rutabaga_create_fence(ptr: &mut rutabaga, fence: &rutabaga_fence) -> i32 {
685 catch_unwind(AssertUnwindSafe(|| {
686 let result = ptr.create_fence(*fence);
687 return_result(result)
688 }))
689 .unwrap_or(-ESRCH)
690 }
691
692 /// # Safety
693 /// - `dir` must be a null-terminated C-string.
694 #[no_mangle]
rutabaga_snapshot(ptr: &mut rutabaga, dir: *const c_char) -> i32695 pub unsafe extern "C" fn rutabaga_snapshot(ptr: &mut rutabaga, dir: *const c_char) -> i32 {
696 catch_unwind(AssertUnwindSafe(|| {
697 let c_str_slice = CStr::from_ptr(dir);
698
699 let result = c_str_slice.to_str();
700 let directory = return_on_error!(result);
701
702 let result = ptr.snapshot(directory);
703 return_result(result)
704 }))
705 .unwrap_or(-ESRCH)
706 }
707
708 /// # Safety
709 /// - `dir` must be a null-terminated C-string.
710 #[no_mangle]
rutabaga_restore(ptr: &mut rutabaga, dir: *const c_char) -> i32711 pub unsafe extern "C" fn rutabaga_restore(ptr: &mut rutabaga, dir: *const c_char) -> i32 {
712 catch_unwind(AssertUnwindSafe(|| {
713 let c_str_slice = CStr::from_ptr(dir);
714
715 let result = c_str_slice.to_str();
716 let directory = return_on_error!(result);
717
718 let result = ptr.restore(directory);
719 return_result(result)
720 }))
721 .unwrap_or(-ESRCH)
722 }
723