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