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 #include <iostream>
12
13 #include <opencv2/core/core.hpp>
14 #include <opencv2/highgui/highgui.hpp>
15 #include <opencv2/imgproc/imgproc.hpp>
16
17 #include <boost/compute/system.hpp>
18 #include <boost/compute/algorithm/inclusive_scan.hpp>
19 #include <boost/compute/algorithm/inclusive_scan.hpp>
20 #include <boost/compute/interop/opencv/core.hpp>
21 #include <boost/compute/interop/opencv/highgui.hpp>
22 #include <boost/compute/random/default_random_engine.hpp>
23 #include <boost/compute/random/uniform_real_distribution.hpp>
24 #include <boost/compute/utility/source.hpp>
25
26 namespace compute = boost::compute;
27
28 // this example uses the random-number generation functions in Boost.Compute
29 // to calculate a large number of random "steps" and then plots the final
30 // random "walk" in a 2D image on the GPU and displays it with OpenCV
main()31 int main()
32 {
33 // number of random steps to take
34 size_t steps = 250000;
35
36 // height and width of image
37 size_t height = 800;
38 size_t width = 800;
39
40 // get default device and setup context
41 compute::device gpu = compute::system::default_device();
42 compute::context context(gpu);
43 compute::command_queue queue(context, gpu);
44
45 using compute::int2_;
46
47 // calaculate random values for each step
48 compute::vector<float> random_values(steps, context);
49 compute::default_random_engine random_engine(queue);
50 compute::uniform_real_distribution<float> random_distribution(0.f, 4.f);
51
52 random_distribution.generate(
53 random_values.begin(), random_values.end(), random_engine, queue
54 );
55
56 // calaculate coordinates for each step
57 compute::vector<int2_> coordinates(steps, context);
58
59 // function to convert random values to random directions (in 2D)
60 BOOST_COMPUTE_FUNCTION(int2_, take_step, (const float x),
61 {
62 if(x < 1.f){
63 // move right
64 return (int2)(1, 0);
65 }
66 if(x < 2.f){
67 // move up
68 return (int2)(0, 1);
69 }
70 if(x < 3.f){
71 // move left
72 return (int2)(-1, 0);
73 }
74 else {
75 // move down
76 return (int2)(0, -1);
77 }
78 });
79
80 // transform the random values into random steps
81 compute::transform(
82 random_values.begin(), random_values.end(), coordinates.begin(), take_step, queue
83 );
84
85 // set staring position
86 int2_ starting_position(width / 2, height / 2);
87 compute::copy_n(&starting_position, 1, coordinates.begin(), queue);
88
89 // scan steps to calculate position after each step
90 compute::inclusive_scan(
91 coordinates.begin(), coordinates.end(), coordinates.begin(), queue
92 );
93
94 // create output image
95 compute::image2d image(
96 context, width, height, compute::image_format(CL_RGBA, CL_UNSIGNED_INT8)
97 );
98
99 // program with two kernels, one to fill the image with white, and then
100 // one the draw to points calculated in coordinates on the image
101 const char draw_walk_source[] = BOOST_COMPUTE_STRINGIZE_SOURCE(
102 __kernel void draw_walk(__global const int2 *coordinates,
103 __write_only image2d_t image)
104 {
105 const uint i = get_global_id(0);
106 const int2 coord = coordinates[i];
107
108 if(coord.x > 0 && coord.x < get_image_width(image) &&
109 coord.y > 0 && coord.y < get_image_height(image)){
110 uint4 black = { 0, 0, 0, 0 };
111 write_imageui(image, coord, black);
112 }
113 }
114
115 __kernel void fill_white(__write_only image2d_t image)
116 {
117 const int2 coord = { get_global_id(0), get_global_id(1) };
118
119 if(coord.x < get_image_width(image) &&
120 coord.y < get_image_height(image)){
121 uint4 white = { 255, 255, 255, 255 };
122 write_imageui(image, coord, white);
123 }
124 }
125 );
126
127 // build the program
128 compute::program draw_program =
129 compute::program::build_with_source(draw_walk_source, context);
130
131 // fill image with white
132 compute::kernel fill_kernel(draw_program, "fill_white");
133 fill_kernel.set_arg(0, image);
134
135 const size_t offset[] = { 0, 0 };
136 const size_t bounds[] = { width, height };
137
138 queue.enqueue_nd_range_kernel(fill_kernel, 2, offset, bounds, 0);
139
140 // draw random walk
141 compute::kernel draw_kernel(draw_program, "draw_walk");
142 draw_kernel.set_arg(0, coordinates);
143 draw_kernel.set_arg(1, image);
144 queue.enqueue_1d_range_kernel(draw_kernel, 0, coordinates.size(), 0);
145
146 // show image
147 compute::opencv_imshow("random walk", image, queue);
148
149 // wait and return
150 cv::waitKey(0);
151
152 return 0;
153 }
154