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"
28 using namespace clover
;
31 void validate_build_program_common(const program
&prog
, cl_uint num_devs
,
32 const cl_device_id
*d_devs
,
33 void (*pfn_notify
)(cl_program
, void *),
36 if ((!pfn_notify
&& user_data
))
37 throw error(CL_INVALID_VALUE
);
39 if (prog
.kernel_ref_count())
40 throw error(CL_INVALID_OPERATION
);
42 if (any_of([&](const device
&dev
) {
43 return !count(dev
, prog
.context().devices());
44 }, objs
<allow_empty_tag
>(d_devs
, num_devs
)))
45 throw error(CL_INVALID_DEVICE
);
50 clCreateProgramWithSource(cl_context d_ctx
, cl_uint count
,
51 const char **strings
, const size_t *lengths
,
52 cl_int
*r_errcode
) try {
53 auto &ctx
= obj(d_ctx
);
56 if (!count
|| !strings
||
57 any_of(is_zero(), range(strings
, count
)))
58 throw error(CL_INVALID_VALUE
);
60 // Concatenate all the provided fragments together
61 for (unsigned i
= 0; i
< count
; ++i
)
62 source
+= (lengths
&& lengths
[i
] ?
63 std::string(strings
[i
], strings
[i
] + lengths
[i
]) :
64 std::string(strings
[i
]));
66 // ...and create a program object for them.
67 ret_error(r_errcode
, CL_SUCCESS
);
68 return new program(ctx
, source
);
71 ret_error(r_errcode
, e
);
76 clCreateProgramWithBinary(cl_context d_ctx
, cl_uint n
,
77 const cl_device_id
*d_devs
,
78 const size_t *lengths
,
79 const unsigned char **binaries
,
80 cl_int
*r_status
, cl_int
*r_errcode
) try {
81 auto &ctx
= obj(d_ctx
);
82 auto devs
= objs(d_devs
, n
);
84 if (!lengths
|| !binaries
)
85 throw error(CL_INVALID_VALUE
);
87 if (any_of([&](const device
&dev
) {
88 return !count(dev
, ctx
.devices());
90 throw error(CL_INVALID_DEVICE
);
92 // Deserialize the provided binaries,
93 std::vector
<std::pair
<cl_int
, module
>> result
= map(
94 [](const unsigned char *p
, size_t l
) -> std::pair
<cl_int
, module
> {
96 return { CL_INVALID_VALUE
, {} };
99 std::stringbuf
bin( { (char*)p
, l
} );
100 std::istream
s(&bin
);
102 return { CL_SUCCESS
, module::deserialize(s
) };
104 } catch (std::istream::failure
&e
) {
105 return { CL_INVALID_BINARY
, {} };
111 // update the status array,
113 copy(map(keys(), result
), r_status
);
115 if (any_of(key_equals(CL_INVALID_VALUE
), result
))
116 throw error(CL_INVALID_VALUE
);
118 if (any_of(key_equals(CL_INVALID_BINARY
), result
))
119 throw error(CL_INVALID_BINARY
);
121 // initialize a program object with them.
122 ret_error(r_errcode
, CL_SUCCESS
);
123 return new program(ctx
, devs
, map(values(), result
));
126 ret_error(r_errcode
, e
);
130 CLOVER_API cl_program
131 clCreateProgramWithBuiltInKernels(cl_context d_ctx
, cl_uint n
,
132 const cl_device_id
*d_devs
,
133 const char *kernel_names
,
134 cl_int
*r_errcode
) try {
135 auto &ctx
= obj(d_ctx
);
136 auto devs
= objs(d_devs
, n
);
138 if (any_of([&](const device
&dev
) {
139 return !count(dev
, ctx
.devices());
141 throw error(CL_INVALID_DEVICE
);
143 // No currently supported built-in kernels.
144 throw error(CL_INVALID_VALUE
);
147 ret_error(r_errcode
, e
);
153 clRetainProgram(cl_program d_prog
) try {
154 obj(d_prog
).retain();
162 clReleaseProgram(cl_program d_prog
) try {
163 if (obj(d_prog
).release())
173 clBuildProgram(cl_program d_prog
, cl_uint num_devs
,
174 const cl_device_id
*d_devs
, const char *p_opts
,
175 void (*pfn_notify
)(cl_program
, void *),
176 void *user_data
) try {
177 auto &prog
= obj(d_prog
);
178 auto devs
= (d_devs
? objs(d_devs
, num_devs
) :
179 ref_vector
<device
>(prog
.context().devices()));
180 auto opts
= (p_opts
? p_opts
: "");
182 validate_build_program_common(prog
, num_devs
, d_devs
, pfn_notify
, user_data
);
184 prog
.build(devs
, opts
);
187 if (e
.get() == CL_INVALID_COMPILER_OPTIONS
)
188 return CL_INVALID_BUILD_OPTIONS
;
189 if (e
.get() == CL_COMPILE_PROGRAM_FAILURE
)
190 return CL_BUILD_PROGRAM_FAILURE
;
195 clCompileProgram(cl_program d_prog
, cl_uint num_devs
,
196 const cl_device_id
*d_devs
, const char *p_opts
,
197 cl_uint num_headers
, const cl_program
*d_header_progs
,
198 const char **header_names
,
199 void (*pfn_notify
)(cl_program
, void *),
200 void *user_data
) try {
201 auto &prog
= obj(d_prog
);
202 auto devs
= (d_devs
? objs(d_devs
, num_devs
) :
203 ref_vector
<device
>(prog
.context().devices()));
204 auto opts
= (p_opts
? p_opts
: "");
207 validate_build_program_common(prog
, num_devs
, d_devs
, pfn_notify
, user_data
);
209 if (bool(num_headers
) != bool(header_names
))
210 throw error(CL_INVALID_VALUE
);
212 if (!prog
.has_source
)
213 throw error(CL_INVALID_OPERATION
);
216 for_each([&](const char *name
, const program
&header
) {
217 if (!header
.has_source
)
218 throw error(CL_INVALID_OPERATION
);
220 if (!any_of(key_equals(name
), headers
))
221 headers
.push_back(std::pair
<std::string
, std::string
>(
222 name
, header
.source()));
224 range(header_names
, num_headers
),
225 objs
<allow_empty_tag
>(d_header_progs
, num_headers
));
227 prog
.build(devs
, opts
, headers
);
240 clUnloadPlatformCompiler(cl_platform_id d_platform
) {
245 clGetProgramInfo(cl_program d_prog
, cl_program_info param
,
246 size_t size
, void *r_buf
, size_t *r_size
) try {
247 property_buffer buf
{ r_buf
, size
, r_size
};
248 auto &prog
= obj(d_prog
);
251 case CL_PROGRAM_REFERENCE_COUNT
:
252 buf
.as_scalar
<cl_uint
>() = prog
.ref_count();
255 case CL_PROGRAM_CONTEXT
:
256 buf
.as_scalar
<cl_context
>() = desc(prog
.context());
259 case CL_PROGRAM_NUM_DEVICES
:
260 buf
.as_scalar
<cl_uint
>() = (prog
.devices().size() ?
261 prog
.devices().size() :
262 prog
.context().devices().size());
265 case CL_PROGRAM_DEVICES
:
266 buf
.as_vector
<cl_device_id
>() = (prog
.devices().size() ?
267 descs(prog
.devices()) :
268 descs(prog
.context().devices()));
271 case CL_PROGRAM_SOURCE
:
272 buf
.as_string() = prog
.source();
275 case CL_PROGRAM_BINARY_SIZES
:
276 buf
.as_vector
<size_t>() = map([&](const device
&dev
) {
277 return prog
.binary(dev
).size();
282 case CL_PROGRAM_BINARIES
:
283 buf
.as_matrix
<unsigned char>() = map([&](const device
&dev
) {
285 std::ostream
s(&bin
);
286 prog
.binary(dev
).serialize(s
);
292 case CL_PROGRAM_NUM_KERNELS
:
293 buf
.as_scalar
<cl_uint
>() = prog
.symbols().size();
296 case CL_PROGRAM_KERNEL_NAMES
:
297 buf
.as_string() = fold([](const std::string
&a
, const module::symbol
&s
) {
298 return ((a
.empty() ? "" : a
+ ";") + s
.name
);
299 }, std::string(), prog
.symbols());
303 throw error(CL_INVALID_VALUE
);
313 clGetProgramBuildInfo(cl_program d_prog
, cl_device_id d_dev
,
314 cl_program_build_info param
,
315 size_t size
, void *r_buf
, size_t *r_size
) try {
316 property_buffer buf
{ r_buf
, size
, r_size
};
317 auto &prog
= obj(d_prog
);
318 auto &dev
= obj(d_dev
);
320 if (!count(dev
, prog
.context().devices()))
321 return CL_INVALID_DEVICE
;
324 case CL_PROGRAM_BUILD_STATUS
:
325 buf
.as_scalar
<cl_build_status
>() = prog
.build_status(dev
);
328 case CL_PROGRAM_BUILD_OPTIONS
:
329 buf
.as_string() = prog
.build_opts(dev
);
332 case CL_PROGRAM_BUILD_LOG
:
333 buf
.as_string() = prog
.build_log(dev
);
337 throw error(CL_INVALID_VALUE
);