Carter Roeser
Carter Roeser

Reputation: 360

OpenCL struct alignment errors

I am having troubles with aligning structs between the host and device in OpenCL. I defined many custom structs on both the host and device, and all of them seem to be working perfectly except for one.

I am sending over two structs in an array. All values in the first struct (sObject[0]) are being read correctly in the device, but the second (sObject[1]) is being read in a seemingly corrupt manner where the values are all mixed up and some are missing.

From what I've read, this is possibly a problem with data alignment where the host and device may have different type allocations or padding, but I have verified that the data types have the same size on both the host and device and I have attempted using alignment such as #pragma pack(8), __attribute__ ((aligned (128))) and __attribute__ ((packed)) although I am unsure if they are working correctly with the compiler (VS2017).

Here is the code for the struct on both the host and device:

Host:

typedef struct _cl_tag_sObject {
    cl_double3 m_vCenter;
    cl_double3 m_vBounds1;
    cl_double3 m_vBounds2;
    cl_double m_dRadius;
    cl_bool m_type;
} sObject;

Device:

typedef struct _cl_tag_sObject {
    double3 m_vCenter;
    double3 m_vBounds1;
    double3 m_vBounds2;
    double m_dRadius;
    bool m_type;
} sObject;

Here are the assigned values on the host and the values read from the device:

Host:

m_vCenter = (0,-100.5,0)
m_vBounds1 = (2,2,2)
m_vBounds2 = (3,3,3)
m_dRadius = 100
m_type = 0

Device:

m_vCenter = (0,0,2)
m_vBounds1 = (2,0,3)
m_vBounds2 = (3,0,100)
m_dRadius = 1
m_type = 0

It seems that the value -100.5 is being omitted and the middle values in (2,2,2) and (3,3,3) are taking the place of padding, although I am new to OpenCL and am unsure as to how this process actually works.

What is causing this problem and how can it be solved?

Thanks.

Upvotes: 3

Views: 680

Answers (1)

mogu
mogu

Reputation: 1119

WRT struct packing: __attribute__ ((packed)) causes zero padding between struct elements on GCC and LLVM. I don't know if your device's implementation uses them. I have almost no experience with VS, but i think #pragma pack(1) is what you need on host side to get zero padding.

Aside from packing, you need to be aware that the cl_<type>3 types are typedef'ed to cl_<type>4 types in CL/cl_platform.h header. So on the host side, they're essentially the same.

So even with packing, your struct has cl_double4 with 4 elements, and should look like this in host memory (cast to array of doubles):

0 100.5 0 0 | 2 2 2 0 | 3 3 3 0 | 100

I suspect your device's compiler ignores the host convention and uses true 3-element vectors for double3. You can verify simply by changing the device-side struct to use double4:

    double4 m_vCenter;
    double4 m_vBounds1;
    double4 m_vBounds2;

Unfortunately structs are a bit of grey area in OpenCL. Might be best to avoid 3-element vectors inside structs..

Upvotes: 2

Related Questions