dimanche 22 avril 2018

OpenCL 2.1 C++ HelloWorld: invalid context?

Similar to this question, I'm trying to implement the HelloWorld example from this video by Wesley Shillingford, except this time with OpenCL 2.1. I can get it to run if I use the default context, but not if I create my own (as the video does).

When I use my own context, it produces a cl::Error (-34 = CL_INVALID_CONTEXT):

From here:

CL_INVALID_CONTEXT = the given context is invalid OpenCL context, or the context associated with certain parameters are not the same.

  1. I'm not sure how I could tell that the context is invalid. I've tried comparing the defaultContext to myContext, and they match of everything except CL_CONTEXT_REFERENCE_COUNT. Which doesn't seem to matter (but maybe it does).
  2. I could be mixing contexts. However, I assign the context I want to use to chosenContext and use that everywhere I need a context.

It seems that something is somehow using the default context instead of my supplied context, but I haven't been able to spot where. Any insights would be appreciated.

The code:

#define CL_HPP_ENABLE_EXCEPTIONS
#define CL_HPP_TARGET_OPENCL_VERSION 200

#include <CL/cl2.hpp>
#include <fstream>
#include <iostream>

int main()
{
    // Get Platform and Device
    std::vector<cl::Platform> platforms;
    cl::Platform::get(&platforms);
    auto platform = platforms.front();
    std::vector<cl::Device> devices;
    platform.getDevices(CL_DEVICE_TYPE_GPU, &devices);
    auto device = devices.front();

    //This context doesn't work. Causes CL_INVALID_CONTEXT (-34)
    cl_context_properties properties[] = {CL_CONTEXT_PLATFORM, (cl_context_properties)platform(), 0};
    cl::Context myContext(device, properties);

    //If I stick with the default context, things work.
    cl::Context defaultContext = cl::Context::getDefault();

    //The choice of context here determines whether it works or not:
    // myContext -> Fails with CL_INVALID_CONTEXT (-34)
    // defaultContext -> works
    auto chosenContext = myContext;

    std::ifstream helloWorldFile("hello_world.cl");
    std::string src(std::istreambuf_iterator<char>(helloWorldFile), (std::istreambuf_iterator<char>()));

    cl::Program program(chosenContext, src);
    program.build("-cl-std=CL2.1");

    //Debugging code: Check to make sure that the contexts are similar
    auto myContextDevices = myContext.getInfo<CL_CONTEXT_DEVICES>();
    auto defaultContextDevices = defaultContext.getInfo<CL_CONTEXT_DEVICES>();
    auto devicesMatch = myContextDevices == defaultContextDevices; //true

    auto myContextProperties = myContext.getInfo<CL_CONTEXT_PROPERTIES>();
    auto defaultContextProperties = defaultContext.getInfo<CL_CONTEXT_PROPERTIES>();
    auto propertiesMatch = myContextProperties == defaultContextProperties; //true

    auto myContextNumDevices = myContext.getInfo<CL_CONTEXT_NUM_DEVICES>();
    auto defaultContextNumDevices = defaultContext.getInfo<CL_CONTEXT_NUM_DEVICES>();
    auto numDevicesMatch = myContextNumDevices == defaultContextNumDevices; //true

    auto myContextRefCount = myContext.getInfo<CL_CONTEXT_REFERENCE_COUNT>();           // 1 if defaultContext, 3 if myContext
    auto defaultContextRefCount = defaultContext.getInfo<CL_CONTEXT_REFERENCE_COUNT>(); // 4 if defaultContext, 2 if myContext
    auto refCountsMatch = myContextRefCount == defaultContextRefCount;                  // false

    auto contextsMatch = myContext == defaultContext; //false
    //End of debugging code

    //Continuing with computation
    char buf[16];
    cl::Buffer outputBuffer = cl::Buffer(CL_MEM_WRITE_ONLY | CL_MEM_HOST_READ_ONLY, sizeof(buf));

    cl::Kernel kernel(program, "HelloWorld");
    kernel.setArg(0, outputBuffer);

    cl::CommandQueue commandQueue(chosenContext, device);
    auto result = commandQueue.enqueueNDRangeKernel(kernel, 0, 1, 1);           //CL_SUCCESS
    commandQueue.enqueueReadBuffer(outputBuffer, CL_TRUE, 0, sizeof(buf), buf); // Execution fails here, raises cl::Error (-34)

    std::cout << buf;

    return EXIT_SUCCESS;
}

Build Command:

g++ -g hello_world_21.cpp -IOpenCL-Headers/opencl21 -std=c++11 -lOpenCL

hello_world.cl:

__kernel void HelloWorld(__global char* output) {
    output[0] = 'H';
    output[1] = 'e';
    output[2] = 'l';
    output[3] = 'l';
    output[4] = 'o';
    output[5] = ' ';
    output[6] = 'W';
    output[7] = 'o';
    output[8] = 'r';
    output[9] = 'l';
    output[10] = 'd';
    output[11] = '!';
    output[12] = '\n';
}

Aucun commentaire:

Enregistrer un commentaire