1

我正在尝试编写一些代码来将原生 C++ 类型的数组转换为 OpenCL 标准定义的适当大小的向量类型。

字节序和打包是特定于 OpenCL 实现的。OpenCL 类型不提供方便的运算符[]。(实际上 API 是 C )另一个问题:cl_int4有一个.s3成员,但cl_int2没有。

我有一些在功能上可以工作的东西,但你可以看到我已经进入了模板疯狂的领域。

这可以以更好的方式完成吗? 这些函数不会经常被调用,所以最好是减少程序二进制大小和更少冗长的源代码的组合。

这是我到目前为止所得到的。我没有向您展示所有维度的特化(省略 3-6),而且我也想至少实现整数类型。

#include <CL/cl.h>

template < typename HOST_T, int NUM_DIM >
struct Payload_t;

// Vector length needs to be (for dims 1-6):  2, 4, 8, 8, 16, 16

//single precision

template < >
struct __attribute__((packed)) Payload_t <float, 1> { 
    cl_float2 vec;
    void setElement( int pos, float value )
    {
        switch (pos) {
            case 0: vec.s0 = value; return;
            case 1: vec.s1 = value; return;
            default: return;
        }
    }
};

template < >
struct __attribute__((packed)) Payload_t <float, 2> { 
    cl_float4 vec;
    void setElement( int pos, float value )
    {
        switch (pos) {
            case 0: vec.s0 = value; return;
            case 1: vec.s1 = value; return;
            case 2: vec.s2 = value; return;
            case 3: vec.s3 = value; return;
            default: return;
        }
    }
};

/// double-precision

template < >
struct __attribute__((packed)) Payload_t <double, 1> { 
    cl_double2 vec;
    void setElement( int pos, double value )
    {
        switch (pos) {
            case 0: vec.s0 = value; return;
            case 1: vec.s1 = value; return;
            default: return;
        }
    }
};

template < >
struct __attribute__((packed)) Payload_t <double, 2> { 
    cl_double4 vec;
    void setElement( int pos, double value )
    {
        switch (pos) {
            case 0: vec.s0 = value; return;
            case 1: vec.s1 = value; return;
            case 2: vec.s2 = value; return;
            case 3: vec.s3 = value; return;
            default: return;
        }
    }
};

我想你可能会好奇我会如何使用这个类。在一个示例中,我有一个以 REAL 类型为模板的类,该类具有以下成员类的实例,其中包含Payload_t.

template <int NUM_DIM >
struct cartesian_box_descriptor_t : cartesian_box_descriptor_base_t
{
    static const int vectorLengthArray[6];
    void set_dx( REAL * dx_vec )
    {
        for (int i = 0; i < NUM_DIM; ++i)
            payload.setElement( i, dx_vec[i] );
    };
    void set_startx( REAL * startx_vec )
    {
        for (int i = 0; i < NUM_DIM; ++i)
            payload.setElement( NUM_DIM + i , startx_vec[i] );
    };

    virtual WxAny getDescriptorStruct() const
    {
        return WxAny( payload ); // packages this simple structure as 'scalar' with hidden type
    };


    Payload_t< REAL, NUM_DIM> payload;
};

封装 OpenCL 支持的getDescriptorStruct()类型,我可以将其作为内核参数发送到 OpenCL API,所有字节都位于正确的位置。

如果有人正在考虑范式转变,我只需要一次设置整个向量。

4

1 回答 1

0

我不确定是为此感到自豪还是感到羞耻,但它确实有效。您确实需要确保对 set() 的所有调用都使用正确的类型。它自动处理新的 cl_ 类型和新大小的 cl_ 类型,仅在 3 个位置进行更改。如果有人愿意,它可能会被进一步清理。

#include<iostream>
#include<assert.h>

struct cl_float1 {
  float s0;
};

struct cl_float2 {
  float s0;
  float s1;
};


#define ZERO_THROUGH_15(pre) \
  pre i0;            \
  pre i1;            \
  pre i2;            \
  pre i3;            \
  pre i4;            \
  pre i5;            \
  pre i6;            \
  pre i7;            \
  pre i8;            \
  pre i9;            \
  pre i10;           \
  pre i11;           \
  pre i12;           \
  pre i13;           \
  pre i14;           \
  pre i15


template<typename SIMD, typename POD>
struct offset {
  static POD SIMD::* data[16];
  ZERO_THROUGH_15(static bool);
  offset() {
    ZERO_THROUGH_15();
  }
};
template<typename SIMD, typename POD>
/*static*/ POD SIMD::* offset<SIMD,POD>::data[16];

template<int n>
struct offsetGetter {
  template<typename SIMD, typename POD>
  static POD SIMD::* get(...) {
    return NULL;
  }
};

#define GET_OFFSET(n) \
template<> \
struct offsetGetter<n> { \
  template<typename SIMD, typename POD, POD SIMD::* OFS> \
  struct check {}; \
\
  template<typename SIMD, typename POD> \
  static POD SIMD::* get(check<SIMD, POD, &SIMD::s ## n>*) { \
    return &SIMD::s ## n; \
  } \
\
  template<typename SIMD, typename POD> \
  static POD SIMD::* get(...) { \
    return NULL; \
  } \
  template<typename SIMD, typename POD> \
  static bool init() { \
    offset<SIMD,POD>::data[n] = get<SIMD,POD>(NULL);    \
  }; \
}; \
template<typename SIMD, typename POD> \
 /*static*/ bool offset<SIMD,POD>::i##n = offsetGetter<n>::init<SIMD,POD>()

GET_OFFSET(0);
GET_OFFSET(1);
GET_OFFSET(2);
GET_OFFSET(3);
GET_OFFSET(4);
GET_OFFSET(5);
GET_OFFSET(6);
GET_OFFSET(7);
GET_OFFSET(8);
GET_OFFSET(9);
GET_OFFSET(10);
GET_OFFSET(11);
GET_OFFSET(12);
GET_OFFSET(13);
GET_OFFSET(14);
GET_OFFSET(15);

template<typename SIMD, typename POD>
void set(SIMD& simd, int n, POD val) {
  offset<SIMD,POD> ignoreme;
  POD SIMD::* ofs = offset<SIMD,POD>::data[n];
  assert(ofs);
  simd.*ofs = val;
}

main(){
  cl_float2 x;
  set(x, 0, 42.0f);
  std::cout << x.s0 << std::endl; // prints 42
  set(x, 1, 52.0f);
  std::cout << x.s1 << std::endl; // prints 52
  cl_float1 y;
  set(y, 1, 42.0f); // assertion failure
}
于 2013-01-04T02:12:38.253 回答