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