| /* | 
 |  * Copyright 2018 Google Inc. | 
 |  * | 
 |  * Use of this source code is governed by a BSD-style license that can be | 
 |  * found in the LICENSE file. | 
 |  */ | 
 |  | 
 | // This is a simple OpenCL Hello World that tests you have a functioning OpenCL setup. | 
 |  | 
 | #include "cl.hpp" | 
 | #include <initializer_list> | 
 | #include <stdio.h> | 
 | #include <stdlib.h> | 
 | #include <string> | 
 | #include <vector> | 
 |  | 
 | static inline void assert_cl(cl_int rc, const char* file, int line) { | 
 |     if (rc != CL_SUCCESS) { | 
 |         fprintf(stderr, "%s:%d, got OpenCL error code %d\n", file,line,rc); | 
 |         exit(1); | 
 |     } | 
 | } | 
 | #define cl_ok(err) assert_cl(err, __FILE__, __LINE__) | 
 |  | 
 | int main(int, char**) { | 
 |     std::vector<cl::Platform> platforms; | 
 |     cl_ok(cl::Platform::get(&platforms)); | 
 |  | 
 |     std::vector<cl::Device> devices; | 
 |     for (cl::Platform platform : platforms) { | 
 |         std::vector<cl::Device> platform_devices; | 
 |         cl_ok(platform.getDevices(CL_DEVICE_TYPE_ALL, &platform_devices)); | 
 |         devices.insert(devices.end(), platform_devices.begin(), platform_devices.end()); | 
 |     } | 
 |  | 
 |     if (devices.empty()) { | 
 |         fprintf(stderr, "No OpenCL devices available. :(\n"); | 
 |         return 1; | 
 |     } | 
 |  | 
 |     // To keep things simple we'll only create single-device cl::Contexts. | 
 |     for (cl::Device device : devices) { | 
 |         std::string name, | 
 |                     version, | 
 |                     driver, | 
 |                     vendor, | 
 |                     extensions; | 
 |         cl_ok(device.getInfo(CL_DEVICE_NAME,       &name)); | 
 |         cl_ok(device.getInfo(CL_DEVICE_VERSION,    &version)); | 
 |         cl_ok(device.getInfo(CL_DEVICE_VENDOR,     &vendor)); | 
 |         cl_ok(device.getInfo(CL_DEVICE_EXTENSIONS, &extensions)); | 
 |         cl_ok(device.getInfo(CL_DRIVER_VERSION,    &driver)); | 
 |  | 
 |         fprintf(stdout, "Using %s%s, vendor %s, version %s, extensions:\n%s\n", | 
 |                 version.c_str(), name.c_str(), vendor.c_str(), driver.c_str(), extensions.c_str()); | 
 |  | 
 |         std::vector<cl::Device> devices = { device }; | 
 |  | 
 |         // Some APIs can't return their cl_int error but might still fail, | 
 |         // so they take a pointer.  cl_ok() is really handy here too. | 
 |         cl_int ok; | 
 |         cl::Context ctx(devices, | 
 |                         nullptr/*optional cl_context_properties*/, | 
 |                         nullptr/*optional error reporting callback*/, | 
 |                         nullptr/*context argument for error reporting callback*/, | 
 |                         &ok); | 
 |         cl_ok(ok); | 
 |  | 
 |         cl::Program program(ctx, | 
 |                             "__kernel void mul(__global const float* a,    " | 
 |                             "                  __global const float* b,    " | 
 |                             "                  __global       float* dst) {" | 
 |                             "    int i = get_global_id(0);                 " | 
 |                             "    dst[i] = a[i] * b[i];                     " | 
 |                             "}                                             ", | 
 |                             /*and build now*/true, | 
 |                             &ok); | 
 |         cl_ok(ok); | 
 |  | 
 |         std::vector<float> a,b,p; | 
 |         for (int i = 0; i < 1000; i++) { | 
 |             a.push_back(+i); | 
 |             b.push_back(-i); | 
 |             p.push_back( 0); | 
 |         } | 
 |  | 
 |         cl::Buffer | 
 |             A(ctx, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR , sizeof(float)*a.size(), a.data()), | 
 |             B(ctx, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR , sizeof(float)*b.size(), b.data()), | 
 |             P(ctx, CL_MEM_WRITE_ONLY| CL_MEM_HOST_READ_ONLY, sizeof(float)*p.size()); | 
 |  | 
 |         cl::Kernel mul(program, "mul", &ok); | 
 |         cl_ok(ok); | 
 |         cl_ok(mul.setArg(0, A)); | 
 |         cl_ok(mul.setArg(1, B)); | 
 |         cl_ok(mul.setArg(2, P)); | 
 |  | 
 |         cl::CommandQueue queue(ctx, device); | 
 |  | 
 |         cl_ok(queue.enqueueNDRangeKernel(mul, cl::NDRange(0)  /*offset*/ | 
 |                                             , cl::NDRange(1000) /*size*/)); | 
 |  | 
 |         cl_ok(queue.enqueueReadBuffer(P, true/*block until read is done*/ | 
 |                                        , 0                     /*offset in bytes*/ | 
 |                                        , sizeof(float)*p.size() /*size in bytes*/ | 
 |                                        , p.data())); | 
 |  | 
 |         fprintf(stdout, "OpenCL sez: %g x %g = %g\n", a[42], b[42], p[42]); | 
 |         for (int i = 0; i < 1000; i++) { | 
 |             if (p[i] != a[i]*b[i]) { | 
 |                 return 1; | 
 |             } | 
 |         } | 
 |     } | 
 |  | 
 |     return 0; | 
 | } |