oneapi_rs/
queue.rs

1//
2// Copyright (C) 2026 Intel Corporation
3//
4// Under the MIT License or the Apache License v2.0.
5// See LICENSE-MIT and LICENSE-APACHE for license information.
6// SPDX-License-Identifier: MIT OR Apache-2.0
7//
8
9use std::cmp::min;
10
11use bytemuck::Pod;
12use oneapi_rs_sys::{queue::ffi, types::ffi::EventPtr};
13
14use crate::{
15    buffer::{
16        Buffer, DeviceBuffer, EnqueuedBuffer, EnqueuedDeviceBuffer, EnqueuedHostBuffer,
17        EnqueuedSharedBuffer, HostBuffer, SharedBuffer,
18    },
19    context::Context,
20    device::Device,
21    event::Event,
22    kernel::{Kernel, KernelArgumentList},
23    range::{NdRange, ValidDimension},
24    usm::{UsmAlloc, UsmAllocator},
25};
26
27/// The `Queue` connects a host program to a single device. Programs submit tasks to a device via the
28/// `Queue` and may monitor the `Queue` for completion. A program initiates the task by submitting
29/// a kernel.
30pub struct Queue(pub(crate) cxx::UniquePtr<ffi::Queue>);
31
32impl Queue {
33    /// Construct a `Queue` based on the device returned from the default selector.
34    pub fn new() -> Self {
35        Self(ffi::new_queue())
36    }
37
38    /// Construct an immediate `Queue` based on the device returned from the default selector.
39    pub fn new_immediate() -> Self {
40        Self(ffi::new_queue_immediate())
41    }
42
43    /// Returns the SYCL queue’s context.
44    pub fn get_context(&self) -> Context {
45        ffi::get_context(&self.0).into()
46    }
47
48    /// Allocates zeroed memory and creates a host-side [`Buffer`] that can store an array of T.
49    pub fn alloc_host<T: Pod>(&mut self, len: usize) -> EnqueuedHostBuffer<T> {
50        unsafe {
51            let mut buffer = self.alloc_uninit_host(len);
52            let event = self.memset(&mut buffer, 0);
53            EnqueuedBuffer::new(buffer, event)
54        }
55    }
56
57    /// Allocates zeroed memory and creates a shared [`Buffer`] that can store an array of T.
58    pub fn alloc_shared<T: Pod>(&mut self, len: usize) -> EnqueuedSharedBuffer<T> {
59        unsafe {
60            let mut buffer = self.alloc_uninit_shared(len);
61            let event = self.memset(&mut buffer, 0);
62            EnqueuedBuffer::new(buffer, event)
63        }
64    }
65
66    /// Allocates zeroed memory and creates a device [`Buffer`] that can store an array of T.
67    pub fn alloc_device<T: Pod>(&mut self, len: usize) -> EnqueuedDeviceBuffer<T> {
68        unsafe {
69            let mut buffer = self.alloc_uninit_device(len);
70            let event = self.memset(&mut buffer, 0);
71            EnqueuedBuffer::new(buffer, event)
72        }
73    }
74
75    /// Allocates memory and creates a host-side [`Buffer`] that can store an array of T.
76    /// Safety: the buffer contents are uninitialized.
77    pub unsafe fn alloc_uninit_host<T>(&self, len: usize) -> HostBuffer<T> {
78        let allocator = UsmAllocator::from(self);
79        unsafe { Buffer::new(allocator, len) }
80    }
81
82    /// Allocates memory and creates a shared [`Buffer`] that can store an array of T.
83    /// Safety: the buffer contents are uninitialized.
84    pub unsafe fn alloc_uninit_shared<T>(&self, len: usize) -> SharedBuffer<T> {
85        let allocator = UsmAllocator::from(self);
86        unsafe { Buffer::new(allocator, len) }
87    }
88
89    /// Allocates memory and creates a device-side [`Buffer`] that can store an array of T.
90    /// Safety: the buffer contents are uninitialized.
91    pub unsafe fn alloc_uninit_device<T>(&self, len: usize) -> DeviceBuffer<T> {
92        let allocator = UsmAllocator::from(self);
93        unsafe { Buffer::new(allocator, len) }
94    }
95
96    /// Sets memory allocated with USM allocations.
97    /// Safety: the caller must make sure the underlying memory isn't being aliased somewhere else.
98    pub unsafe fn memset<T, A: UsmAlloc>(
99        &mut self,
100        buffer: &mut Buffer<T, A>,
101        value: i32,
102    ) -> Event {
103        unsafe { self.memset_with_deps(buffer, value, &[]) }
104    }
105
106    /// Sets memory allocated with USM allocations after all specified events finish.
107    /// Safety: the caller must make sure the underlying memory isn't being aliased somewhere else.
108    pub unsafe fn memset_with_deps<T, A: UsmAlloc>(
109        &mut self,
110        buffer: &mut Buffer<T, A>,
111        value: i32,
112        dep_events: &[&Event],
113    ) -> Event {
114        let ptr = buffer.get_byte_ptr();
115        let num_bytes = buffer.get_byte_size();
116        let dep_events = dep_events
117            .iter()
118            .map(|e| EventPtr {
119                ptr: (*e).clone().0,
120            })
121            .collect::<Vec<_>>();
122        unsafe { ffi::memset(&mut self.0, ptr, value, num_bytes, dep_events) }.into()
123    }
124
125    /// Submits a barrier to the queue.
126    pub fn barrier(&mut self) -> Event {
127        self.barrier_with_deps(&[])
128    }
129
130    /// Submits a barrier to the queue after all specified events finish.
131    pub fn barrier_with_deps(&mut self, dep_events: &[&Event]) -> Event {
132        let dep_events = dep_events
133            .iter()
134            .map(|e| EventPtr {
135                ptr: (*e).clone().0,
136            })
137            .collect::<Vec<_>>();
138        ffi::barrier(&mut self.0, dep_events).into()
139    }
140
141    /// Performs a blocking wait for the completion of all enqueued tasks in the queue.
142    pub fn wait(&mut self) {
143        ffi::wait(&mut self.0);
144    }
145
146    /// Enqueues a kernel object to the queue as an ND-range kernel, using the number of work-items
147    /// specified by the [`NdRange`] nd_range.
148    pub unsafe fn launch<const ARGC: usize, const DIMENSIONS: usize>(
149        &mut self,
150        nd_range: NdRange<DIMENSIONS>,
151        kernel: &Kernel,
152        args: impl KernelArgumentList<ARGC>,
153    ) -> Event
154    where
155        NdRange<DIMENSIONS>: ValidDimension,
156    {
157        unsafe { nd_range.launch(self, kernel, args) }
158    }
159
160    /// Copies the contents of the source buffer to the destination buffer.
161    ///
162    /// If the buffer sizes don't match the destination buffer is filled with as many elements from
163    /// source buffer as possible.
164    pub fn copy<T, A1, A2>(&mut self, src: &Buffer<T, A1>, dst: &mut Buffer<T, A2>) -> Event
165    where
166        T: Pod,
167        A1: UsmAlloc,
168        A2: UsmAlloc,
169    {
170        self.copy_with_deps(src, dst, &[])
171    }
172
173    /// Copies the contents of the source buffer to the destination buffer after all specified
174    /// events finish.
175    ///
176    /// If the buffer sizes don't match the destination buffer is filled with as many elements from
177    /// source buffer as possible.
178    pub fn copy_with_deps<T, A1, A2>(
179        &mut self,
180        src: &Buffer<T, A1>,
181        dst: &mut Buffer<T, A2>,
182        dep_events: &[&Event],
183    ) -> Event
184    where
185        T: Pod,
186        A1: UsmAlloc,
187        A2: UsmAlloc,
188    {
189        // TODO: Resolve the C++ lifetime elision issue
190        let dep_events = dep_events
191            .iter()
192            .map(|e| EventPtr {
193                ptr: (*e).clone().0,
194            })
195            .collect::<Vec<_>>();
196
197        let amount = min(src.get_len(), dst.get_len());
198        let num_bytes = amount * size_of::<T>();
199        unsafe {
200            ffi::memcpy(
201                &mut self.0,
202                dst.get_byte_ptr(),
203                src.get_byte_ptr(),
204                num_bytes,
205                dep_events,
206            )
207        }
208        .into()
209    }
210}
211
212impl From<&Device> for Queue {
213    fn from(value: &Device) -> Self {
214        Self(ffi::new_queue_from_device(&value.0))
215    }
216}
217
218impl From<cxx::UniquePtr<ffi::Queue>> for Queue {
219    fn from(value: cxx::UniquePtr<ffi::Queue>) -> Self {
220        Self(value)
221    }
222}
223
224impl Clone for Queue {
225    fn clone(&self) -> Self {
226        ffi::clone(&self.0).into()
227    }
228}