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