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