OpenCLを使ったアプリケーションを作成する際には、とりあえずは何らかのSDKをインストールして使うというのが普通のようです。導入に関して検索してみるとだいたい下記の手順が紹介されていたりします。
- Intel SDK fo OpenCL
- NVIDIA OpenCL SDK
- Accelerated Parallel Processing (APP) SDK
しかし、これらのSDKをインストールすること無しに、OpenCLの機能を呼び出すことを目的としてしばらく記事を書いてみようと思います。
必要なもの
さすがに何も用意しないでできるわけでもないので、最低限ヘッダファイルを準備する必要があります。
クロノスのOpenCLのページ http://www.khronos.org/registry/cl/ から下記のヘッダファイルを入手します。
- opencl.h
- cl_platform.h
- cl.h
拡張機能のことも考えると下記のヘッダも同様に入手します。
- cl_ext.h
- cl_d3d10.h
- cl_d3d11.h
- cl_dx9_media_sharing.h
これらのヘッダファイルを、作業するC++プロジェクトのフォルダにおいて
“CL”というフォルダを作成して、その中にコピーしておきます。
+ testOpenCL + CL +- opencl.h +- cl_platform.h +- cl.h そして、インクルードディレクトリとして testOpenCLのフォルダを指定しておきます。
サンプルプログラム
早速サンプルプログラムを下記に示します。
ちょっと手間がかかりますが、これで実行できるOpenCLアプリの第1歩となります。
C++0x使ってしまっているので、下記のプログラムはVisualStudio2012以降でコンパイルしてください。
(for文のところを修正すれば、以前のバージョンでも問題ないとは思います)
#include#include #include "cl/CL.h" #include typedef cl_int (CL_API_CALL *PFNCLGETPLATFORMIDS)(cl_uint /* num_entries */, cl_platform_id * /* platforms */, cl_uint * /* num_platforms */); typedef cl_int (CL_API_CALL *PFNCLGETPLATFORMINFO)(cl_platform_id /* platform */, cl_platform_info /* param_name */, size_t /* param_value_size */, void * /* param_value */, size_t * /* param_value_size_ret */); /* Device APIs */ typedef cl_int (CL_API_CALL *PFNCLGETDEVICEIDS)(cl_platform_id /* platform */, cl_device_type /* device_type */, cl_uint /* num_entries */, cl_device_id * /* devices */, cl_uint * /* num_devices */); typedef cl_int (CL_API_CALL *PFNCLGETDEVICEINFO)(cl_device_id /* device */, cl_device_info /* param_name */, size_t /* param_value_size */, void * /* param_value */, size_t * /* param_value_size_ret */); PFNCLGETPLATFORMIDS _g_clGetPlatformIDs = NULL; PFNCLGETPLATFORMINFO _g_clGetPlatformInfo = NULL; PFNCLGETDEVICEIDS _g_clGetDeviceIDs = NULL; PFNCLGETDEVICEINFO _g_clGetDeviceInfo = NULL; int main() { HMODULE h = LoadLibraryA( "opencl.dll" ); _g_clGetPlatformIDs = (PFNCLGETPLATFORMIDS)GetProcAddress( h, "clGetPlatformIDs" ); _g_clGetPlatformInfo = (PFNCLGETPLATFORMINFO) GetProcAddress( h, "clGetPlatformInfo" ); _g_clGetDeviceIDs = (PFNCLGETDEVICEIDS)GetProcAddress( h, "clGetDeviceIDs" ); _g_clGetDeviceInfo = (PFNCLGETDEVICEINFO)GetProcAddress( h, "clGetDeviceInfo" ); // OpenCL情報の取得. cl_uint numPlatforms = 0; cl_int retCl = _g_clGetPlatformIDs( 0, NULL, &numPlatforms ); if( retCl != CL_SUCCESS ) { return -1; } std::vector clPlatforms( numPlatforms ); retCl = _g_clGetPlatformIDs( numPlatforms, &(clPlatforms[0]), NULL ); if( retCl != CL_SUCCESS ) { return -1; } for( auto pid : clPlatforms ) { cl_uint numDevices = 0; char buf[4096] = { 0 }; size_t bufSize = sizeof(buf); retCl = _g_clGetPlatformInfo( pid, CL_PLATFORM_NAME, bufSize, buf, NULL ); if( retCl == CL_SUCCESS ) { printf( "PlatformName: %s\n", buf ); } retCl = _g_clGetDeviceIDs( pid, CL_DEVICE_TYPE_ALL, 0, NULL, &numDevices ); if( retCl != CL_SUCCESS ) { continue; } std::vector devices( numDevices ); retCl = _g_clGetDeviceIDs( pid, CL_DEVICE_TYPE_ALL, numDevices, &(devices[0]), NULL ); if( retCl != CL_SUCCESS ) { continue; } for( auto did : devices ) { bufSize = sizeof(buf); retCl = _g_clGetDeviceInfo( did, CL_DEVICE_NAME, bufSize, buf, NULL ); if( retCl == CL_SUCCESS ) { printf( " DeviceName: %s\n", buf ); } bufSize = sizeof(buf); retCl = _g_clGetDeviceInfo( did, CL_DEVICE_EXTENSIONS, bufSize, buf, NULL ); if( retCl == CL_SUCCESS ) { printf( " > DeviceExtensions: %s\n", buf ); } printf( "\n" ); } } FreeLibrary( h ); return 0; }
説明
コードを見ると一目瞭然なのですが、DLLから実際処理する関数を取り出しています。そして得られた関数アドレスに対して実行することでOpenCLとしての実行を行っています。
他のライブラリに依存せず、OpenGLの初期化を行う場合に非常に似ているため、OpenGLでそういったプログラムを組まれている人にとってはかなり自然なコードになっているのではないでしょうか。
実行結果
手元の環境で実行すると下記のようになりました。特にAPPのSDKはインストールしていませんが、AMDのグラフィックボードを使っているためドライバによって導入されているようです。そのため並列実行の処理デバイスとしてはAPPがOpenCLによって選択されているという感じのようです。また意外なことにCPUも処理対象として候補となっているようです。
PlatformName: AMD Accelerated Parallel Processing DeviceName: Barts > DeviceExtensions: cl_khr_global_int32_base_atomics cl_khr_global_int32_exten ded_atomics cl_khr_local_int32_base_atomics cl_khr_local_int32_extended_atomics cl_khr_3d_image_writes cl_khr_byte_addressable_store cl_khr_gl_sharing cl_ext_at omic_counters_32 cl_amd_device_attribute_query cl_amd_vec3 cl_amd_printf cl_amd_ media_ops cl_amd_media_ops2 cl_amd_popcnt cl_khr_d3d10_sharing DeviceName: Intel(R) Core(TM) i7 CPU 870 @ 2.93GHz > DeviceExtensions: cl_khr_fp64 cl_amd_fp64 cl_khr_global_int32_base_atomics c l_khr_global_int32_extended_atomics cl_khr_local_int32_base_atomics cl_khr_local _int32_extended_atomics cl_khr_3d_image_writes cl_khr_byte_addressable_store cl_ khr_gl_sharing cl_ext_device_fission cl_amd_device_attribute_query cl_amd_vec3 c l_amd_printf cl_amd_media_ops cl_amd_media_ops2 cl_amd_popcnt cl_khr_d3d10_shari ng
次回は演算も含めたサンプルを作ってみる予定です。