clover: make module::symbol::name a string
[mesa.git] / src / gallium / state_trackers / clover / api / program.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/program.hpp"
25
26 using namespace clover;
27
28 namespace {
29 void validate_build_program_common(const program &prog, cl_uint num_devs,
30 const cl_device_id *d_devs,
31 void (*pfn_notify)(cl_program, void *),
32 void *user_data) {
33
34 if ((!pfn_notify && user_data))
35 throw error(CL_INVALID_VALUE);
36
37 if (prog.kernel_ref_count())
38 throw error(CL_INVALID_OPERATION);
39
40 if (any_of([&](const device &dev) {
41 return !count(dev, prog.context().devices());
42 }, objs<allow_empty_tag>(d_devs, num_devs)))
43 throw error(CL_INVALID_DEVICE);
44 }
45 }
46
47 CLOVER_API cl_program
48 clCreateProgramWithSource(cl_context d_ctx, cl_uint count,
49 const char **strings, const size_t *lengths,
50 cl_int *r_errcode) try {
51 auto &ctx = obj(d_ctx);
52 std::string source;
53
54 if (!count || !strings ||
55 any_of(is_zero(), range(strings, count)))
56 throw error(CL_INVALID_VALUE);
57
58 // Concatenate all the provided fragments together
59 for (unsigned i = 0; i < count; ++i)
60 source += (lengths && lengths[i] ?
61 std::string(strings[i], strings[i] + lengths[i]) :
62 std::string(strings[i]));
63
64 // ...and create a program object for them.
65 ret_error(r_errcode, CL_SUCCESS);
66 return new program(ctx, source);
67
68 } catch (error &e) {
69 ret_error(r_errcode, e);
70 return NULL;
71 }
72
73 CLOVER_API cl_program
74 clCreateProgramWithBinary(cl_context d_ctx, cl_uint n,
75 const cl_device_id *d_devs,
76 const size_t *lengths,
77 const unsigned char **binaries,
78 cl_int *r_status, cl_int *r_errcode) try {
79 auto &ctx = obj(d_ctx);
80 auto devs = objs(d_devs, n);
81
82 if (!lengths || !binaries)
83 throw error(CL_INVALID_VALUE);
84
85 if (any_of([&](const device &dev) {
86 return !count(dev, ctx.devices());
87 }, devs))
88 throw error(CL_INVALID_DEVICE);
89
90 // Deserialize the provided binaries,
91 std::vector<std::pair<cl_int, module>> result = map(
92 [](const unsigned char *p, size_t l) -> std::pair<cl_int, module> {
93 if (!p || !l)
94 return { CL_INVALID_VALUE, {} };
95
96 try {
97 compat::istream::buffer_t bin(p, l);
98 compat::istream s(bin);
99
100 return { CL_SUCCESS, module::deserialize(s) };
101
102 } catch (compat::istream::error &e) {
103 return { CL_INVALID_BINARY, {} };
104 }
105 },
106 range(binaries, n),
107 range(lengths, n));
108
109 // update the status array,
110 if (r_status)
111 copy(map(keys(), result), r_status);
112
113 if (any_of(key_equals(CL_INVALID_VALUE), result))
114 throw error(CL_INVALID_VALUE);
115
116 if (any_of(key_equals(CL_INVALID_BINARY), result))
117 throw error(CL_INVALID_BINARY);
118
119 // initialize a program object with them.
120 ret_error(r_errcode, CL_SUCCESS);
121 return new program(ctx, devs, map(values(), result));
122
123 } catch (error &e) {
124 ret_error(r_errcode, e);
125 return NULL;
126 }
127
128 CLOVER_API cl_program
129 clCreateProgramWithBuiltInKernels(cl_context d_ctx, cl_uint n,
130 const cl_device_id *d_devs,
131 const char *kernel_names,
132 cl_int *r_errcode) try {
133 auto &ctx = obj(d_ctx);
134 auto devs = objs(d_devs, n);
135
136 if (any_of([&](const device &dev) {
137 return !count(dev, ctx.devices());
138 }, devs))
139 throw error(CL_INVALID_DEVICE);
140
141 // No currently supported built-in kernels.
142 throw error(CL_INVALID_VALUE);
143
144 } catch (error &e) {
145 ret_error(r_errcode, e);
146 return NULL;
147 }
148
149
150 CLOVER_API cl_int
151 clRetainProgram(cl_program d_prog) try {
152 obj(d_prog).retain();
153 return CL_SUCCESS;
154
155 } catch (error &e) {
156 return e.get();
157 }
158
159 CLOVER_API cl_int
160 clReleaseProgram(cl_program d_prog) try {
161 if (obj(d_prog).release())
162 delete pobj(d_prog);
163
164 return CL_SUCCESS;
165
166 } catch (error &e) {
167 return e.get();
168 }
169
170 CLOVER_API cl_int
171 clBuildProgram(cl_program d_prog, cl_uint num_devs,
172 const cl_device_id *d_devs, const char *p_opts,
173 void (*pfn_notify)(cl_program, void *),
174 void *user_data) try {
175 auto &prog = obj(d_prog);
176 auto devs = (d_devs ? objs(d_devs, num_devs) :
177 ref_vector<device>(prog.context().devices()));
178 auto opts = (p_opts ? p_opts : "");
179
180 validate_build_program_common(prog, num_devs, d_devs, pfn_notify, user_data);
181
182 prog.build(devs, opts);
183 return CL_SUCCESS;
184 } catch (error &e) {
185 if (e.get() == CL_INVALID_COMPILER_OPTIONS)
186 return CL_INVALID_BUILD_OPTIONS;
187 if (e.get() == CL_COMPILE_PROGRAM_FAILURE)
188 return CL_BUILD_PROGRAM_FAILURE;
189 return e.get();
190 }
191
192 CLOVER_API cl_int
193 clCompileProgram(cl_program d_prog, cl_uint num_devs,
194 const cl_device_id *d_devs, const char *p_opts,
195 cl_uint num_headers, const cl_program *d_header_progs,
196 const char **header_names,
197 void (*pfn_notify)(cl_program, void *),
198 void *user_data) try {
199 auto &prog = obj(d_prog);
200 auto devs = (d_devs ? objs(d_devs, num_devs) :
201 ref_vector<device>(prog.context().devices()));
202 auto opts = (p_opts ? p_opts : "");
203 header_map headers;
204
205 validate_build_program_common(prog, num_devs, d_devs, pfn_notify, user_data);
206
207 if (bool(num_headers) != bool(header_names))
208 throw error(CL_INVALID_VALUE);
209
210 if (!prog.has_source)
211 throw error(CL_INVALID_OPERATION);
212
213
214 for_each([&](const char *name, const program &header) {
215 if (!header.has_source)
216 throw error(CL_INVALID_OPERATION);
217
218 if (!any_of(key_equals(name), headers))
219 headers.push_back(std::pair<std::string, std::string>(
220 name, header.source()));
221 },
222 range(header_names, num_headers),
223 objs<allow_empty_tag>(d_header_progs, num_headers));
224
225 prog.build(devs, opts, headers);
226 return CL_SUCCESS;
227
228 } catch (error &e) {
229 return e.get();
230 }
231
232 CLOVER_API cl_int
233 clUnloadCompiler() {
234 return CL_SUCCESS;
235 }
236
237 CLOVER_API cl_int
238 clUnloadPlatformCompiler(cl_platform_id d_platform) {
239 return CL_SUCCESS;
240 }
241
242 CLOVER_API cl_int
243 clGetProgramInfo(cl_program d_prog, cl_program_info param,
244 size_t size, void *r_buf, size_t *r_size) try {
245 property_buffer buf { r_buf, size, r_size };
246 auto &prog = obj(d_prog);
247
248 switch (param) {
249 case CL_PROGRAM_REFERENCE_COUNT:
250 buf.as_scalar<cl_uint>() = prog.ref_count();
251 break;
252
253 case CL_PROGRAM_CONTEXT:
254 buf.as_scalar<cl_context>() = desc(prog.context());
255 break;
256
257 case CL_PROGRAM_NUM_DEVICES:
258 buf.as_scalar<cl_uint>() = (prog.devices().size() ?
259 prog.devices().size() :
260 prog.context().devices().size());
261 break;
262
263 case CL_PROGRAM_DEVICES:
264 buf.as_vector<cl_device_id>() = (prog.devices().size() ?
265 descs(prog.devices()) :
266 descs(prog.context().devices()));
267 break;
268
269 case CL_PROGRAM_SOURCE:
270 buf.as_string() = prog.source();
271 break;
272
273 case CL_PROGRAM_BINARY_SIZES:
274 buf.as_vector<size_t>() = map([&](const device &dev) {
275 return prog.binary(dev).size();
276 },
277 prog.devices());
278 break;
279
280 case CL_PROGRAM_BINARIES:
281 buf.as_matrix<unsigned char>() = map([&](const device &dev) {
282 compat::ostream::buffer_t bin;
283 compat::ostream s(bin);
284 prog.binary(dev).serialize(s);
285 return bin;
286 },
287 prog.devices());
288 break;
289
290 case CL_PROGRAM_NUM_KERNELS:
291 buf.as_scalar<cl_uint>() = prog.symbols().size();
292 break;
293
294 case CL_PROGRAM_KERNEL_NAMES:
295 buf.as_string() = fold([](const std::string &a, const module::symbol &s) {
296 return ((a.empty() ? "" : a + ";") + s.name);
297 }, std::string(), prog.symbols());
298 break;
299
300 default:
301 throw error(CL_INVALID_VALUE);
302 }
303
304 return CL_SUCCESS;
305
306 } catch (error &e) {
307 return e.get();
308 }
309
310 CLOVER_API cl_int
311 clGetProgramBuildInfo(cl_program d_prog, cl_device_id d_dev,
312 cl_program_build_info param,
313 size_t size, void *r_buf, size_t *r_size) try {
314 property_buffer buf { r_buf, size, r_size };
315 auto &prog = obj(d_prog);
316 auto &dev = obj(d_dev);
317
318 if (!count(dev, prog.context().devices()))
319 return CL_INVALID_DEVICE;
320
321 switch (param) {
322 case CL_PROGRAM_BUILD_STATUS:
323 buf.as_scalar<cl_build_status>() = prog.build_status(dev);
324 break;
325
326 case CL_PROGRAM_BUILD_OPTIONS:
327 buf.as_string() = prog.build_opts(dev);
328 break;
329
330 case CL_PROGRAM_BUILD_LOG:
331 buf.as_string() = prog.build_log(dev);
332 break;
333
334 default:
335 throw error(CL_INVALID_VALUE);
336 }
337
338 return CL_SUCCESS;
339
340 } catch (error &e) {
341 return e.get();
342 }