gpu_display/
gpu_display_android.rs

1// Copyright 2024 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
5use std::ffi::c_char;
6use std::ffi::CStr;
7use std::ffi::CString;
8use std::panic::catch_unwind;
9use std::process::abort;
10use std::ptr::NonNull;
11use std::rc::Rc;
12use std::slice;
13
14use base::error;
15use base::AsRawDescriptor;
16use base::Event;
17use base::RawDescriptor;
18use base::VolatileSlice;
19use vm_control::gpu::DisplayParameters;
20
21use crate::DisplayT;
22use crate::GpuDisplayError;
23use crate::GpuDisplayFramebuffer;
24use crate::GpuDisplayResult;
25use crate::GpuDisplaySurface;
26use crate::SurfaceType;
27use crate::SysDisplayT;
28
29// Opaque blob
30#[repr(C)]
31pub(crate) struct AndroidDisplayContext {
32    _data: [u8; 0],
33    _marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
34}
35
36// Opaque blob
37#[repr(C)]
38pub(crate) struct AndroidDisplaySurface {
39    _data: [u8; 0],
40    _marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
41}
42
43// Should be the same as ANativeWindow_Buffer in android/native_window.h
44// Note that this struct is part of NDK; guaranteed to be stable, so we use it directly across the
45// FFI.
46#[repr(C)]
47pub(crate) struct ANativeWindow_Buffer {
48    width: i32,
49    height: i32,
50    stride: i32, // in number of pixels, NOT bytes
51    format: i32,
52    bits: *mut u8,
53    reserved: [u32; 6],
54}
55
56pub(crate) type ErrorCallback = unsafe extern "C" fn(message: *const c_char);
57
58extern "C" {
59    /// Constructs an AndroidDisplayContext for this backend. This awlays returns a valid (ex:
60    /// non-null) handle to the context. The `name` parameter is from crosvm commandline and the
61    /// client of crosvm will use it to locate and communicate to the AndroidDisplayContext. For
62    /// example, this can be a path to UNIX domain socket where a RPC binder server listens on.
63    /// `error_callback` is a function pointer to an error reporting function, and will be used by
64    /// this and other functions below when something goes wrong. The returned context should be
65    /// destroyed by calling `destroy_android_display_context` if this backend is no longer in use.
66    fn create_android_display_context(
67        name: *const c_char,
68        error_callback: ErrorCallback,
69    ) -> *mut AndroidDisplayContext;
70
71    /// Destroys the AndroidDisplayContext created from `create_android_display_context`.
72    fn destroy_android_display_context(self_: *mut AndroidDisplayContext);
73
74    /// Creates an Android Surface (which is also called as Window) of given size. If the surface
75    /// can't be created for whatever reason, null pointer is returned, in which case we shouldn't
76    /// proceed further.
77    fn create_android_surface(
78        ctx: *mut AndroidDisplayContext,
79        width: u32,
80        height: u32,
81        for_cursor: bool,
82    ) -> *mut AndroidDisplaySurface;
83
84    /// Destroys the Android surface created from `create_android_surface`.
85    #[allow(dead_code)]
86    fn destroy_android_surface(
87        ctx: *mut AndroidDisplayContext,
88        surface: *mut AndroidDisplaySurface,
89    );
90
91    /// Obtains one buffer from the given Android Surface. The information about the buffer (buffer
92    /// address, size, stride, etc) is reported via the `ANativeWindow_Buffer` struct. It shouldn't
93    /// be null. The size of the buffer is guaranteed to be bigger than (width * stride * 4) bytes.
94    /// This function locks the buffer for the client, which means the caller has the exclusive
95    /// access to the buffer until it is returned back to Android display stack (surfaceflinger) by
96    /// calling `post_android_surface_buffer`. This function may fail (in which case false is
97    /// returned), then the caller shouldn't try to read `out_buffer` or use the buffer in any way.
98    fn get_android_surface_buffer(
99        ctx: *mut AndroidDisplayContext,
100        surface: *mut AndroidDisplaySurface,
101        out_buffer: *mut ANativeWindow_Buffer,
102    ) -> bool;
103
104    fn set_android_surface_position(ctx: *mut AndroidDisplayContext, x: u32, y: u32);
105
106    /// Posts the buffer obtained from `get_android_surface_buffer` to the Android display system
107    /// so that it can be displayed on the screen. Once this is called, the caller shouldn't use
108    /// the buffer any more.
109    fn post_android_surface_buffer(
110        ctx: *mut AndroidDisplayContext,
111        surface: *mut AndroidDisplaySurface,
112    );
113}
114
115unsafe extern "C" fn error_callback(message: *const c_char) {
116    catch_unwind(|| {
117        error!(
118            "{}",
119            // SAFETY: message is null terminated
120            unsafe { CStr::from_ptr(message) }.to_string_lossy()
121        )
122    })
123    .unwrap_or_else(|_| abort())
124}
125
126struct AndroidDisplayContextWrapper(NonNull<AndroidDisplayContext>);
127
128impl Drop for AndroidDisplayContextWrapper {
129    fn drop(&mut self) {
130        // SAFETY: this object is constructed from create_android_display_context
131        unsafe { destroy_android_display_context(self.0.as_ptr()) };
132    }
133}
134
135impl Default for ANativeWindow_Buffer {
136    fn default() -> Self {
137        Self {
138            width: 0,
139            height: 0,
140            stride: 0,
141            format: 0,
142            bits: std::ptr::null_mut(),
143            reserved: [0u32; 6],
144        }
145    }
146}
147
148impl From<ANativeWindow_Buffer> for GpuDisplayFramebuffer<'_> {
149    fn from(anb: ANativeWindow_Buffer) -> Self {
150        // TODO: check anb.format to see if it's ARGB8888?
151        // TODO: infer bpp from anb.format?
152        const BYTES_PER_PIXEL: u32 = 4;
153        let stride_bytes = BYTES_PER_PIXEL * u32::try_from(anb.stride).unwrap();
154        let buffer_size = stride_bytes * u32::try_from(anb.height).unwrap();
155        let buffer =
156            // SAFETY: get_android_surface_buffer guarantees that bits points to a valid buffer and
157            // the buffer remains available until post_android_surface_buffer is called.
158            unsafe { slice::from_raw_parts_mut(anb.bits, buffer_size.try_into().unwrap()) };
159        Self::new(VolatileSlice::new(buffer), stride_bytes, BYTES_PER_PIXEL)
160    }
161}
162
163struct AndroidSurface {
164    context: Rc<AndroidDisplayContextWrapper>,
165    surface: NonNull<AndroidDisplaySurface>,
166}
167
168impl GpuDisplaySurface for AndroidSurface {
169    fn framebuffer(&mut self) -> Option<GpuDisplayFramebuffer> {
170        let mut anb = ANativeWindow_Buffer::default();
171        // SAFETY: context and surface are opaque handles and buf is used as the out parameter to
172        // hold the return values.
173        let success = unsafe {
174            get_android_surface_buffer(
175                self.context.0.as_ptr(),
176                self.surface.as_ptr(),
177                &mut anb as *mut ANativeWindow_Buffer,
178            )
179        };
180        if success {
181            Some(anb.into())
182        } else {
183            None
184        }
185    }
186
187    fn flip(&mut self) {
188        // SAFETY: context and surface are opaque handles.
189        unsafe { post_android_surface_buffer(self.context.0.as_ptr(), self.surface.as_ptr()) }
190    }
191
192    fn set_position(&mut self, x: u32, y: u32) {
193        // SAFETY: context is an opaque handle.
194        unsafe { set_android_surface_position(self.context.0.as_ptr(), x, y) };
195    }
196}
197
198pub struct DisplayAndroid {
199    context: Rc<AndroidDisplayContextWrapper>,
200    /// This event is never triggered and is used solely to fulfill AsRawDescriptor.
201    event: Event,
202}
203
204impl DisplayAndroid {
205    pub fn new(name: &str) -> GpuDisplayResult<DisplayAndroid> {
206        let name = CString::new(name).unwrap();
207        let context = NonNull::new(
208            // SAFETY: service_name is not leaked outside of this function
209            unsafe { create_android_display_context(name.as_ptr(), error_callback) },
210        )
211        .ok_or(GpuDisplayError::Unsupported)?;
212        let context = AndroidDisplayContextWrapper(context);
213        let event = Event::new().map_err(|_| GpuDisplayError::CreateEvent)?;
214        Ok(DisplayAndroid {
215            context: context.into(),
216            event,
217        })
218    }
219}
220
221impl DisplayT for DisplayAndroid {
222    fn create_surface(
223        &mut self,
224        parent_surface_id: Option<u32>,
225        _surface_id: u32,
226        _scanout_id: Option<u32>,
227        display_params: &DisplayParameters,
228        _surf_type: SurfaceType,
229    ) -> GpuDisplayResult<Box<dyn GpuDisplaySurface>> {
230        let (requested_width, requested_height) = display_params.get_virtual_display_size();
231        // SAFETY: context is an opaque handle.
232        let surface = NonNull::new(unsafe {
233            create_android_surface(
234                self.context.0.as_ptr(),
235                requested_width,
236                requested_height,
237                parent_surface_id.is_some(),
238            )
239        })
240        .ok_or(GpuDisplayError::CreateSurface)?;
241
242        Ok(Box::new(AndroidSurface {
243            context: self.context.clone(),
244            surface,
245        }))
246    }
247}
248
249impl SysDisplayT for DisplayAndroid {}
250
251impl AsRawDescriptor for DisplayAndroid {
252    fn as_raw_descriptor(&self) -> RawDescriptor {
253        self.event.as_raw_descriptor()
254    }
255}