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.hpp"
11 #include <initializer_list>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string>
15 #include <vector>
16
assert_cl(cl_int rc,const char * file,int line)17 static inline void assert_cl(cl_int rc, const char* file, int line) {
18 if (rc != CL_SUCCESS) {
19 fprintf(stderr, "%s:%d, got OpenCL error code %d\n", file,line,rc);
20 exit(1);
21 }
22 }
23 #define cl_ok(err) assert_cl(err, __FILE__, __LINE__)
24
main(int,char **)25 int main(int, char**) {
26 std::vector<cl::Platform> platforms;
27 cl_ok(cl::Platform::get(&platforms));
28
29 std::vector<cl::Device> devices;
30 for (cl::Platform platform : platforms) {
31 std::vector<cl::Device> platform_devices;
32 cl_ok(platform.getDevices(CL_DEVICE_TYPE_ALL, &platform_devices));
33 devices.insert(devices.end(), platform_devices.begin(), platform_devices.end());
34 }
35
36 if (devices.empty()) {
37 fprintf(stderr, "No OpenCL devices available. :(\n");
38 return 1;
39 }
40
41 // To keep things simple we'll only create single-device cl::Contexts.
42 for (cl::Device device : devices) {
43 std::string name,
44 version,
45 driver,
46 vendor,
47 extensions;
48 cl_ok(device.getInfo(CL_DEVICE_NAME, &name));
49 cl_ok(device.getInfo(CL_DEVICE_VERSION, &version));
50 cl_ok(device.getInfo(CL_DEVICE_VENDOR, &vendor));
51 cl_ok(device.getInfo(CL_DEVICE_EXTENSIONS, &extensions));
52 cl_ok(device.getInfo(CL_DRIVER_VERSION, &driver));
53
54 fprintf(stdout, "Using %s%s, vendor %s, version %s, extensions:\n%s\n",
55 version.c_str(), name.c_str(), vendor.c_str(), driver.c_str(), extensions.c_str());
56
57 std::vector<cl::Device> devices = { device };
58
59 // Some APIs can't return their cl_int error but might still fail,
60 // so they take a pointer. cl_ok() is really handy here too.
61 cl_int ok;
62 cl::Context ctx(devices,
63 nullptr/*optional cl_context_properties*/,
64 nullptr/*optional error reporting callback*/,
65 nullptr/*context argument for error reporting callback*/,
66 &ok);
67 cl_ok(ok);
68
69 cl::Program program(ctx,
70 "__kernel void mul(__global const float* a, "
71 " __global const float* b, "
72 " __global float* dst) {"
73 " int i = get_global_id(0); "
74 " dst[i] = a[i] * b[i]; "
75 "} ",
76 /*and build now*/true,
77 &ok);
78 cl_ok(ok);
79
80 std::vector<float> a,b,p;
81 for (int i = 0; i < 1000; i++) {
82 a.push_back(+i);
83 b.push_back(-i);
84 p.push_back( 0);
85 }
86
87 cl::Buffer
88 A(ctx, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR , sizeof(float)*a.size(), a.data()),
89 B(ctx, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR , sizeof(float)*b.size(), b.data()),
90 P(ctx, CL_MEM_WRITE_ONLY| CL_MEM_HOST_READ_ONLY, sizeof(float)*p.size());
91
92 cl::Kernel mul(program, "mul", &ok);
93 cl_ok(ok);
94 cl_ok(mul.setArg(0, A));
95 cl_ok(mul.setArg(1, B));
96 cl_ok(mul.setArg(2, P));
97
98 cl::CommandQueue queue(ctx, device);
99
100 cl_ok(queue.enqueueNDRangeKernel(mul, cl::NDRange(0) /*offset*/
101 , cl::NDRange(1000) /*size*/));
102
103 cl_ok(queue.enqueueReadBuffer(P, true/*block until read is done*/
104 , 0 /*offset in bytes*/
105 , sizeof(float)*p.size() /*size in bytes*/
106 , p.data()));
107
108 fprintf(stdout, "OpenCL sez: %g x %g = %g\n", a[42], b[42], p[42]);
109 for (int i = 0; i < 1000; i++) {
110 if (p[i] != a[i]*b[i]) {
111 return 1;
112 }
113 }
114 }
115
116 return 0;
117 }
118