I recently created a small utility library for OpenCL with C++. It consists of a set of function based on the OpenCL C++ bindings to help set up an OpenCL context, compiling OpenCL code and viewing error functions. I hope these functions can be useful for others and I’m planning on adding more utility functions in the future. Note that I haven’t tested it on all platforms yet. Feedback and comments are most welcome.

The source code can be downloaded from my GitHub page.

Context creation

Creating a context with OpenCL can sometimes be a hassle if you want to choose the platform of a specific vendor such as AMD, Intel or NVIDIA. But also if you want to use OpenCL-OpenGL interoperability. I have created two function to ease the pain of OpenCL contextes. To simply create a context with no specifications towards processor type or vendor:

#include "openCLUtilities.hpp"
 
cl::Context context = createCLContext();

If you want to specify processor type you can pass the cl_device_type as the first argument:

#include "openCLUtilities.hpp"
 
cl::Context context = createCLContext(CL_DEVICE_TYPE_GPU);

The second argument to this function can be used to specify which vendor platform you want to use. Currently the following vendors are specified: VENDOR_AMD, VENDOR_INTEL, VENDOR_NVIDIA.

#include "openCLUtilities.hpp"
 
cl::Context context = createCLContext(CL_DEVICE_TYPE_CPU, VENDOR_AMD);

Choosing device type and vendor by program arguments

I’ve also created a function that allows you to specify which type of device or vendor should be used through program arguments. This function is called createCLContextFromArguments and takes argc and argv from your main method as input:

#include "openCLUtilities.hpp"
 
int main(int argc, char ** argv) {
    // Using this function you can add --device gpu/cpu 
    // or --vendor nvidia/amd/intel to your program arguments
    cl::Context context = createCLContextFromArguments(argc, argv);
}

If you now want to specify that you want to use a GPU you can add the “–device gpu” to your executable. And if you wish to specify vendor platform you can do so by adding “–vendor nvidia”.

OpenCL-OpenGL Interoperability

To set up an OpenCL context with OpenGL interopability some extra OS specific properties has to be specified and some libraries included. To make this easier I created an extra function called createCLGLContext(). This function takes the same arguments as the createCLContext() function above.

#include "openCLGLUtilities.hpp"
 
cl::Context context = createCLGLContext();

Note that the file “openCLGLUtilities.hpp” is included instead of “openCLUtilities.hpp”.
This is how the actual function is implemented:

cl::Context createCLGLContext(cl_device_type type, cl_vendor vendor) {
    cl::Platform platform = getPlatform(type, vendor);
 
#if defined(__APPLE__) || defined(__MACOSX)
    // Apple (untested)
    cl_context_properties cps[] = {
        CL_CGL_SHAREGROUP_KHR,
        (cl_context_properties)CGLGetShareGroup(CGLGetCurrentContext()),
        CL_CONTEXT_PLATFORM,
        (cl_context_properties)(platform)(),
        0
    };
#else
#ifdef _WIN32
    // Windows
    cl_context_properties cps[] = {
        CL_GL_CONTEXT_KHR,
        (cl_context_properties)wglGetCurrentContext(),
        CL_WGL_HDC_KHR,
        (cl_context_properties)wglGetCurrentDC(),
        CL_CONTEXT_PLATFORM,
        (cl_context_properties)(platform)(),
        0
    };
#else
    // Linux
    cl_context_properties cps[] = {
        CL_GL_CONTEXT_KHR,
        (cl_context_properties)glXGetCurrentContext(),
        CL_GLX_DISPLAY_KHR,
        (cl_context_properties)glXGetCurrentDisplay(),
        CL_CONTEXT_PLATFORM,
        (cl_context_properties)(platform)(),
        0
    };
#endif
#endif
 
    try {
        cl::Context context = cl::Context(type, cps);
 
        return context;
    } catch(cl::Error error) {
        throw cl::Error(1, "Failed to create an OpenCL context!");
    }
}

Compiling source code and print compile errors

The function buildProgramFromSource() will compile the source file specified for all devices in the given OpenCL context and throw an exception and print out any OpenCL compilation errors. Quite usueful when developing OpenCL kernels.

#include "openCLUtilities.hpp"
 
cl::Context context = createCLContext();
cl::Program program = buildProgramFromSource(context, "kernels.cl");

The compilation errors are retrieved in the following way:

try{
    program.build(devices);
} catch(cl::Error error) {
    if(error.err() == CL_BUILD_PROGRAM_FAILURE) {
        std::cout << "Build log:" << std::endl << program.getBuildInfo<CL_PROGRAM_BUILD_LOG>(devices[0]) << std::endl;
    }   
    throw error;
}

The source code can be downloaded from my GitHub page.