Search code examples
copenclopencl-c

Passing C structures to OpenCL kernel


I have next structure in my host program:

typedef struct  s_figure
{
    cl_float        reflection;
    cl_int          color;
    enum e_figure   type;
    cl_float3       vector1;
    cl_float3       vector2;
    cl_float        param1;
    cl_float        param2;
}                       t_figure;

I have next structure in my kernel:

typedef struct          s_figure
{
    float       reflection;
    int         color;
    enum e_figure   type;
    float3      vector1;
    float3      vector2;
    float       param1;
    float       param2;
}                       t_figure;

Also you can see enum for both of it:

enum            e_figure
{
    BadFigure = -1,
    InfinitePlane = 0,
    Sphere = 1,
    InfiniteCylinder = 2,
    InfiniteCone = 3
};

While passing data to the OpenCL kernel in this way (where figures is an correct parsed structures array):

buf_figures = clCreateBuffer(context, CL_MEM_USE_HOST_PTR, sizeof(t_figure) * figures_count, figures, &err);
clEnqueueWriteBuffer(view->cl->queue, buf_figures, CL_TRUE, 0,sizeof(t_figure) * figures_count, figures, 0, NULL, NULL);

I have a problems with data distortion, for example color after transferring data to OpenCL kernel can be changed to very different (0xFFFFFF->0x007FC2). Also raytrace algorithms works in another way every program execution. How can I fix it? I think gcc compiler make structures in different way than openclc but how to sync it?


Solution

  • You need to specify __attribute__ ((packed)) for a struct declaration for both host and device. Otherwise different compilers (host compiler and device compiler) may create different memory layout for a struct.

    EDIT: Given that sizeof(t_figure) is 52 on both host and device, then the root cause is probably not related to the struct.

    Since you create a buffer with CL_MEM_USE_HOST_PTR, there are some caveats you need to consider:

    1. figures pointer that you specify with CL_MEM_USE_HOST_PTR must point to a valid memory while a buffer is alive, because it is actually used as an underlying memory storage for cl_mem object.

    2. Buffer created with CL_MEM_USE_HOST_PTR already uses a memory (or a copy of it) pointed by figures, so a subsequent write with clEnqueueWriteBuffer is redundant here. More importantly, I'm not even sure how clEnqueueWriteBuffer behaves in this case, because this operation is essentially a memcpy(figures,figures, size).