1 //---------------------------------------------------------------------------//
2 // Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com>
4 // Distributed under the Boost Software License, Version 1.0
5 // See accompanying file LICENSE_1_0.txt or copy at
6 // http://www.boost.org/LICENSE_1_0.txt
8 // See http://boostorg.github.com/compute for more information.
9 //---------------------------------------------------------------------------//
11 #define BOOST_TEST_MODULE TestProgram
12 #include <boost/test/unit_test.hpp>
14 // disable the automatic kernel compilation debug messages. this allows the
15 // test for program to check that compilation error exceptions are properly
16 // thrown when invalid kernel code is passed to program::build().
17 #undef BOOST_COMPUTE_DEBUG_KERNEL_COMPILATION
19 #include <boost/compute/kernel.hpp>
20 #include <boost/compute/system.hpp>
21 #include <boost/compute/program.hpp>
22 #include <boost/compute/utility/source.hpp>
25 #include "context_setup.hpp"
27 namespace compute
= boost::compute
;
30 "__kernel void foo(__global float *x, const uint n) { }\n"
31 "__kernel void bar(__global int *x, __global int *y) { }\n";
34 BOOST_AUTO_TEST_CASE(get_program_info
)
37 boost::compute::program program
=
38 boost::compute::program::create_with_source(source
, context
);
44 #ifndef BOOST_COMPUTE_USE_OFFLINE_CACHE
45 BOOST_CHECK(program
.source().empty() == false);
47 BOOST_CHECK(program
.get_context() == context
);
50 BOOST_AUTO_TEST_CASE(program_source
)
52 // create program from source
53 boost::compute::program program
=
54 boost::compute::program::create_with_source(source
, context
);
56 BOOST_CHECK_EQUAL(std::string(source
), program
.source());
59 BOOST_AUTO_TEST_CASE(program_multiple_sources
)
61 std::vector
<std::string
> sources
;
62 sources
.push_back("__kernel void foo(__global int* x) { }\n");
63 sources
.push_back("__kernel void bar(__global float* y) { }\n");
65 // create program from sources
66 boost::compute::program program
=
67 boost::compute::program::create_with_source(sources
, context
);
70 boost::compute::kernel foo
= program
.create_kernel("foo");
71 boost::compute::kernel bar
= program
.create_kernel("bar");
74 BOOST_AUTO_TEST_CASE(program_source_no_file
)
76 // create program from a non-existant source file
77 // and verifies it throws.
78 BOOST_CHECK_THROW(boost::compute::program program
=
79 boost::compute::program::create_with_source_file
80 (std::string(), context
),
81 std::ios_base::failure
);
84 BOOST_AUTO_TEST_CASE(create_kernel
)
86 boost::compute::program program
=
87 boost::compute::program::create_with_source(source
, context
);
90 boost::compute::kernel foo
= program
.create_kernel("foo");
91 boost::compute::kernel bar
= program
.create_kernel("bar");
93 // try to create a kernel that doesn't exist
94 BOOST_CHECK_THROW(program
.create_kernel("baz"), boost::compute::opencl_error
);
97 BOOST_AUTO_TEST_CASE(create_with_binary
)
99 // create program from source
100 boost::compute::program source_program
=
101 boost::compute::program::create_with_source(source
, context
);
102 source_program
.build();
104 // create kernels in source program
105 boost::compute::kernel source_foo_kernel
= source_program
.create_kernel("foo");
106 boost::compute::kernel source_bar_kernel
= source_program
.create_kernel("bar");
108 // check source kernels
109 BOOST_CHECK_EQUAL(source_foo_kernel
.name(), std::string("foo"));
110 BOOST_CHECK_EQUAL(source_bar_kernel
.name(), std::string("bar"));
113 std::vector
<unsigned char> binary
= source_program
.binary();
115 // create program from binary
116 boost::compute::program binary_program
=
117 boost::compute::program::create_with_binary(binary
, context
);
118 binary_program
.build();
120 // create kernels in binary program
121 boost::compute::kernel binary_foo_kernel
= binary_program
.create_kernel("foo");
122 boost::compute::kernel binary_bar_kernel
= binary_program
.create_kernel("bar");
124 // check binary kernels
125 BOOST_CHECK_EQUAL(binary_foo_kernel
.name(), std::string("foo"));
126 BOOST_CHECK_EQUAL(binary_bar_kernel
.name(), std::string("bar"));
129 #ifdef BOOST_COMPUTE_CL_VERSION_2_1
130 BOOST_AUTO_TEST_CASE(create_with_il
)
132 size_t device_address_space_size
= device
.address_bits();
133 std::string
file_path(BOOST_COMPUTE_TEST_DATA_PATH
);
134 if(device_address_space_size
== 64)
136 file_path
+= "/program.spirv64";
140 file_path
+= "/program.spirv32";
143 // create program from il
144 boost::compute::program il_program
;
145 BOOST_CHECK_NO_THROW(
146 il_program
= boost::compute::program::create_with_il_file(
150 BOOST_CHECK_NO_THROW(il_program
.build());
152 // create kernel (to check if program was loaded correctly)
153 BOOST_CHECK_NO_THROW(il_program
.create_kernel("foobar"));
156 BOOST_AUTO_TEST_CASE(get_program_il_binary
)
158 size_t device_address_space_size
= device
.address_bits();
159 std::string
file_path(BOOST_COMPUTE_TEST_DATA_PATH
);
160 if(device_address_space_size
== 64)
162 file_path
+= "/program.spirv64";
166 file_path
+= "/program.spirv32";
169 // create program from il
170 boost::compute::program il_program
;
171 BOOST_CHECK_NO_THROW(
172 il_program
= boost::compute::program::create_with_il_file(
176 BOOST_CHECK_NO_THROW(il_program
.build());
178 std::vector
<unsigned char> il_binary
;
179 BOOST_CHECK_NO_THROW(il_binary
= il_program
.il_binary());
181 // create program from loaded il binary
182 BOOST_CHECK_NO_THROW(
183 il_program
= boost::compute::program::create_with_il(il_binary
, context
)
185 BOOST_CHECK_NO_THROW(il_program
.build());
187 // create kernel (to check if program was loaded correctly)
188 BOOST_CHECK_NO_THROW(il_program
.create_kernel("foobar"));
191 BOOST_AUTO_TEST_CASE(get_program_il_binary_empty
)
193 boost::compute::program program
;
194 BOOST_CHECK_NO_THROW(
195 program
= boost::compute::program::create_with_source(source
, context
)
197 BOOST_CHECK_NO_THROW(program
.build());
199 std::vector
<unsigned char> il_binary
;
200 il_binary
= program
.il_binary();
201 BOOST_CHECK(il_binary
.empty());
203 #endif // BOOST_COMPUTE_CL_VERSION_2_1
205 BOOST_AUTO_TEST_CASE(create_with_source_doctest
)
207 //! [create_with_source]
208 std::string source
= "__kernel void foo(__global int *data) { }";
210 boost::compute::program foo_program
=
211 boost::compute::program::create_with_source(source
, context
);
212 //! [create_with_source]
217 #ifdef BOOST_COMPUTE_CL_VERSION_1_2
218 BOOST_AUTO_TEST_CASE(compile_and_link
)
220 REQUIRES_OPENCL_VERSION(1,2);
222 if(!supports_compile_program(device
) || !supports_link_program(device
)) {
226 // create the library program
227 const char library_source
[] = BOOST_COMPUTE_STRINGIZE_SOURCE(
228 // for some reason the apple opencl compilers complains if a prototype
229 // for the square() function is not available, so we add it here
232 // generic square function definition
233 T
square(T x
) { return x
* x
; }
236 compute::program library_program
=
237 compute::program::create_with_source(library_source
, context
);
239 library_program
.compile("-DT=int");
241 // create the kernel program
242 const char kernel_source
[] = BOOST_COMPUTE_STRINGIZE_SOURCE(
243 // forward declare square function
244 extern int square(int);
246 // square kernel definition
247 __kernel
void square_kernel(__global
int *x
)
253 compute::program square_program
=
254 compute::program::create_with_source(kernel_source
, context
);
256 square_program
.compile();
259 std::vector
<compute::program
> programs
;
260 programs
.push_back(library_program
);
261 programs
.push_back(square_program
);
263 compute::program linked_program
=
264 compute::program::link(programs
, context
);
266 // create the square kernel
267 compute::kernel square_kernel
=
268 linked_program
.create_kernel("square_kernel");
269 BOOST_CHECK_EQUAL(square_kernel
.name(), "square_kernel");
272 BOOST_AUTO_TEST_CASE(compile_and_link_with_headers
)
274 REQUIRES_OPENCL_VERSION(1,2);
276 if(!supports_compile_program(device
) || !supports_link_program(device
)) {
280 // create the header programs
281 const char square_header_source
[] = BOOST_COMPUTE_STRINGIZE_SOURCE(
282 T
square(T x
) { return x
* x
; }
284 const char div2_header_source
[] = BOOST_COMPUTE_STRINGIZE_SOURCE(
285 T
div2(T x
) { return x
/ 2; }
288 compute::program square_header_program
=
289 compute::program::create_with_source(square_header_source
, context
);
290 compute::program div2_header_program
=
291 compute::program::create_with_source(div2_header_source
, context
);
293 // create the kernel program
294 const char kernel_source
[] =
295 "#include \"square.h\"\n"
296 "#include \"div2.h\"\n"
297 "__kernel void squareby2_kernel(__global int *x)"
299 " x[0] = div2(square(x[0]));"
302 compute::program square_program
=
303 compute::program::create_with_source(kernel_source
, context
);
305 std::vector
<std::pair
<std::string
, compute::program
> > header_programs
;
306 header_programs
.push_back(std::make_pair("square.h", square_header_program
));
307 header_programs
.push_back(std::make_pair("div2.h", div2_header_program
));
309 square_program
.compile("-DT=int", header_programs
);
312 std::vector
<compute::program
> programs
;
313 programs
.push_back(square_program
);
315 compute::program linked_program
=
316 compute::program::link(programs
, context
);
318 // create the square kernel
319 compute::kernel square_kernel
=
320 linked_program
.create_kernel("squareby2_kernel");
321 BOOST_CHECK_EQUAL(square_kernel
.name(), "squareby2_kernel");
323 #endif // BOOST_COMPUTE_CL_VERSION_1_2
325 BOOST_AUTO_TEST_CASE(build_log
)
327 const char invalid_source
[] =
328 "__kernel void foo(__global int *input) { !@#$%^&*() }";
330 compute::program invalid_program
=
331 compute::program::create_with_source(invalid_source
, context
);
334 invalid_program
.build();
336 // should not get here
339 catch(compute::opencl_error
&){
340 std::string log
= invalid_program
.build_log();
341 BOOST_CHECK(!log
.empty());
345 BOOST_AUTO_TEST_SUITE_END()