1

ネイティブ C++ 型の配列を、OpenCL 標準で定義された適切なサイズのベクトル型に変換するコードを作成しようとしています。

エンディアンとパッキングは OpenCL 実装固有です。OpenCL 型は便利な operator[] を提供しません。(実際には API は C です) 別の問題:メンバーはありますが、cl_int4ありません。.s3cl_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;
        }
    }
};

このクラスをどのように使用するのか興味があるかもしれません。1 つの例では、次のメンバー クラスのインスタンスを持つ 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 に答える