c++visual-studioopenclopencl-c

OpenCL C++ HelloWorld


Good afternoon! I am learning OpenCL C++ in this tutorial: Click (it's not necessary)

The video uses CL API version 1.2, so I downloaded the OpenCL 1.2 headers from the link in this reply: https://stackoverflow.com/a/57017982/11968932

Visual Studio 2022 shows no errors, but the program outputs these symbols:

╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠

It's supposed to say "Hello World!".

Here is the program itself. Host:

#define CL_USE_DEPRECATED_OPENCL_1_2_APIS

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

int main() 
{
    std::vector<cl::Platform> platforms;
    cl::Platform::get(&platforms);

    auto platform = platforms.front();
    std::vector<cl::Device> devices;
    platform.getDevices(CL_DEVICE_TYPE_ALL, &devices);

    auto device = devices.front();

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

    cl::Program::Sources sources(1, std::make_pair(src.c_str(), src.length() + 1));

    cl::Context context(device);
    cl::Program program(context, sources);

    auto err = program.build("cl-std=CL1.2");

    char buf[16];
    cl::Buffer memBuf(context, CL_MEM_WRITE_ONLY | CL_MEM_READ_ONLY, sizeof(buf));
    cl::Kernel kernel(program, "HelloWorld", &err);
    kernel.setArg(0, memBuf);

    cl::CommandQueue queue(context, device);
    queue.enqueueTask(kernel);
    queue.enqueueReadBuffer(memBuf, CL_TRUE, 0, sizeof(buf), buf);

    std::cout << buf << " - buf" << std::endl;
}

HelloWorld.cl:

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

Thanks ;)


Solution

  • Three mistakes:

    1. It is either __kernel or kernel, but not _kernel with one underscore; same for __global
    2. cl::Buffer memBuf(context, CL_MEM_READ_WRITE, 16*sizeof(buf)); - here 2 things were wrong: the CL_MEM_WRITE_ONLY | CL_MEM_READ_ONLY flags meant the buffer on the device side was entirely inaccessible, and it only allocated memory for the first character (forgot the 16*sizeof(buf))
    3. queue.enqueueReadBuffer(memBuf, CL_TRUE, 0, 16*sizeof(buf), (void*)buf); - forgot the 16*sizeof(buf)

    I also had to do auto err = program.build(); without any arguments.

    Also note:


    Lastly, a bit of an advertising: I created an OpenCL-Wrapper to greatly simplify learning and working with OpenCL. This Wrapper eliminates the need to keep track of for example buffer sizes or to have duplicate buffers for CPU and device. The code you need to write for the HelloWorld example is significantly shorter and easier:

    #include "opencl.hpp"
    int main() {
        const Device device(select_device_with_most_flops()); // compile OpenCL C code for the fastest available device
        const uint N = 16u; // size of vectors
        Memory<char> buf(device, N); // allocate memory on both host and device
        const Kernel HelloWorld(device, N, "HelloWorld", buf); // kernel that runs on the device
        HelloWorld.run(); // run add_kernel on the device
        buf.read_from_device(); // copy data from device memory to host memory
        println(buf.data());
    }
    
    #include "kernel.hpp" // note: string literals can't be arbitrarily long, so periodically interrupt with )+R(
    string opencl_c_container() { return R( // ########################## begin of OpenCL C code ####################################################################
    
    kernel void HelloWorld(global char* data) {
        data[0] = 'H';
        data[1] = 'e';
        data[2] = 'l';
        data[3] = 'l';
        data[4] = 'o';
        data[5] = 32; // spaces are wrongly converted with stringification macro, so use ascii code here instead of ' '
        data[6] = 'W';
        data[7] = 'o';
        data[8] = 'r';
        data[9] = 'l';
        data[10] = 'd';
        data[11] = '!';
        data[12] = '\n';
    }
    
    );} // ############################################################### end of OpenCL C code #####################################################################