skia2/tools/hello-opencl.cpp
Mike Klein 640654d145 run all available OpenCL devices
Change-Id: I6d18be3f6178003eb5153d32d4b618101ddcb3d9
Reviewed-on: https://skia-review.googlesource.com/c/191297
Auto-Submit: Mike Klein <mtklein@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
2019-02-11 21:29:33 +00:00

118 lines
4.3 KiB
C++

/*
* 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;
}