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