2012-04-03 65 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

相關問題