17ec681f3Smrg//
27ec681f3Smrg// Copyright 2012 Francisco Jerez
37ec681f3Smrg//
47ec681f3Smrg// Permission is hereby granted, free of charge, to any person obtaining a
57ec681f3Smrg// copy of this software and associated documentation files (the "Software"),
67ec681f3Smrg// to deal in the Software without restriction, including without limitation
77ec681f3Smrg// the rights to use, copy, modify, merge, publish, distribute, sublicense,
87ec681f3Smrg// and/or sell copies of the Software, and to permit persons to whom the
97ec681f3Smrg// Software is furnished to do so, subject to the following conditions:
107ec681f3Smrg//
117ec681f3Smrg// The above copyright notice and this permission notice shall be included in
127ec681f3Smrg// all copies or substantial portions of the Software.
137ec681f3Smrg//
147ec681f3Smrg// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
157ec681f3Smrg// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
167ec681f3Smrg// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
177ec681f3Smrg// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
187ec681f3Smrg// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
197ec681f3Smrg// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
207ec681f3Smrg// OTHER DEALINGS IN THE SOFTWARE.
217ec681f3Smrg//
227ec681f3Smrg
237ec681f3Smrg#include "api/util.hpp"
247ec681f3Smrg#include "core/event.hpp"
257ec681f3Smrg
267ec681f3Smrgusing namespace clover;
277ec681f3Smrg
287ec681f3SmrgCLOVER_API cl_event
297ec681f3SmrgclCreateUserEvent(cl_context d_ctx, cl_int *r_errcode) try {
307ec681f3Smrg   auto &ctx = obj(d_ctx);
317ec681f3Smrg
327ec681f3Smrg   ret_error(r_errcode, CL_SUCCESS);
337ec681f3Smrg   return desc(new soft_event(ctx, {}, false));
347ec681f3Smrg
357ec681f3Smrg} catch (error &e) {
367ec681f3Smrg   ret_error(r_errcode, e);
377ec681f3Smrg   return NULL;
387ec681f3Smrg}
397ec681f3Smrg
407ec681f3SmrgCLOVER_API cl_int
417ec681f3SmrgclSetUserEventStatus(cl_event d_ev, cl_int status) try {
427ec681f3Smrg   auto &sev = obj<soft_event>(d_ev);
437ec681f3Smrg
447ec681f3Smrg   if (status > 0)
457ec681f3Smrg      return CL_INVALID_VALUE;
467ec681f3Smrg
477ec681f3Smrg   if (sev.status() <= 0)
487ec681f3Smrg      return CL_INVALID_OPERATION;
497ec681f3Smrg
507ec681f3Smrg   if (status)
517ec681f3Smrg      sev.abort(status);
527ec681f3Smrg   else
537ec681f3Smrg      sev.trigger();
547ec681f3Smrg
557ec681f3Smrg   return CL_SUCCESS;
567ec681f3Smrg
577ec681f3Smrg} catch (error &e) {
587ec681f3Smrg   return e.get();
597ec681f3Smrg}
607ec681f3Smrg
617ec681f3SmrgCLOVER_API cl_int
627ec681f3SmrgclWaitForEvents(cl_uint num_evs, const cl_event *d_evs) try {
637ec681f3Smrg   auto evs = objs(d_evs, num_evs);
647ec681f3Smrg
657ec681f3Smrg   for (auto &ev : evs) {
667ec681f3Smrg      if (ev.context() != evs.front().context())
677ec681f3Smrg         throw error(CL_INVALID_CONTEXT);
687ec681f3Smrg
697ec681f3Smrg      if (ev.status() < 0)
707ec681f3Smrg         throw error(CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST);
717ec681f3Smrg   }
727ec681f3Smrg
737ec681f3Smrg   // Create a temporary soft event that depends on all the events in
747ec681f3Smrg   // the wait list
757ec681f3Smrg   auto sev = create<soft_event>(evs.front().context(), evs, true);
767ec681f3Smrg
777ec681f3Smrg   // ...and wait on it.
787ec681f3Smrg   sev().wait();
797ec681f3Smrg
807ec681f3Smrg   return CL_SUCCESS;
817ec681f3Smrg
827ec681f3Smrg} catch (error &e) {
837ec681f3Smrg   return e.get();
847ec681f3Smrg}
857ec681f3Smrg
867ec681f3SmrgCLOVER_API cl_int
877ec681f3SmrgclGetEventInfo(cl_event d_ev, cl_event_info param,
887ec681f3Smrg               size_t size, void *r_buf, size_t *r_size) try {
897ec681f3Smrg   property_buffer buf { r_buf, size, r_size };
907ec681f3Smrg   auto &ev = obj(d_ev);
917ec681f3Smrg
927ec681f3Smrg   switch (param) {
937ec681f3Smrg   case CL_EVENT_COMMAND_QUEUE:
947ec681f3Smrg      buf.as_scalar<cl_command_queue>() = desc(ev.queue());
957ec681f3Smrg      break;
967ec681f3Smrg
977ec681f3Smrg   case CL_EVENT_CONTEXT:
987ec681f3Smrg      buf.as_scalar<cl_context>() = desc(ev.context());
997ec681f3Smrg      break;
1007ec681f3Smrg
1017ec681f3Smrg   case CL_EVENT_COMMAND_TYPE:
1027ec681f3Smrg      buf.as_scalar<cl_command_type>() = ev.command();
1037ec681f3Smrg      break;
1047ec681f3Smrg
1057ec681f3Smrg   case CL_EVENT_COMMAND_EXECUTION_STATUS:
1067ec681f3Smrg      buf.as_scalar<cl_int>() = ev.status();
1077ec681f3Smrg      break;
1087ec681f3Smrg
1097ec681f3Smrg   case CL_EVENT_REFERENCE_COUNT:
1107ec681f3Smrg      buf.as_scalar<cl_uint>() = ev.ref_count();
1117ec681f3Smrg      break;
1127ec681f3Smrg
1137ec681f3Smrg   default:
1147ec681f3Smrg      throw error(CL_INVALID_VALUE);
1157ec681f3Smrg   }
1167ec681f3Smrg
1177ec681f3Smrg   return CL_SUCCESS;
1187ec681f3Smrg
1197ec681f3Smrg} catch (error &e) {
1207ec681f3Smrg   return e.get();
1217ec681f3Smrg}
1227ec681f3Smrg
1237ec681f3SmrgCLOVER_API cl_int
1247ec681f3SmrgclSetEventCallback(cl_event d_ev, cl_int type,
1257ec681f3Smrg                   void (CL_CALLBACK *pfn_notify)(cl_event, cl_int, void *),
1267ec681f3Smrg                   void *user_data) try {
1277ec681f3Smrg   auto &ev = obj(d_ev);
1287ec681f3Smrg
1297ec681f3Smrg   if (!pfn_notify ||
1307ec681f3Smrg       (type != CL_COMPLETE && type != CL_SUBMITTED && type != CL_RUNNING))
1317ec681f3Smrg      throw error(CL_INVALID_VALUE);
1327ec681f3Smrg
1337ec681f3Smrg   // Create a temporary soft event that depends on ev, with
1347ec681f3Smrg   // pfn_notify as completion action.
1357ec681f3Smrg   create<soft_event>(ev.context(), ref_vector<event> { ev }, true,
1367ec681f3Smrg                      [=, &ev](event &) {
1377ec681f3Smrg                         ev.wait();
1387ec681f3Smrg                         pfn_notify(desc(ev), ev.status(), user_data);
1397ec681f3Smrg                      });
1407ec681f3Smrg
1417ec681f3Smrg   return CL_SUCCESS;
1427ec681f3Smrg
1437ec681f3Smrg} catch (error &e) {
1447ec681f3Smrg   return e.get();
1457ec681f3Smrg}
1467ec681f3Smrg
1477ec681f3SmrgCLOVER_API cl_int
1487ec681f3SmrgclRetainEvent(cl_event d_ev) try {
1497ec681f3Smrg   obj(d_ev).retain();
1507ec681f3Smrg   return CL_SUCCESS;
1517ec681f3Smrg
1527ec681f3Smrg} catch (error &e) {
1537ec681f3Smrg   return e.get();
1547ec681f3Smrg}
1557ec681f3Smrg
1567ec681f3SmrgCLOVER_API cl_int
1577ec681f3SmrgclReleaseEvent(cl_event d_ev) try {
1587ec681f3Smrg   if (obj(d_ev).release())
1597ec681f3Smrg      delete pobj(d_ev);
1607ec681f3Smrg
1617ec681f3Smrg   return CL_SUCCESS;
1627ec681f3Smrg
1637ec681f3Smrg} catch (error &e) {
1647ec681f3Smrg   return e.get();
1657ec681f3Smrg}
1667ec681f3Smrg
1677ec681f3SmrgCLOVER_API cl_int
1687ec681f3SmrgclEnqueueMarker(cl_command_queue d_q, cl_event *rd_ev) try {
1697ec681f3Smrg   auto &q = obj(d_q);
1707ec681f3Smrg
1717ec681f3Smrg   if (!rd_ev)
1727ec681f3Smrg      throw error(CL_INVALID_VALUE);
1737ec681f3Smrg
1747ec681f3Smrg   *rd_ev = desc(new hard_event(q, CL_COMMAND_MARKER, {}));
1757ec681f3Smrg
1767ec681f3Smrg   return CL_SUCCESS;
1777ec681f3Smrg
1787ec681f3Smrg} catch (error &e) {
1797ec681f3Smrg   return e.get();
1807ec681f3Smrg}
1817ec681f3Smrg
1827ec681f3SmrgCLOVER_API cl_int
1837ec681f3SmrgclEnqueueMarkerWithWaitList(cl_command_queue d_q, cl_uint num_deps,
1847ec681f3Smrg                            const cl_event *d_deps, cl_event *rd_ev) try {
1857ec681f3Smrg   auto &q = obj(d_q);
1867ec681f3Smrg   auto deps = objs<wait_list_tag>(d_deps, num_deps);
1877ec681f3Smrg
1887ec681f3Smrg   for (auto &ev : deps) {
1897ec681f3Smrg      if (ev.context() != q.context())
1907ec681f3Smrg         throw error(CL_INVALID_CONTEXT);
1917ec681f3Smrg   }
1927ec681f3Smrg
1937ec681f3Smrg   // Create a hard event that depends on the events in the wait list:
1947ec681f3Smrg   // previous commands in the same queue are implicitly serialized
1957ec681f3Smrg   // with respect to it -- hard events always are.
1967ec681f3Smrg   auto hev = create<hard_event>(q, CL_COMMAND_MARKER, deps);
1977ec681f3Smrg
1987ec681f3Smrg   ret_object(rd_ev, hev);
1997ec681f3Smrg   return CL_SUCCESS;
2007ec681f3Smrg
2017ec681f3Smrg} catch (error &e) {
2027ec681f3Smrg   return e.get();
2037ec681f3Smrg}
2047ec681f3Smrg
2057ec681f3SmrgCLOVER_API cl_int
2067ec681f3SmrgclEnqueueBarrier(cl_command_queue d_q) try {
2077ec681f3Smrg   obj(d_q);
2087ec681f3Smrg
2097ec681f3Smrg   // No need to do anything, q preserves data ordering strictly.
2107ec681f3Smrg
2117ec681f3Smrg   return CL_SUCCESS;
2127ec681f3Smrg
2137ec681f3Smrg} catch (error &e) {
2147ec681f3Smrg   return e.get();
2157ec681f3Smrg}
2167ec681f3Smrg
2177ec681f3SmrgCLOVER_API cl_int
2187ec681f3SmrgclEnqueueBarrierWithWaitList(cl_command_queue d_q, cl_uint num_deps,
2197ec681f3Smrg                             const cl_event *d_deps, cl_event *rd_ev) try {
2207ec681f3Smrg   auto &q = obj(d_q);
2217ec681f3Smrg   auto deps = objs<wait_list_tag>(d_deps, num_deps);
2227ec681f3Smrg
2237ec681f3Smrg   for (auto &ev : deps) {
2247ec681f3Smrg      if (ev.context() != q.context())
2257ec681f3Smrg         throw error(CL_INVALID_CONTEXT);
2267ec681f3Smrg   }
2277ec681f3Smrg
2287ec681f3Smrg   // Create a hard event that depends on the events in the wait list:
2297ec681f3Smrg   // subsequent commands in the same queue will be implicitly
2307ec681f3Smrg   // serialized with respect to it -- hard events always are.
2317ec681f3Smrg   auto hev = create<hard_event>(q, CL_COMMAND_BARRIER, deps);
2327ec681f3Smrg
2337ec681f3Smrg   ret_object(rd_ev, hev);
2347ec681f3Smrg   return CL_SUCCESS;
2357ec681f3Smrg
2367ec681f3Smrg} catch (error &e) {
2377ec681f3Smrg   return e.get();
2387ec681f3Smrg}
2397ec681f3Smrg
2407ec681f3SmrgCLOVER_API cl_int
2417ec681f3SmrgclEnqueueWaitForEvents(cl_command_queue d_q, cl_uint num_evs,
2427ec681f3Smrg                       const cl_event *d_evs) try {
2437ec681f3Smrg   // The wait list is mandatory for clEnqueueWaitForEvents().
2447ec681f3Smrg   objs(d_evs, num_evs);
2457ec681f3Smrg
2467ec681f3Smrg   return clEnqueueBarrierWithWaitList(d_q, num_evs, d_evs, NULL);
2477ec681f3Smrg
2487ec681f3Smrg} catch (error &e) {
2497ec681f3Smrg   return e.get();
2507ec681f3Smrg}
2517ec681f3Smrg
2527ec681f3SmrgCLOVER_API cl_int
2537ec681f3SmrgclGetEventProfilingInfo(cl_event d_ev, cl_profiling_info param,
2547ec681f3Smrg                        size_t size, void *r_buf, size_t *r_size) try {
2557ec681f3Smrg   property_buffer buf { r_buf, size, r_size };
2567ec681f3Smrg   hard_event &hev = dynamic_cast<hard_event &>(obj(d_ev));
2577ec681f3Smrg
2587ec681f3Smrg   if (hev.status() != CL_COMPLETE)
2597ec681f3Smrg      throw error(CL_PROFILING_INFO_NOT_AVAILABLE);
2607ec681f3Smrg
2617ec681f3Smrg   switch (param) {
2627ec681f3Smrg   case CL_PROFILING_COMMAND_QUEUED:
2637ec681f3Smrg      buf.as_scalar<cl_ulong>() = hev.time_queued();
2647ec681f3Smrg      break;
2657ec681f3Smrg
2667ec681f3Smrg   case CL_PROFILING_COMMAND_SUBMIT:
2677ec681f3Smrg      buf.as_scalar<cl_ulong>() = hev.time_submit();
2687ec681f3Smrg      break;
2697ec681f3Smrg
2707ec681f3Smrg   case CL_PROFILING_COMMAND_START:
2717ec681f3Smrg      buf.as_scalar<cl_ulong>() = hev.time_start();
2727ec681f3Smrg      break;
2737ec681f3Smrg
2747ec681f3Smrg   case CL_PROFILING_COMMAND_END:
2757ec681f3Smrg   case CL_PROFILING_COMMAND_COMPLETE:
2767ec681f3Smrg      buf.as_scalar<cl_ulong>() = hev.time_end();
2777ec681f3Smrg      break;
2787ec681f3Smrg
2797ec681f3Smrg   default:
2807ec681f3Smrg      throw error(CL_INVALID_VALUE);
2817ec681f3Smrg   }
2827ec681f3Smrg
2837ec681f3Smrg   return CL_SUCCESS;
2847ec681f3Smrg
2857ec681f3Smrg} catch (std::bad_cast &) {
2867ec681f3Smrg   return CL_PROFILING_INFO_NOT_AVAILABLE;
2877ec681f3Smrg
2887ec681f3Smrg} catch (lazy<cl_ulong>::undefined_error &) {
2897ec681f3Smrg   return CL_PROFILING_INFO_NOT_AVAILABLE;
2907ec681f3Smrg
2917ec681f3Smrg} catch (error &e) {
2927ec681f3Smrg   return e.get();
2937ec681f3Smrg}
2947ec681f3Smrg
2957ec681f3SmrgCLOVER_API cl_int
2967ec681f3SmrgclFinish(cl_command_queue d_q) try {
2977ec681f3Smrg   auto &q = obj(d_q);
2987ec681f3Smrg
2997ec681f3Smrg   // Create a temporary hard event -- it implicitly depends on all
3007ec681f3Smrg   // the previously queued hard events.
3017ec681f3Smrg   auto hev = create<hard_event>(q, 0, ref_vector<event> {});
3027ec681f3Smrg
3037ec681f3Smrg   // And wait on it.
3047ec681f3Smrg   hev().wait();
3057ec681f3Smrg
3067ec681f3Smrg   return CL_SUCCESS;
3077ec681f3Smrg
3087ec681f3Smrg} catch (error &e) {
3097ec681f3Smrg   return e.get();
3107ec681f3Smrg}
311