clover: Switch to the new utility code.
[mesa.git] / src / gallium / state_trackers / clover / api / event.cpp
1 //
2 // Copyright 2012 Francisco Jerez
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining a
5 // copy of this software and associated documentation files (the "Software"),
6 // to deal in the Software without restriction, including without limitation
7 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 // and/or sell copies of the Software, and to permit persons to whom the
9 // Software is furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 // OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 // OTHER DEALINGS IN THE SOFTWARE.
21 //
22
23 #include "api/util.hpp"
24 #include "core/event.hpp"
25
26 using namespace clover;
27
28 PUBLIC cl_event
29 clCreateUserEvent(cl_context ctx, cl_int *errcode_ret) try {
30 if (!ctx)
31 throw error(CL_INVALID_CONTEXT);
32
33 ret_error(errcode_ret, CL_SUCCESS);
34 return new soft_event(*ctx, {}, false);
35
36 } catch(error &e) {
37 ret_error(errcode_ret, e);
38 return NULL;
39 }
40
41 PUBLIC cl_int
42 clSetUserEventStatus(cl_event ev, cl_int status) {
43 if (!dynamic_cast<soft_event *>(ev))
44 return CL_INVALID_EVENT;
45
46 if (status > 0)
47 return CL_INVALID_VALUE;
48
49 if (ev->status() <= 0)
50 return CL_INVALID_OPERATION;
51
52 if (status)
53 ev->abort(status);
54 else
55 ev->trigger();
56
57 return CL_SUCCESS;
58 }
59
60 PUBLIC cl_int
61 clWaitForEvents(cl_uint num_evs, const cl_event *evs) try {
62 if (!num_evs || !evs)
63 throw error(CL_INVALID_VALUE);
64
65 std::for_each(evs, evs + num_evs, [&](const cl_event ev) {
66 if (!ev)
67 throw error(CL_INVALID_EVENT);
68
69 if (&ev->ctx != &evs[0]->ctx)
70 throw error(CL_INVALID_CONTEXT);
71
72 if (ev->status() < 0)
73 throw error(CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST);
74 });
75
76 // Create a temporary soft event that depends on all the events in
77 // the wait list
78 ref_ptr<soft_event> sev = transfer(
79 new soft_event(evs[0]->ctx, { evs, evs + num_evs }, true));
80
81 // ...and wait on it.
82 sev->wait();
83
84 return CL_SUCCESS;
85
86 } catch(error &e) {
87 return e.get();
88 }
89
90 PUBLIC cl_int
91 clGetEventInfo(cl_event ev, cl_event_info param,
92 size_t size, void *buf, size_t *size_ret) {
93 if (!ev)
94 return CL_INVALID_EVENT;
95
96 switch (param) {
97 case CL_EVENT_COMMAND_QUEUE:
98 return scalar_property<cl_command_queue>(buf, size, size_ret, ev->queue());
99
100 case CL_EVENT_CONTEXT:
101 return scalar_property<cl_context>(buf, size, size_ret, &ev->ctx);
102
103 case CL_EVENT_COMMAND_TYPE:
104 return scalar_property<cl_command_type>(buf, size, size_ret, ev->command());
105
106 case CL_EVENT_COMMAND_EXECUTION_STATUS:
107 return scalar_property<cl_int>(buf, size, size_ret, ev->status());
108
109 case CL_EVENT_REFERENCE_COUNT:
110 return scalar_property<cl_uint>(buf, size, size_ret, ev->ref_count());
111
112 default:
113 return CL_INVALID_VALUE;
114 }
115 }
116
117 PUBLIC cl_int
118 clSetEventCallback(cl_event ev, cl_int type,
119 void (CL_CALLBACK *pfn_event_notify)(cl_event, cl_int,
120 void *),
121 void *user_data) try {
122 if (!ev)
123 throw error(CL_INVALID_EVENT);
124
125 if (!pfn_event_notify || type != CL_COMPLETE)
126 throw error(CL_INVALID_VALUE);
127
128 // Create a temporary soft event that depends on ev, with
129 // pfn_event_notify as completion action.
130 ref_ptr<soft_event> sev = transfer(
131 new soft_event(ev->ctx, { ev }, true,
132 [=](event &) {
133 ev->wait();
134 pfn_event_notify(ev, ev->status(), user_data);
135 }));
136
137 return CL_SUCCESS;
138
139 } catch(error &e) {
140 return e.get();
141 }
142
143 PUBLIC cl_int
144 clRetainEvent(cl_event ev) {
145 if (!ev)
146 return CL_INVALID_EVENT;
147
148 ev->retain();
149 return CL_SUCCESS;
150 }
151
152 PUBLIC cl_int
153 clReleaseEvent(cl_event ev) {
154 if (!ev)
155 return CL_INVALID_EVENT;
156
157 if (ev->release())
158 delete ev;
159
160 return CL_SUCCESS;
161 }
162
163 PUBLIC cl_int
164 clEnqueueMarker(cl_command_queue q, cl_event *ev) try {
165 if (!q)
166 throw error(CL_INVALID_COMMAND_QUEUE);
167
168 if (!ev)
169 throw error(CL_INVALID_VALUE);
170
171 *ev = new hard_event(*q, CL_COMMAND_MARKER, {});
172
173 return CL_SUCCESS;
174
175 } catch(error &e) {
176 return e.get();
177 }
178
179 PUBLIC cl_int
180 clEnqueueBarrier(cl_command_queue q) {
181 if (!q)
182 return CL_INVALID_COMMAND_QUEUE;
183
184 // No need to do anything, q preserves data ordering strictly.
185 return CL_SUCCESS;
186 }
187
188 PUBLIC cl_int
189 clEnqueueWaitForEvents(cl_command_queue q, cl_uint num_evs,
190 const cl_event *evs) try {
191 if (!q)
192 throw error(CL_INVALID_COMMAND_QUEUE);
193
194 if (!num_evs || !evs)
195 throw error(CL_INVALID_VALUE);
196
197 std::for_each(evs, evs + num_evs, [&](const cl_event ev) {
198 if (!ev)
199 throw error(CL_INVALID_EVENT);
200
201 if (&ev->ctx != &q->ctx)
202 throw error(CL_INVALID_CONTEXT);
203 });
204
205 // Create a hard event that depends on the events in the wait list:
206 // subsequent commands in the same queue will be implicitly
207 // serialized with respect to it -- hard events always are.
208 ref_ptr<hard_event> hev = transfer(
209 new hard_event(*q, 0, { evs, evs + num_evs }));
210
211 return CL_SUCCESS;
212
213 } catch(error &e) {
214 return e.get();
215 }
216
217 PUBLIC cl_int
218 clGetEventProfilingInfo(cl_event ev, cl_profiling_info param,
219 size_t size, void *buf, size_t *size_ret) try {
220 hard_event *hev = dynamic_cast<hard_event *>(ev);
221
222 if (!ev)
223 return CL_INVALID_EVENT;
224
225 if (!hev || hev->status() != CL_COMPLETE)
226 return CL_PROFILING_INFO_NOT_AVAILABLE;
227
228 switch (param) {
229 case CL_PROFILING_COMMAND_QUEUED:
230 return scalar_property<cl_ulong>(buf, size, size_ret, hev->time_queued());
231
232 case CL_PROFILING_COMMAND_SUBMIT:
233 return scalar_property<cl_ulong>(buf, size, size_ret, hev->time_submit());
234
235 case CL_PROFILING_COMMAND_START:
236 return scalar_property<cl_ulong>(buf, size, size_ret, hev->time_start());
237
238 case CL_PROFILING_COMMAND_END:
239 return scalar_property<cl_ulong>(buf, size, size_ret, hev->time_end());
240
241 default:
242 return CL_INVALID_VALUE;
243 }
244
245 } catch (lazy<cl_ulong>::undefined_error &e) {
246 return CL_PROFILING_INFO_NOT_AVAILABLE;
247
248 } catch (error &e) {
249 return e.get();
250 }
251
252 PUBLIC cl_int
253 clFinish(cl_command_queue q) try {
254 if (!q)
255 throw error(CL_INVALID_COMMAND_QUEUE);
256
257 // Create a temporary hard event -- it implicitly depends on all
258 // the previously queued hard events.
259 ref_ptr<hard_event> hev = transfer(new hard_event(*q, 0, { }));
260
261 // And wait on it.
262 hev->wait();
263
264 return CL_SUCCESS;
265
266 } catch(error &e) {
267 return e.get();
268 }