1 //---------------------------------------------------------------------------//
2 // Copyright (c) 2013-2014 Kyle Lutz <kyle.r.lutz@gmail.com>
3 //
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
7 //
8 // See http://boostorg.github.com/compute for more information.
9 //---------------------------------------------------------------------------//
10
11 #define BOOST_TEST_MODULE TestClosure
12 #include <boost/test/unit_test.hpp>
13
14 #include <boost/compute/system.hpp>
15 #include <boost/compute/closure.hpp>
16 #include <boost/compute/function.hpp>
17 #include <boost/compute/algorithm/copy.hpp>
18 #include <boost/compute/algorithm/transform.hpp>
19 #include <boost/compute/algorithm/transform_reduce.hpp>
20 #include <boost/compute/container/array.hpp>
21 #include <boost/compute/container/vector.hpp>
22 #include <boost/compute/iterator/counting_iterator.hpp>
23
24 #include "check_macros.hpp"
25 #include "context_setup.hpp"
26
27 namespace compute = boost::compute;
28
BOOST_AUTO_TEST_CASE(add_two)29 BOOST_AUTO_TEST_CASE(add_two)
30 {
31 int two = 2;
32 BOOST_COMPUTE_CLOSURE(int, add_two, (int x), (two),
33 {
34 return x + two;
35 });
36
37 int data[] = { 1, 2, 3, 4 };
38 compute::vector<int> vector(data, data + 4, queue);
39
40 compute::transform(
41 vector.begin(), vector.end(), vector.begin(), add_two, queue
42 );
43 CHECK_RANGE_EQUAL(int, 4, vector, (3, 4, 5, 6));
44 }
45
BOOST_AUTO_TEST_CASE(add_two_and_pi)46 BOOST_AUTO_TEST_CASE(add_two_and_pi)
47 {
48 int two = 2;
49 float pi = 3.14f;
50 BOOST_COMPUTE_CLOSURE(float, add_two_and_pi, (float x), (two, pi),
51 {
52 return x + two + pi;
53 });
54
55 float data[] = { 1.9f, 2.2f, 3.4f, 4.7f };
56 compute::vector<float> vector(data, data + 4, queue);
57
58 compute::transform(
59 vector.begin(), vector.end(), vector.begin(), add_two_and_pi, queue
60 );
61
62 std::vector<float> results(4);
63 compute::copy(vector.begin(), vector.end(), results.begin(), queue);
64 BOOST_CHECK_CLOSE(results[0], 7.04f, 1e-6);
65 BOOST_CHECK_CLOSE(results[1], 7.34f, 1e-6);
66 BOOST_CHECK_CLOSE(results[2], 8.54f, 1e-6);
67 BOOST_CHECK_CLOSE(results[3], 9.84f, 1e-6);
68 }
69
BOOST_AUTO_TEST_CASE(add_y)70 BOOST_AUTO_TEST_CASE(add_y)
71 {
72 // setup input and output vectors
73 int data[] = { 1, 2, 3, 4 };
74 compute::vector<int> input(data, data + 4, queue);
75 compute::vector<int> output(4, context);
76
77 // make closure which adds 'y' to each value
78 int y = 2;
79 BOOST_COMPUTE_CLOSURE(int, add_y, (int x), (y),
80 {
81 return x + y;
82 });
83
84 compute::transform(
85 input.begin(), input.end(), output.begin(), add_y, queue
86 );
87 CHECK_RANGE_EQUAL(int, 4, output, (3, 4, 5, 6));
88
89 // change y and run again
90 y = 4;
91
92 compute::transform(
93 input.begin(), input.end(), output.begin(), add_y, queue
94 );
95 CHECK_RANGE_EQUAL(int, 4, output, (5, 6, 7, 8));
96 }
97
BOOST_AUTO_TEST_CASE(scale_add_vec)98 BOOST_AUTO_TEST_CASE(scale_add_vec)
99 {
100 const int N = 10;
101 float s = 4.5;
102 compute::vector<float> a(N, context);
103 compute::vector<float> b(N, context);
104 a.assign(N, 1.0f, queue);
105 b.assign(N, 2.0f, queue);
106
107 BOOST_COMPUTE_CLOSURE(float, scaleAddVec, (float b, float a), (s),
108 {
109 return b * s + a;
110 });
111 compute::transform(b.begin(), b.end(), a.begin(), b.begin(), scaleAddVec, queue);
112 }
113
BOOST_AUTO_TEST_CASE(capture_vector)114 BOOST_AUTO_TEST_CASE(capture_vector)
115 {
116 int data[] = { 6, 7, 8, 9 };
117 compute::vector<int> vec(data, data + 4, queue);
118
119 BOOST_COMPUTE_CLOSURE(int, get_vec, (int i), (vec),
120 {
121 return vec[i];
122 });
123
124 // run using a counting iterator to copy from vec to output
125 compute::vector<int> output(4, context);
126 compute::transform(
127 compute::make_counting_iterator(0),
128 compute::make_counting_iterator(4),
129 output.begin(),
130 get_vec,
131 queue
132 );
133 CHECK_RANGE_EQUAL(int, 4, output, (6, 7, 8, 9));
134
135 // fill vec with 4's and run again
136 compute::fill(vec.begin(), vec.end(), 4, queue);
137 compute::transform(
138 compute::make_counting_iterator(0),
139 compute::make_counting_iterator(4),
140 output.begin(),
141 get_vec,
142 queue
143 );
144 CHECK_RANGE_EQUAL(int, 4, output, (4, 4, 4, 4));
145 }
146
BOOST_AUTO_TEST_CASE(capture_array)147 BOOST_AUTO_TEST_CASE(capture_array)
148 {
149 int data[] = { 1, 2, 3, 4 };
150 compute::array<int, 4> array(context);
151 compute::copy(data, data + 4, array.begin(), queue);
152
153 BOOST_COMPUTE_CLOSURE(int, negative_array_value, (int i), (array),
154 {
155 return -array[i];
156 });
157
158 compute::vector<int> output(4, context);
159 compute::transform(
160 compute::make_counting_iterator(0),
161 compute::make_counting_iterator(4),
162 output.begin(),
163 negative_array_value,
164 queue
165 );
166 CHECK_RANGE_EQUAL(int, 4, output, (-1, -2, -3, -4));
167 }
168
BOOST_AUTO_TEST_CASE(triangle_area)169 BOOST_AUTO_TEST_CASE(triangle_area)
170 {
171 using compute::uint4_;
172 using compute::float4_;
173
174 compute::vector<uint4_> triangle_indices(context);
175 compute::vector<float4_> triangle_vertices(context);
176
177 triangle_vertices.push_back(float4_(0, 0, 0, 1), queue);
178 triangle_vertices.push_back(float4_(1, 1, 0, 1), queue);
179 triangle_vertices.push_back(float4_(1, 0, 0, 1), queue);
180 triangle_vertices.push_back(float4_(2, 0, 0, 1), queue);
181
182 triangle_indices.push_back(uint4_(0, 1, 2, 0), queue);
183 triangle_indices.push_back(uint4_(2, 1, 3, 0), queue);
184
185 queue.finish();
186
187 BOOST_COMPUTE_CLOSURE(float, triangle_area, (const uint4_ i), (triangle_vertices),
188 {
189 // load triangle vertices
190 const float4 a = triangle_vertices[i.x];
191 const float4 b = triangle_vertices[i.y];
192 const float4 c = triangle_vertices[i.z];
193
194 // return area of triangle
195 return length(cross(b-a, c-a)) / 2;
196 });
197
198 // compute area of each triangle
199 compute::vector<float> triangle_areas(triangle_indices.size(), context);
200
201 compute::transform(
202 triangle_indices.begin(),
203 triangle_indices.end(),
204 triangle_areas.begin(),
205 triangle_area,
206 queue
207 );
208
209 // compute total area of all triangles
210 float total_area = 0;
211
212 compute::transform_reduce(
213 triangle_indices.begin(),
214 triangle_indices.end(),
215 &total_area,
216 triangle_area,
217 compute::plus<float>(),
218 queue
219 );
220 BOOST_CHECK_CLOSE(total_area, 1.f, 1e-6);
221 }
222
223 BOOST_AUTO_TEST_SUITE_END()
224