Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to pass a string to the GPU and get it back from kernel to display it? (C++ OpenCL)

Tags:

c++

opencl

I would like to pass a string to my GPU and get it back from the GPU to print it. It is for understanding purposes - I know, the idea sounds senseless.

I tried:

OpenCL:

__kernel void same_in_same_out_char(__global uchar * out, __constant uchar * in){
  for (unsigned int ui=0; ui<3; ui++) out[ui]=in[ui];
}

C++:

#define __CL_ENABLE_EXCEPTIONS

#include <fstream>
#include <iostream>
#include <iterator>
#include <CL/cl.hpp>
#include <CL/opencl.h>


using namespace std;
int main () {

    vector<cl::Platform> platforms;
    vector<cl::Device> devices;
    vector<cl::Kernel> kernels;
    
    try {
    
        // create platform
        cl::Platform::get(&platforms);
        platforms[0].getDevices(CL_DEVICE_TYPE_GPU, &devices);

        // create context
        cl::Context context(devices);

        // create command queue
        cl::CommandQueue queue(context, devices[0]);

        // load opencl source
        ifstream cl_file("inout.cl");
        string cl_string(istreambuf_iterator<char>(cl_file), (istreambuf_iterator<char>()));
        cl::Program::Sources source(1, make_pair(cl_string.c_str(), 
            cl_string.length() + 1));

        // create program
        cl::Program program(context, source);

        // compile opencl source
        program.build(devices);

        // load named kernel from opencl source
        cl::Kernel kernel(program, "same_in_same_out_char");

        // create a message to send to kernel 
        const char pwd[] = "MAX";
        cout << "char pwd[] : " << pwd << endl;
        cl_uchar * password = (cl_uchar*) &pwd;
        int bufferA_size = 3; // array size is 3

        int bufferC_size = 3; // array size is 3
        cout << " -- OpenCL -- " << endl;

        // allocate device buffer to hold message
        cl::Buffer bufferA(context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, sizeof(cl_uchar) * bufferA_size, password);
        cl::Buffer bufferC(context, CL_MEM_WRITE_ONLY, sizeof(cl_uchar) * bufferC_size);

        // set message as kernel argument
        kernel.setArg(0, bufferC);
        kernel.setArg(1, bufferA);

         // execute kernel
        queue.enqueueTask(kernel);

        // wait for completion
        queue.finish();
        // ----------------------

        cl_uint out_global[bufferC_size];
    queue.enqueueReadBuffer(bufferC, CL_TRUE, 0, bufferC_size*sizeof(cl_uchar), &out_global);

        cout << "Output \t\t:" << *out_global << endl << "Output[1..n] \t:";
        for (unsigned int i=0; i<bufferC_size; i ++) cout << out_global[i] << " " ;

        cout << endl;
    } catch (cl::Error e) {
        cout << endl << e.what() << " : " << e.err() << endl;
    }
    
    return 0;
    
}

But I failed. Output is

Output :5783885

Output[1..n] :5783885 0 26

But not

MAX or 77 65 88

(for M A X).

Regard, Marcus

like image 774
marcus Avatar asked Mar 24 '23 06:03

marcus


1 Answers

It is if fact giving you the answer you expect, but you are putting it in the wrong data type.

What you are getting is the single integer 5783885, which is 0x0058414D (in hexadecimal.) You are on a little-endian platform, so these bytes are arranged in memory from low-order to high-order, i.e. if you look at the memory, the bytes will be (still in hex):

4D, 41, 58, 00, ...

These, displayed in decimal will be:

77, 65, 88, 0, ...

In other words, exactly what you expect.

Your problem (one of your problems, at least) is that you've declared out_global as an array of cl_uints, instead of cl_uchar or cl_char or something.

So change the following line, and you'll probably be fine.

cl_uint out_global[bufferC_size];
like image 109
yzt Avatar answered Apr 06 '23 20:04

yzt