Skip to main content

kgsl_libmagma/
kgsl_libmagma.rs

1// Copyright 2025 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use magma::{
6    MAGMA_STATUS_OK, magma_buffer_get_handle, magma_buffer_id_t, magma_buffer_t,
7    magma_command_descriptor_t, magma_connection_create_buffer, magma_connection_create_context2,
8    magma_connection_create_semaphore, magma_connection_execute_command,
9    magma_connection_map_buffer, magma_connection_release, magma_connection_release_buffer,
10    magma_connection_release_context, magma_connection_release_semaphore, magma_connection_t,
11    magma_device_create_connection, magma_device_import, magma_device_query, magma_device_release,
12    magma_device_t, magma_handle_t, magma_initialize_logging, magma_priority_t, magma_query_t,
13    magma_semaphore_id_t, magma_semaphore_reset, magma_semaphore_signal, magma_semaphore_t,
14    magma_status_t,
15};
16use starnix_logging::log_error;
17use std::panic::Location;
18use std::sync::Arc;
19use zx::HandleBased;
20
21fn magma_result(status: magma_status_t) -> Result<(), magma_status_t> {
22    if status == MAGMA_STATUS_OK { Ok(()) } else { Err(status) }
23}
24
25trait KgslErrorLogger {
26    #[track_caller]
27    fn kgsl_log_error(self) -> Self;
28}
29
30impl<T> KgslErrorLogger for Result<T, magma_status_t> {
31    #[track_caller]
32    fn kgsl_log_error(self) -> Self {
33        match self {
34            Ok(v) => Ok(v),
35            Err(status) => {
36                let caller = Location::caller();
37                log_error!("kgsl: {}({}): {}", caller.file(), caller.line(), status);
38                Err(status)
39            }
40        }
41    }
42}
43
44pub fn initialize_logging(channel: zx::Channel) -> Result<(), ()> {
45    // Safety: magma_initialize_logging takes ownership of the channel.
46    let result = unsafe { magma_initialize_logging(channel.into_raw()) };
47    if result == MAGMA_STATUS_OK { Ok(()) } else { Err(()) }
48}
49
50#[derive(Debug)]
51pub enum QueryOutput {
52    Value(u64),
53    Buffer(zx::Vmo),
54}
55
56#[derive(Debug, Clone)]
57pub struct Device {
58    inner: Arc<DeviceInternal>,
59}
60
61#[derive(Debug)]
62struct DeviceInternal {
63    magma_device: magma_device_t,
64}
65
66impl Drop for DeviceInternal {
67    fn drop(&mut self) {
68        // Safety: magma_device_release takes ownership of the device handle.
69        unsafe { magma_device_release(self.magma_device) };
70    }
71}
72
73impl Device {
74    pub fn from_channel(channel: zx::Channel) -> Result<Self, magma_status_t> {
75        let mut magma_device: magma_device_t = 0;
76        // Safety: magma_device_import takes ownership of the channel and returns a
77        // device handle.
78        let result = unsafe { magma_device_import(channel.into_raw(), &mut magma_device) };
79        magma_result(result).kgsl_log_error()?;
80        Ok(Device { inner: Arc::new(DeviceInternal { magma_device }) })
81    }
82
83    pub fn query(&self, id: magma_query_t) -> Result<QueryOutput, magma_status_t> {
84        let mut result_out: u64 = 0;
85        let mut result_buffer_out: magma_handle_t = 0;
86        // Safety: magma_device_query borrows the device handle and maybe returns a
87        // buffer handle.
88        let result = unsafe {
89            magma_device_query(self.inner.magma_device, id, &mut result_buffer_out, &mut result_out)
90        };
91        magma_result(result).kgsl_log_error()?;
92        if result_buffer_out != 0 {
93            // Safety: from_raw takes ownership of the buffer handle.
94            return Ok(QueryOutput::Buffer(zx::Vmo::from_handle(unsafe {
95                zx::NullableHandle::from_raw(result_buffer_out)
96            })));
97        }
98        Ok(QueryOutput::Value(result_out))
99    }
100
101    pub fn create_connection(&self) -> Result<Connection, magma_status_t> {
102        let mut magma_connection: magma_connection_t = 0;
103        // Safety: magma_device_create_connection borrows the device handle and returns
104        // a connection handle.
105        let result = unsafe {
106            magma_device_create_connection(self.inner.magma_device, &mut magma_connection)
107        };
108        magma_result(result).kgsl_log_error()?;
109        Ok(Connection { inner: Arc::new(ConnectionInternal { magma_connection }) })
110    }
111}
112
113#[derive(Debug, Clone)]
114pub struct Connection {
115    inner: Arc<ConnectionInternal>,
116}
117
118#[derive(Debug)]
119struct ConnectionInternal {
120    magma_connection: magma_connection_t,
121}
122
123impl Drop for ConnectionInternal {
124    fn drop(&mut self) {
125        // Safety: magma_connection_release takes ownership of the connection handle.
126        unsafe { magma_connection_release(self.magma_connection) };
127    }
128}
129
130impl Connection {
131    pub fn create_context(&self, priority: magma_priority_t) -> Result<Context, magma_status_t> {
132        let mut magma_context_id: u32 = 0;
133        // Safety: magma_connection_create_context2 borrows the connection handle and
134        // returns a context id.
135        let result = unsafe {
136            magma_connection_create_context2(
137                self.inner.magma_connection,
138                priority,
139                &mut magma_context_id,
140            )
141        };
142        magma_result(result).kgsl_log_error()?;
143        Ok(Context {
144            inner: Arc::new(ContextInternal { connection: self.inner.clone(), magma_context_id }),
145        })
146    }
147
148    pub fn create_semaphore(&self) -> Result<Semaphore, magma_status_t> {
149        let mut magma_semaphore: magma_semaphore_t = 0;
150        let mut magma_semaphore_id: magma_semaphore_id_t = 0;
151        // Safety: magma_connection_create_semaphore borrows the connection handle and
152        // returns a semaphore handle.
153        let result = unsafe {
154            magma_connection_create_semaphore(
155                self.inner.magma_connection,
156                &mut magma_semaphore,
157                &mut magma_semaphore_id,
158            )
159        };
160        magma_result(result).kgsl_log_error()?;
161        Ok(Semaphore {
162            inner: Arc::new(SemaphoreInternal {
163                connection: self.inner.clone(),
164                magma_semaphore,
165                magma_semaphore_id,
166            }),
167        })
168    }
169
170    pub fn create_buffer(&self, size: u64) -> Result<Buffer, magma_status_t> {
171        let mut size_out: u64 = 0;
172        let mut magma_buffer: magma_buffer_t = 0;
173        let mut magma_buffer_id: magma_buffer_id_t = 0;
174        // Safety: magma_connection_create_buffer borrows the connection handle and
175        // returns a buffer handle.
176        let result = unsafe {
177            magma_connection_create_buffer(
178                self.inner.magma_connection,
179                size,
180                &mut size_out,
181                &mut magma_buffer,
182                &mut magma_buffer_id,
183            )
184        };
185        magma_result(result).kgsl_log_error()?;
186        Ok(Buffer {
187            inner: Arc::new(BufferInternal {
188                connection: self.inner.clone(),
189                magma_buffer,
190                magma_buffer_id,
191                size: size_out,
192            }),
193        })
194    }
195}
196
197#[derive(Debug, Clone)]
198pub struct Context {
199    inner: Arc<ContextInternal>,
200}
201
202#[derive(Debug)]
203struct ContextInternal {
204    connection: Arc<ConnectionInternal>,
205    magma_context_id: u32,
206}
207
208impl Drop for ContextInternal {
209    fn drop(&mut self) {
210        // Safety: magma_connection_release_context borrows the connection handle and
211        // takes ownership of the context id.
212        unsafe {
213            magma_connection_release_context(
214                self.connection.magma_connection,
215                self.magma_context_id,
216            )
217        };
218    }
219}
220
221pub struct ExecResource {
222    pub buffer: Buffer,
223    pub offset: u64,
224    pub length: u64,
225}
226
227impl Context {
228    pub fn execute_command(
229        &self,
230        command_buffers: Vec<ExecResource>,
231        resources: Vec<ExecResource>,
232        wait_semaphores: Vec<Semaphore>,
233        signal_semaphores: Vec<Semaphore>,
234        flags: u64,
235    ) -> Result<(), magma_status_t> {
236        // Concatenate resources and command buffers into a single list of resources.
237        let mut magma_resources: Vec<magma::magma_exec_resource> = resources
238            .iter()
239            .chain(command_buffers.iter())
240            .map(|r| magma::magma_exec_resource {
241                buffer_id: r.buffer.id(),
242                offset: r.offset,
243                length: r.length,
244            })
245            .collect();
246
247        // Create command buffers, pointing to the command buffer resources.
248        let mut magma_command_buffers: Vec<magma::magma_exec_command_buffer> = command_buffers
249            .iter()
250            .enumerate()
251            .map(|(i, _)| magma::magma_exec_command_buffer {
252                resource_index: (resources.len() + i) as u32,
253                unused: 0,
254                start_offset: 0,
255            })
256            .collect();
257
258        // Concatenate wait and signal semaphores.
259        let mut semaphore_ids: Vec<u64> = wait_semaphores
260            .iter()
261            .map(|s| s.id())
262            .chain(signal_semaphores.iter().map(|s| s.id()))
263            .collect();
264
265        let mut descriptor = magma_command_descriptor_t {
266            resource_count: magma_resources.len() as u32,
267            command_buffer_count: magma_command_buffers.len() as u32,
268            wait_semaphore_count: wait_semaphores.len() as u32,
269            signal_semaphore_count: signal_semaphores.len() as u32,
270            resources: magma_resources.as_mut_ptr(),
271            command_buffers: magma_command_buffers.as_mut_ptr(),
272            semaphore_ids: semaphore_ids.as_mut_ptr(),
273            flags,
274        };
275
276        // Safety: magma_connection_execute_command borrows all parameters.
277        let result = unsafe {
278            magma_connection_execute_command(
279                self.inner.connection.magma_connection,
280                self.inner.magma_context_id,
281                &mut descriptor,
282            )
283        };
284        magma_result(result).kgsl_log_error()?;
285        Ok(())
286    }
287}
288
289#[derive(Debug, Clone)]
290pub struct Semaphore {
291    inner: Arc<SemaphoreInternal>,
292}
293
294impl Semaphore {
295    pub fn id(&self) -> magma_semaphore_id_t {
296        self.inner.magma_semaphore_id
297    }
298
299    pub fn signal(&self) {
300        // Safety: magma_semaphore_signal borrows the semaphore handle.
301        unsafe { magma_semaphore_signal(self.inner.magma_semaphore) }
302    }
303
304    pub fn reset(&self) {
305        // Safety: magma_semaphore_reset borrows the semaphore handle.
306        unsafe { magma_semaphore_reset(self.inner.magma_semaphore) }
307    }
308}
309
310#[derive(Debug)]
311struct SemaphoreInternal {
312    connection: Arc<ConnectionInternal>,
313    magma_semaphore: magma_semaphore_t,
314    magma_semaphore_id: magma_semaphore_id_t,
315}
316
317impl Drop for SemaphoreInternal {
318    fn drop(&mut self) {
319        // Safety: magma_connection_release_semaphore borrows the connection handle and
320        // takes ownership of the semaphore handle.
321        unsafe {
322            magma_connection_release_semaphore(
323                self.connection.magma_connection,
324                self.magma_semaphore,
325            )
326        };
327    }
328}
329
330#[derive(Debug, Clone)]
331pub struct Buffer {
332    inner: Arc<BufferInternal>,
333}
334
335impl Buffer {
336    pub fn id(&self) -> magma_buffer_id_t {
337        self.inner.magma_buffer_id
338    }
339
340    pub fn size(&self) -> u64 {
341        self.inner.size
342    }
343
344    pub fn get_handle(&self) -> Result<zx::NullableHandle, magma_status_t> {
345        let mut handle: magma_handle_t = 0;
346        // Safety: magma_buffer_get_handle borrows the buffer handle and maybe returns a handle.
347        let result = unsafe { magma_buffer_get_handle(self.inner.magma_buffer, &mut handle) };
348        magma_result(result).kgsl_log_error()?;
349        // Safety: from_raw takes ownership of the handle.
350        let handle = unsafe { zx::NullableHandle::from_raw(handle) };
351        Ok(handle)
352    }
353
354    pub fn map(
355        &self,
356        hw_va: u64,
357        offset: u64,
358        length: u64,
359        flags: u64,
360    ) -> Result<(), magma_status_t> {
361        // Safety: magma_connection_map_buffer borrows the connection handle and buffer handle.
362        let result = unsafe {
363            magma_connection_map_buffer(
364                self.inner.connection.magma_connection,
365                hw_va,
366                self.inner.magma_buffer,
367                offset,
368                length,
369                flags,
370            )
371        };
372        magma_result(result).kgsl_log_error()?;
373        Ok(())
374    }
375}
376
377#[derive(Debug)]
378struct BufferInternal {
379    connection: Arc<ConnectionInternal>,
380    magma_buffer: magma_buffer_t,
381    magma_buffer_id: magma_buffer_id_t,
382    size: u64,
383}
384
385impl Drop for BufferInternal {
386    fn drop(&mut self) {
387        // Safety: magma_connection_release_buffer borrows the connection handle and
388        // takes ownership of the buffer handle.
389        unsafe {
390            magma_connection_release_buffer(self.connection.magma_connection, self.magma_buffer)
391        };
392    }
393}