1use std::collections::HashMap;
6use std::ffi::c_char;
7use std::ffi::CStr;
8use std::ffi::CString;
9use std::os::fd::AsFd;
10use std::os::fd::AsRawFd;
11use std::panic::catch_unwind;
12use std::process::abort;
13use std::ptr::NonNull;
14use std::rc::Rc;
15use std::slice;
16use std::sync::Arc;
17use std::sync::RwLock;
18
19use anyhow::bail;
20use base::error;
21use base::AsRawDescriptor;
22use base::Event;
23use base::RawDescriptor;
24use base::VolatileSlice;
25use rutabaga_gfx::AhbInfo;
26use sync::Waitable;
27use vm_control::gpu::DisplayParameters;
28
29use crate::DisplayExternalResourceImport;
30use crate::DisplayT;
31use crate::FlipToExtraInfo;
32use crate::GpuDisplayError;
33use crate::GpuDisplayFramebuffer;
34use crate::GpuDisplayResult;
35use crate::GpuDisplaySurface;
36use crate::SemaphoreTimepoint;
37use crate::SurfaceType;
38use crate::SysDisplayT;
39
40#[repr(C)]
42pub(crate) struct AndroidDisplayContext {
43 _data: [u8; 0],
44 _marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
45}
46
47#[repr(C)]
49pub(crate) struct AndroidDisplaySurface {
50 _data: [u8; 0],
51 _marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
52}
53
54#[repr(C)]
58pub(crate) struct ANativeWindow_Buffer {
59 width: i32,
60 height: i32,
61 stride: i32, format: i32,
63 bits: *mut u8,
64 reserved: [u32; 6],
65}
66
67pub(crate) type ErrorCallback = unsafe extern "C" fn(message: *const c_char);
68
69extern "C" {
70 fn create_android_display_context(
78 name: *const c_char,
79 error_callback: ErrorCallback,
80 ) -> *mut AndroidDisplayContext;
81
82 fn destroy_android_display_context(self_: *mut AndroidDisplayContext);
84
85 fn create_android_surface(
89 ctx: *mut AndroidDisplayContext,
90 width: u32,
91 height: u32,
92 for_cursor: bool,
93 ) -> *mut AndroidDisplaySurface;
94
95 #[allow(dead_code)]
97 fn destroy_android_surface(
98 ctx: *mut AndroidDisplayContext,
99 surface: *mut AndroidDisplaySurface,
100 );
101
102 fn get_android_surface_buffer(
110 ctx: *mut AndroidDisplayContext,
111 surface: *mut AndroidDisplaySurface,
112 out_buffer: *mut ANativeWindow_Buffer,
113 ) -> bool;
114
115 fn set_android_surface_position(ctx: *mut AndroidDisplayContext, x: u32, y: u32);
116
117 fn post_android_surface_buffer(
121 ctx: *mut AndroidDisplayContext,
122 surface: *mut AndroidDisplaySurface,
123 );
124
125 fn android_display_flip_to(
126 ctx: *mut AndroidDisplayContext,
127 _surface: *mut AndroidDisplaySurface,
128 ahb_info: *const AHardwareBufferInfo,
129 );
130}
131
132unsafe extern "C" fn error_callback(message: *const c_char) {
133 catch_unwind(|| {
134 error!(
135 "{}",
136 unsafe { CStr::from_ptr(message) }.to_string_lossy()
138 )
139 })
140 .unwrap_or_else(|_| abort())
141}
142
143struct AndroidDisplayContextWrapper(NonNull<AndroidDisplayContext>);
144
145impl Drop for AndroidDisplayContextWrapper {
146 fn drop(&mut self) {
147 unsafe { destroy_android_display_context(self.0.as_ptr()) };
149 }
150}
151
152impl Default for ANativeWindow_Buffer {
153 fn default() -> Self {
154 Self {
155 width: 0,
156 height: 0,
157 stride: 0,
158 format: 0,
159 bits: std::ptr::null_mut(),
160 reserved: [0u32; 6],
161 }
162 }
163}
164
165impl From<ANativeWindow_Buffer> for GpuDisplayFramebuffer<'_> {
166 fn from(anb: ANativeWindow_Buffer) -> Self {
167 const BYTES_PER_PIXEL: u32 = 4;
170 let stride_bytes = BYTES_PER_PIXEL * u32::try_from(anb.stride).unwrap();
171 let buffer_size = stride_bytes * u32::try_from(anb.height).unwrap();
172 let buffer =
173 unsafe { slice::from_raw_parts_mut(anb.bits, buffer_size.try_into().unwrap()) };
176 Self::new(VolatileSlice::new(buffer), stride_bytes, BYTES_PER_PIXEL)
177 }
178}
179
180#[repr(C)]
181pub struct AHardwareBufferInfo {
182 pub num_fds: usize,
183 pub fds_ptr: *const i32,
184 pub metadata_len: usize,
185 pub metadata_ptr: *const u8,
186}
187
188type AHardwareBufferImportMap = HashMap<u32, AhbInfo>;
190
191struct AndroidSurface {
192 context: Rc<AndroidDisplayContextWrapper>,
193 surface: NonNull<AndroidDisplaySurface>,
194 ahb_import_map: Arc<RwLock<AHardwareBufferImportMap>>,
195}
196
197impl GpuDisplaySurface for AndroidSurface {
198 fn framebuffer(&mut self) -> Option<GpuDisplayFramebuffer> {
199 let mut anb = ANativeWindow_Buffer::default();
200 let success = unsafe {
203 get_android_surface_buffer(
204 self.context.0.as_ptr(),
205 self.surface.as_ptr(),
206 &mut anb as *mut ANativeWindow_Buffer,
207 )
208 };
209 if success {
210 Some(anb.into())
211 } else {
212 None
213 }
214 }
215
216 fn flip(&mut self) {
217 unsafe { post_android_surface_buffer(self.context.0.as_ptr(), self.surface.as_ptr()) }
219 }
220
221 fn set_position(&mut self, x: u32, y: u32) {
222 unsafe { set_android_surface_position(self.context.0.as_ptr(), x, y) };
224 }
225
226 fn flip_to(
227 &mut self,
228 import_id: u32,
229 _acquire_timepoint: Option<SemaphoreTimepoint>,
230 _release_timepoint: Option<SemaphoreTimepoint>,
231 _extra_info: Option<FlipToExtraInfo>,
232 ) -> anyhow::Result<Waitable> {
233 {
234 let ahb_import_map = self.ahb_import_map.read().expect("failed to get a lock");
235 let ahb = ahb_import_map
236 .get(&import_id)
237 .ok_or(GpuDisplayError::InvalidImportId)?;
238 let fds: Vec<i32> = ahb.fds.iter().map(|fd| fd.as_fd().as_raw_fd()).collect();
239
240 let info = AHardwareBufferInfo {
241 num_fds: fds.len(),
242 fds_ptr: fds.as_ptr(),
243 metadata_len: ahb.metadata.len(),
244 metadata_ptr: ahb.metadata.as_ptr(),
245 };
246 unsafe {
250 android_display_flip_to(
251 self.context.0.as_ptr(),
252 self.surface.as_ptr(),
253 &info as *const AHardwareBufferInfo,
254 )
255 };
256 }
257 Ok(Waitable::signaled())
258 }
259}
260
261pub struct DisplayAndroid {
262 context: Rc<AndroidDisplayContextWrapper>,
263 event: Event,
265 surface_ahbs_map: HashMap<u32, Arc<RwLock<AHardwareBufferImportMap>>>,
267}
268
269impl DisplayAndroid {
270 pub fn new(name: &str) -> GpuDisplayResult<DisplayAndroid> {
271 let name = CString::new(name).unwrap();
272 let context = NonNull::new(
273 unsafe { create_android_display_context(name.as_ptr(), error_callback) },
275 )
276 .ok_or(GpuDisplayError::Unsupported)?;
277 let context = AndroidDisplayContextWrapper(context);
278 let event = Event::new().map_err(|_| GpuDisplayError::CreateEvent)?;
279 Ok(DisplayAndroid {
280 context: context.into(),
281 event,
282 surface_ahbs_map: HashMap::new(),
283 })
284 }
285}
286
287impl DisplayT for DisplayAndroid {
288 fn create_surface(
289 &mut self,
290 parent_surface_id: Option<u32>,
291 surface_id: u32,
292 _scanout_id: Option<u32>,
293 display_params: &DisplayParameters,
294 _surf_type: SurfaceType,
295 ) -> GpuDisplayResult<Box<dyn GpuDisplaySurface>> {
296 let (requested_width, requested_height) = display_params.get_virtual_display_size();
297 let surface = NonNull::new(unsafe {
299 create_android_surface(
300 self.context.0.as_ptr(),
301 requested_width,
302 requested_height,
303 parent_surface_id.is_some(),
304 )
305 })
306 .ok_or(GpuDisplayError::CreateSurface)?;
307 let ahb_import_map = self.surface_ahbs_map.entry(surface_id).or_default();
308
309 Ok(Box::new(AndroidSurface {
310 context: self.context.clone(),
311 surface,
312 ahb_import_map: Arc::clone(ahb_import_map),
313 }))
314 }
315
316 fn release_surface(&mut self, surface_id: u32) {
317 self.surface_ahbs_map.remove(&surface_id);
318 }
319
320 fn import_resource(
321 &mut self,
322 import_id: u32,
323 surface_id: u32,
324 external_display_resource: DisplayExternalResourceImport,
325 ) -> anyhow::Result<()> {
326 let DisplayExternalResourceImport::AHardwareBuffer { info } = external_display_resource
327 else {
328 bail!("gpu_display_android only supports AHardwareBufferInfo imports");
329 };
330
331 {
332 let mut ahbs = self
333 .surface_ahbs_map
334 .entry(surface_id)
335 .or_default()
336 .write()
337 .expect("failed to get a lock");
338 ahbs.insert(import_id, info);
339 }
340 Ok(())
341 }
342
343 fn release_import(&mut self, surface_id: u32, import_id: u32) {
344 let mut ahbs = self
345 .surface_ahbs_map
346 .entry(surface_id)
347 .or_default()
348 .write()
349 .expect("failed to get a lock");
350 ahbs.remove(&import_id);
351 }
352}
353
354impl SysDisplayT for DisplayAndroid {}
355
356impl AsRawDescriptor for DisplayAndroid {
357 fn as_raw_descriptor(&self) -> RawDescriptor {
358 self.event.as_raw_descriptor()
359 }
360}