parallel:openclclass
OpenCL Klasse
Die Funktionen der OpenCL-Bibliothek lassen sich, in eine Klasse gekapselt, einfacher nutzen. Gordon Taft lieferte dafür die Vorlage. Diese wurde leicht modifiziert, um auch Fehlermeldungen beim Übersetzen des CL-Kernels anzuzeigen.
// OpenCL.h //------------------------------------ // modified from: http://gordon-taft.net/OpenCL_Header.html // R.Ri 2011-03-01: refactored/regrouped, log() added, no copy/assign // R.Ri 2011-03-06: header-only class // R.Ri 2011-03-06: bindings from http://gordon-taft.net/OpenCL_Binding.html #ifndef OPENCL_CLASS_H #define OPENCL_CLASS_H #include <string> #include <iostream> #include <map> // #define __NO_STD_VECTOR // Use cl::vector and cl::string and // #define __NO_STD_STRING // not STL versions, see: <CL/cl.hpp> #include <CL/cl.h> class OpenCL { public: enum { CPU = CL_DEVICE_TYPE_CPU, GPU = CL_DEVICE_TYPE_GPU, ALL = CL_DEVICE_TYPE_ALL, READ = CL_MEM_READ_ONLY, // G.Taft typo ??? WRITE = CL_MEM_WRITE_ONLY, READ_WRITE = CL_MEM_READ_WRITE }; OpenCL(int type) { status_ = clGetDeviceIDs(NULL, type, 1, &id_, NULL); log("Error: Failed to create a device group!", CL_SUCCESS != status_); // Create a compute context context_ = clCreateContext(0, 1, &id_, NULL, NULL, &status_); log("Error: Failed to create a compute context!", !context_); // Create a command queue commands_ = clCreateCommandQueue(context_, id_, 0, &status_); log("Error: Failed to create a command commands!", !commands_); } ~OpenCL() { clReleaseProgram(program_); clReleaseCommandQueue(commands_); clReleaseContext(context_); } void program(char const* name) { // Create the compute program from the source buffer program_ = clCreateProgramWithSource(context_, 1, (char const **) &name, NULL, &status_); log("Error: Failed to create compute program!", !program_); // Build the program executable status_ = clBuildProgram(program_, 0, NULL, NULL, NULL, NULL); if (CL_SUCCESS != status_) { // R.Ri: + get kernel compile error // http://forums.amd.com/forum/messageview.cfm?catid=390&threadid=119211 char programLog[1024]; status_ = clGetProgramBuildInfo(program_, id_, CL_PROGRAM_BUILD_LOG, 1024, programLog, 0); log(programLog); log("Error: Failed to build program executable!"); exit(1); // R.Ri: throw instead? } } cl_kernel kernel(std::string const& name) { arguments_[name] = 0; return kernels_[name] = clCreateKernel(program_, name.c_str(), &status_); } size_t size(std::string const& name) { return size(kernels_[name]); } size_t size(const cl_kernel& kernel) { size_t local; clGetKernelWorkGroupInfo(kernel, id_, CL_KERNEL_WORK_GROUP_SIZE, sizeof(local), &local, NULL); return local; } void call(std::string const& name, size_t global) { call(kernels_[name], global); } void call(const cl_kernel& kernel, size_t global) { size_t local = size(kernel); if (global < local) global = local; // status_ = clEnqueueNDRangeKernel(commands_, kernel, 1, NULL, &global, &local, 0, NULL, NULL); // let OpenCL determine local work size: status_ = clEnqueueNDRangeKernel(commands_, kernel, 1, NULL, &global, NULL, 0, NULL, NULL); if (CL_SUCCESS != status_) { std::ostringstream out; out << "Error: Failed to execute kernel! Result: " << status_ << '\n' << " global size: " << global << '\n' << " local size : " << local << '\n'; log(out.str()); } } void wait() { clFinish(commands_); } // memory bindings template<typename U> inline int bind(std::string const& name, U source, int argPos = -1) { if (argPos == -1) argPos = arguments_[name]++; clSetKernelArg(kernels_[name], argPos, sizeof(source), &source); return argPos; } int bind(std::string const& name, void* source, size_t size, int type = READ_WRITE) { Binding binding = { binding.memory = clCreateBuffer(context_, type, size, NULL, NULL), size, source, true, true }; if (type == WRITE) binding.readAccess = false; if (type == READ) binding.writeAccess = false; memory_[name].push_back(binding); clSetKernelArg(kernels_[name],arguments_[name],sizeof(binding.memory), &binding.memory); return arguments_[name]++; } void resetBind(std::string const& name) { try { std::vector<Binding> elements = memory_[name]; for (int t = 0; t < elements.size(); t++) clReleaseMemObject(elements[t].memory); memory_[name].clear(); arguments_[name] = 0; } catch (...) { } } void toDevice(std::string const& name) { std::vector<Binding> elements = memory_[name]; for (int i = 0; i < elements.size(); i++) { if (elements[i].readAccess) clEnqueueWriteBuffer(commands_, elements[i].memory, CL_TRUE, 0, elements[i].size, elements[i].source, 0, NULL, NULL); } } void fromDevice(std::string const& name) { std::vector<Binding> elements = memory_[name]; for (int i = 0; i < elements.size(); i++) { if (elements[i].writeAccess) clEnqueueReadBuffer (commands_, elements[i].memory, CL_TRUE, 0, elements[i].size, elements[i].source, 0, NULL, NULL); } } // debug messages static void log(std::string message, bool condition = true) { if (condition) std::cerr << message << std::endl; } private: cl_device_id id_; cl_int status_; cl_context context_; cl_command_queue commands_; cl_program program_; std::map<std::string, cl_kernel> kernels_; OpenCL(OpenCL const&); // = delete; OpenCL& operator=(OpenCL const&); // = delete; struct Binding { cl_mem memory; size_t size; void* source; bool readAccess; bool writeAccess; }; std::map<std::string, std::vector<Binding> > memory_; std::map<std::string, int> arguments_; }; inline void log(std::string message, bool condition = true) { OpenCL::log(message, condition); } #endif // OPENCL_CLASS_H
parallel/openclclass.txt · Zuletzt geändert: 2020-07-26 18:47 von 127.0.0.1