2012-04-03 48 views
1

我正在尝试编写一些代码来将本机C++类型的数组转换为由OpenCL标准定义的适当大小的向量类型。如何更好地处理依赖于模板参数的类成员类型?

Endian-ness和包装是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; 
}; 

getDescriptorStruct()包的方式OpenCL的支持的类型,我可以发送到的OpenCL API与所有字节掉落在正确的地方内核参数。

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

+0

链接到OpenCL矢量类型规范。 http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/vectorDataTypes.html – NoahR 2012-04-04 01:17:18

回答

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 
} 
+0

哇。我一直在试图通过这种方式来解决问题。 现在有几个笔记。 cl_float1不是OpenCL类型,它将是cl_float。我使用OpenCL头替换了两个结构定义,如我的示例代码中所示。有了这些更改,即使在main()中的任何set()行之前,我也会从'assert(ofs)'行收到断言错误。 我也收到了80条警告,我认为所有与'static bool init()'函数有关的函数都不会返回。你能评论这两个问题吗? – NoahR 2013-01-10 23:43:58

相关问题