Образ OpenCL пишет в OS X

Я пытался написать ядро ​​OpenCL, которое заполняет образ OpenCL значениями. Однако у меня были проблемы с некоторыми текселями, которые не записывались. Кажется, я не могу заставить функцию write_image() писать в тексели с разными координатами x и y.

Я создал программу сокращения здесь. Надеюсь, это достаточно просто, чтобы его можно было прочитать:

#include <iostream>

#include <cassert>

#include <OpenCL/OpenCL.h>

const char* clSource[] = {
    "kernel void set(write_only image2d_t image)\n",
    "{\n",
    "    int x = get_global_id(0);\n",
    "    int y = get_global_id(1);\n",
    "    float4 result = float4(1.0, 1.0, 1.0, 1.0);\n",
    "    printf(\"Writing dimensions %d x %d: %d, %d, %d, %d\\n\", x, y,\n",
    "        (int)result.x*255, (int)result.y*255, (int)result.z*255, (int)result.w*255);\n",
    "    write_imagef(image, int2(x, y), result);\n",
    "}\n",
};

int main(int argc, const char * argv[])
{
    const unsigned int WIDTH = 3;
    const unsigned int HEIGHT = 3;
    cl_int clError;
    cl_platform_id platform;
    clError = clGetPlatformIDs(1, &platform, nullptr);
    assert(clError == CL_SUCCESS);
    cl_device_id device;
    clError = clGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU, 1, &device, nullptr);
    assert(clError == CL_SUCCESS);
    cl_context_properties properties[] = {
        CL_CONTEXT_PLATFORM, (cl_context_properties)platform,
        0
    };
    cl_context openCLContext = clCreateContext(properties, 1, &device, nullptr, nullptr, &clError);
    assert(clError == CL_SUCCESS);
    cl_command_queue commandQueue = clCreateCommandQueue(openCLContext, device, 0, &clError);
    assert(clError == CL_SUCCESS);

    cl_program program = clCreateProgramWithSource(openCLContext, sizeof(clSource) / sizeof(const char*), clSource, nullptr, &clError);
    assert(clError == CL_SUCCESS);
    clError = clBuildProgram(program, 1, &device, "", nullptr, nullptr);
    assert(clError == CL_SUCCESS);
    cl_kernel kernel = clCreateKernel(program, "set", &clError);
    assert(clError == CL_SUCCESS);

    cl_image_format imageFormat;
    imageFormat.image_channel_data_type = CL_UNORM_INT8;
    imageFormat.image_channel_order = CL_RGBA;
    cl_image_desc imageDesc;
    imageDesc.image_type = CL_MEM_OBJECT_IMAGE2D;
    imageDesc.image_width = WIDTH;
    imageDesc.image_height = HEIGHT;
    imageDesc.image_depth = 1;
    imageDesc.image_array_size = 1;
    imageDesc.image_row_pitch = 0;
    imageDesc.image_slice_pitch = 0;
    imageDesc.num_mip_levels = 0;
    imageDesc.num_samples = 0;
    imageDesc.buffer = nullptr;
    cl_mem clTexture = clCreateImage(openCLContext, CL_MEM_WRITE_ONLY, &imageFormat, &imageDesc, nullptr, &clError);
    assert(clError == CL_SUCCESS);
    clError = clSetKernelArg(kernel, 0, sizeof(cl_mem), &clTexture);
    assert(clError == CL_SUCCESS);
    size_t globalWorkOffset[] = {0, 0, 0};
    size_t globalWorkSize[] = {WIDTH, HEIGHT, 0};
    size_t localWorkSize[] = {1, 1, 0};
    cl_event event1;
    clError = clEnqueueNDRangeKernel(commandQueue, kernel, 2, globalWorkOffset, globalWorkSize, localWorkSize, 0, nullptr, &event1);
    assert(clError == CL_SUCCESS);

    unsigned char* bitmap = new unsigned char[WIDTH * HEIGHT * 4];
    size_t origin[] = {0, 0, 0};
    size_t region[] = {WIDTH, HEIGHT, 1};
    cl_event event2;
    clError = clEnqueueReadImage(commandQueue, clTexture, CL_TRUE, origin, region, 0, 0, bitmap, 1, &event1, &event2);

    std::cout << "============================================" << std::endl;
    clError = clWaitForEvents(1, &event2);
    assert(clError == CL_SUCCESS);
    for (size_t i = 0; i < HEIGHT; ++i) {
        for (size_t j = 0; j < WIDTH; ++j) {
            std::cout << "Reading dimensions " << j << " x " << i << ": ";
            std::cout << static_cast<int>(bitmap[4*(i*WIDTH+j)+0]) << ", ";
            std::cout << static_cast<int>(bitmap[4*(i*WIDTH+j)+1]) << ", ";
            std::cout << static_cast<int>(bitmap[4*(i*WIDTH+j)+2]) << ", ";
            std::cout << static_cast<int>(bitmap[4*(i*WIDTH+j)+3]) << std::endl;
        }
    }
    delete[] bitmap;

    clError = clReleaseEvent(event1);
    assert(clError == CL_SUCCESS);
    clError = clReleaseEvent(event2);
    assert(clError == CL_SUCCESS);
    clError = clReleaseMemObject(clTexture);
    assert(clError == CL_SUCCESS);
    clError = clReleaseKernel(kernel);
    assert(clError == CL_SUCCESS);
    clError = clReleaseProgram(program);
    assert(clError == CL_SUCCESS);
    clError = clReleaseCommandQueue(commandQueue);
    assert(clError == CL_SUCCESS);
    clError = clReleaseDevice(device);
    assert(clError == CL_SUCCESS);
    clError = clReleaseContext(openCLContext);
    assert(clError == CL_SUCCESS);
    return 0;
}

После всего этого вот вывод на OS X (10.9):

Writing dimensions 0 x 0: 255, 255, 255, 255
Writing dimensions 1 x 0: 255, 255, 255, 255
Writing dimensions 2 x 0: 255, 255, 255, 255
Writing dimensions 0 x 1: 255, 255, 255, 255
Writing dimensions 1 x 1: 255, 255, 255, 255
Writing dimensions 2 x 1: 255, 255, 255, 255
Writing dimensions 0 x 2: 255, 255, 255, 255
Writing dimensions 1 x 2: 255, 255, 255, 255
Writing dimensions 2 x 2: 255, 255, 255, 255
============================================
Reading dimensions 0 x 0: 255, 255, 255, 255
Reading dimensions 1 x 0: 0, 0, 0, 0
Reading dimensions 2 x 0: 0, 0, 0, 0
Reading dimensions 0 x 1: 0, 0, 0, 0
Reading dimensions 1 x 1: 255, 255, 255, 255
Reading dimensions 2 x 1: 0, 0, 0, 0
Reading dimensions 0 x 2: 0, 0, 0, 0
Reading dimensions 1 x 2: 0, 0, 0, 0
Reading dimensions 2 x 2: 255, 255, 255, 255
Program ended with exit code: 0

Я получаю тот же результат на ATI Radeon HD 5750, что и на NVIDIA GeForce GT 650M.

Проблемы с текстурами OpenCL и OpenGL и opencl image2d_t не записывает обратно значения, похоже, имеет похожие проблемы, но ни один из них не помогает мне.

Я делаю что-то неправильно? Или запись образа просто не поддерживается драйверами Mavericks?


person Litherum    schedule 04.01.2014    source источник


Ответы (2)


Проблема в том, как вы строите векторные значения. Вместо этого:

typeN(a, b, ..., k)

Вы должны делать это:

(typeN)(a, b, ..., k)

Первый фактически вызывает ошибку компиляции на платформах, отличных от Apple, поэтому я не совсем уверен, как компилятор Apple интерпретирует этот код.

Итак, для вашего ядра необходимо изменить две соответствующие строки:

float4 result = float4(1.0, 1.0, 1.0, 1.0);
...
write_imagef(image, int2(x, y), result);

Что теперь должно стать:

float4 result = (float4)(1.0, 1.0, 1.0, 1.0);
...
write_imagef(image, (int2)(x, y), result);
person jprice    schedule 04.01.2014
comment
GLSL против OpenCL снова наносит удар! - person Litherum; 04.01.2014

Мне удалось скомпилировать и успешно запустить вашу программу со следующим изменением ядра:

const char* clSource[] = {
    "__kernel void set(write_only image2d_t image)\n",
    "{\n",
    "    int x = get_global_id(0);\n",
    "    int y = get_global_id(1);\n",
    "    float4 result = (float4)(1.0, 1.0, 1.0, 1.0);\n",
    "    printf(\"Writing dimensions %d x %d: %d, %d, %d, %d\\n\", x, y,\n",
    "        (int)result.x*255, (int)result.y*255, (int)result.z*255, (int)result.w*255);\n",
    "    write_imagef(image, (int2)(x, y), result);\n",
    "}\n",
};

Например, вы не можете написать float4(1.0.... но вы должны написать его как приведение типов в стиле C (float4). Я понятия не имею, почему он даже чисто скомпилирован с вашими драйверами.

Еще одна действительно странная проблема в выводе заключается в том, что ваш вывод, похоже, исходит из случая, когда WIDTH и HEIGHT в строке 23 были равны 3. Является ли вывод версией, где он действительно равен 3?

Тем не менее, после изменений он работает нормально.

person sharpneli    schedule 04.01.2014
comment
Re: 2 против 3: Да, я изменил 2 на 3 перед вставкой в ​​вывод и забыл изменить затем в исходном коде. Я обновил вопрос. - person Litherum; 04.01.2014
comment
Я рад, что этому есть объяснение; меня это тоже сбивало с толку. Спасибо за то, что дали нам знать! - person Dithermaster; 04.01.2014