0

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 ;)

Robert Crovella
  • 143,785
  • 11
  • 213
  • 257
maxet24
  • 111
  • 1
  • 10
  • 1
    `╠` means uninitialized stack memory on msvc in debug mode. Related: [https://stackoverflow.com/questions/12905027/displaying-this-symbol-instead-of-desired-characters](https://stackoverflow.com/questions/12905027/displaying-this-symbol-instead-of-desired-characters) – drescherjm Jan 29 '22 at 14:16
  • Yes, this happens because the program does not start and does not change the buffer value. – maxet24 Jan 29 '22 at 15:23
  • Are you sure that the `HelloWorld.cl` file was even read? Perhaps its in the wrong folder. Your code does not exit when an error happens. – drescherjm Jan 29 '22 at 15:27
  • @drescherjm Yep, i just checked it. I can see both files in the explorer and VS explorer and they are in the same folder. I tried to remove HelloWorld.cl and i saw same error. So looks like it just can't find file, but don't show error about that. – maxet24 Jan 29 '22 at 17:53
  • @drescherjm Actually CL 1.2 is obsolete, so I tried not to install the current version of CUDA which has the latest version of the headers (c.hpp and OpenCL.lib). In this case there is no function queue.enqueueTask(kernel); and I don't know which function in the new version is responsible for it. Do you know? And yes, thank you for responding! – maxet24 Jan 29 '22 at 17:56
  • If you are running Visual Studio Community the .cl file likely needs to be in the same folder as you project because the working directory is set to $(ProjectDir) when you run your program in the IDE. If you run from the windows file explorer you need that file to be in the same folder as the executable because the working directory in that case will be the same folder as the executable. – drescherjm Jan 29 '22 at 17:59
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/241516/discussion-between-maxet24-and-drescherjm). – maxet24 Jan 29 '22 at 18:12
  • @drescherjm Lol, sorry, I just saw that the program gives an error before displaying those weird characters: `Could not open file: C:\Users\user\AppData\Local\Temp\dep-776979.d ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ - buf` – maxet24 Jan 29 '22 at 20:07

1 Answers1

2

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:

  • While it works, stack allocation (char buf[16];) limits the buffer size. Use heap allocation (char* buf = new char[16];) instead (and don't forget delete[] buf;).
  • Don't use queue.enqueueTask(kernel);, but queue.enqueueNDRangeKernel(cl_kernel, cl::NullRange, cl::NDRange(...), cl::NDRange(32)); instead. With this you can specify the global and local ranges.

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 #####################################################################
ProjectPhysX
  • 4,535
  • 2
  • 14
  • 34