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