1 use crate::api::event::create_and_queue;
2 use crate::api::icd::*;
3 use crate::api::util::*;
4 use crate::core::context::*;
5 use crate::core::device::*;
6 use crate::core::event::*;
7 use crate::core::queue::*;
8
9 use mesa_rust_util::properties::*;
10 use rusticl_opencl_gen::*;
11 use rusticl_proc_macros::cl_entrypoint;
12 use rusticl_proc_macros::cl_info_entrypoint;
13
14 use std::ptr;
15 use std::sync::Arc;
16
17 #[cl_info_entrypoint(clGetCommandQueueInfo)]
18 unsafe impl CLInfo<cl_command_queue_info> for cl_command_queue {
query(&self, q: cl_command_queue_info, v: CLInfoValue) -> CLResult<CLInfoRes>19 fn query(&self, q: cl_command_queue_info, v: CLInfoValue) -> CLResult<CLInfoRes> {
20 let queue = Queue::ref_from_raw(*self)?;
21 match q {
22 CL_QUEUE_CONTEXT => {
23 // Note we use as_ptr here which doesn't increase the reference count.
24 let ptr = Arc::as_ptr(&queue.context);
25 v.write::<cl_context>(cl_context::from_ptr(ptr))
26 }
27 CL_QUEUE_DEVICE => v.write::<cl_device_id>(cl_device_id::from_ptr(queue.device)),
28 CL_QUEUE_DEVICE_DEFAULT => v.write::<cl_command_queue>(ptr::null_mut()),
29 CL_QUEUE_PROPERTIES => v.write::<cl_command_queue_properties>(queue.props),
30 CL_QUEUE_PROPERTIES_ARRAY => {
31 v.write::<&Properties<cl_queue_properties>>(&queue.props_v2)
32 }
33 CL_QUEUE_REFERENCE_COUNT => v.write::<cl_uint>(Queue::refcnt(*self)?),
34 // clGetCommandQueueInfo, passing CL_QUEUE_SIZE Returns CL_INVALID_COMMAND_QUEUE since
35 // command_queue cannot be a valid device command-queue.
36 CL_QUEUE_SIZE => Err(CL_INVALID_COMMAND_QUEUE),
37 // CL_INVALID_VALUE if param_name is not one of the supported values
38 _ => Err(CL_INVALID_VALUE),
39 }
40 }
41 }
42
43 #[cl_entrypoint(clSetCommandQueueProperty)]
set_command_queue_property( _command_queue: cl_command_queue, _properties: cl_command_queue_properties, _enable: cl_bool, _old_properties: *mut cl_command_queue_properties, ) -> CLResult<()>44 fn set_command_queue_property(
45 _command_queue: cl_command_queue,
46 _properties: cl_command_queue_properties,
47 _enable: cl_bool,
48 _old_properties: *mut cl_command_queue_properties,
49 ) -> CLResult<()> {
50 // clSetCommandQueueProperty may unconditionally return an error if no devices in the context
51 // associated with command_queue support modifying the properties of a command-queue. Support
52 // for modifying the properties of a command-queue is required only for OpenCL 1.0 devices.
53 //
54 // CL_INVALID_OPERATION if no devices in the context associated with command_queue support
55 // modifying the properties of a command-queue.
56 Err(CL_INVALID_OPERATION)
57 }
58
valid_command_queue_properties(properties: cl_command_queue_properties) -> bool59 fn valid_command_queue_properties(properties: cl_command_queue_properties) -> bool {
60 let valid_flags = cl_bitfield::from(
61 CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE
62 | CL_QUEUE_PROFILING_ENABLE
63 | CL_QUEUE_ON_DEVICE
64 | CL_QUEUE_ON_DEVICE_DEFAULT,
65 );
66 properties & !valid_flags == 0
67 }
68
supported_command_queue_properties( dev: &Device, properties: cl_command_queue_properties, ) -> bool69 fn supported_command_queue_properties(
70 dev: &Device,
71 properties: cl_command_queue_properties,
72 ) -> bool {
73 let mut valid_flags = CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE;
74 if dev.caps.has_timestamp {
75 valid_flags |= CL_QUEUE_PROFILING_ENABLE;
76 }
77
78 // add on device queue properties here once supported and called from `clCreateCommandQueueWithProperties`
79
80 if properties & !cl_bitfield::from(valid_flags) != 0 {
81 return false;
82 }
83
84 true
85 }
86
create_command_queue_impl( context: cl_context, device: cl_device_id, properties: cl_command_queue_properties, properties_v2: Properties<cl_queue_properties>, ) -> CLResult<cl_command_queue>87 pub fn create_command_queue_impl(
88 context: cl_context,
89 device: cl_device_id,
90 properties: cl_command_queue_properties,
91 properties_v2: Properties<cl_queue_properties>,
92 ) -> CLResult<cl_command_queue> {
93 let c = Context::arc_from_raw(context)?;
94 let d = Device::ref_from_raw(device)?
95 .to_static()
96 .ok_or(CL_INVALID_DEVICE)?;
97
98 // CL_INVALID_DEVICE if device [...] is not associated with context.
99 if !c.devs.contains(&d) {
100 return Err(CL_INVALID_DEVICE);
101 }
102
103 // CL_INVALID_VALUE if values specified in properties are not valid.
104 if !valid_command_queue_properties(properties) {
105 return Err(CL_INVALID_VALUE);
106 }
107
108 // CL_INVALID_QUEUE_PROPERTIES if values specified in properties are valid but are not supported by the device.
109 if !supported_command_queue_properties(d, properties) {
110 return Err(CL_INVALID_QUEUE_PROPERTIES);
111 }
112
113 Ok(Queue::new(c, d, properties, properties_v2)?.into_cl())
114 }
115
116 #[cl_entrypoint(clCreateCommandQueue)]
create_command_queue( context: cl_context, device: cl_device_id, properties: cl_command_queue_properties, ) -> CLResult<cl_command_queue>117 fn create_command_queue(
118 context: cl_context,
119 device: cl_device_id,
120 properties: cl_command_queue_properties,
121 ) -> CLResult<cl_command_queue> {
122 create_command_queue_impl(context, device, properties, Properties::default())
123 }
124
125 #[cl_entrypoint(clCreateCommandQueueWithProperties)]
create_command_queue_with_properties( context: cl_context, device: cl_device_id, properties: *const cl_queue_properties, ) -> CLResult<cl_command_queue>126 fn create_command_queue_with_properties(
127 context: cl_context,
128 device: cl_device_id,
129 properties: *const cl_queue_properties,
130 ) -> CLResult<cl_command_queue> {
131 let mut queue_properties = cl_command_queue_properties::default();
132
133 // SAFETY: properties is a 0 terminated array by spec.
134 let properties = unsafe { Properties::new(properties) }.ok_or(CL_INVALID_PROPERTY)?;
135 for (k, v) in properties.iter() {
136 match *k as cl_uint {
137 CL_QUEUE_PROPERTIES => queue_properties = *v,
138 // CL_INVALID_QUEUE_PROPERTIES if values specified in properties are valid but are not
139 // supported by the device.
140 CL_QUEUE_SIZE => return Err(CL_INVALID_QUEUE_PROPERTIES),
141 _ => return Err(CL_INVALID_PROPERTY),
142 }
143 }
144
145 create_command_queue_impl(context, device, queue_properties, properties)
146 }
147
148 #[cl_entrypoint(clEnqueueMarker)]
enqueue_marker(command_queue: cl_command_queue, event: *mut cl_event) -> CLResult<()>149 fn enqueue_marker(command_queue: cl_command_queue, event: *mut cl_event) -> CLResult<()> {
150 let q = Queue::arc_from_raw(command_queue)?;
151
152 // TODO marker makes sure previous commands did complete
153 create_and_queue(
154 q,
155 CL_COMMAND_MARKER,
156 Vec::new(),
157 event,
158 false,
159 Box::new(|_, _| Ok(())),
160 )
161 }
162
163 #[cl_entrypoint(clEnqueueMarkerWithWaitList)]
enqueue_marker_with_wait_list( command_queue: cl_command_queue, num_events_in_wait_list: cl_uint, event_wait_list: *const cl_event, event: *mut cl_event, ) -> CLResult<()>164 fn enqueue_marker_with_wait_list(
165 command_queue: cl_command_queue,
166 num_events_in_wait_list: cl_uint,
167 event_wait_list: *const cl_event,
168 event: *mut cl_event,
169 ) -> CLResult<()> {
170 let q = Queue::arc_from_raw(command_queue)?;
171 let evs = event_list_from_cl(&q, num_events_in_wait_list, event_wait_list)?;
172
173 // TODO marker makes sure previous commands did complete
174 create_and_queue(
175 q,
176 CL_COMMAND_MARKER,
177 evs,
178 event,
179 false,
180 Box::new(|_, _| Ok(())),
181 )
182 }
183
184 #[cl_entrypoint(clEnqueueBarrier)]
enqueue_barrier(command_queue: cl_command_queue) -> CLResult<()>185 fn enqueue_barrier(command_queue: cl_command_queue) -> CLResult<()> {
186 let q = Queue::arc_from_raw(command_queue)?;
187
188 // TODO barriers make sure previous commands did complete and other commands didn't start
189 let e = Event::new(&q, CL_COMMAND_BARRIER, Vec::new(), Box::new(|_, _| Ok(())));
190 q.queue(e);
191 Ok(())
192 }
193
194 #[cl_entrypoint(clEnqueueBarrierWithWaitList)]
enqueue_barrier_with_wait_list( command_queue: cl_command_queue, num_events_in_wait_list: cl_uint, event_wait_list: *const cl_event, event: *mut cl_event, ) -> CLResult<()>195 fn enqueue_barrier_with_wait_list(
196 command_queue: cl_command_queue,
197 num_events_in_wait_list: cl_uint,
198 event_wait_list: *const cl_event,
199 event: *mut cl_event,
200 ) -> CLResult<()> {
201 let q = Queue::arc_from_raw(command_queue)?;
202 let evs = event_list_from_cl(&q, num_events_in_wait_list, event_wait_list)?;
203
204 // TODO barriers make sure previous commands did complete and other commands didn't start
205 create_and_queue(
206 q,
207 CL_COMMAND_BARRIER,
208 evs,
209 event,
210 false,
211 Box::new(|_, _| Ok(())),
212 )
213 }
214
215 #[cl_entrypoint(clFlush)]
flush(command_queue: cl_command_queue) -> CLResult<()>216 fn flush(command_queue: cl_command_queue) -> CLResult<()> {
217 // CL_INVALID_COMMAND_QUEUE if command_queue is not a valid host command-queue.
218 Queue::ref_from_raw(command_queue)?.flush(false)
219 }
220
221 #[cl_entrypoint(clFinish)]
finish(command_queue: cl_command_queue) -> CLResult<()>222 fn finish(command_queue: cl_command_queue) -> CLResult<()> {
223 // CL_INVALID_COMMAND_QUEUE if command_queue is not a valid host command-queue.
224 Queue::ref_from_raw(command_queue)?.flush(true)
225 }
226
227 #[cl_entrypoint(clRetainCommandQueue)]
retain_command_queue(command_queue: cl_command_queue) -> CLResult<()>228 fn retain_command_queue(command_queue: cl_command_queue) -> CLResult<()> {
229 Queue::retain(command_queue)
230 }
231
232 #[cl_entrypoint(clReleaseCommandQueue)]
release_command_queue(command_queue: cl_command_queue) -> CLResult<()>233 fn release_command_queue(command_queue: cl_command_queue) -> CLResult<()> {
234 // clReleaseCommandQueue performs an implicit flush to issue any previously queued OpenCL
235 // commands in command_queue.
236 flush(command_queue)?;
237 Queue::release(command_queue)
238 }
239