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