1 /*
2 * Copyright 2018 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 // This is a simple OpenCL Hello World that tests you have a functioning OpenCL setup.
9
10 #include <CL/cl.hpp>
11 #include <initializer_list>
12
13 extern "C" {
14 #include "cl/assert_cl.h" // for cl(), cl_ok() macros
15 #include "cl/find_cl.h" // for clFindIdsByName
16 }
17
main(int argc,char ** argv)18 int main(int argc, char** argv) {
19 // Find any OpenCL platform+device with these substrings.
20 const char* platform_match = argc > 1 ? argv[1] : "";
21 const char* device_match = argc > 2 ? argv[2] : "";
22
23 cl_platform_id platform_id;
24 cl_device_id device_id;
25
26 char device_name[256];
27 size_t device_name_len;
28
29 // clFindIdsByName will narrate what it's doing when this is set.
30 bool verbose = true;
31
32 // The cl() macro prepends cl to its argument, calls it, and asserts that it succeeded,
33 // printing out the file, line, and somewhat readable version of the error code on failure.
34 //
35 // It's generally used to call OpenCL APIs, but here we've written clFindIdsByName to match
36 // the convention, as its error conditions are just going to be passed along from OpenCL.
37 cl(FindIdsByName(platform_match, device_match,
38 &platform_id, &device_id,
39 sizeof(device_name), device_name, &device_name_len,
40 verbose));
41
42 printf("picked %.*s\n", (int)device_name_len, device_name);
43
44 // Allan's code is all C using OpenCL's C API,
45 // but we can mix that freely with the C++ API found in cl.hpp.
46 // cl_ok() comes in handy here, which is cl() without the extra cl- prefix.
47
48 cl::Device device(device_id);
49
50 std::string name,
51 vendor,
52 extensions;
53 cl_ok(device.getInfo(CL_DEVICE_NAME, &name));
54 cl_ok(device.getInfo(CL_DEVICE_VENDOR, &vendor));
55 cl_ok(device.getInfo(CL_DEVICE_EXTENSIONS, &extensions));
56
57 printf("name %s, vendor %s, extensions:\n%s\n",
58 name.c_str(), vendor.c_str(), extensions.c_str());
59
60 std::vector<cl::Device> devices = { device };
61
62 // Some APIs can't return their cl_int error but might still fail,
63 // so they take a pointer. cl_ok() is really handy here too.
64 cl_int ok;
65 cl::Context ctx(devices,
66 nullptr/*optional cl_context_properties*/,
67 nullptr/*optional error reporting callback*/,
68 nullptr/*context arguement for error reporting callback*/,
69 &ok);
70 cl_ok(ok);
71
72 cl::Program program(ctx,
73 "__kernel void mul(__global const float* a, "
74 " __global const float* b, "
75 " __global float* dst) {"
76 " int i = get_global_id(0); "
77 " dst[i] = a[i] * b[i]; "
78 "} ",
79 /*and build now*/true,
80 &ok);
81 cl_ok(ok);
82
83 std::vector<float> a,b,p;
84 for (int i = 0; i < 1000; i++) {
85 a.push_back(+i);
86 b.push_back(-i);
87 p.push_back( 0);
88 }
89
90 cl::Buffer A(ctx, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR , sizeof(float)*a.size(), a.data()),
91 B(ctx, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR , sizeof(float)*b.size(), b.data()),
92 P(ctx, CL_MEM_WRITE_ONLY| CL_MEM_HOST_READ_ONLY, sizeof(float)*p.size());
93
94 cl::Kernel mul(program, "mul", &ok);
95 cl_ok(ok);
96 cl_ok(mul.setArg(0, A));
97 cl_ok(mul.setArg(1, B));
98 cl_ok(mul.setArg(2, P));
99
100 cl::CommandQueue queue(ctx, device);
101
102 cl_ok(queue.enqueueNDRangeKernel(mul, cl::NDRange(0) /*offset*/
103 , cl::NDRange(1000) /*size*/));
104
105 cl_ok(queue.enqueueReadBuffer(P, true/*block until read is done*/
106 , 0 /*offset in bytes*/
107 , sizeof(float)*p.size() /*size in bytes*/
108 , p.data()));
109
110 for (int i = 0; i < 1000; i++) {
111 if (p[i] != a[i]*b[i]) {
112 return 1;
113 }
114 }
115
116 printf("OpenCL sez: %g x %g = %g\n", a[42], b[42], p[42]);
117 return 0;
118 }
119