• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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