2 // Copyright 2012 Francisco Jerez
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:
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
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.
23 #include "api/util.hpp"
24 #include "core/program.hpp"
26 using namespace clover
;
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 *),
34 if ((!pfn_notify
&& user_data
))
35 throw error(CL_INVALID_VALUE
);
37 if (prog
.kernel_ref_count())
38 throw error(CL_INVALID_OPERATION
);
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
);
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
);
54 if (!count
|| !strings
||
55 any_of(is_zero(), range(strings
, count
)))
56 throw error(CL_INVALID_VALUE
);
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
]));
64 // ...and create a program object for them.
65 ret_error(r_errcode
, CL_SUCCESS
);
66 return new program(ctx
, source
);
69 ret_error(r_errcode
, e
);
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
);
82 if (!lengths
|| !binaries
)
83 throw error(CL_INVALID_VALUE
);
85 if (any_of([&](const device
&dev
) {
86 return !count(dev
, ctx
.devices());
88 throw error(CL_INVALID_DEVICE
);
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
> {
94 return { CL_INVALID_VALUE
, {} };
97 compat::istream::buffer_t
bin(p
, l
);
98 compat::istream
s(bin
);
100 return { CL_SUCCESS
, module::deserialize(s
) };
102 } catch (compat::istream::error
&e
) {
103 return { CL_INVALID_BINARY
, {} };
109 // update the status array,
111 copy(map(keys(), result
), r_status
);
113 if (any_of(key_equals(CL_INVALID_VALUE
), result
))
114 throw error(CL_INVALID_VALUE
);
116 if (any_of(key_equals(CL_INVALID_BINARY
), result
))
117 throw error(CL_INVALID_BINARY
);
119 // initialize a program object with them.
120 ret_error(r_errcode
, CL_SUCCESS
);
121 return new program(ctx
, devs
, map(values(), result
));
124 ret_error(r_errcode
, e
);
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
);
136 if (any_of([&](const device
&dev
) {
137 return !count(dev
, ctx
.devices());
139 throw error(CL_INVALID_DEVICE
);
141 // No currently supported built-in kernels.
142 throw error(CL_INVALID_VALUE
);
145 ret_error(r_errcode
, e
);
151 clRetainProgram(cl_program d_prog
) try {
152 obj(d_prog
).retain();
160 clReleaseProgram(cl_program d_prog
) try {
161 if (obj(d_prog
).release())
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
: "");
180 validate_build_program_common(prog
, num_devs
, d_devs
, pfn_notify
, user_data
);
182 prog
.build(devs
, opts
);
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
;
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
: "");
205 validate_build_program_common(prog
, num_devs
, d_devs
, pfn_notify
, user_data
);
207 if (bool(num_headers
) != bool(header_names
))
208 throw error(CL_INVALID_VALUE
);
210 if (!prog
.has_source
)
211 throw error(CL_INVALID_OPERATION
);
214 for_each([&](const char *name
, const program
&header
) {
215 if (!header
.has_source
)
216 throw error(CL_INVALID_OPERATION
);
218 if (!any_of(key_equals(name
), headers
))
219 headers
.push_back(std::pair
<std::string
, std::string
>(
220 name
, header
.source()));
222 range(header_names
, num_headers
),
223 objs
<allow_empty_tag
>(d_header_progs
, num_headers
));
225 prog
.build(devs
, opts
, headers
);
238 clUnloadPlatformCompiler(cl_platform_id d_platform
) {
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
);
249 case CL_PROGRAM_REFERENCE_COUNT
:
250 buf
.as_scalar
<cl_uint
>() = prog
.ref_count();
253 case CL_PROGRAM_CONTEXT
:
254 buf
.as_scalar
<cl_context
>() = desc(prog
.context());
257 case CL_PROGRAM_NUM_DEVICES
:
258 buf
.as_scalar
<cl_uint
>() = (prog
.devices().size() ?
259 prog
.devices().size() :
260 prog
.context().devices().size());
263 case CL_PROGRAM_DEVICES
:
264 buf
.as_vector
<cl_device_id
>() = (prog
.devices().size() ?
265 descs(prog
.devices()) :
266 descs(prog
.context().devices()));
269 case CL_PROGRAM_SOURCE
:
270 buf
.as_string() = prog
.source();
273 case CL_PROGRAM_BINARY_SIZES
:
274 buf
.as_vector
<size_t>() = map([&](const device
&dev
) {
275 return prog
.binary(dev
).size();
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
);
290 case CL_PROGRAM_NUM_KERNELS
:
291 buf
.as_scalar
<cl_uint
>() = prog
.symbols().size();
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());
301 throw error(CL_INVALID_VALUE
);
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
);
318 if (!count(dev
, prog
.context().devices()))
319 return CL_INVALID_DEVICE
;
322 case CL_PROGRAM_BUILD_STATUS
:
323 buf
.as_scalar
<cl_build_status
>() = prog
.build_status(dev
);
326 case CL_PROGRAM_BUILD_OPTIONS
:
327 buf
.as_string() = prog
.build_opts(dev
);
330 case CL_PROGRAM_BUILD_LOG
:
331 buf
.as_string() = prog
.build_log(dev
);
335 throw error(CL_INVALID_VALUE
);