CLProgramCreate

OpenCL プログラムをソースコードから作成します。

int  CLProgramCreate(
  int          context,    // OpenCL コンテキストのハンドル
  const string  source      // ソースコード
  );

オーバーロード関数は OpenCL プログラムを作成し、渡された文字列にコンパイラメッセージを書き込みます。

int  CLProgramCreate(
  int          context,    // OpenCL コンテキストのハンドル
  const string  source,      // ソースコード
  string      &build_log    // コンパイルログを受け取る文字列
  );

パラメータ

context

[in]  OpenCL コンテンツのハンドル

source

[in]  OpenCL プログラムのソースコードを含む文字列

&build_log

[in]  OpenCL コンパイラメッセージを受け取る文字列

戻り値

成功の場合 OpenCL オブジェクトハンドル。エラーの場合は -1。エラー情報を取得するには、GetLastError() 関数が呼ばれます。

注意事項

現時点では、次のエラーコードが使用されます。

  • ERR_OPENCL_INVALID_HANDLE – 不正な OpenCL コンテキストハンドル
  • ERR_INVALID_PARAMETER – 不正な文字列パラメータ
  • ERR_NOT_ENOUGH_MEMORY – 操作完了に不充分なメモリ
  • ERR_OPENCL_PROGRAM_CREATE – OpenCL 内部エラーまたはコンパイルエラー

グラフィックカードによっては double 型の数の操作はデフォルトでは無効にされています。これはコンパイルエラー5105 につながります。double 型数値のサポートを有効にするには #pragma OPENCL EXTENSION cl_khr_fp64 : enable ディレクティブをお使いのプログラムに追加してください。 グラフィックカードが double をサポートしない場合は、ディレクティブの使用はサポートを有効にしません。

例:

//+------------------------------------------------------------------+
//| OpenCL カーネル                                                     |
//+------------------------------------------------------------------+
const string
cl_src=
      //--- デフォルトでは double をサポートしない GPU がある
      //--- cl_khr_fp64 directive が double の操作を有効にするために使用される
      "#pragma OPENCL EXTENSION cl_khr_fp64 : enable      \r\n"
      //--- OpenCL カーネル関数
      "__kernel void Test_GPU(__global double *data,      \r\n"
      "                       const    int N,             \r\n"
      "                       const    int total_arrays)  \r\n"
      "  {                                                \r\n"
      "   uint kernel_index=get_global_id(0);             \r\n"
      "   if (kernel_index>total_arrays) return;          \r\n"
      "   uint local_start_offset=kernel_index*N;         \r\n"
      "   for(int i=0; i<N; i++)                          \r\n"
      "     {                                             \r\n"
      "       data[i+local_start_offset] *= 2.0;          \r\n"
      "     }                                             \r\n"
      "  }                                                \r\n";
//+------------------------------------------------------------------+
//| Test_CPU                                                         |
//+------------------------------------------------------------------+
bool Test_CPU(double &data[],const int N,const int id,const int total_arrays)
 {
//--- 配列サイズをチェックする
  if(ArraySize(data)==0) return(false);
//--- 配列インデックスをチェックする
  if(id>total_arrays) return(false);
//--- インデックス id の配列のローカルオフセットを計算する
  int local_start_offset=id*N;
//--- 要素を二倍にする
  for(int i=0; i<N; i++)
    {
     data[i+local_start_offset]*=2.0;
    }
  return true;
 }
//---
#define ARRAY_SIZE   100 // 配列サイズ
#define TOTAL_ARRAYS 5   // 全ての配列
//--- OpenCL ハンドル
int cl_ctx; // OpenCL コンテキストハンドル
int cl_prg; // OpenCL プログラムハンドル
int cl_krn; // OpenCL カーネルハンドル
int cl_mem; // OpenCL バッファハンドル
//---
double DataArray1[]; // CPU 計算のためのデータ配列
double DataArray2[]; // GPU 計算のためのデータ配列
//+------------------------------------------------------------------+
//| スクリプトプログラムを開始する関数                                          |
//+------------------------------------------------------------------+
int OnStart()
 {
//--- OpenCL オブジェクトを初期化する
//--- OpenCL コンテキストを作成する
  if((cl_ctx=CLContextCreate())==INVALID_HANDLE)
    {
    Print("OpenCL not found. Error=",GetLastError());
    return(1);
    }
//--- OpenCL プログラムを作成する
  if((cl_prg=CLProgramCreate(cl_ctx,cl_src))==INVALID_HANDLE)
    {
    CLContextFree(cl_ctx);
    Print("OpenCL program create failed. Error=",GetLastError());
    return(1);
    }
//--- OpenCL カーネルを作成する
  if((cl_krn=CLKernelCreate(cl_prg,"Test_GPU"))==INVALID_HANDLE)
    {
    CLProgramFree(cl_prg);
    CLContextFree(cl_ctx);
    Print("OpenCL kernel create failed. Error=",GetLastError());
    return(1);
    }
//--- OpenCL バッファを作成する
  if((cl_mem=CLBufferCreate(cl_ctx,ARRAY_SIZE*TOTAL_ARRAYS*sizeof(double),CL_MEM_READ_WRITE))==INVALID_HANDLE)
    {
    CLKernelFree(cl_krn);
    CLProgramFree(cl_prg);
    CLContextFree(cl_ctx);
    Print("OpenCL buffer create failed. Error=",GetLastError());
    return(1);
    }
//--- OpenCL カーネルの定数パラメータを設定する
  CLSetKernelArgMem(cl_krn,0,cl_mem);
  CLSetKernelArg(cl_krn,1,ARRAY_SIZE);
  CLSetKernelArg(cl_krn,2,TOTAL_ARRAYS);
//--- データ配列を準備する
  ArrayResize(DataArray1,ARRAY_SIZE*TOTAL_ARRAYS);
  ArrayResize(DataArray2,ARRAY_SIZE*TOTAL_ARRAYS);
//--- データに配列を書き込む
  for(int j=0; j<TOTAL_ARRAYS; j++)
    {
    //--- j 番目の配列のローカル開始オフセットを計算する
    uint local_offset=j*ARRAY_SIZE;
    //--- インデックス j の配列を準備する
    for(int i=0; i<ARRAY_SIZE; i++)
       {
        //--- MathCos(i+j) の結果を配列に書き込む
        DataArray1[i+local_offset]=MathCos(i+j);
        DataArray2[i+local_offset]=MathCos(i+j);
       }
    };
//--- CPU 計算をテストする
  for(int j=0; j<TOTAL_ARRAYS; j++)
    {
    //--- インデックス j の配列の計算
     Test_CPU(DataArray1,ARRAY_SIZE,j,TOTAL_ARRAYS);
    }
//--- CLExecute パラメータを準備する
  uint  offset[]={0};
//--- グローバルワークサイズ
  uint  work[]={TOTAL_ARRAYS};
//--- OpenCL バッファにデータを書く
  CLBufferWrite(cl_mem,DataArray2);
//--- OpenCL カーネルを実行する
  CLExecute(cl_krn,1,offset,work);
//--- OpenCL バッファからデータを読む
  CLBufferRead(cl_mem,DataArray2);
//--- エラーの合計
  double total_error=0;
//--- 結果を比較してエラーを計算する
  for(int j=0; j<TOTAL_ARRAYS; j++)
    {
    //--- j 番目の配列のローカルオフセットを計算する
    uint local_offset=j*ARRAY_SIZE;
    //--- 結果を比較する
    for(int i=0; i<ARRAY_SIZE; i++)
       {
        double v1=DataArray1[i+local_offset];
        double v2=DataArray2[i+local_offset];
        double delta=MathAbs(v2-v1);
        total_error+=delta;
        //--- 最初と最後の配列を表示する
        if((j==0) || (j==TOTAL_ARRAYS-1))
          PrintFormat("array %d of %d, element [%d]:  %f, %f, [error]=%f",j+1,TOTAL_ARRAYS,i,v1,v2,delta);
       }
    }
  PrintFormat("Total error: %f",total_error);
//--- OpenCL オブジェクトを削除する
//--- OpenCL バッファを解放する
  CLBufferFree(cl_mem);
//--- OpenCL カーネルを解放する
  CLKernelFree(cl_krn);
//--- OpenCL プログラムを解放する
  CLProgramFree(cl_prg);
//--- OpenCL コンテキストを解放する
  CLContextFree(cl_ctx);
//---
  return(0);
 }