1use core::ffi::c_void;
9
10use crate::drv::{
11 self, Loaded, ZeCommandListDesc, ZeCommandListHandle, ZeCommandQueueDesc, ZeCommandQueueHandle,
12 ZeContextDesc, ZeContextHandle, ZeDeviceHandle, ZeDeviceMemAllocDesc, ZeDriverHandle,
13 ZeGroupCount, ZeHostMemAllocDesc, ZeKernelDesc, ZeKernelHandle, ZeModuleDesc, ZeModuleHandle,
14 ZE_COMMAND_QUEUE_MODE_DEFAULT, ZE_COMMAND_QUEUE_PRIORITY_NORMAL, ZE_MODULE_FORMAT_IL_SPIRV,
15 ZE_RESULT_SUCCESS, ZE_STRUCTURE_TYPE_COMMAND_LIST_DESC, ZE_STRUCTURE_TYPE_COMMAND_QUEUE_DESC,
16 ZE_STRUCTURE_TYPE_CONTEXT_DESC, ZE_STRUCTURE_TYPE_DEVICE_MEM_ALLOC_DESC,
17 ZE_STRUCTURE_TYPE_HOST_MEM_ALLOC_DESC, ZE_STRUCTURE_TYPE_KERNEL_DESC,
18 ZE_STRUCTURE_TYPE_MODULE_DESC,
19};
20
21pub struct Context {
22 l: &'static Loaded,
23 pub driver: ZeDriverHandle,
24 pub device: ZeDeviceHandle,
25 pub context: ZeContextHandle,
26 pub queue: ZeCommandQueueHandle,
27 pub list: ZeCommandListHandle,
28 pub queue_ordinal: u32,
31}
32
33impl Context {
34 pub fn new(global_ordinal: u32) -> Option<Self> {
38 let l = drv::loaded()?;
39 unsafe {
40 let (driver, device) = locate_device(l, global_ordinal)?;
41
42 let mut context: ZeContextHandle = core::ptr::null_mut();
43 let ctx_desc = ZeContextDesc {
44 stype: ZE_STRUCTURE_TYPE_CONTEXT_DESC,
45 p_next: core::ptr::null(),
46 flags: 0,
47 };
48 if (l.ze_context_create)(driver, &ctx_desc, &mut context) != ZE_RESULT_SUCCESS {
49 return None;
50 }
51
52 let queue_ordinal = 0u32;
57
58 let mut queue: ZeCommandQueueHandle = core::ptr::null_mut();
59 let q_desc = ZeCommandQueueDesc {
60 stype: ZE_STRUCTURE_TYPE_COMMAND_QUEUE_DESC,
61 p_next: core::ptr::null(),
62 ordinal: queue_ordinal,
63 index: 0,
64 flags: 0,
65 mode: ZE_COMMAND_QUEUE_MODE_DEFAULT,
66 priority: ZE_COMMAND_QUEUE_PRIORITY_NORMAL,
67 };
68 if (l.ze_command_queue_create)(context, device, &q_desc, &mut queue)
69 != ZE_RESULT_SUCCESS
70 {
71 (l.ze_context_destroy)(context);
72 return None;
73 }
74
75 let mut list: ZeCommandListHandle = core::ptr::null_mut();
76 let l_desc = ZeCommandListDesc {
77 stype: ZE_STRUCTURE_TYPE_COMMAND_LIST_DESC,
78 p_next: core::ptr::null(),
79 command_queue_group_ordinal: queue_ordinal,
80 flags: 0,
81 };
82 if (l.ze_command_list_create)(context, device, &l_desc, &mut list) != ZE_RESULT_SUCCESS
83 {
84 (l.ze_command_queue_destroy)(queue);
85 (l.ze_context_destroy)(context);
86 return None;
87 }
88
89 Some(Context {
90 l,
91 driver,
92 device,
93 context,
94 queue,
95 list,
96 queue_ordinal,
97 })
98 }
99 }
100}
101
102impl Context {
103 pub fn alloc_device(&self, size: usize, alignment: usize) -> Option<DeviceBuffer> {
107 let desc = ZeDeviceMemAllocDesc {
108 stype: ZE_STRUCTURE_TYPE_DEVICE_MEM_ALLOC_DESC,
109 p_next: core::ptr::null(),
110 flags: 0,
111 ordinal: self.queue_ordinal,
112 };
113 let mut ptr: *mut c_void = core::ptr::null_mut();
114 unsafe {
115 if (self.l.ze_mem_alloc_device)(
116 self.context,
117 &desc,
118 size,
119 alignment,
120 self.device,
121 &mut ptr,
122 ) != ZE_RESULT_SUCCESS
123 {
124 return None;
125 }
126 }
127 Some(DeviceBuffer {
128 l: self.l,
129 context: self.context,
130 ptr,
131 size,
132 })
133 }
134
135 pub fn alloc_shared(&self, size: usize, alignment: usize) -> Option<DeviceBuffer> {
137 let ddesc = ZeDeviceMemAllocDesc {
138 stype: ZE_STRUCTURE_TYPE_DEVICE_MEM_ALLOC_DESC,
139 p_next: core::ptr::null(),
140 flags: 0,
141 ordinal: self.queue_ordinal,
142 };
143 let hdesc = ZeHostMemAllocDesc {
144 stype: ZE_STRUCTURE_TYPE_HOST_MEM_ALLOC_DESC,
145 p_next: core::ptr::null(),
146 flags: 0,
147 };
148 let mut ptr: *mut c_void = core::ptr::null_mut();
149 unsafe {
150 if (self.l.ze_mem_alloc_shared)(
151 self.context,
152 &ddesc,
153 &hdesc,
154 size,
155 alignment,
156 self.device,
157 &mut ptr,
158 ) != ZE_RESULT_SUCCESS
159 {
160 return None;
161 }
162 }
163 Some(DeviceBuffer {
164 l: self.l,
165 context: self.context,
166 ptr,
167 size,
168 })
169 }
170
171 pub fn load_spirv(&self, spirv: &[u8]) -> Option<Module> {
173 let desc = ZeModuleDesc {
174 stype: ZE_STRUCTURE_TYPE_MODULE_DESC,
175 p_next: core::ptr::null(),
176 format: ZE_MODULE_FORMAT_IL_SPIRV,
177 input_size: spirv.len(),
178 p_input_module: spirv.as_ptr(),
179 p_build_flags: core::ptr::null(),
180 p_constants: core::ptr::null(),
181 };
182 let mut module: ZeModuleHandle = core::ptr::null_mut();
183 unsafe {
184 if (self.l.ze_module_create)(
185 self.context,
186 self.device,
187 &desc,
188 &mut module,
189 core::ptr::null_mut(),
190 ) != ZE_RESULT_SUCCESS
191 {
192 return None;
193 }
194 }
195 Some(Module { l: self.l, module })
196 }
197
198 pub fn launch(&self, kernel: &Kernel, group_count: [u32; 3]) -> Result<(), u32> {
202 let gc = ZeGroupCount {
203 group_count_x: group_count[0],
204 group_count_y: group_count[1],
205 group_count_z: group_count[2],
206 };
207 unsafe {
208 let r = (self.l.ze_command_list_append_launch_kernel)(
209 self.list,
210 kernel.kernel,
211 &gc,
212 core::ptr::null_mut(),
213 0,
214 core::ptr::null_mut(),
215 );
216 if r != ZE_RESULT_SUCCESS {
217 return Err(r);
218 }
219 let r = (self.l.ze_command_list_close)(self.list);
220 if r != ZE_RESULT_SUCCESS {
221 return Err(r);
222 }
223 let lists = [self.list];
224 let r = (self.l.ze_command_queue_execute_command_lists)(
225 self.queue,
226 1,
227 lists.as_ptr(),
228 core::ptr::null_mut(),
229 );
230 if r != ZE_RESULT_SUCCESS {
231 return Err(r);
232 }
233 let r = (self.l.ze_command_queue_synchronize)(self.queue, u64::MAX);
234 if r != ZE_RESULT_SUCCESS {
235 return Err(r);
236 }
237 let _ = (self.l.ze_command_list_reset)(self.list);
238 }
239 Ok(())
240 }
241}
242
243impl Drop for Context {
244 fn drop(&mut self) {
245 unsafe {
246 (self.l.ze_command_list_destroy)(self.list);
247 (self.l.ze_command_queue_destroy)(self.queue);
248 (self.l.ze_context_destroy)(self.context);
249 }
250 }
251}
252
253pub struct DeviceBuffer {
254 l: &'static Loaded,
255 context: ZeContextHandle,
256 pub ptr: *mut c_void,
257 pub size: usize,
258}
259
260impl Drop for DeviceBuffer {
261 fn drop(&mut self) {
262 unsafe {
263 (self.l.ze_mem_free)(self.context, self.ptr);
264 }
265 }
266}
267
268pub struct Module {
269 l: &'static Loaded,
270 pub module: ZeModuleHandle,
271}
272
273impl Module {
274 pub fn kernel(&self, name: &str) -> Option<Kernel> {
276 let cname = std::ffi::CString::new(name).ok()?;
277 let desc = ZeKernelDesc {
278 stype: ZE_STRUCTURE_TYPE_KERNEL_DESC,
279 p_next: core::ptr::null(),
280 flags: 0,
281 p_kernel_name: cname.as_ptr(),
282 };
283 let mut k: ZeKernelHandle = core::ptr::null_mut();
284 unsafe {
285 if (self.l.ze_kernel_create)(self.module, &desc, &mut k) != ZE_RESULT_SUCCESS {
286 return None;
287 }
288 }
289 Some(Kernel {
290 l: self.l,
291 kernel: k,
292 })
293 }
294}
295
296impl Drop for Module {
297 fn drop(&mut self) {
298 unsafe {
299 (self.l.ze_module_destroy)(self.module);
300 }
301 }
302}
303
304pub struct Kernel {
305 l: &'static Loaded,
306 pub kernel: ZeKernelHandle,
307}
308
309impl Kernel {
310 pub fn set_group_size(&self, gx: u32, gy: u32, gz: u32) -> Result<(), u32> {
311 unsafe {
312 match (self.l.ze_kernel_set_group_size)(self.kernel, gx, gy, gz) {
313 ZE_RESULT_SUCCESS => Ok(()),
314 e => Err(e),
315 }
316 }
317 }
318
319 pub unsafe fn set_arg<T>(&self, index: u32, value: &T) -> Result<(), u32> {
326 match (self.l.ze_kernel_set_argument_value)(
327 self.kernel,
328 index,
329 core::mem::size_of::<T>(),
330 value as *const T as *const c_void,
331 ) {
332 ZE_RESULT_SUCCESS => Ok(()),
333 e => Err(e),
334 }
335 }
336}
337
338impl Drop for Kernel {
339 fn drop(&mut self) {
340 unsafe {
341 (self.l.ze_kernel_destroy)(self.kernel);
342 }
343 }
344}
345
346unsafe fn locate_device(l: &Loaded, target: u32) -> Option<(ZeDriverHandle, ZeDeviceHandle)> {
347 let mut driver_count: u32 = 0;
348 if (l.ze_driver_get)(&mut driver_count, core::ptr::null_mut()) != ZE_RESULT_SUCCESS
349 || driver_count == 0
350 {
351 return None;
352 }
353 let mut drivers = vec![core::ptr::null_mut::<c_void>(); driver_count as usize];
354 if (l.ze_driver_get)(&mut driver_count, drivers.as_mut_ptr()) != ZE_RESULT_SUCCESS {
355 return None;
356 }
357 let mut seen = 0u32;
358 for driver in drivers.into_iter().take(driver_count as usize) {
359 let mut dev_count: u32 = 0;
360 if (l.ze_device_get)(driver, &mut dev_count, core::ptr::null_mut()) != ZE_RESULT_SUCCESS
361 || dev_count == 0
362 {
363 continue;
364 }
365 let mut devs = vec![core::ptr::null_mut::<c_void>(); dev_count as usize];
366 if (l.ze_device_get)(driver, &mut dev_count, devs.as_mut_ptr()) != ZE_RESULT_SUCCESS {
367 continue;
368 }
369 for dev in devs.into_iter().take(dev_count as usize) {
370 if seen == target {
371 return Some((driver, dev));
372 }
373 seen += 1;
374 }
375 }
376 None
377}