Почему это ядро ​​pyopencl не может правильно преобразовать скаляры в цвета?

Я написал ядро ​​opencl для преобразования скалярных значений в цвета, потому что выполнение этого в обычном python занимает несколько секунд.

К сожалению, ядро ​​(которое является урезанной версией некоторой логики, которая работает в другом месте), похоже, полностью не справляется со своей задачей преобразования из uint32 в триплеты из uint8 [sic] (r, g, b).

import numpy
import pyopencl as cl
from matplotlib.image import imsave


def generate_kernel(ctx):
    return """
float3 hue_to_rgb(float hue)
{
    float tmp = (hue-floor(hue))*6;
    if (tmp<1) {
        return (float3)( 1, tmp, 0);
    } else if (tmp<2) {
        float s = tmp-1;
        float t = 2-tmp;
        return (float3)( t, 1, 0);
    } else if (tmp<3) {
        float s = tmp-2;
        float t = 3-tmp;
        return (float3)(0, 1,s);
    } else if (tmp<4) {
        float s = tmp-3;
        float t = 4-tmp;
        return (float3)(0, t,1);
    } else if (tmp<5) {
        float s = tmp-4;
        float t = 5-tmp;
        return (float3)(s, 0,1);
    } else {
        float s = tmp-5;
        float t = 6-tmp;
        return (float3)(1, 0,t);
    }
    return (float3)(1,0,0);
}

__kernel void apply_color_map(__global uint*counts, __global uint8 *rgbs, int max_iter)
{
    int idx = get_global_id(0);

    int base = idx*3;

    //printf("%d %d %d\\n", idx, base, counts[idx]);

    if ( counts[idx] >= max_iter) {
        rgbs[base] = 0;
        rgbs[base+1] = 0;
        rgbs[base+2] = 0;
    } else {
        float3 rgb = 255.9f*hue_to_rgb(counts[idx]/255.0f);
        rgb.x = 0x80; // yeah, even something as simple as this does not work
        rgb.y = 0x0;
        rgb.z = 0x0;
        rgbs[base] = floor(rgb.x);
        rgbs[base+1] = floor(rgb.y);
        rgbs[base+2] = floor(rgb.z);
        //printf(" %v3f\\n", rgb);
        //printf("counts[%d] = %d ; %v3f <%x,%u,%u>\\n", idx, counts[idx], rgb, rgbs[base], rgbs[base+1], rgbs[base+2]);
    }
}
"""

def mission1(ctx, queue):
    source = generate_kernel(ctx)
    print (source)
    prg = cl.Program(ctx, source).build()

    width=256
    height=16
    #counts = numpy.load("/tmp/mandelbrot.npy");
    counts = [ [x for x in range(width)] for y in range(height) ]
    counts = numpy.array(counts, dtype=numpy.uint32)

    print(counts)

    kernel = prg.apply_color_map
    kernel.set_scalar_arg_dtypes([None, None, numpy.uint32])

    counts_len = width*height
    counts_g = cl.Buffer(ctx, cl.mem_flags.READ_ONLY, counts_len*4)
    rgb_g = cl.Buffer(ctx, cl.mem_flags.READ_WRITE, counts_len*3)

    rgb = numpy.zeros([height,width,3], dtype=numpy.uint8)

    cl.enqueue_copy(queue, counts_g, counts).wait()
    kernel(queue, [width*height], None, counts_g, rgb_g, 256) .wait()
    cl.enqueue_copy(queue, rgb, rgb_g).wait()

    imsave("/tmp/ramp.png", rgb)
#

ctx = cl.create_some_context()
queue = cl.CommandQueue(ctx)
mission1(ctx, queue)

Я ожидаю, что выходное изображение будет выглядеть как сплошной темно-красный (потому что я заменяю значения радуги в качестве теста отладки), но оно выглядит как некоторые странные полосы и блоки шума.

что это за фигня

1 ответ

Очевидно, мне нужно изменить

__kernel void apply_color_map(__global uint*counts, __global uint8 *rgbs, int max_iter)

в

__kernel void apply_color_map(__global uint*counts, __global unsigned char *rgbs, int max_iter)

Если кто-то может указать на документацию, которая объясняет, почему unsigned char а также uint8 отличаются от pyopencl в этом контексте, я приму их ответ.

Другие вопросы по тегам