1use std::ffi::c_void;
2
3use cudarc::driver::{self, SyncOnDrop};
4
5pub use cudarc::driver::{
6 sys, CudaSlice, CudaStream, CudaView, CudaViewMut, DevicePtr, DevicePtrMut, DeviceRepr,
7 DeviceSlice, DriverError, LaunchConfig, ValidAsZeroBits,
8};
9
10pub use crate::device::CudaFunction;
11
12mod sealed {
13 pub trait KernelScalarSealed {}
14
15 macro_rules! impl_kernel_scalar_sealed {
16 ($($ty:ty),* $(,)?) => {
17 $(impl KernelScalarSealed for $ty {})*
18 };
19 }
20
21 impl_kernel_scalar_sealed!(
22 bool, i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize, f32, f64
23 );
24}
25
26pub trait KernelParamStorage {
28 fn as_kernel_param(&self) -> *mut c_void;
29}
30
31#[derive(Debug)]
32pub struct ScalarParamStorage<T>(T);
33
34impl<T> KernelParamStorage for ScalarParamStorage<T> {
35 fn as_kernel_param(&self) -> *mut c_void {
36 (&self.0 as *const T).cast_mut().cast()
37 }
38}
39
40#[derive(Debug)]
41pub struct DeviceParamStorage<'a> {
42 ptr: driver::sys::CUdeviceptr,
43 _sync: Option<SyncOnDrop<'a>>,
44}
45
46impl<'a> DeviceParamStorage<'a> {
47 pub fn synced(ptr: driver::sys::CUdeviceptr, sync: SyncOnDrop<'a>) -> Self {
48 Self {
49 ptr,
50 _sync: Some(sync),
51 }
52 }
53
54 pub fn unsynced(ptr: driver::sys::CUdeviceptr) -> Self {
55 Self { ptr, _sync: None }
56 }
57}
58
59impl KernelParamStorage for DeviceParamStorage<'_> {
60 fn as_kernel_param(&self) -> *mut c_void {
61 (&self.ptr as *const driver::sys::CUdeviceptr)
62 .cast_mut()
63 .cast()
64 }
65}
66
67pub trait AsKernelParam {
69 fn as_kernel_param(&self) -> *mut c_void;
70}
71
72pub trait IntoKernelParamStorage {
74 type Storage: KernelParamStorage;
75
76 fn into_kernel_param_storage(self) -> Self::Storage;
77}
78
79pub trait KernelScalar:
81 sealed::KernelScalarSealed
82 + cudarc::driver::DeviceRepr
83 + Copy
84 + 'static
85 + AsKernelParam
86 + IntoKernelParamStorage
87{
88}
89
90macro_rules! impl_kernel_scalar {
91 ($($ty:ty),* $(,)?) => {
92 $(
93 impl KernelScalar for $ty {}
94
95 impl AsKernelParam for $ty {
96 fn as_kernel_param(&self) -> *mut c_void {
97 (self as *const $ty).cast_mut().cast()
98 }
99 }
100
101 impl AsKernelParam for &$ty {
102 fn as_kernel_param(&self) -> *mut c_void {
103 (*self as *const $ty).cast_mut().cast()
104 }
105 }
106
107 impl AsKernelParam for &mut $ty {
108 fn as_kernel_param(&self) -> *mut c_void {
109 (*self as *const $ty).cast_mut().cast()
110 }
111 }
112
113 impl IntoKernelParamStorage for $ty {
114 type Storage = ScalarParamStorage<$ty>;
115
116 fn into_kernel_param_storage(self) -> Self::Storage {
117 ScalarParamStorage(self)
118 }
119 }
120 )*
121 };
122}
123
124impl_kernel_scalar!(bool, i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize, f32, f64);
125
126impl<'a, T> IntoKernelParamStorage for &'a CudaSlice<T> {
127 type Storage = DeviceParamStorage<'a>;
128
129 fn into_kernel_param_storage(self) -> Self::Storage {
130 let stream = self.stream();
131 let (ptr, sync) = cudarc::driver::DevicePtr::device_ptr(self, stream);
132 DeviceParamStorage::synced(ptr, sync)
133 }
134}
135
136impl<T> IntoKernelParamStorage for &mut CudaSlice<T> {
137 type Storage = DeviceParamStorage<'static>;
138
139 fn into_kernel_param_storage(self) -> Self::Storage {
140 let stream = self.stream().clone();
141 let (ptr, sync) = cudarc::driver::DevicePtrMut::device_ptr_mut(self, &stream);
142 std::mem::forget(sync);
143 DeviceParamStorage::unsynced(ptr)
144 }
145}
146
147impl<'a, 'b, T> IntoKernelParamStorage for &'a CudaView<'b, T> {
148 type Storage = DeviceParamStorage<'a>;
149
150 fn into_kernel_param_storage(self) -> Self::Storage {
151 let stream = self.stream();
152 let (ptr, sync) = cudarc::driver::DevicePtr::device_ptr(self, stream);
153 DeviceParamStorage::synced(ptr, sync)
154 }
155}
156
157impl<'a, 'b, T> IntoKernelParamStorage for &'a CudaViewMut<'b, T> {
158 type Storage = DeviceParamStorage<'a>;
159
160 fn into_kernel_param_storage(self) -> Self::Storage {
161 let stream = self.stream();
162 let (ptr, sync) = cudarc::driver::DevicePtr::device_ptr(self, stream);
163 DeviceParamStorage::synced(ptr, sync)
164 }
165}
166
167impl<'a, 'b, T> IntoKernelParamStorage for &'a mut CudaViewMut<'b, T> {
168 type Storage = DeviceParamStorage<'static>;
169
170 fn into_kernel_param_storage(self) -> Self::Storage {
171 let stream = self.stream().clone();
172 let (ptr, sync) = cudarc::driver::DevicePtrMut::device_ptr_mut(self, &stream);
173 std::mem::forget(sync);
174 DeviceParamStorage::unsynced(ptr)
175 }
176}
177
178pub unsafe trait LaunchAsync<Params> {
186 unsafe fn launch(self, cfg: LaunchConfig, params: Params) -> Result<(), DriverError>;
192
193 unsafe fn launch_on_stream(
199 self,
200 stream: &CudaStream,
201 cfg: LaunchConfig,
202 params: Params,
203 ) -> Result<(), DriverError>;
204
205 unsafe fn launch_cooperative(
212 self,
213 cfg: LaunchConfig,
214 params: Params,
215 ) -> Result<(), DriverError>;
216
217 unsafe fn launch_cooperative_on_stream(
224 self,
225 stream: &CudaStream,
226 cfg: LaunchConfig,
227 params: Params,
228 ) -> Result<(), DriverError>;
229}
230
231unsafe impl LaunchAsync<&mut [*mut c_void]> for CudaFunction {
232 unsafe fn launch(
233 self,
234 cfg: LaunchConfig,
235 params: &mut [*mut c_void],
236 ) -> Result<(), DriverError> {
237 self.launch_raw(cfg, params)
238 }
239
240 unsafe fn launch_on_stream(
241 self,
242 stream: &CudaStream,
243 cfg: LaunchConfig,
244 params: &mut [*mut c_void],
245 ) -> Result<(), DriverError> {
246 self.launch_raw_on_stream(stream, cfg, params)
247 }
248
249 unsafe fn launch_cooperative(
250 self,
251 cfg: LaunchConfig,
252 params: &mut [*mut c_void],
253 ) -> Result<(), DriverError> {
254 self.launch_raw_cooperative(cfg, params)
255 }
256
257 unsafe fn launch_cooperative_on_stream(
258 self,
259 stream: &CudaStream,
260 cfg: LaunchConfig,
261 params: &mut [*mut c_void],
262 ) -> Result<(), DriverError> {
263 self.launch_raw_cooperative_on_stream(stream, cfg, params)
264 }
265}
266
267unsafe impl LaunchAsync<&mut Vec<*mut c_void>> for CudaFunction {
268 unsafe fn launch(
269 self,
270 cfg: LaunchConfig,
271 params: &mut Vec<*mut c_void>,
272 ) -> Result<(), DriverError> {
273 self.launch_raw(cfg, params)
274 }
275
276 unsafe fn launch_on_stream(
277 self,
278 stream: &CudaStream,
279 cfg: LaunchConfig,
280 params: &mut Vec<*mut c_void>,
281 ) -> Result<(), DriverError> {
282 self.launch_raw_on_stream(stream, cfg, params)
283 }
284
285 unsafe fn launch_cooperative(
286 self,
287 cfg: LaunchConfig,
288 params: &mut Vec<*mut c_void>,
289 ) -> Result<(), DriverError> {
290 self.launch_raw_cooperative(cfg, params)
291 }
292
293 unsafe fn launch_cooperative_on_stream(
294 self,
295 stream: &CudaStream,
296 cfg: LaunchConfig,
297 params: &mut Vec<*mut c_void>,
298 ) -> Result<(), DriverError> {
299 self.launch_raw_cooperative_on_stream(stream, cfg, params)
300 }
301}
302
303macro_rules! impl_launch_tuple {
304 ([$($var:ident),*], [$($idx:tt),*]) => {
305 #[allow(non_snake_case)]
306 unsafe impl<$($var: IntoKernelParamStorage),*> LaunchAsync<($($var,)*)> for CudaFunction {
307 unsafe fn launch(
308 self,
309 cfg: LaunchConfig,
310 params: ($($var,)*),
311 ) -> Result<(), DriverError> {
312 let ($($var,)*) = params;
313 $(let $var = $var.into_kernel_param_storage();)*
314 let mut raw = [$( $var.as_kernel_param(), )*];
315 self.launch_raw(cfg, &mut raw)
316 }
317
318 unsafe fn launch_on_stream(
319 self,
320 stream: &CudaStream,
321 cfg: LaunchConfig,
322 params: ($($var,)*),
323 ) -> Result<(), DriverError> {
324 let ($($var,)*) = params;
325 $(let $var = $var.into_kernel_param_storage();)*
326 let mut raw = [$( $var.as_kernel_param(), )*];
327 self.launch_raw_on_stream(stream, cfg, &mut raw)
328 }
329
330 unsafe fn launch_cooperative(
331 self,
332 cfg: LaunchConfig,
333 params: ($($var,)*),
334 ) -> Result<(), DriverError> {
335 let ($($var,)*) = params;
336 $(let $var = $var.into_kernel_param_storage();)*
337 let mut raw = [$( $var.as_kernel_param(), )*];
338 self.launch_raw_cooperative(cfg, &mut raw)
339 }
340
341 unsafe fn launch_cooperative_on_stream(
342 self,
343 stream: &CudaStream,
344 cfg: LaunchConfig,
345 params: ($($var,)*),
346 ) -> Result<(), DriverError> {
347 let ($($var,)*) = params;
348 $(let $var = $var.into_kernel_param_storage();)*
349 let mut raw = [$( $var.as_kernel_param(), )*];
350 self.launch_raw_cooperative_on_stream(stream, cfg, &mut raw)
351 }
352 }
353 };
354}
355
356impl_launch_tuple!([A], [0]);
357impl_launch_tuple!([A, B], [0, 1]);
358impl_launch_tuple!([A, B, C], [0, 1, 2]);
359impl_launch_tuple!([A, B, C, D], [0, 1, 2, 3]);
360impl_launch_tuple!([A, B, C, D, E], [0, 1, 2, 3, 4]);
361impl_launch_tuple!([A, B, C, D, E, F], [0, 1, 2, 3, 4, 5]);
362impl_launch_tuple!([A, B, C, D, E, F, G], [0, 1, 2, 3, 4, 5, 6]);
363impl_launch_tuple!([A, B, C, D, E, F, G, H], [0, 1, 2, 3, 4, 5, 6, 7]);
364impl_launch_tuple!([A, B, C, D, E, F, G, H, I], [0, 1, 2, 3, 4, 5, 6, 7, 8]);
365impl_launch_tuple!(
366 [A, B, C, D, E, F, G, H, I, J],
367 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
368);
369impl_launch_tuple!(
370 [A, B, C, D, E, F, G, H, I, J, K],
371 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
372);
373impl_launch_tuple!(
374 [A, B, C, D, E, F, G, H, I, J, K, L],
375 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
376);
377impl_launch_tuple!(
378 [A, B, C, D, E, F, G, H, I, J, K, L, M],
379 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
380);