Na koniec przedstawię obiektowe API OpenCL dla języka C++.
Jedyne co musimy zrobić, to pobrać plik „cl.hpp” ze strony Khronosa i umieścić go w tym samym katalogu co plik „cl.h”, czyli „dependencies\OpenCL\include\CL”.
Poniższy przykład wykonuje takie same operacji jak program z poprzedniej części, czyli sumuje dwa wektory.
Kod pliku Main.cpp
#define __CL_ENABLE_EXCEPTIONS #define __NO_STD_VECTOR #include <iostream> #include <fstream> #include <string> #include <CL/cl.hpp> void randomizeArray(cl_int* data, size_t vectorSize) { for (size_t i = 0; i < vectorSize; ++i) { data[i] = rand() % 10; } } int main() { try { // Allocate and initialize host arrays size_t vectorSize = 32; size_t localWorkSize = 8; cl_int* a = new cl_int[vectorSize]; cl_int* b = new cl_int[vectorSize]; cl_int* c = new cl_int[vectorSize]; randomizeArray(a, vectorSize); randomizeArray(b, vectorSize); // Get platforms. cl::vector<cl::Platform> platforms; cl::Platform::get(&platforms); for (cl::vector<cl::Platform>::iterator i = platforms.begin(); i != platforms.end(); ++i) { cl::Platform platform = *i; std::string name; platform.getInfo(CL_PLATFORM_NAME, &name); std::cout << "Name:\t\t" << name << std::endl; platform.getInfo(CL_PLATFORM_VENDOR, &name); std::cout << "Vendor:\t\t" << name << std::endl; std::cout << std::endl; } // Create a context. cl_context_properties cps[3] = { CL_CONTEXT_PLATFORM, (cl_context_properties)(platforms[1])(), 0 }; cl::Context context( CL_DEVICE_TYPE_GPU, cps); // Get devices. cl::vector<cl::Device> devices = context.getInfo<CL_CONTEXT_DEVICES>(); for (cl::vector<cl::Device>::iterator i = devices.begin(); i != devices.end(); ++i) { cl::Device device = *i; std::string name; device.getInfo(CL_DEVICE_NAME, &name); std::cout << "Name:\t\t" << name << std::endl; device.getInfo(CL_DEVICE_VENDOR, &name); std::cout << "Vendor:\t\t" << name << std::endl; device.getInfo(CL_DEVICE_VERSION, &name); std::cout << "Version:\t" << name << std::endl; std::cout << std::endl; } // Create a command queue. cl::CommandQueue queue = cl::CommandQueue(context, devices[0]); // Read the OpenCL kernel in from source file. std::ifstream file(".\\bin\\Add.cl", std::ifstream::in); std::string sourceCode(std::istreambuf_iterator<char>(file), (std::istreambuf_iterator<char>())); cl::Program::Sources source(1, std::make_pair(sourceCode.c_str(), sourceCode.length() + 1)); // Create program. cl::Program program = cl::Program(context, source); // Build program. program.build(devices); // Create kernel. cl::Kernel kernel(program, "Add"); // Allocate the OpenCL buffer memory objects for source and result on the device. cl::Buffer bufferA = cl::Buffer(context, CL_MEM_READ_ONLY , sizeof(cl_int) * vectorSize); cl::Buffer bufferB = cl::Buffer(context, CL_MEM_READ_ONLY , sizeof(cl_int) * vectorSize); cl::Buffer bufferC = cl::Buffer(context, CL_MEM_WRITE_ONLY, sizeof(cl_int) * vectorSize); // Asynchronous write of data to GPU device. queue.enqueueWriteBuffer(bufferA, CL_TRUE, 0, sizeof(cl_int) * vectorSize, a); queue.enqueueWriteBuffer(bufferB, CL_TRUE, 0, sizeof(cl_int) * vectorSize, b); // Set the Argument values. kernel.setArg(0, bufferA); kernel.setArg(1, bufferB); kernel.setArg(2, bufferC); kernel.setArg(3, vectorSize); // Launch kernel. cl::NDRange global(vectorSize); cl::NDRange local(8); queue.enqueueNDRangeKernel(kernel, cl::NullRange, global, local); // Read back results and check accumulated errors. queue.enqueueReadBuffer(bufferC, CL_TRUE, 0, sizeof(cl_int) * vectorSize, c); // Print results. for (size_t i = 0; i < vectorSize; ++i) { std::cout << a[i] << " + " << b[i] << " = " << c[i] << std::endl; } delete[] a; delete[] b; delete[] c; } catch (cl::Error error) { std::cout << error.what() << "(" << error.err() << ")" << std::endl; } // Press Enter, to quit application. std::cin.get(); return 0; }
Zdefiniowanie „__CL_ENABLE_EXCEPTIONS” przed dołączeniem pliku „cl.hpp” pozwoli na przechwytywanie wyjątków w przypadku wystąpienia błędów.
Zdefiniowanie „__NO_STD_VECTOR” powoduje, że OpenCL używa własnej klasy wektora. Jeżeli usuniemy definicję, to możemy używać wektora z biblioteki STL.
Kod pliku Add.cl
__kernel void Add(__global int* a, __global int* b, __global int* c, int size) { // Find position in global arrays. int n = get_global_id(0); // Bound check. if (n < size) { c[n] = a[n] + b[n]; } }
Źródła w serwisie GitLab.
Linki
http://www.thebigblob.com/using-the-cpp-bindings-for-opencl/