1use crate::error::{LevelZeroError, LevelZeroResult};
8
9#[cfg(any(target_os = "linux", target_os = "windows"))]
12use std::{ffi::c_void, sync::Arc};
13
14#[cfg(any(target_os = "linux", target_os = "windows"))]
15use libloading::Library;
16
17#[cfg(any(target_os = "linux", target_os = "windows"))]
20type ZeDriverHandle = *mut c_void;
21
22#[cfg(any(target_os = "linux", target_os = "windows"))]
23type ZeDeviceHandle = *mut c_void;
24
25#[cfg(any(target_os = "linux", target_os = "windows"))]
26type ZeContextHandle = *mut c_void;
27
28#[cfg(any(target_os = "linux", target_os = "windows"))]
29pub(crate) type ZeCommandQueueHandle = *mut c_void;
30
31#[cfg(any(target_os = "linux", target_os = "windows"))]
32pub(crate) type ZeCommandListHandle = *mut c_void;
33
34#[cfg(any(target_os = "linux", target_os = "windows"))]
35pub(crate) type ZeModuleHandle = *mut c_void;
36
37#[cfg(any(target_os = "linux", target_os = "windows"))]
38pub(crate) type ZeKernelHandle = *mut c_void;
39
40#[cfg(any(target_os = "linux", target_os = "windows"))]
43const ZE_RESULT_SUCCESS: u32 = 0;
44
45#[cfg(any(target_os = "linux", target_os = "windows"))]
46const ZE_DEVICE_TYPE_GPU: u32 = 1;
47
48#[cfg(any(target_os = "linux", target_os = "windows"))]
54const ZE_STRUCTURE_TYPE_CONTEXT_DESC: u32 = 0xd;
55
56#[cfg(any(target_os = "linux", target_os = "windows"))]
57const ZE_STRUCTURE_TYPE_COMMAND_QUEUE_DESC: u32 = 0xe;
58
59#[cfg(any(target_os = "linux", target_os = "windows"))]
60pub(crate) const ZE_STRUCTURE_TYPE_COMMAND_LIST_DESC: u32 = 0xf;
61
62#[cfg(any(target_os = "linux", target_os = "windows"))]
63pub(crate) const ZE_STRUCTURE_TYPE_DEVICE_MEM_ALLOC_DESC: u32 = 0x15;
64
65#[cfg(any(target_os = "linux", target_os = "windows"))]
66pub(crate) const ZE_STRUCTURE_TYPE_HOST_MEM_ALLOC_DESC: u32 = 0x16;
67
68#[cfg(any(target_os = "linux", target_os = "windows"))]
69const ZE_STRUCTURE_TYPE_DEVICE_PROPERTIES: u32 = 0x3;
70
71#[cfg(any(target_os = "linux", target_os = "windows"))]
72pub(crate) const ZE_STRUCTURE_TYPE_MODULE_DESC: u32 = 0x1d;
73
74#[cfg(any(target_os = "linux", target_os = "windows"))]
75pub(crate) const ZE_STRUCTURE_TYPE_KERNEL_DESC: u32 = 0x1f;
76
77#[cfg(any(target_os = "linux", target_os = "windows"))]
78pub(crate) const ZE_MODULE_FORMAT_IL_SPIRV: u32 = 0;
79
80#[cfg(any(target_os = "linux", target_os = "windows"))]
83#[repr(C)]
84pub(crate) struct ZeContextDesc {
85 pub(crate) stype: u32,
86 pub(crate) p_next: *const c_void,
87}
88
89#[cfg(any(target_os = "linux", target_os = "windows"))]
90#[repr(C)]
91pub(crate) struct ZeCommandQueueDesc {
92 stype: u32,
93 p_next: *const c_void,
94 ordinal: u32,
95 index: u32,
96 flags: u32,
97 mode: u32,
98 priority: u32,
99}
100
101#[cfg(any(target_os = "linux", target_os = "windows"))]
102#[repr(C)]
103pub(crate) struct ZeCommandListDesc {
104 pub stype: u32,
105 pub p_next: *const c_void,
106 pub command_queue_group_ordinal: u32,
107 pub flags: u32,
108}
109
110#[cfg(any(target_os = "linux", target_os = "windows"))]
111#[repr(C)]
112pub(crate) struct ZeDeviceMemAllocDesc {
113 pub stype: u32,
114 pub p_next: *const c_void,
115 pub flags: u32,
116 pub ordinal: u32,
117}
118
119#[cfg(any(target_os = "linux", target_os = "windows"))]
120#[repr(C)]
121pub(crate) struct ZeHostMemAllocDesc {
122 pub stype: u32,
123 pub p_next: *const c_void,
124 pub flags: u32,
125}
126
127#[cfg(any(target_os = "linux", target_os = "windows"))]
128#[repr(C)]
129pub(crate) struct ZeDeviceProperties {
130 stype: u32,
134 p_next: *const c_void,
135 device_type: u32,
136 vendor_id: u32,
137 device_id: u32,
138 _flags: u32,
139 _sub_device_id: u32,
140 _core_clock_rate: u32,
141 _max_mem_alloc_size: u64,
142 _max_hardware_contexts: u32,
143 _max_command_queue_priority: u32,
144 _num_threads_per_eu: u32,
145 _physical_eu_simd_width: u32,
146 _num_eus_per_sub_slice: u32,
147 _num_sub_slices_per_slice: u32,
148 _num_slices: u32,
149 _timer_resolution: u64,
150 _timestamp_valid_bits: u32,
151 _kernel_timestamp_valid_bits: u32,
152 _uuid: [u8; 16],
153 name: [u8; 256],
154}
155
156#[cfg(any(target_os = "linux", target_os = "windows"))]
157#[repr(C)]
158pub(crate) struct ZeModuleDesc {
159 pub stype: u32,
160 pub p_next: *const c_void,
161 pub format: u32,
162 pub input_size: usize,
163 pub p_input_module: *const u8,
164 pub p_build_flags: *const u8,
165 pub p_constants: *const c_void,
166}
167
168#[cfg(any(target_os = "linux", target_os = "windows"))]
169#[repr(C)]
170pub(crate) struct ZeKernelDesc {
171 pub stype: u32,
172 pub p_next: *const c_void,
173 pub flags: u32,
174 pub p_kernel_name: *const u8,
175}
176
177#[cfg(any(target_os = "linux", target_os = "windows"))]
178#[repr(C)]
179pub(crate) struct ZeGroupCount {
180 pub group_count_x: u32,
181 pub group_count_y: u32,
182 pub group_count_z: u32,
183}
184
185#[cfg(any(target_os = "linux", target_os = "windows"))]
188type ZeInitFn = unsafe extern "C" fn(flags: u32) -> u32;
189
190#[cfg(any(target_os = "linux", target_os = "windows"))]
191type ZeDriverGetFn = unsafe extern "C" fn(count: *mut u32, drivers: *mut ZeDriverHandle) -> u32;
192
193#[cfg(any(target_os = "linux", target_os = "windows"))]
194type ZeDeviceGetFn = unsafe extern "C" fn(
195 driver: ZeDriverHandle,
196 count: *mut u32,
197 devices: *mut ZeDeviceHandle,
198) -> u32;
199
200#[cfg(any(target_os = "linux", target_os = "windows"))]
201type ZeDeviceGetPropertiesFn =
202 unsafe extern "C" fn(device: ZeDeviceHandle, props: *mut ZeDeviceProperties) -> u32;
203
204#[cfg(any(target_os = "linux", target_os = "windows"))]
205type ZeContextCreateFn = unsafe extern "C" fn(
206 driver: ZeDriverHandle,
207 desc: *const ZeContextDesc,
208 context: *mut ZeContextHandle,
209) -> u32;
210
211#[cfg(any(target_os = "linux", target_os = "windows"))]
212type ZeContextDestroyFn = unsafe extern "C" fn(context: ZeContextHandle) -> u32;
213
214#[cfg(any(target_os = "linux", target_os = "windows"))]
215type ZeCommandQueueCreateFn = unsafe extern "C" fn(
216 context: ZeContextHandle,
217 device: ZeDeviceHandle,
218 desc: *const ZeCommandQueueDesc,
219 queue: *mut ZeCommandQueueHandle,
220) -> u32;
221
222#[cfg(any(target_os = "linux", target_os = "windows"))]
223type ZeCommandQueueDestroyFn = unsafe extern "C" fn(queue: ZeCommandQueueHandle) -> u32;
224
225#[cfg(any(target_os = "linux", target_os = "windows"))]
226type ZeCommandQueueSynchronizeFn =
227 unsafe extern "C" fn(queue: ZeCommandQueueHandle, timeout: u64) -> u32;
228
229#[cfg(any(target_os = "linux", target_os = "windows"))]
230type ZeCommandQueueExecuteCommandListsFn = unsafe extern "C" fn(
231 queue: ZeCommandQueueHandle,
232 count: u32,
233 lists: *const ZeCommandListHandle,
234 fence: usize,
235) -> u32;
236
237#[cfg(any(target_os = "linux", target_os = "windows"))]
238type ZeCommandListCreateFn = unsafe extern "C" fn(
239 context: ZeContextHandle,
240 device: ZeDeviceHandle,
241 desc: *const ZeCommandListDesc,
242 list: *mut ZeCommandListHandle,
243) -> u32;
244
245#[cfg(any(target_os = "linux", target_os = "windows"))]
246type ZeCommandListDestroyFn = unsafe extern "C" fn(list: ZeCommandListHandle) -> u32;
247
248#[cfg(any(target_os = "linux", target_os = "windows"))]
249type ZeCommandListCloseFn = unsafe extern "C" fn(list: ZeCommandListHandle) -> u32;
250
251#[cfg(any(target_os = "linux", target_os = "windows"))]
252type ZeCommandListResetFn = unsafe extern "C" fn(list: ZeCommandListHandle) -> u32;
253
254#[cfg(any(target_os = "linux", target_os = "windows"))]
255type ZeCommandListAppendMemoryCopyFn = unsafe extern "C" fn(
256 list: ZeCommandListHandle,
257 dst: *mut c_void,
258 src: *const c_void,
259 size: usize,
260 signal_event: usize,
261 wait_count: u32,
262 wait_events: *const usize,
263) -> u32;
264
265#[cfg(any(target_os = "linux", target_os = "windows"))]
266type ZeMemAllocDeviceFn = unsafe extern "C" fn(
267 context: ZeContextHandle,
268 desc: *const ZeDeviceMemAllocDesc,
269 size: usize,
270 alignment: usize,
271 device: ZeDeviceHandle,
272 ptr: *mut *mut c_void,
273) -> u32;
274
275#[cfg(any(target_os = "linux", target_os = "windows"))]
276type ZeMemAllocHostFn = unsafe extern "C" fn(
277 context: ZeContextHandle,
278 desc: *const ZeHostMemAllocDesc,
279 size: usize,
280 alignment: usize,
281 ptr: *mut *mut c_void,
282) -> u32;
283
284#[cfg(any(target_os = "linux", target_os = "windows"))]
285type ZeMemFreeFn = unsafe extern "C" fn(context: ZeContextHandle, ptr: *mut c_void) -> u32;
286
287#[cfg(any(target_os = "linux", target_os = "windows"))]
288type ZeModuleCreateFn = unsafe extern "C" fn(
289 context: ZeContextHandle,
290 device: ZeDeviceHandle,
291 desc: *const ZeModuleDesc,
292 module: *mut ZeModuleHandle,
293 build_log: *mut *mut c_void,
294) -> u32;
295
296#[cfg(any(target_os = "linux", target_os = "windows"))]
297type ZeModuleDestroyFn = unsafe extern "C" fn(module: ZeModuleHandle) -> u32;
298
299#[cfg(any(target_os = "linux", target_os = "windows"))]
300type ZeKernelCreateFn = unsafe extern "C" fn(
301 module: ZeModuleHandle,
302 desc: *const ZeKernelDesc,
303 kernel: *mut ZeKernelHandle,
304) -> u32;
305
306#[cfg(any(target_os = "linux", target_os = "windows"))]
307type ZeKernelDestroyFn = unsafe extern "C" fn(kernel: ZeKernelHandle) -> u32;
308
309#[cfg(any(target_os = "linux", target_os = "windows"))]
310type ZeKernelSetGroupSizeFn =
311 unsafe extern "C" fn(kernel: ZeKernelHandle, x: u32, y: u32, z: u32) -> u32;
312
313#[cfg(any(target_os = "linux", target_os = "windows"))]
314type ZeKernelSetArgumentValueFn = unsafe extern "C" fn(
315 kernel: ZeKernelHandle,
316 arg_index: u32,
317 arg_size: usize,
318 p_arg_value: *const c_void,
319) -> u32;
320
321#[cfg(any(target_os = "linux", target_os = "windows"))]
322type ZeCommandListAppendLaunchKernelFn = unsafe extern "C" fn(
323 list: ZeCommandListHandle,
324 kernel: ZeKernelHandle,
325 launch_func_args: *const ZeGroupCount,
326 signal_event: usize,
327 wait_count: u32,
328 wait_events: *const usize,
329) -> u32;
330
331#[cfg(any(target_os = "linux", target_os = "windows"))]
337pub(crate) struct L0Api {
338 _lib: Library,
340 pub ze_init: ZeInitFn,
341 pub ze_driver_get: ZeDriverGetFn,
342 pub ze_device_get: ZeDeviceGetFn,
343 pub ze_device_get_properties: ZeDeviceGetPropertiesFn,
344 pub ze_context_create: ZeContextCreateFn,
345 pub ze_context_destroy: ZeContextDestroyFn,
346 pub ze_command_queue_create: ZeCommandQueueCreateFn,
347 pub ze_command_queue_destroy: ZeCommandQueueDestroyFn,
348 pub ze_command_queue_synchronize: ZeCommandQueueSynchronizeFn,
349 pub ze_command_queue_execute_command_lists: ZeCommandQueueExecuteCommandListsFn,
350 pub ze_command_list_create: ZeCommandListCreateFn,
351 pub ze_command_list_destroy: ZeCommandListDestroyFn,
352 pub ze_command_list_close: ZeCommandListCloseFn,
353 #[allow(dead_code)]
354 pub ze_command_list_reset: ZeCommandListResetFn,
355 pub ze_command_list_append_memory_copy: ZeCommandListAppendMemoryCopyFn,
356 pub ze_mem_alloc_device: ZeMemAllocDeviceFn,
357 pub ze_mem_alloc_host: ZeMemAllocHostFn,
358 pub ze_mem_free: ZeMemFreeFn,
359 pub ze_module_create: ZeModuleCreateFn,
360 pub ze_module_destroy: ZeModuleDestroyFn,
361 pub ze_kernel_create: ZeKernelCreateFn,
362 pub ze_kernel_destroy: ZeKernelDestroyFn,
363 pub ze_kernel_set_group_size: ZeKernelSetGroupSizeFn,
364 pub ze_kernel_set_argument_value: ZeKernelSetArgumentValueFn,
365 pub ze_command_list_append_launch_kernel: ZeCommandListAppendLaunchKernelFn,
366}
367
368#[cfg(any(target_os = "linux", target_os = "windows"))]
369impl L0Api {
370 unsafe fn load() -> LevelZeroResult<Self> {
378 #[cfg(target_os = "linux")]
379 let lib_name = "libze_loader.so.1";
380 #[cfg(target_os = "windows")]
381 let lib_name = "ze_loader.dll";
382
383 let lib = unsafe {
386 Library::new(lib_name)
387 .map_err(|e| LevelZeroError::LibraryNotFound(format!("{lib_name}: {e}")))?
388 };
389
390 macro_rules! sym {
391 ($name:literal, $ty:ty) => {{
392 *unsafe {
396 lib.get::<$ty>($name).map_err(|e| {
397 LevelZeroError::LibraryNotFound(format!(
398 "symbol {}: {e}",
399 stringify!($name)
400 ))
401 })?
402 }
403 }};
404 }
405
406 let ze_init = sym!(b"zeInit\0", ZeInitFn);
407 let ze_driver_get = sym!(b"zeDriverGet\0", ZeDriverGetFn);
408 let ze_device_get = sym!(b"zeDeviceGet\0", ZeDeviceGetFn);
409 let ze_device_get_properties = sym!(b"zeDeviceGetProperties\0", ZeDeviceGetPropertiesFn);
410 let ze_context_create = sym!(b"zeContextCreate\0", ZeContextCreateFn);
411 let ze_context_destroy = sym!(b"zeContextDestroy\0", ZeContextDestroyFn);
412 let ze_command_queue_create = sym!(b"zeCommandQueueCreate\0", ZeCommandQueueCreateFn);
413 let ze_command_queue_destroy = sym!(b"zeCommandQueueDestroy\0", ZeCommandQueueDestroyFn);
414 let ze_command_queue_synchronize =
415 sym!(b"zeCommandQueueSynchronize\0", ZeCommandQueueSynchronizeFn);
416 let ze_command_queue_execute_command_lists = sym!(
417 b"zeCommandQueueExecuteCommandLists\0",
418 ZeCommandQueueExecuteCommandListsFn
419 );
420 let ze_command_list_create = sym!(b"zeCommandListCreate\0", ZeCommandListCreateFn);
421 let ze_command_list_destroy = sym!(b"zeCommandListDestroy\0", ZeCommandListDestroyFn);
422 let ze_command_list_close = sym!(b"zeCommandListClose\0", ZeCommandListCloseFn);
423 let ze_command_list_reset = sym!(b"zeCommandListReset\0", ZeCommandListResetFn);
424 let ze_command_list_append_memory_copy = sym!(
425 b"zeCommandListAppendMemoryCopy\0",
426 ZeCommandListAppendMemoryCopyFn
427 );
428 let ze_mem_alloc_device = sym!(b"zeMemAllocDevice\0", ZeMemAllocDeviceFn);
429 let ze_mem_alloc_host = sym!(b"zeMemAllocHost\0", ZeMemAllocHostFn);
430 let ze_mem_free = sym!(b"zeMemFree\0", ZeMemFreeFn);
431 let ze_module_create = sym!(b"zeModuleCreate\0", ZeModuleCreateFn);
432 let ze_module_destroy = sym!(b"zeModuleDestroy\0", ZeModuleDestroyFn);
433 let ze_kernel_create = sym!(b"zeKernelCreate\0", ZeKernelCreateFn);
434 let ze_kernel_destroy = sym!(b"zeKernelDestroy\0", ZeKernelDestroyFn);
435 let ze_kernel_set_group_size = sym!(b"zeKernelSetGroupSize\0", ZeKernelSetGroupSizeFn);
436 let ze_kernel_set_argument_value =
437 sym!(b"zeKernelSetArgumentValue\0", ZeKernelSetArgumentValueFn);
438 let ze_command_list_append_launch_kernel = sym!(
439 b"zeCommandListAppendLaunchKernel\0",
440 ZeCommandListAppendLaunchKernelFn
441 );
442
443 Ok(Self {
444 _lib: lib,
445 ze_init,
446 ze_driver_get,
447 ze_device_get,
448 ze_device_get_properties,
449 ze_context_create,
450 ze_context_destroy,
451 ze_command_queue_create,
452 ze_command_queue_destroy,
453 ze_command_queue_synchronize,
454 ze_command_queue_execute_command_lists,
455 ze_command_list_create,
456 ze_command_list_destroy,
457 ze_command_list_close,
458 ze_command_list_reset,
459 ze_command_list_append_memory_copy,
460 ze_mem_alloc_device,
461 ze_mem_alloc_host,
462 ze_mem_free,
463 ze_module_create,
464 ze_module_destroy,
465 ze_kernel_create,
466 ze_kernel_destroy,
467 ze_kernel_set_group_size,
468 ze_kernel_set_argument_value,
469 ze_command_list_append_launch_kernel,
470 })
471 }
472}
473
474pub struct LevelZeroDevice {
481 #[cfg(any(target_os = "linux", target_os = "windows"))]
483 pub(crate) api: Arc<L0Api>,
484 #[cfg(any(target_os = "linux", target_os = "windows"))]
486 pub(crate) context: ZeContextHandle,
487 #[cfg(any(target_os = "linux", target_os = "windows"))]
489 pub(crate) device: ZeDeviceHandle,
490 #[cfg(any(target_os = "linux", target_os = "windows"))]
492 pub(crate) queue: ZeCommandQueueHandle,
493 device_name: String,
495}
496
497impl LevelZeroDevice {
498 pub fn new() -> LevelZeroResult<Self> {
502 #[cfg(any(target_os = "linux", target_os = "windows"))]
503 {
504 let api = Arc::new(unsafe { L0Api::load()? });
507
508 let rc = unsafe { (api.ze_init)(0) };
511 if rc != ZE_RESULT_SUCCESS {
512 return Err(LevelZeroError::ZeError(rc, "zeInit failed".into()));
513 }
514
515 let mut driver_count: u32 = 0;
517 let rc =
519 unsafe { (api.ze_driver_get)(&mut driver_count as *mut u32, std::ptr::null_mut()) };
520 if rc != ZE_RESULT_SUCCESS {
521 return Err(LevelZeroError::ZeError(
522 rc,
523 "zeDriverGet (count) failed".into(),
524 ));
525 }
526 if driver_count == 0 {
527 return Err(LevelZeroError::NoSuitableDevice);
528 }
529
530 let mut drivers: Vec<ZeDriverHandle> =
531 vec![std::ptr::null_mut(); driver_count as usize];
532 let rc =
534 unsafe { (api.ze_driver_get)(&mut driver_count as *mut u32, drivers.as_mut_ptr()) };
535 if rc != ZE_RESULT_SUCCESS {
536 return Err(LevelZeroError::ZeError(
537 rc,
538 "zeDriverGet (enumerate) failed".into(),
539 ));
540 }
541
542 let driver = drivers[0];
543
544 let mut device_count: u32 = 0;
546 let rc = unsafe {
548 (api.ze_device_get)(driver, &mut device_count as *mut u32, std::ptr::null_mut())
549 };
550 if rc != ZE_RESULT_SUCCESS {
551 return Err(LevelZeroError::ZeError(
552 rc,
553 "zeDeviceGet (count) failed".into(),
554 ));
555 }
556 if device_count == 0 {
557 return Err(LevelZeroError::NoSuitableDevice);
558 }
559
560 let mut devices: Vec<ZeDeviceHandle> =
561 vec![std::ptr::null_mut(); device_count as usize];
562 let rc = unsafe {
564 (api.ze_device_get)(driver, &mut device_count as *mut u32, devices.as_mut_ptr())
565 };
566 if rc != ZE_RESULT_SUCCESS {
567 return Err(LevelZeroError::ZeError(
568 rc,
569 "zeDeviceGet (enumerate) failed".into(),
570 ));
571 }
572
573 let mut chosen_device: Option<ZeDeviceHandle> = None;
575 let mut device_name = String::from("Intel GPU");
576
577 for &dev in &devices {
578 let mut props =
581 unsafe { std::mem::MaybeUninit::<ZeDeviceProperties>::zeroed().assume_init() };
582 props.stype = ZE_STRUCTURE_TYPE_DEVICE_PROPERTIES;
583 props.p_next = std::ptr::null();
584
585 let rc = unsafe {
588 (api.ze_device_get_properties)(dev, &mut props as *mut ZeDeviceProperties)
589 };
590 if rc != ZE_RESULT_SUCCESS {
591 continue;
592 }
593
594 if props.device_type == ZE_DEVICE_TYPE_GPU {
595 let name_len = props
597 .name
598 .iter()
599 .position(|&b| b == 0)
600 .unwrap_or(props.name.len());
601 device_name = String::from_utf8_lossy(&props.name[..name_len]).into_owned();
602 chosen_device = Some(dev);
603 break;
604 }
605 }
606
607 let device = chosen_device.ok_or(LevelZeroError::NoSuitableDevice)?;
608
609 let ctx_desc = ZeContextDesc {
611 stype: ZE_STRUCTURE_TYPE_CONTEXT_DESC,
612 p_next: std::ptr::null(),
613 };
614 let mut context: ZeContextHandle = std::ptr::null_mut();
615 let rc = unsafe {
617 (api.ze_context_create)(driver, &ctx_desc, &mut context as *mut ZeContextHandle)
618 };
619 if rc != ZE_RESULT_SUCCESS {
620 return Err(LevelZeroError::ZeError(rc, "zeContextCreate failed".into()));
621 }
622
623 let queue_desc = ZeCommandQueueDesc {
625 stype: ZE_STRUCTURE_TYPE_COMMAND_QUEUE_DESC,
626 p_next: std::ptr::null(),
627 ordinal: 0,
628 index: 0,
629 flags: 0,
630 mode: 0, priority: 0,
632 };
633 let mut queue: ZeCommandQueueHandle = std::ptr::null_mut();
634 let rc = unsafe {
637 (api.ze_command_queue_create)(
638 context,
639 device,
640 &queue_desc,
641 &mut queue as *mut ZeCommandQueueHandle,
642 )
643 };
644 if rc != ZE_RESULT_SUCCESS {
645 unsafe { (api.ze_context_destroy)(context) };
648 return Err(LevelZeroError::ZeError(
649 rc,
650 "zeCommandQueueCreate failed".into(),
651 ));
652 }
653
654 tracing::info!("Level Zero device selected: {device_name}");
655
656 Ok(Self {
657 api,
658 context,
659 device,
660 queue,
661 device_name,
662 })
663 }
664
665 #[cfg(not(any(target_os = "linux", target_os = "windows")))]
666 {
667 Err(LevelZeroError::UnsupportedPlatform)
668 }
669 }
670
671 pub fn name(&self) -> &str {
673 &self.device_name
674 }
675}
676
677impl Drop for LevelZeroDevice {
680 fn drop(&mut self) {
681 #[cfg(any(target_os = "linux", target_os = "windows"))]
682 {
683 unsafe {
686 (self.api.ze_command_queue_destroy)(self.queue);
687 (self.api.ze_context_destroy)(self.context);
688 }
689 }
690 }
691}
692
693unsafe impl Send for LevelZeroDevice {}
701unsafe impl Sync for LevelZeroDevice {}
704
705impl std::fmt::Debug for LevelZeroDevice {
708 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
709 write!(f, "LevelZeroDevice({})", self.device_name)
710 }
711}
712
713#[cfg(test)]
716mod tests {
717 use super::*;
718
719 #[test]
720 #[cfg(any(target_os = "linux", target_os = "windows"))]
721 fn level_zero_device_graceful_init() {
722 match LevelZeroDevice::new() {
723 Ok(dev) => {
724 assert!(!dev.name().is_empty());
725 let dbg = format!("{dev:?}");
726 assert!(dbg.contains("LevelZeroDevice"));
727 }
728 Err(LevelZeroError::LibraryNotFound(_)) => {
729 }
731 Err(LevelZeroError::NoSuitableDevice) => {
732 }
734 Err(LevelZeroError::ZeError(_, _)) => {
735 }
737 Err(e) => {
738 let _ = format!("Level Zero device init error (non-fatal): {e}");
740 }
741 }
742 }
743
744 #[test]
745 #[cfg(not(any(target_os = "linux", target_os = "windows")))]
746 fn level_zero_device_unsupported_on_macos() {
747 let result = LevelZeroDevice::new();
748 assert!(matches!(result, Err(LevelZeroError::UnsupportedPlatform)));
749 }
750}