blob: 12b51f50f6b9f6200a110d0baa9e0336080e20c5 [file] [log] [blame]
Mike Kleinf9ae6702018-06-20 14:05:05 -04001/*
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
Mike Klein8a1f15d2019-02-11 11:59:41 -050010#include "cl.hpp"
Mike Kleinf9ae6702018-06-20 14:05:05 -040011#include <initializer_list>
Mike Klein8a1f15d2019-02-11 11:59:41 -050012#include <stdio.h>
13#include <stdlib.h>
14#include <string>
15#include <vector>
Mike Kleinf9ae6702018-06-20 14:05:05 -040016
Mike Klein8a1f15d2019-02-11 11:59:41 -050017static 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 }
Mike Kleinf9ae6702018-06-20 14:05:05 -040022}
Mike Klein8a1f15d2019-02-11 11:59:41 -050023#define cl_ok(err) assert_cl(err, __FILE__, __LINE__)
Mike Kleinf9ae6702018-06-20 14:05:05 -040024
Mike Klein640654d2019-02-11 14:59:56 -050025int main(int, char**) {
26 std::vector<cl::Platform> platforms;
27 cl_ok(cl::Platform::get(&platforms));
Mike Kleinf9ae6702018-06-20 14:05:05 -040028
Mike Klein640654d2019-02-11 14:59:56 -050029 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());
Mike Klein8a1f15d2019-02-11 11:59:41 -050034 }
Mike Kleinf9ae6702018-06-20 14:05:05 -040035
Mike Klein640654d2019-02-11 14:59:56 -050036 if (devices.empty()) {
37 fprintf(stderr, "No OpenCL devices available. :(\n");
38 return 1;
Mike Klein8a1f15d2019-02-11 11:59:41 -050039 }
Mike Kleinf9ae6702018-06-20 14:05:05 -040040
Mike Klein640654d2019-02-11 14:59:56 -050041 // 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));
Mike Kleinf9ae6702018-06-20 14:05:05 -040053
Mike Klein640654d2019-02-11 14:59:56 -050054 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());
Mike Kleinf9ae6702018-06-20 14:05:05 -040056
Mike Klein640654d2019-02-11 14:59:56 -050057 std::vector<cl::Device> devices = { device };
Mike Kleinf9ae6702018-06-20 14:05:05 -040058
Mike Klein640654d2019-02-11 14:59:56 -050059 // 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*/,
Mike Kleinf9ae6702018-06-20 14:05:05 -040066 &ok);
Mike Klein640654d2019-02-11 14:59:56 -050067 cl_ok(ok);
Mike Kleinf9ae6702018-06-20 14:05:05 -040068
Mike Klein640654d2019-02-11 14:59:56 -050069 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);
Mike Kleinf9ae6702018-06-20 14:05:05 -040079
Mike Klein640654d2019-02-11 14:59:56 -050080 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 }
Mike Kleinf9ae6702018-06-20 14:05:05 -040086
Mike Klein640654d2019-02-11 14:59:56 -050087 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());
Mike Kleinf9ae6702018-06-20 14:05:05 -040091
Mike Klein640654d2019-02-11 14:59:56 -050092 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));
Mike Kleinf9ae6702018-06-20 14:05:05 -040097
Mike Klein640654d2019-02-11 14:59:56 -050098 cl::CommandQueue queue(ctx, device);
Mike Kleinf9ae6702018-06-20 14:05:05 -040099
Mike Klein640654d2019-02-11 14:59:56 -0500100 cl_ok(queue.enqueueNDRangeKernel(mul, cl::NDRange(0) /*offset*/
101 , cl::NDRange(1000) /*size*/));
Mike Kleinf9ae6702018-06-20 14:05:05 -0400102
Mike Klein640654d2019-02-11 14:59:56 -0500103 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 }
Mike Kleinf9ae6702018-06-20 14:05:05 -0400113 }
114 }
115
Mike Kleinf9ae6702018-06-20 14:05:05 -0400116 return 0;
117}