Как использовать clEnqueueWriteBufferRect в OpenCL - PullRequest
0 голосов
/ 15 января 2020

Я хочу использовать clEnqueueReadBufferRect в OpenCL. Чтобы сделать это, мне нужно определить region как один из проходящих аргументов. Но существует несоответствие между ссылками OpenCL. В онлайн reference упоминается, что

(ширина, высота, глубина) в байтах считываемого 2D или 3D прямоугольника или написано. Для 2D-копии прямоугольника значение глубины, заданное region [2], должно быть 1.

, но в справочнике , стр. 77 упоминается, что

region определяет (ширину в байтах, высоту в строках, глубину в срезах) для считываемого или записываемого 2D или 3D прямоугольника. Для 2D-копии прямоугольника значение глубины, заданное region [2], должно быть 1. Значения в region не могут быть 0

, но, к сожалению, ни одно из этих руководств не сработало для меня, и я должен предоставить region в (ширина в столбцах, высота в строках, глубина в слайсах), в противном случае, когда я определил их как байты, а не строки / столбцы, я получил ошибку CL_INVALID_VALUE. Теперь какой из них правильный?

    #define WGX 16
    #define WGY 16
    #include "misc.hpp"


    int main(int argc, char** argv)
    {
    int i;
    int n = 1000; 
    int filterWidth = 3;
    int filterRadius = (int) filterWidth/2;
    int padding      = filterRadius * 2;
    double h = 1.0 / n;


    int width_x[2];
    int height_x[2];

    int deviceWidth[2];
    int deviceHeight[2];  
    int deviceDataSize[2];

    for (i = 0; i < 2; ++i)
    {
        set_domain_length(n, n, height_x[i], width_x[i], i);
    }

    float* x = new float [height_x[0]    * width_x[0]];

    init_unknown(x,             height_x[0], width_x[0], 0);

    set_bndryCond(x, width_x[0], h);

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

    assert(platforms.size() > 0);
    cl::Platform myPlatform = platforms[0];

    std::vector<cl::Device> devices;
    myPlatform.getDevices(CL_DEVICE_TYPE_GPU, &devices);

    assert(devices.size() > 0);

    cl::Device myDevice = devices[0];
    cl_display_info(myPlatform, myDevice);
    cl::Context context(myDevice);

    std::ifstream kernelFile("iterative_scheme.cl");

    std::string src(std::istreambuf_iterator<char>(kernelFile), (std::istreambuf_iterator<char>()));

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

    cl::CommandQueue queue(context, myDevice);

    deviceWidth[0]    = roundUp(width_x[0], WGX);
    deviceHeight[0]   = height_x[0];  
    deviceDataSize[0] = deviceWidth[0] * deviceHeight[0] * sizeof(float);

    cl::Buffer buffer_x;
    try
    {
        buffer_x = cl::Buffer(context, CL_MEM_READ_WRITE,  deviceDataSize[0]);

    } catch (cl::Error& error)
    {
        std::cout << "     ---> Problem in creating buffer(s) " << std::endl;
        std::cout << "     ---> " << getErrorString(error) << std::endl;
        exit(0);
    }

    cl::size_t<3> buffer_origin;
    buffer_origin[0] = 0;
    buffer_origin[1] = 0;
    buffer_origin[2] = 0;

    cl::size_t<3> host_origin;
    host_origin[0] = 0;
    host_origin[1] = 0;
    host_origin[2] = 0;

    cl::size_t<3> region;
    region[0] = (size_t)(deviceWidth[0] * sizeof(float));
    region[1] = (size_t)(height_x[0]);
    region[2] = 1;

    std::cout << "===> Start writing data to device" << std::endl;
    try
    {
        queue.enqueueWriteBufferRect(buffer_x, CL_TRUE, buffer_origin, host_origin, region,
                                    deviceWidth[0] * sizeof(float), 0, width_x[0] * sizeof(float), 0, x);

    } catch (cl::Error& error)
    {
        std::cout << "     ---> Problem in writing data from Host to Device: " << std::endl;
        std::cout << "     ---> " << getErrorString(error) << std::endl;
        exit(0);
    }


    // Build the program  
    std::cout << "===> Start building program" << std::endl;

    try
    {
        program.build("-cl-std=CL2.0");
        std::cout << "     ---> Build Successfully " << std::endl;
    } catch(cl::Error& error)
    {
        std::cout << "     ---> Problem in building program " << std::endl;
        std::cout << "     ---> " << getErrorString(error) << std::endl;
        std::cout << "     ---> " << program.getBuildInfo<CL_PROGRAM_BUILD_LOG>(myDevice) << std::endl;
        exit(0);
    }


    std::cout << "===> Start reading data from device" << std::endl;
    // read result y and residual from the device 
    buffer_origin[0] = (size_t)(filterRadius * sizeof(float));
    buffer_origin[1] = (size_t)filterRadius;
    buffer_origin[2] = 0;

    host_origin[0] = (size_t)(filterRadius * sizeof(float));
    host_origin[1] = (size_t)filterRadius;
    host_origin[2] = 0;

    // region of x
    region[0] = (size_t)((width_x[0]  - padding) * sizeof(float));
    region[1] = (size_t)(height_x[0] - padding);
    region[2] = 1;

    try
    {
        queue.enqueueReadBufferRect(buffer_x, CL_TRUE, buffer_origin, host_origin,
            region, deviceWidth[0] * sizeof(float), 0, deviceWidth[0] * sizeof(float), 0, x);
    } catch (cl::Error& error)
    {
        std::cout << "     ---> Problem reading buffer in device: "  << std::endl;
        std::cout << "     ---> " << getErrorString(error) << std::endl;
        exit(0);
    }

    delete[] (x);
    return 0;
    } 

Ответы [ 2 ]

1 голос
/ 17 января 2020

Я выяснил, в чем причина проблемы, по онлайн-ссылке

CL_INVALID_VALUE, если host_row_pitch не равно 0 и меньше, чем регион [0].

, поэтому enqueueWriteBufferRect должно измениться следующим образом:

queue.enqueueWriteBufferRect(buffer_x, CL_TRUE, buffer_origin, host_origin, region,
                            deviceWidth[0] * sizeof(float), 0, deviceWidth[0] * sizeof(float), 0, x);

, что означает host_row_pitch = deviceWidth[0] * sizeof(float) вместо host_row_pitch = width_x[0] * sizeof(float).

1 голос
/ 16 января 2020

Ссылка, которую вы указали онлайн, гласит:

регион

(ширина в байтах, высота в строках, глубина в срезах) считываемого 2D или 3D прямоугольника или написано. Для двухмерной копии прямоугольника значение глубины, заданное region [2], должно быть 1. Значения в region не могут быть 0.

Это соответствует тому, что вы цитировали позже как «справочник». Это потому, что ваша первая ссылка указывает на OpenCL 2.0, а вторая ссылка на 1.2.

Указанная вами несоответствие существует между онлайн-руководством 1.2 и PDF 1.2, но онлайн-руководство 2.0 соответствует PDF. Поэтому я предполагаю, что это была ошибка в онлайн-руководстве по версии 1.2, которая была исправлена ​​в 2.0

, в противном случае, когда я определил их как байт, а не строки / столбцы

Что такое столбец ", а чем он отличается от байтов?

«Элементы» буферной прямоугольной копии всегда являются байтами. Если вы читаете / записываете 1D прямоугольник из буфера, он просто передает region[0] байтов. Причина, по которой API имеет «строки» и «срезы», заключается в том, что при использовании 2D / 3D-областей вы можете иметь отступ между данными; но вы не можете иметь отступ между элементами в одномерной области.

...