CLBufferRead

OpenCL バッファを配列に読み込んで読まれた要素の数を返します。

uint  CLBufferRead(
  int          buffer,                   // OpenCL バッファハンドル
  const void&  data[],                   // 値の配列
  uint         buffer_offset=0,           // OpenCL バッファ内のバイト単位のオフセット(デフォルトで 0)
  uint         data_offset=0,             // OpenCL バッファ内の要素数でのオフセット(デフォルトで 0)
  uint        data_count=WHOLE_ARRAY     // バッファから読まれる値の数(デフォルトではバッファ全体)
  );

行列とベクトルを処理するためのバージョンもあります。

OpenCLバッファの値を行列に読み込み、成功した場合は true を返します。

uint  CLBufferRead(
  int          buffer,                   // OpenCL バッファハンドル
  uint         buffer_offset,             // OpenCL バッファ内のバイト単位のオフセット
  const matrxi& mat,                       // バッファから値を受け取る行列
  ulong         rows=-1,                   // 行列の行数
  ulong         cols=-1                   // 行列の列数
  );

OpenCLバッファの値をベクトルに読み込み、成功した場合は true を返します。

uint  CLBufferRead(
  int          buffer,                   // OpenCL バッファハンドル
  uint         buffer_offset,             // OpenCL バッファ内のバイト単位のオフセット
  const vector& vec,                       // バッファから値を受け取るベクトル
  ulong         size-1,                   // ベクトルの長さ
  );

パラメータ

buffer

[in]  OpenCL バッファハンドル

data[]

[in]  OpenCL バッファから値を受け取る配列。参照で引き渡されます。

buffer_offset

[in]  OpenCL バッファ内のバイト単位での読み込みが始まるオフセット。デフォルトでは読み込みはバッファの一番初めから始まります。

data_offset

[in]  OpenCLのバッファの値を書き込むための最初の配列要素のインデックス。デフォルトでは、配列への読み込み値の書き込みはゼロインデックスから始まります。

data_count

[in]  読まれる値の数。デフォルトでは OpenCL バファ全体が読まれます。

mat

[out] バッファにデータを書き込む行列は、matrix、matrixf、matrixc の 3 つのタイプのいずれかです。

vec

[out] バッファにデータを書き込むベクトルは、vector、vectorf、vectorc の 3 つのタイプのいずれかです。

rows=-1

[in]  パラメータが指定されている場合、colsパラメータも指定する必要があります。新しい行列の次元が指定されていない場合は、現在の次元が使用されます。値が -1 の場合、行数は変わりません。

cols=-1

[in]  パラメータが指定されていない場合、rowsパラメータもスキップする必要があります。行列は次のルールに従います。両方のパラメータが指定されているか、何も指定されていない場合、エラーが発生します。両方のパラメータ(rowscols)が指定されている場合、行列のサイズが変更されます。-1の場合、列数は変わりません。

size=-1

[in] パラメータが指定されていない場合、またはその値が -1 の場合、ベクトルの長さは変わりません。

戻り値

読まれた要素の数。エラーの場合 0 。エラー情報を取得するには、GetLastError() 関数が呼ばれます。

行列またはベクトルが正常に処理された場合は true、それ以外の場合は false

注意事項

1 次元配列では OpenCL バッファへの書き入れが始まる要素の番号はAS_SERIES フラグを考慮して計算されます。

2 次元以上の配列は1 次元として提示されます。この場合 data_offset は、1 次元目の要素の数ではなく、抜かされるべき要素の数です。

式を使用した Pi の計算の

pi_calculation_formula

#define _num_steps       1000000000
#define _divisor         40000
#define _step             1.0 / _num_steps
#define _intrnCnt         _num_steps / _divisor
 
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
string D2S(double arg, int digits) { return DoubleToString(arg, digits); }
string I2S(int arg)                { return IntegerToString(arg); }
 
//--- OpenCL プログラムコード
const string clSource=
"#define _step "+D2S(_step, 12)+"                   \r\n"
"#define _intrnCnt "+I2S(_intrnCnt)+"               \r\n"
"                                                   \r\n"
"__kernel void Pi( __global double *out )           \r\n"
"{                                                  \r\n"
"  int i = get_global_id( 0 );                      \r\n"
"  double partsum = 0.0;                            \r\n"
"  double x = 0.0;                                  \r\n"
"  long from = i * _intrnCnt;                       \r\n"
"  long to = from + _intrnCnt;                      \r\n"
"  for( long j = from; j < to; j ++ )               \r\n"
"  {                                                \r\n"
"     x = ( j + 0.5 ) * _step;                      \r\n"
"     partsum += 4.0 / ( 1. + x * x );              \r\n"
"  }                                                \r\n"
"  out[ i ] = partsum;                              \r\n"
"}                                                  \r\n";
 
//+------------------------------------------------------------------+
//| メモリを解放する補助ルーチン                                              |
//+------------------------------------------------------------------+
void CLFreeAll(const int clMem, const int clKrn, const int clPrg, const int clCtx)
{
CLBufferFree(clMem);
CLKernelFree(clKrn);
CLProgramFree(clPrg);
CLContextFree(clCtx);
}
//+------------------------------------------------------------------+
//| スクリプトプログラム開始関数                                               |
//+------------------------------------------------------------------+
int OnStart()
{
Print("Pi Calculation: step = "+D2S(_step, 12)+"; _intrnCnt = "+I2S(_intrnCnt));
//--- OpenCL コンテキストを準備する
int clCtx;
if((clCtx=CLContextCreate(CL_USE_GPU_ONLY))==INVALID_HANDLE)
  {
  Print("OpenCL not found");
  return(-1);
  }
int clPrg = CLProgramCreate(clCtx, clSource);
int clKrn = CLKernelCreate(clPrg, "Pi");
int clMem=CLBufferCreate(clCtx, _divisor*sizeof(double), CL_MEM_READ_WRITE);
CLSetKernelArgMem(clKrn, 0, clMem);
 
const uint offs[1]  = {0};
const uint works[1] = {_divisor};
//--- OpenCL プログラムを起動する
ulong start=GetMicrosecondCount();
if(!CLExecute(clKrn, 1, offs, works))
  {
  Print("CLExecute(clKrn, 1, offs, works) failed! Error ", GetLastError());
  CLFreeAll(clMem, clKrn, clPrg, clCtx);
  return(-1);
  }
//--- OpenCL デバイスから結果を取得する
vector buffer(_divisor);
if(!CLBufferRead(clMem, 0, buffer))
  {
  Print("CLBufferRead(clMem, 0, buffer) failed! Error ", GetLastError());
  CLFreeAll(clMem, clKrn, clPrg, clCtx);
  return(-1);
  }
//--- すべての値を合計して Pi を計算する
double Pi=buffer.Sum()*_step;
 
double time=(GetMicrosecondCount()-start)/1000.;
Print("OpenCL: Pi calculated for "+D2S(time, 2)+" ms");
Print("Pi = "+DoubleToString(Pi, 12));
//--- メモリを開放する
CLFreeAll(clMem, clKrn, clPrg, clCtx);
//--- 成功
return(0);
}
 /*
Pi Calculation: step = 0.000000001000; _intrnCnt = 25000
OpenCL: GPU device 'Ellesmere' selected
OpenCL: Pi calculated for 99.98 ms
Pi = 3.141592653590
 */