namespace cpp {}

C++ lernen, kennen, anwenden

Benutzer-Werkzeuge

Webseiten-Werkzeuge


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

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki