xref: /aosp_15_r20/external/mesa3d/src/gallium/frontends/rusticl/api/event.rs (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 use crate::api::icd::*;
2 use crate::api::types::*;
3 use crate::api::util::*;
4 use crate::core::context::*;
5 use crate::core::event::*;
6 use crate::core::queue::*;
7 
8 use rusticl_opencl_gen::*;
9 use rusticl_proc_macros::cl_entrypoint;
10 use rusticl_proc_macros::cl_info_entrypoint;
11 
12 use std::collections::HashSet;
13 use std::mem::MaybeUninit;
14 use std::ptr;
15 use std::sync::Arc;
16 
17 #[cl_info_entrypoint(clGetEventInfo)]
18 impl CLInfo<cl_event_info> for cl_event {
query(&self, q: cl_event_info, _: &[u8]) -> CLResult<Vec<MaybeUninit<u8>>>19     fn query(&self, q: cl_event_info, _: &[u8]) -> CLResult<Vec<MaybeUninit<u8>>> {
20         let event = Event::ref_from_raw(*self)?;
21         Ok(match *q {
22             CL_EVENT_COMMAND_EXECUTION_STATUS => cl_prop::<cl_int>(event.status()),
23             CL_EVENT_CONTEXT => {
24                 // Note we use as_ptr here which doesn't increase the reference count.
25                 let ptr = Arc::as_ptr(&event.context);
26                 cl_prop::<cl_context>(cl_context::from_ptr(ptr))
27             }
28             CL_EVENT_COMMAND_QUEUE => {
29                 let ptr = match event.queue.as_ref() {
30                     // Note we use as_ptr here which doesn't increase the reference count.
31                     Some(queue) => Arc::as_ptr(queue),
32                     None => ptr::null_mut(),
33                 };
34                 cl_prop::<cl_command_queue>(cl_command_queue::from_ptr(ptr))
35             }
36             CL_EVENT_REFERENCE_COUNT => cl_prop::<cl_uint>(Event::refcnt(*self)?),
37             CL_EVENT_COMMAND_TYPE => cl_prop::<cl_command_type>(event.cmd_type),
38             _ => return Err(CL_INVALID_VALUE),
39         })
40     }
41 }
42 
43 #[cl_info_entrypoint(clGetEventProfilingInfo)]
44 impl CLInfo<cl_profiling_info> for cl_event {
query(&self, q: cl_profiling_info, _: &[u8]) -> CLResult<Vec<MaybeUninit<u8>>>45     fn query(&self, q: cl_profiling_info, _: &[u8]) -> CLResult<Vec<MaybeUninit<u8>>> {
46         let event = Event::ref_from_raw(*self)?;
47         if event.cmd_type == CL_COMMAND_USER {
48             // CL_PROFILING_INFO_NOT_AVAILABLE [...] if event is a user event object.
49             return Err(CL_PROFILING_INFO_NOT_AVAILABLE);
50         }
51 
52         Ok(match *q {
53             CL_PROFILING_COMMAND_QUEUED => cl_prop::<cl_ulong>(event.get_time(EventTimes::Queued)),
54             CL_PROFILING_COMMAND_SUBMIT => cl_prop::<cl_ulong>(event.get_time(EventTimes::Submit)),
55             CL_PROFILING_COMMAND_START => cl_prop::<cl_ulong>(event.get_time(EventTimes::Start)),
56             CL_PROFILING_COMMAND_END => cl_prop::<cl_ulong>(event.get_time(EventTimes::End)),
57             // For now, we treat Complete the same as End
58             CL_PROFILING_COMMAND_COMPLETE => cl_prop::<cl_ulong>(event.get_time(EventTimes::End)),
59             _ => return Err(CL_INVALID_VALUE),
60         })
61     }
62 }
63 
64 #[cl_entrypoint(clCreateUserEvent)]
create_user_event(context: cl_context) -> CLResult<cl_event>65 fn create_user_event(context: cl_context) -> CLResult<cl_event> {
66     let c = Context::arc_from_raw(context)?;
67     Ok(Event::new_user(c).into_cl())
68 }
69 
70 #[cl_entrypoint(clRetainEvent)]
retain_event(event: cl_event) -> CLResult<()>71 fn retain_event(event: cl_event) -> CLResult<()> {
72     Event::retain(event)
73 }
74 
75 #[cl_entrypoint(clReleaseEvent)]
release_event(event: cl_event) -> CLResult<()>76 fn release_event(event: cl_event) -> CLResult<()> {
77     Event::release(event)
78 }
79 
80 #[cl_entrypoint(clWaitForEvents)]
wait_for_events(num_events: cl_uint, event_list: *const cl_event) -> CLResult<()>81 fn wait_for_events(num_events: cl_uint, event_list: *const cl_event) -> CLResult<()> {
82     let evs = Event::arcs_from_arr(event_list, num_events)?;
83 
84     // CL_INVALID_VALUE if num_events is zero or event_list is NULL.
85     if evs.is_empty() {
86         return Err(CL_INVALID_VALUE);
87     }
88 
89     // CL_INVALID_CONTEXT if events specified in event_list do not belong to the same context.
90     let contexts: HashSet<_> = evs.iter().map(|e| &e.context).collect();
91     if contexts.len() != 1 {
92         return Err(CL_INVALID_CONTEXT);
93     }
94 
95     // find all queues we have to flush
96     for q in Event::deep_unflushed_queues(&evs) {
97         q.flush(false)?;
98     }
99 
100     // now wait on all events and check if we got any errors
101     let mut err = false;
102     for e in evs {
103         err |= e.wait() < 0;
104     }
105 
106     // CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST if the execution status of any of the events
107     // in event_list is a negative integer value.
108     if err {
109         return Err(CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST);
110     }
111 
112     Ok(())
113 }
114 
115 #[cl_entrypoint(clSetEventCallback)]
set_event_callback( event: cl_event, command_exec_callback_type: cl_int, pfn_event_notify: Option<FuncEventCB>, user_data: *mut ::std::os::raw::c_void, ) -> CLResult<()>116 fn set_event_callback(
117     event: cl_event,
118     command_exec_callback_type: cl_int,
119     pfn_event_notify: Option<FuncEventCB>,
120     user_data: *mut ::std::os::raw::c_void,
121 ) -> CLResult<()> {
122     let e = Event::ref_from_raw(event)?;
123 
124     // CL_INVALID_VALUE [...] if command_exec_callback_type is not CL_SUBMITTED, CL_RUNNING, or CL_COMPLETE.
125     if ![CL_SUBMITTED, CL_RUNNING, CL_COMPLETE].contains(&(command_exec_callback_type as cl_uint)) {
126         return Err(CL_INVALID_VALUE);
127     }
128 
129     // SAFETY: The requirements on `EventCB::new` match the requirements
130     // imposed by the OpenCL specification. It is the caller's duty to uphold them.
131     let cb = unsafe { EventCB::new(pfn_event_notify, user_data)? };
132 
133     e.add_cb(command_exec_callback_type, cb);
134 
135     Ok(())
136 }
137 
138 #[cl_entrypoint(clSetUserEventStatus)]
set_user_event_status(event: cl_event, execution_status: cl_int) -> CLResult<()>139 fn set_user_event_status(event: cl_event, execution_status: cl_int) -> CLResult<()> {
140     let e = Event::ref_from_raw(event)?;
141 
142     // CL_INVALID_VALUE if the execution_status is not CL_COMPLETE or a negative integer value.
143     if execution_status != CL_COMPLETE as cl_int && execution_status > 0 {
144         return Err(CL_INVALID_VALUE);
145     }
146 
147     // CL_INVALID_OPERATION if the execution_status for event has already been changed by a
148     // previous call to clSetUserEventStatus.
149     if e.status() != CL_SUBMITTED as cl_int {
150         return Err(CL_INVALID_OPERATION);
151     }
152 
153     e.set_user_status(execution_status);
154     Ok(())
155 }
156 
157 /// implements CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST when `block = true`
create_and_queue( q: Arc<Queue>, cmd_type: cl_command_type, deps: Vec<Arc<Event>>, event: *mut cl_event, block: bool, work: EventSig, ) -> CLResult<()>158 pub fn create_and_queue(
159     q: Arc<Queue>,
160     cmd_type: cl_command_type,
161     deps: Vec<Arc<Event>>,
162     event: *mut cl_event,
163     block: bool,
164     work: EventSig,
165 ) -> CLResult<()> {
166     let e = Event::new(&q, cmd_type, deps, work);
167     if !event.is_null() {
168         // SAFETY: we check for null and valid API use is to pass in a valid pointer
169         unsafe {
170             event.write(Arc::clone(&e).into_cl());
171         }
172     }
173     if block {
174         q.queue(Arc::clone(&e));
175         q.flush(true)?;
176         if e.deps.iter().any(|dep| dep.is_error()) {
177             return Err(CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST);
178         }
179         // return any execution errors when blocking
180         let err = e.status();
181         if err < 0 {
182             return Err(err);
183         }
184     } else {
185         q.queue(e);
186     }
187     Ok(())
188 }
189