と言うわけで、OpenCLのカーネルプログラムの引数に値を渡して、その結果を返してもらうサンプルを作った。
カーネル側の*var1,*var2にintの値を与え、*retへ結果を格納。
・clCreateBufferでデバイスにメモリ確保、
・clEnqueueWriteBufferで確保したメモリへ値を代入
・clSetKernelArgでカーネルプログラムの引数に確保したメモリのアドレスを指定
・clEnqueueReadBufferでデバイス上のメモリから値を取得
・clReleaseMemObjectでデバイスのメモリを解放
と言ったところだろうか。
http://www.fixstars.com/ja/news/books/opencl/
↑この本を参考に書いたが、これ、関数のインタフェースに関してはもちろん事典として記載はあるのだが、具体的にどう使うのかは実例を見て解読するしかないという所が多いように思う。clEnqueueWriteBufferとか、なんとかググらずに済んだが不親切だ。
#pragma warning(disable : 4996 ) #include <windows.h> #include <CL/cl.h> #include <string.h> #include <stdlib.h> #include <iostream> #pragma comment(lib,"OpenCL.lib") #define MAX_SOURCE_SIZE 0x100000 int cl_inout(){ cl_device_id device_id = NULL; cl_context context = NULL; cl_command_queue command_queue = NULL; cl_program program = NULL; cl_kernel kernel = NULL; cl_platform_id platform_id = NULL; cl_uint ret_num_devices; cl_uint ret_num_platforms; cl_int ret; char *source_str; size_t source_size; source_str = (char*)malloc(MAX_SOURCE_SIZE); strcpy(source_str, "__kernel void hello(" " __global int* var1," " __global int* var2," " __global int* ret" ")\n" "{\n" " *ret = *var1 + *var2;\n" "}\n" ); source_size = strlen(source_str); /* プラットフォーム・デバイスの情報の取得 */ ret = clGetPlatformIDs(1, &platform_id, &ret_num_platforms); ret = clGetDeviceIDs(platform_id, CL_DEVICE_TYPE_DEFAULT, 1, &device_id, &ret_num_devices); /* OpenCLコンテキストの作成 */ context = clCreateContext(NULL, 1, &device_id, NULL, NULL, &ret); /* コマンドキューの作成 */ command_queue = clCreateCommandQueue(context, device_id, 0, &ret); /* メモリバッファの作成 引数として使用 */ cl_mem arg1_X = NULL; cl_mem arg2_Y = NULL; cl_mem arg3_R = NULL; arg1_X = clCreateBuffer(context, CL_MEM_READ_WRITE, sizeof(int), NULL, &ret); arg2_Y = clCreateBuffer(context, CL_MEM_READ_WRITE, sizeof(int), NULL, &ret); arg3_R = clCreateBuffer(context, CL_MEM_READ_WRITE, sizeof(int), NULL, &ret); /* 読み込んだソースからカーネルプログラムを作成 */ program = clCreateProgramWithSource(context, 1, (const char **)&source_str, (const size_t *)&source_size, &ret); /* カーネルプログラムをビルド */ ret = clBuildProgram(program, 1, &device_id, NULL, NULL, NULL); /* OpenCL カーネルの作成 */ kernel = clCreateKernel(program, "hello", &ret); /* カーネルプログラムの引数に値を設定 */ int val1 = 20, val2 = 50; clEnqueueWriteBuffer(command_queue, arg1_X, CL_TRUE, 0, sizeof(int), &val1, 0, nullptr, nullptr); clEnqueueWriteBuffer(command_queue, arg2_Y, CL_TRUE, 0, sizeof(int), &val2, 0, nullptr, nullptr); /* OpenCLカーネル引数の設定 */ ret = clSetKernelArg(kernel, 0, sizeof(cl_mem), (void *)&arg1_X); ret = clSetKernelArg(kernel, 1, sizeof(cl_mem), (void *)&arg2_Y); ret = clSetKernelArg(kernel, 2, sizeof(cl_mem), (void *)&arg3_R); /* OpenCL カーネルを実行 */ ret = clEnqueueTask(command_queue, kernel, 0, NULL, NULL); /* メモリバッファから結果を取得 */ int ret_val; ret = clEnqueueReadBuffer(command_queue, arg3_R, CL_TRUE, 0, sizeof(int), &ret_val, 0, NULL, NULL); /* 終了処理 */ ret = clFlush(command_queue); ret = clFinish(command_queue); ret = clReleaseKernel(kernel); ret = clReleaseProgram(program); ret = clReleaseMemObject(arg1_X); ret = clReleaseMemObject(arg2_Y); ret = clReleaseMemObject(arg3_R); ret = clReleaseCommandQueue(command_queue); ret = clReleaseContext(context); free(source_str); /* 結果の表示 */ std::cout << ret_val; int k; std::cin >> k; return 0; }