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/context.hpp"
25#include "core/platform.hpp"
26
27using namespace clover;
28
29CLOVER_API cl_context
30clCreateContext(const cl_context_properties *d_props, cl_uint num_devs,
31                const cl_device_id *d_devs,
32                void (CL_CALLBACK *pfn_notify)(const char *, const void *,
33                                               size_t, void *),
34                void *user_data, cl_int *r_errcode) try {
35   auto props = obj<property_list_tag>(d_props);
36   auto devs = objs(d_devs, num_devs);
37
38   if (!pfn_notify && user_data)
39      throw error(CL_INVALID_VALUE);
40
41   for (auto &prop : props) {
42      if (prop.first == CL_CONTEXT_PLATFORM)
43         find_platform(prop.second.as<cl_platform_id>());
44      else
45         throw error(CL_INVALID_PROPERTY);
46   }
47
48   const auto notify = (!pfn_notify ? context::notify_action() :
49                        [=](const char *s) {
50                           pfn_notify(s, NULL, 0, user_data);
51                        });
52
53   ret_error(r_errcode, CL_SUCCESS);
54   return desc(new context(props, devs, notify));
55
56} catch (error &e) {
57   ret_error(r_errcode, e);
58   return NULL;
59}
60
61CLOVER_API cl_context
62clCreateContextFromType(const cl_context_properties *d_props,
63                        cl_device_type type,
64                        void (CL_CALLBACK *pfn_notify)(
65                           const char *, const void *, size_t, void *),
66                        void *user_data, cl_int *r_errcode) try {
67   cl_platform_id d_platform;
68   cl_uint num_platforms;
69   cl_int ret;
70   std::vector<cl_device_id> devs;
71   cl_uint num_devices;
72
73   ret = clGetPlatformIDs(1, &d_platform, &num_platforms);
74   if (ret || !num_platforms)
75      throw error(CL_INVALID_PLATFORM);
76
77   ret = clGetDeviceIDs(d_platform, type, 0, NULL, &num_devices);
78   if (ret)
79      throw error(CL_DEVICE_NOT_FOUND);
80   devs.resize(num_devices);
81   ret = clGetDeviceIDs(d_platform, type, num_devices, devs.data(), 0);
82   if (ret)
83      throw error(CL_DEVICE_NOT_FOUND);
84
85   return clCreateContext(d_props, num_devices, devs.data(), pfn_notify,
86                          user_data, r_errcode);
87
88} catch (error &e) {
89   ret_error(r_errcode, e);
90   return NULL;
91}
92
93CLOVER_API cl_int
94clRetainContext(cl_context d_ctx) try {
95   obj(d_ctx).retain();
96   return CL_SUCCESS;
97
98} catch (error &e) {
99   return e.get();
100}
101
102CLOVER_API cl_int
103clReleaseContext(cl_context d_ctx) try {
104   if (obj(d_ctx).release())
105      delete pobj(d_ctx);
106
107   return CL_SUCCESS;
108
109} catch (error &e) {
110   return e.get();
111}
112
113CLOVER_API cl_int
114clGetContextInfo(cl_context d_ctx, cl_context_info param,
115                 size_t size, void *r_buf, size_t *r_size) try {
116   property_buffer buf { r_buf, size, r_size };
117   auto &ctx = obj(d_ctx);
118
119   switch (param) {
120   case CL_CONTEXT_REFERENCE_COUNT:
121      buf.as_scalar<cl_uint>() = ctx.ref_count();
122      break;
123
124   case CL_CONTEXT_NUM_DEVICES:
125      buf.as_scalar<cl_uint>() = ctx.devices().size();
126      break;
127
128   case CL_CONTEXT_DEVICES:
129      buf.as_vector<cl_device_id>() = descs(ctx.devices());
130      break;
131
132   case CL_CONTEXT_PROPERTIES:
133      buf.as_vector<cl_context_properties>() = desc(ctx.properties());
134      break;
135
136   default:
137      throw error(CL_INVALID_VALUE);
138   }
139
140   return CL_SUCCESS;
141
142} catch (error &e) {
143   return e.get();
144}
145
146CLOVER_API cl_int
147clSetContextDestructorCallback(cl_context d_ctx,
148                               void (CL_CALLBACK *pfn_notify)(cl_context, void *),
149                               void *user_data) try {
150   CLOVER_NOT_SUPPORTED_UNTIL("3.0");
151   auto &ctx = obj(d_ctx);
152
153   if (!pfn_notify)
154      return CL_INVALID_VALUE;
155
156   ctx.destroy_notify([=]{ pfn_notify(d_ctx, user_data); });
157
158   return CL_SUCCESS;
159
160} catch (error &e) {
161   return e.get();
162}
163