krun_display/
rust_to_c.rs1use crate::{
2 DisplayBackend, DisplayBackendError, DisplayBasicFramebufferVtable, DisplayFeatures,
3 DisplayVtable, Rect, ResourceFormat,
4};
5use log::error;
6use std::ffi::c_void;
7use std::marker::PhantomData;
8use std::ptr;
9use std::ptr::{null, null_mut};
10
11pub trait DisplayBackendNew<T: Sync> {
12 fn new(userdata: Option<&T>) -> Self;
13}
14
15pub trait DisplayBackendBasicFramebuffer {
16 fn configure_scanout(
17 &mut self,
18 scanout_id: u32,
19 display_width: u32,
20 display_height: u32,
21 width: u32,
22 height: u32,
23 format: ResourceFormat,
24 ) -> Result<(), DisplayBackendError>;
25
26 fn disable_scanout(&mut self, scanout_id: u32) -> Result<(), DisplayBackendError>;
27
28 fn alloc_frame(&mut self, scanout_id: u32) -> Result<(u32, &mut [u8]), DisplayBackendError>;
29
30 fn present_frame(
31 &mut self,
32 scanout_id: u32,
33 frame_id: u32,
34 rect: Option<&Rect>,
35 ) -> Result<(), DisplayBackendError>;
36}
37
38pub trait IntoDisplayBackend<T: Sync> {
39 fn into_display_backend(userdata: Option<&T>) -> DisplayBackend<'_>;
40}
41
42impl<T: Sync, I: DisplayBackendBasicFramebuffer + DisplayBackendNew<T>> IntoDisplayBackend<T>
43 for I
44{
45 fn into_display_backend(userdata: Option<&T>) -> DisplayBackend<'_> {
46 extern "C" fn create_fn<T: Sync, I: DisplayBackendNew<T>>(
47 instance: *mut *mut c_void,
48 userdata: *const c_void,
49 _reserved: *const c_void,
50 ) -> i32 {
51 unsafe {
52 assert_ne!(
53 instance,
54 null_mut(),
55 "Pointer to location where to create instance cannot be null"
56 );
57 let userdata_ref = (userdata as *const T).as_ref();
58 *(instance as *mut *mut I) = Box::into_raw(Box::new(I::new(userdata_ref)));
59 }
60 0
61 }
62
63 extern "C" fn destroy_fn<I>(instance: *mut c_void) -> i32 {
64 drop(unsafe { Box::from_raw(instance as *mut I) });
65 0
66 }
67
68 fn cast_instance<'a, I: DisplayBackendBasicFramebuffer>(
69 instance: *mut c_void,
70 ) -> &'a mut I {
71 assert_ne!(instance, null_mut());
72 unsafe { &mut *(instance as *mut I) }
73 }
74
75 extern "C" fn configure_scanout_fn<I: DisplayBackendBasicFramebuffer>(
76 instance: *mut c_void,
77 scanout_id: u32,
78 display_width: u32,
79 display_height: u32,
80 width: u32,
81 height: u32,
82 format: u32,
83 ) -> i32 {
84 let Ok(format) = ResourceFormat::try_from(format) else {
85 error!("Unknown display format: {format}");
86 return DisplayBackendError::InvalidParam as i32;
87 };
88
89 from_rust_result(cast_instance::<I>(instance).configure_scanout(
90 scanout_id,
91 display_width,
92 display_height,
93 width,
94 height,
95 format,
96 ))
97 }
98
99 extern "C" fn disable_scanout_fb<I: DisplayBackendBasicFramebuffer>(
100 instance: *mut c_void,
101 scanout_id: u32,
102 ) -> i32 {
103 from_rust_result(cast_instance::<I>(instance).disable_scanout(scanout_id))
104 }
105
106 extern "C" fn alloc_frame<I: DisplayBackendBasicFramebuffer>(
107 instance: *mut c_void,
108 scanout_id: u32,
109 buffer: *mut *mut u8,
110 buffer_size: *mut usize,
111 ) -> i32 {
112 match cast_instance::<I>(instance).alloc_frame(scanout_id) {
113 Ok((frame_id, allocated_buffer)) => {
114 unsafe {
115 *buffer_size = allocated_buffer.len();
116 *buffer = allocated_buffer.as_mut_ptr();
117 }
118 frame_id as i32
119 }
120 Err(e) => e as i32,
121 }
122 }
123
124 extern "C" fn present_frame<I: DisplayBackendBasicFramebuffer>(
125 instance: *mut c_void,
126 scanout_id: u32,
127 frame_id: u32,
128 rect: *const Rect,
129 ) -> i32 {
130 let rect: Option<&Rect> = unsafe { ptr_to_option_ref(rect) };
132 from_rust_result(cast_instance::<I>(instance).present_frame(scanout_id, frame_id, rect))
133 }
134
135 DisplayBackend {
136 create_userdata: userdata.map_or(null(), |t| ptr::from_ref(t) as *const c_void),
137 create_userdata_lifetime: PhantomData,
138 features: DisplayFeatures::BASIC_FRAMEBUFFER.bits(),
139 create_fn: Some(create_fn::<T, I>),
140 vtable: DisplayVtable {
141 basic_framebuffer: DisplayBasicFramebufferVtable {
142 destroy: Some(destroy_fn::<I>),
143 configure_scanout: Some(configure_scanout_fn::<I>),
144 present_frame: Some(present_frame::<I>),
145 alloc_frame: Some(alloc_frame::<I>),
146 disable_scanout: Some(disable_scanout_fb::<I>),
147 },
148 },
149 }
150 }
151}
152
153unsafe fn ptr_to_option_ref<'a, T>(x: *const T) -> Option<&'a T> {
154 if x.is_null() {
155 None
156 } else {
157 unsafe { Some(&*x) }
159 }
160}
161
162fn from_rust_result(result: Result<(), DisplayBackendError>) -> i32 {
163 match result {
164 Ok(()) => 0,
165 Err(e) => e as i32,
166 }
167}