xref: /aosp_15_r20/external/mesa3d/src/gallium/frontends/rusticl/api/queue.rs (revision 6104692788411f58d303aa86923a9ff6ecaded22)
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::mem::MaybeUninit;
15 use std::ptr;
16 use std::sync::Arc;
17 
18 #[cl_info_entrypoint(clGetCommandQueueInfo)]
19 impl CLInfo<cl_command_queue_info> for cl_command_queue {
query(&self, q: cl_command_queue_info, _: &[u8]) -> CLResult<Vec<MaybeUninit<u8>>>20     fn query(&self, q: cl_command_queue_info, _: &[u8]) -> CLResult<Vec<MaybeUninit<u8>>> {
21         let queue = Queue::ref_from_raw(*self)?;
22         Ok(match q {
23             CL_QUEUE_CONTEXT => {
24                 // Note we use as_ptr here which doesn't increase the reference count.
25                 let ptr = Arc::as_ptr(&queue.context);
26                 cl_prop::<cl_context>(cl_context::from_ptr(ptr))
27             }
28             CL_QUEUE_DEVICE => cl_prop::<cl_device_id>(cl_device_id::from_ptr(queue.device)),
29             CL_QUEUE_DEVICE_DEFAULT => cl_prop::<cl_command_queue>(ptr::null_mut()),
30             CL_QUEUE_PROPERTIES => cl_prop::<cl_command_queue_properties>(queue.props),
31             CL_QUEUE_PROPERTIES_ARRAY => {
32                 cl_prop::<&Option<Properties<cl_queue_properties>>>(&queue.props_v2)
33             }
34             CL_QUEUE_REFERENCE_COUNT => cl_prop::<cl_uint>(Queue::refcnt(*self)?),
35             // clGetCommandQueueInfo, passing CL_QUEUE_SIZE Returns CL_INVALID_COMMAND_QUEUE since
36             // command_queue cannot be a valid device command-queue.
37             CL_QUEUE_SIZE => return Err(CL_INVALID_COMMAND_QUEUE),
38             // CL_INVALID_VALUE if param_name is not one of the supported values
39             _ => return Err(CL_INVALID_VALUE),
40         })
41     }
42 }
43 
44 #[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<()>45 fn set_command_queue_property(
46     _command_queue: cl_command_queue,
47     _properties: cl_command_queue_properties,
48     _enable: cl_bool,
49     _old_properties: *mut cl_command_queue_properties,
50 ) -> CLResult<()> {
51     // clSetCommandQueueProperty may unconditionally return an error if no devices in the context
52     // associated with command_queue support modifying the properties of a command-queue. Support
53     // for modifying the properties of a command-queue is required only for OpenCL 1.0 devices.
54     //
55     // CL_INVALID_OPERATION if no devices in the context associated with command_queue support
56     // modifying the properties of a command-queue.
57     Err(CL_INVALID_OPERATION)
58 }
59 
valid_command_queue_properties(properties: cl_command_queue_properties) -> bool60 fn valid_command_queue_properties(properties: cl_command_queue_properties) -> bool {
61     let valid_flags = cl_bitfield::from(
62         CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE
63             | CL_QUEUE_PROFILING_ENABLE
64             | CL_QUEUE_ON_DEVICE
65             | CL_QUEUE_ON_DEVICE_DEFAULT,
66     );
67     properties & !valid_flags == 0
68 }
69 
supported_command_queue_properties( dev: &Device, properties: cl_command_queue_properties, ) -> bool70 fn supported_command_queue_properties(
71     dev: &Device,
72     properties: cl_command_queue_properties,
73 ) -> bool {
74     let profiling = cl_bitfield::from(CL_QUEUE_PROFILING_ENABLE);
75     let valid_flags = profiling;
76     if properties & !valid_flags != 0 {
77         return false;
78     }
79 
80     if properties & profiling != 0 && !dev.caps.has_timestamp {
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: Option<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: Option<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, None)
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     let properties = if properties.is_null() {
133         None
134     } else {
135         let properties = Properties::from_ptr(properties).ok_or(CL_INVALID_PROPERTY)?;
136 
137         for (k, v) in &properties.props {
138             match *k as cl_uint {
139                 CL_QUEUE_PROPERTIES => queue_properties = *v,
140                 // CL_INVALID_QUEUE_PROPERTIES if values specified in properties are valid but are not
141                 // supported by the device.
142                 CL_QUEUE_SIZE => return Err(CL_INVALID_QUEUE_PROPERTIES),
143                 _ => return Err(CL_INVALID_PROPERTY),
144             }
145         }
146 
147         Some(properties)
148     };
149 
150     create_command_queue_impl(context, device, queue_properties, properties)
151 }
152 
153 #[cl_entrypoint(clEnqueueMarker)]
enqueue_marker(command_queue: cl_command_queue, event: *mut cl_event) -> CLResult<()>154 fn enqueue_marker(command_queue: cl_command_queue, event: *mut cl_event) -> CLResult<()> {
155     let q = Queue::arc_from_raw(command_queue)?;
156 
157     // TODO marker makes sure previous commands did complete
158     create_and_queue(
159         q,
160         CL_COMMAND_MARKER,
161         Vec::new(),
162         event,
163         false,
164         Box::new(|_, _| Ok(())),
165     )
166 }
167 
168 #[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<()>169 fn enqueue_marker_with_wait_list(
170     command_queue: cl_command_queue,
171     num_events_in_wait_list: cl_uint,
172     event_wait_list: *const cl_event,
173     event: *mut cl_event,
174 ) -> CLResult<()> {
175     let q = Queue::arc_from_raw(command_queue)?;
176     let evs = event_list_from_cl(&q, num_events_in_wait_list, event_wait_list)?;
177 
178     // TODO marker makes sure previous commands did complete
179     create_and_queue(
180         q,
181         CL_COMMAND_MARKER,
182         evs,
183         event,
184         false,
185         Box::new(|_, _| Ok(())),
186     )
187 }
188 
189 #[cl_entrypoint(clEnqueueBarrier)]
enqueue_barrier(command_queue: cl_command_queue) -> CLResult<()>190 fn enqueue_barrier(command_queue: cl_command_queue) -> CLResult<()> {
191     let q = Queue::arc_from_raw(command_queue)?;
192 
193     // TODO barriers make sure previous commands did complete and other commands didn't start
194     let e = Event::new(&q, CL_COMMAND_BARRIER, Vec::new(), Box::new(|_, _| Ok(())));
195     q.queue(e);
196     Ok(())
197 }
198 
199 #[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<()>200 fn enqueue_barrier_with_wait_list(
201     command_queue: cl_command_queue,
202     num_events_in_wait_list: cl_uint,
203     event_wait_list: *const cl_event,
204     event: *mut cl_event,
205 ) -> CLResult<()> {
206     let q = Queue::arc_from_raw(command_queue)?;
207     let evs = event_list_from_cl(&q, num_events_in_wait_list, event_wait_list)?;
208 
209     // TODO barriers make sure previous commands did complete and other commands didn't start
210     create_and_queue(
211         q,
212         CL_COMMAND_BARRIER,
213         evs,
214         event,
215         false,
216         Box::new(|_, _| Ok(())),
217     )
218 }
219 
220 #[cl_entrypoint(clFlush)]
flush(command_queue: cl_command_queue) -> CLResult<()>221 fn flush(command_queue: cl_command_queue) -> CLResult<()> {
222     // CL_INVALID_COMMAND_QUEUE if command_queue is not a valid host command-queue.
223     Queue::ref_from_raw(command_queue)?.flush(false)
224 }
225 
226 #[cl_entrypoint(clFinish)]
finish(command_queue: cl_command_queue) -> CLResult<()>227 fn finish(command_queue: cl_command_queue) -> CLResult<()> {
228     // CL_INVALID_COMMAND_QUEUE if command_queue is not a valid host command-queue.
229     Queue::ref_from_raw(command_queue)?.flush(true)
230 }
231 
232 #[cl_entrypoint(clRetainCommandQueue)]
retain_command_queue(command_queue: cl_command_queue) -> CLResult<()>233 fn retain_command_queue(command_queue: cl_command_queue) -> CLResult<()> {
234     Queue::retain(command_queue)
235 }
236 
237 #[cl_entrypoint(clReleaseCommandQueue)]
release_command_queue(command_queue: cl_command_queue) -> CLResult<()>238 fn release_command_queue(command_queue: cl_command_queue) -> CLResult<()> {
239     // clReleaseCommandQueue performs an implicit flush to issue any previously queued OpenCL
240     // commands in command_queue.
241     flush(command_queue)?;
242     Queue::release(command_queue)
243 }
244