Изображението на 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 style typecast (float4). Нямам представа защо дори се компилира чисто с вашите драйвери.

Друг наистина странен проблем в изхода е, че вашият изход изглежда идва от случая, когато WIDTH и HEIGHT на ред 23 са 3. Изходът от версия ли е, където наистина е 3?

Независимо от това работи добре след промените.

person sharpneli    schedule 04.01.2014
comment
Re: 2 срещу 3: Да, промених 2s на 3s преди да поставя в изхода и забравих да променя след това в оригиналния източник. Актуализирах въпроса. - person Litherum; 04.01.2014
comment
Радвам се, че имаше обяснение за това; и мен беше странно. Благодаря, че ни уведомихте! - person Dithermaster; 04.01.2014