xref: /aosp_15_r20/external/mesa3d/src/gallium/frontends/rusticl/api/types.rs (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 use crate::api::icd::CLResult;
2 use crate::api::icd::ReferenceCountedAPIPointer;
3 use crate::core::context::Context;
4 use crate::core::event::Event;
5 use crate::core::memory::MemBase;
6 use crate::core::program::Program;
7 use crate::core::queue::Queue;
8 
9 use rusticl_opencl_gen::*;
10 
11 use std::borrow::Borrow;
12 use std::ffi::c_void;
13 use std::ffi::CStr;
14 use std::iter::Product;
15 
16 macro_rules! cl_callback {
17     ($cb:ident($fn_alias:ident) {
18         $($p:ident : $ty:ty,)*
19     }) => {
20         pub type $fn_alias = unsafe extern "C" fn(
21             $($p: $ty,)*
22         );
23 
24         // INVARIANT:
25         // All safety requirements on `func` and `data` documented on `$cb::new` are invariants.
26         #[allow(dead_code)]
27         pub struct $cb {
28             func: $fn_alias,
29             data: *mut c_void,
30         }
31 
32         #[allow(dead_code)]
33         impl $cb {
34             /// Creates a new `$cb`. Returns `Err(CL_INVALID_VALUE)` if `func` is `None`.
35             ///
36             /// # SAFETY:
37             ///
38             /// If `func` is `None`, there are no safety requirements. Otherwise:
39             ///
40             /// - `func` must be a thread-safe fn.
41             /// - Passing `data` as the last parameter to `func` must not cause unsoundness.
42             /// - CreateContextCB: `func` must be soundly callable as documented on
43             ///   [`clCreateContext`] in the OpenCL specification.
44             /// - DeleteContextCB: `func` must be soundly callable as documented on
45             ///   [`clSetContextDestructorCallback`] in the OpenCL specification.
46             /// - EventCB: `func` must be soundly callable as documented on
47             ///   [`clSetEventCallback`] in the OpenCL specification.
48             /// - MemCB: `func` must be soundly callable as documented on
49             ///   [`clSetMemObjectDestructorCallback`] in the OpenCL specification.
50             /// - ProgramCB: `func` must be soundly callable as documented on
51             ///   [`clBuildProgram`] in the OpenCL specification.
52             /// - SVMFreeCb: `func` must be soundly callable as documented on
53             ///   [`clEnqueueSVMFree`] in the OpenCL specification.
54             ///
55             /// [`clCreateContext`]: https://registry.khronos.org/OpenCL/specs/3.0-unified/html/OpenCL_API.html#clCreateContext
56             /// [`clSetContextDestructorCallback`]: https://registry.khronos.org/OpenCL/specs/3.0-unified/html/OpenCL_API.html#clSetContextDestructorCallback
57             /// [`clSetEventCallback`]: https://registry.khronos.org/OpenCL/specs/3.0-unified/html/OpenCL_API.html#clSetEventCallback
58             /// [`clSetMemObjectDestructorCallback`]: https://registry.khronos.org/OpenCL/specs/3.0-unified/html/OpenCL_API.html#clSetMemObjectDestructorCallback
59             /// [`clBuildProgram`]: https://registry.khronos.org/OpenCL/specs/3.0-unified/html/OpenCL_API.html#clBuildProgram
60             /// [`clEnqueueSVMFree`]: https://registry.khronos.org/OpenCL/specs/3.0-unified/html/OpenCL_API.html#clEnqueueSVMFree
61             pub unsafe fn new(func: Option<$fn_alias>, data: *mut c_void) -> CLResult<Self> {
62                 let Some(func) = func else {
63                     return Err(CL_INVALID_VALUE);
64                 };
65                 Ok(Self { func, data })
66             }
67 
68             /// Creates a new Option(`$cb`). Returns:
69             /// - `Ok(Some($cb)) if `func` is `Some(_)`.
70             /// - `Ok(None)` if `func` is `None` and `data` is `null`.
71             /// - `Err(CL_INVALID_VALUE)` if `func` is `None` and `data` is not `null`.
72             ///
73             /// # SAFETY:
74             ///
75             /// The safety requirements are identical to those of [`new`].
76             pub unsafe fn try_new(func: Option<$fn_alias>, data: *mut c_void) -> CLResult<Option<Self>> {
77                 let Some(func) = func else {
78                     return if data.is_null() {
79                         Ok(None)
80                     } else {
81                         Err(CL_INVALID_VALUE)
82                     };
83                 };
84                 Ok(Some(Self { func, data }))
85             }
86         }
87 
88         unsafe impl Send for $cb {}
89         unsafe impl Sync for $cb {}
90     }
91 }
92 
93 cl_callback!(
94     CreateContextCB(FuncCreateContextCB) {
95         errinfo: *const ::std::os::raw::c_char,
96         private_info: *const c_void,
97         cb: usize,
98         user_data: *mut c_void,
99     }
100 );
101 
102 impl CreateContextCB {
_call(self, err_msg: &CStr, private_info: &[u8])103     pub fn _call(self, err_msg: &CStr, private_info: &[u8]) {
104         let err_msg_ptr = err_msg.as_ptr();
105         let private_info_ptr = private_info.as_ptr().cast::<c_void>();
106         // SAFETY: The first parameter must be a valid pointer to a NUL-terminated C string. We
107         // know this is satisfied since that is `CStr`'s type invariant.
108         // The second parameter must be a valid pointer to binary data with the length given in the
109         // thrid parameter. We know both of these are correct since we just got them from a byte slice.
110         // All other requirements are covered by this callback's type invariants.
111         unsafe { (self.func)(err_msg_ptr, private_info_ptr, private_info.len(), self.data) };
112     }
113 }
114 
115 cl_callback!(
116     DeleteContextCB(FuncDeleteContextCB) {
117         context: cl_context,
118         user_data: *mut c_void,
119     }
120 );
121 
122 impl DeleteContextCB {
call(self, ctx: &Context)123     pub fn call(self, ctx: &Context) {
124         let cl = cl_context::from_ptr(ctx);
125         // SAFETY: `cl` must have pointed to an OpenCL context, which is where we just got it from.
126         // All other requirements are covered by this callback's type invariants.
127         unsafe { (self.func)(cl, self.data) };
128     }
129 }
130 
131 cl_callback!(
132     EventCB(FuncEventCB) {
133         event: cl_event,
134         event_command_status: cl_int,
135         user_data: *mut c_void,
136     }
137 );
138 
139 impl EventCB {
call(self, event: &Event, status: cl_int)140     pub fn call(self, event: &Event, status: cl_int) {
141         let cl = cl_event::from_ptr(event);
142         // SAFETY: `cl` must be a valid pointer to an OpenCL event, which is where we just got it from.
143         // All other requirements are covered by this callback's type invariants.
144         unsafe { (self.func)(cl, status, self.data) };
145     }
146 }
147 
148 cl_callback!(
149     MemCB(FuncMemCB) {
150         memobj: cl_mem,
151         user_data: *mut c_void,
152     }
153 );
154 
155 impl MemCB {
call(self, mem: &MemBase)156     pub fn call(self, mem: &MemBase) {
157         let cl = cl_mem::from_ptr(mem);
158         // SAFETY: `cl` must have pointed to an OpenCL context, which is where we just got it from.
159         // All other requirements are covered by this callback's type invariants.
160         unsafe { (self.func)(cl, self.data) };
161     }
162 }
163 
164 cl_callback!(
165     ProgramCB(FuncProgramCB) {
166         program: cl_program,
167         user_data: *mut c_void,
168     }
169 );
170 
171 impl ProgramCB {
call(self, program: &Program)172     pub fn call(self, program: &Program) {
173         let cl = cl_program::from_ptr(program);
174         // SAFETY: `cl` must have pointed to an OpenCL program, which is where we just got it from.
175         // All other requirements are covered by this callback's type invariants.
176         unsafe { (self.func)(cl, self.data) };
177     }
178 }
179 
180 cl_callback!(
181     SVMFreeCb(FuncSVMFreeCb) {
182         queue: cl_command_queue,
183         num_svm_pointers: cl_uint,
184         svm_pointers: *mut *mut c_void,
185         user_data: *mut c_void,
186     }
187 );
188 
189 impl SVMFreeCb {
call(self, queue: &Queue, svm_pointers: &mut [usize])190     pub fn call(self, queue: &Queue, svm_pointers: &mut [usize]) {
191         let cl = cl_command_queue::from_ptr(queue);
192         // SAFETY: `cl` must be a valid pointer to an OpenCL queue, which is where we just got it from.
193         // All other requirements are covered by this callback's type invariants.
194         unsafe {
195             (self.func)(
196                 cl,
197                 svm_pointers.len() as u32,
198                 svm_pointers.as_mut_ptr().cast(),
199                 self.data,
200             )
201         };
202     }
203 }
204 
205 // a lot of APIs use 3 component vectors passed as C arrays
206 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
207 pub struct CLVec<T> {
208     vals: [T; 3],
209 }
210 
211 impl<T: Copy> CLVec<T> {
new(vals: [T; 3]) -> Self212     pub fn new(vals: [T; 3]) -> Self {
213         Self { vals: vals }
214     }
215 
216     /// # Safety
217     ///
218     /// This function is intended for use around OpenCL vectors of size 3.
219     /// Most commonly for `origin` and `region` API arguments.
220     ///
221     /// Using it for anything else is undefined.
from_raw(v: *const T) -> Self222     pub unsafe fn from_raw(v: *const T) -> Self {
223         Self {
224             vals: unsafe { *v.cast() },
225         }
226     }
227 
pixels<'a>(&'a self) -> T where T: Product<&'a T>,228     pub fn pixels<'a>(&'a self) -> T
229     where
230         T: Product<&'a T>,
231     {
232         self.vals.iter().product()
233     }
234 }
235 
236 impl CLVec<usize> {
237     /// returns the offset of point in linear memory.
calc_offset<T: Borrow<Self>>(point: T, pitch: [usize; 3]) -> usize238     pub fn calc_offset<T: Borrow<Self>>(point: T, pitch: [usize; 3]) -> usize {
239         *point.borrow() * pitch
240     }
241 
242     /// returns the scalar size of the described region in linear memory.
calc_size<T: Borrow<Self>>(region: T, pitch: [usize; 3]) -> usize243     pub fn calc_size<T: Borrow<Self>>(region: T, pitch: [usize; 3]) -> usize {
244         (*region.borrow() - [0, 1, 1]) * pitch
245     }
246 
calc_offset_size<T1: Borrow<Self>, T2: Borrow<Self>>( base: T1, region: T2, pitch: [usize; 3], ) -> (usize, usize)247     pub fn calc_offset_size<T1: Borrow<Self>, T2: Borrow<Self>>(
248         base: T1,
249         region: T2,
250         pitch: [usize; 3],
251     ) -> (usize, usize) {
252         (
253             Self::calc_offset(base, pitch),
254             Self::calc_size(region, pitch),
255         )
256     }
257 }
258 
259 impl<T: Default + Copy> Default for CLVec<T> {
default() -> Self260     fn default() -> Self {
261         Self {
262             vals: [T::default(); 3],
263         }
264     }
265 }
266 
267 // provides a ton of functions
268 impl<T> std::ops::Deref for CLVec<T> {
269     type Target = [T; 3];
270 
deref(&self) -> &Self::Target271     fn deref(&self) -> &Self::Target {
272         &self.vals
273     }
274 }
275 
276 impl<T> std::ops::DerefMut for CLVec<T> {
deref_mut(&mut self) -> &mut Self::Target277     fn deref_mut(&mut self) -> &mut Self::Target {
278         &mut self.vals
279     }
280 }
281 
282 impl<T: Copy + std::ops::Add<Output = T>> std::ops::Add for CLVec<T> {
283     type Output = Self;
284 
add(self, other: Self) -> Self285     fn add(self, other: Self) -> Self {
286         self + other.vals
287     }
288 }
289 
290 impl<T: Copy + std::ops::Add<Output = T>> std::ops::Add<[T; 3]> for CLVec<T> {
291     type Output = Self;
292 
add(self, other: [T; 3]) -> Self293     fn add(self, other: [T; 3]) -> Self {
294         Self {
295             vals: [self[0] + other[0], self[1] + other[1], self[2] + other[2]],
296         }
297     }
298 }
299 
300 impl<T: Copy + std::ops::Sub<Output = T>> std::ops::Sub<[T; 3]> for CLVec<T> {
301     type Output = Self;
302 
sub(self, other: [T; 3]) -> Self303     fn sub(self, other: [T; 3]) -> Self {
304         Self {
305             vals: [self[0] - other[0], self[1] - other[1], self[2] - other[2]],
306         }
307     }
308 }
309 
310 impl<T> std::ops::Mul for CLVec<T>
311 where
312     T: Copy + std::ops::Mul<Output = T> + std::ops::Add<Output = T>,
313 {
314     type Output = T;
315 
mul(self, other: Self) -> T316     fn mul(self, other: Self) -> T {
317         self * other.vals
318     }
319 }
320 
321 impl<T> std::ops::Mul<[T; 3]> for CLVec<T>
322 where
323     T: Copy + std::ops::Mul<Output = T> + std::ops::Add<Output = T>,
324 {
325     type Output = T;
326 
mul(self, other: [T; 3]) -> T327     fn mul(self, other: [T; 3]) -> T {
328         self[0] * other[0] + self[1] * other[1] + self[2] * other[2]
329     }
330 }
331 
332 impl<S, T> TryInto<[T; 3]> for CLVec<S>
333 where
334     S: Copy,
335     T: TryFrom<S>,
336     [T; 3]: TryFrom<Vec<T>>,
337 {
338     type Error = cl_int;
339 
try_into(self) -> Result<[T; 3], cl_int>340     fn try_into(self) -> Result<[T; 3], cl_int> {
341         let vec: Result<Vec<T>, _> = self
342             .vals
343             .iter()
344             .map(|v| T::try_from(*v).map_err(|_| CL_OUT_OF_HOST_MEMORY))
345             .collect();
346         vec?.try_into().map_err(|_| CL_OUT_OF_HOST_MEMORY)
347     }
348 }
349 
350 impl<T> From<[T; 3]> for CLVec<T>
351 where
352     T: Copy,
353 {
from(arr: [T; 3]) -> Self354     fn from(arr: [T; 3]) -> Self {
355         Self::new(arr)
356     }
357 }
358 
359 #[allow(non_snake_case)]
360 pub mod IdpAccelProps {
361     use rusticl_opencl_gen::cl_bool;
362     use rusticl_opencl_gen::cl_device_integer_dot_product_acceleration_properties_khr;
new( signed_accelerated: cl_bool, unsigned_accelerated: cl_bool, mixed_signedness_accelerated: cl_bool, accumulating_saturating_signed_accelerated: cl_bool, accumulating_saturating_unsigned_accelerated: cl_bool, accumulating_saturating_mixed_signedness_accelerated: cl_bool, ) -> cl_device_integer_dot_product_acceleration_properties_khr363     pub fn new(
364         signed_accelerated: cl_bool,
365         unsigned_accelerated: cl_bool,
366         mixed_signedness_accelerated: cl_bool,
367         accumulating_saturating_signed_accelerated: cl_bool,
368         accumulating_saturating_unsigned_accelerated: cl_bool,
369         accumulating_saturating_mixed_signedness_accelerated: cl_bool,
370     ) -> cl_device_integer_dot_product_acceleration_properties_khr {
371         cl_device_integer_dot_product_acceleration_properties_khr {
372             signed_accelerated,
373             unsigned_accelerated,
374             mixed_signedness_accelerated,
375             accumulating_saturating_signed_accelerated,
376             accumulating_saturating_unsigned_accelerated,
377             accumulating_saturating_mixed_signedness_accelerated,
378         }
379     }
380 }
381