「OpenCLのC++ Bindingsを使ってみる - その1」、「OpenCLのC++ Bindingsを使ってみる - その2」、「OpenCLのC++ Bindingsを使ってみる - その3」に引き続き、今回はOpenCLのC++ Bindingsを使って、メモリオブジェクトの生成とメモリオブジェクトをカーネルにセットすることにする。これまでと同様に前回までのコードに追記していく。
#define __CL_ENABLE_EXCEPTIONS #if defined(__APPLE__) || defined(__MACOSX) #include <OpenCL/cl.hpp> #else #include <CL/cl.hpp> #endif #include <iostream> const int nElements = 9000000; float input1[nElements]; float input2[nElements]; float output[nElements]; int main(int argc, char* argv[]) { cl_int error = CL_SUCCESS; try{ std::vector platforms; cl::Platform::get(&platforms); if(platforms.size() == 0){ std::cout << "Any Platforms is NOT FOUNT." << std::endl; return 1; } cl_context_properties properties[] = {CL_CONTEXT_PLATFORM, (cl_context_properties)(platforms[0])(), 0}; cl::Context context(CL_DEVICE_TYPE_GPU, properties); std::vector devices = context.getInfo(); char* addVector = { "__kernel void\n\ addVector(__global const float *input1,\n\ __global const float *input2,\n\ __global float *output)\n\ {\n\ int index = get_global_id(0);\n\ output[index] = sin(input1[index]) * sin(input2[index]);\n\ output[index] = cos(output[index]);\n\ output[index] = pow(output[index], output[index]);\n\ }\n"}; cl::Program::Sources source(1,std::make_pair(addVector, strlen(addVector))); cl::Program program = cl::Program(context, source); program.build(devices); cl::Kernel kernel(program, "addVector", &error); for(int i = 0; i< nElements; i++){ input1[i] = (float)i * 10.0f; input2[i] = (float)i / 20.0f; output[i] = 0.0f; } cl::Buffer memInput1 = cl::Buffer(context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, sizeof(cl_float) * nElements, input1, &error); cl::Buffer memInput2 = cl::Buffer(context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, sizeof(cl_float) * nElements, input2, &error); cl::Buffer memOutput = cl::Buffer(context, CL_MEM_WRITE_ONLY, sizeof(cl_float) * nElements, NULL, &error); kernel.setArg(0, memInput1); kernel.setArg(1, memInput2); kernel.setArg(2, memOutput); }catch(cl::Error err){ std::cerr << "ERROR: " << err.what() << "(" << err.err() << ")" << std::endl; } return 0; }
太字に下部分が今回追加したコードになる。
まず、addVectorに渡す引数であるinput1, input2, outputを用意する。このあたりの初期値は「OpenCLで実際に計算してみる」で使用したものを流用した。
次に、用意した配列からメモリオブジェクトを生成する。
cl::Buffer memInput1 = cl::Buffer(context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, sizeof(cl_float) * nElements, input1, &error);
上記はinput1のメモリオブジェクトを生成している。コンテキストとメモリオブジェクトのフラグ、配列のサイズと配列のポインタ、エラーコード用変数からcl::Bufferのインスタンスを生成する。メモリオブジェクトのフラグはOpenCL 1.1 Specification [PDF]のTable 5.3に一覧が記載されている。この辺の引数はC++ Bindingsを使用しない場合と特に変わらない。
続いて、生成したメモリオブジェクトをカーネル引数にセットする。
kernel.setArg(0, memInput1);
セットする引数のインデックスと、メモリオブジェクトを指定する。たとえばinput1はaddVectorの第一引数なので、0をインデックスとする。
次回はコマンドキューの生成と、カーネルをキューに入れ実行してみようと思う。
3/19 : 2カ所修正
- 入力データをグローバルに移動 (Stack Overflowの可能性があるため)→安易
- output用のメモリオブジェクトのフラグをCL_MEM_WRITE_ONLYに変更、CL_MEM_READ_ONLYだと結果を書き込めない。
コメント