OpenCL
OpenCL を用いたGPUおよびCPUでの並列計算。

■ 1. LUX.GPU.OpenCL ライブラリ
TOpenCL:TCLSystem のシングルトン
┃
TCLSystem:システム
┗TCLPlatfos:プラットフォームリスト
┗TCLPlatfo:プラットフォーム
┣TCLExtenss:拡張機能リスト
┣TCLDevices:デバイスリスト
┃ ┗TCLDevice:デバイス
┗TCLContexs:コンテキストリスト
┗TCLContex:コンテキスト
┣TCLQueuers:コマンドキューリスト
┃ ┗TCLQueuer:コマンドキュー
┣TCLArgumes:実引数リスト
┃ ┣TCLBuffer:バッファー
┃ ┣TCLImager:イメージ
┃ ┗TCLSamplr:サンプラー
┣TCLLibrars:ライブラリリスト
┃ ┗TCLLibrar:ライブラリ
┗TCLExecuts:実行プログラムリスト
┗TCLExecut:実行プログラム
┣TCLBuildrs:ビルドリスト
┃ ┗TCLBuildr:ビルド
┗TCLKernels:カーネルリスト
┗TCLKernel:カーネル
┗TCLParames:仮引数リスト
┗TCLParame:仮引数
■ 2. ライブラリの利用方法
TOpenCLクラスは、TCLSystemクラスのシングルトンです。
TCLSystemクラスは、実行マシンにおけるすべての計算用デバイスを自動的に検出します。
⬤ 2.1. プラットフォーム
“プラットフォーム”オブジェクト (TCLPlatfo) は、各デバイスベンダーが定義する環境を表します。
TCLSystemクラスは、すべてのプラットフォームを自動的に検出し、Platfos[]プロパティに列挙されます。
Object PascalTOpenCL.Platfos.Count :Integer // 全プラットフォームの数 TOpenCL.Platfos[*] :TCLPlatfo // 全プラットフォームの配列
特定のプラットフォームに関する情報は、TCLPlatfoクラスのプロパティから取得できます。
Object Pascal_Platfo := TOpenCL.Platfos[0]; // 特定プラットフォームの選択 _Platfo.Handle :T_cl_platform_id // ポインタ _Platfo.Profile :String // プロファイル _Platfo.Version :String // バージョン _Platfo.Name :String // 名前 _Platfo.Vendor :String // ベンダー名 _Platfo.Extenss.Count :Integer // 拡張機能の数 _Platfo.Extenss[*] :String // 拡張機能の配列
⬤ 2.2. デバイス
デバイスオブジェクト (TCLDevice) は、物理的なGPUやCPUを表します。
TCLPlatfoクラスは、特定のプラットフォーム内のすべてのデバイスを自動的に検出し、Devices[]プロパティに列挙されます。
Object Pascal_Platfo.Devices.Count :Integer // デバイスの数 _Platfo.Devices[*] :TCLDevice // デバイスの配列
特定のデバイスに関する情報は、TCLDeviceクラスのプロパティから取得できます。
Object Pascal_Device := _Platfo.Devices[0]; // 特定デバイスの選択 _Device.Handle :T_cl_device_id // ポインタ _Device.DEVICE_TYPE :T_cl_device_type // タイプ _Device.DEVICE_VENDOR_ID :T_cl_uint // ベンダーID _Device.DEVICE_NAME :String // 名前 _Device.DEVICE_VENDOR :String // ベンダー _Device.DRIVER_VERSION :String // ドライバのバージョン _Device.DEVICE_PROFILE :String // プロファイル _Device.DEVICE_VERSION :String // バージョン
⬤ 2.3. コンテキスト
“コンテキスト” (TCLContex) は、関連するデータやプログラムを管理および保持します。
TCLContexクラスは、TCLPlatfoクラスを引数として生成できます。
Object Pascal_Contex := TCLContex.Create( _Platfo );
生成されたTCLContexクラスは、TCLPlatfoクラスのContexs[]プロパティへ登録されます。
Object Pascal_Platfo.Contexs.Count :Integer // コンテキストの数 _Platfo.Contexs[*] :TCLContex // コンテキストの配列
⬤ 2.4. コマンドキュー
“コマンドキュー”オブジェクト (TCLQueuer) は、デバイスに送られる命令を管理します。
つまり、コンテキストとデバイス間での命令のやり取りを管理します。
TCLQueuerクラスは、TCLContexクラスとTCLDeviceクラスを引数として生成できます。
Object Pascal_Queuer := TCLQueuer.Create( _Contex, _Device ); {or} _Queuer := _Contex.Queuers[ _Device ];
生成されたTCLQueuerクラスは、TCLContexクラスのQueuers[]プロパティへ登録されます。
Object Pascal_Contex.Queuers.Count :Integer // コマンドキューの数 _Contex.Queuers[*] :TCLQueuer // コマンドキューの配列
なお、異なるプラットフォームのコンテキストとデバイスを接続するコマンドキューは生成できません。
Object PascalP0 := TOpenCL.Platfos[0]; P1 := TOpenCL.Platfos[1]; P2 := TOpenCL.Platfos[2]; D00 := P0.Devices[0]; D01 := P0.Devices[1]; D02 := P0.Devices[2]; D10 := P1.Devices[0]; D20 := P2.Devices[0]; C0 := TCLContex.Create( P0 ); C1 := TCLContex.Create( P1 ); C2 := TCLContex.Create( P2 ); Q00 := TCLQueuer.Create( C0, D00 ); // OK Q01 := TCLQueuer.Create( C0, D01 ); // OK Q02 := TCLQueuer.Create( C0, D02 ); // OK Q10 := TCLQueuer.Create( C1, D00 ); // エラー Q11 := TCLQueuer.Create( C1, D01 ); // エラー Q12 := TCLQueuer.Create( C1, D02 ); // エラー Q20 := TCLQueuer.Create( C2, D00 ); // エラー Q21 := TCLQueuer.Create( C2, D10 ); // エラー Q22 := TCLQueuer.Create( C2, D20 ); // OK
⬤ 2.5. 実引数
▼ 2.5.1. メモリー
“メモリー”オブジェクト (TCLMemory) は、さまざまなデータを保存し、デバイスと共有します。
TCLMemoryクラスは、TCLContexクラスとTCLQueuerクラスを引数として生成できます。
TCLMemoryクラスは抽象クラスであり、TCLBufferクラスとTCLImagerクラスを派生させます。
▽ 2.5.1.1. バッファー
TCLBufferクラスは、任意の“単純型”や“レコード型”の配列を格納します。
デバイスへ以下のような構造体型の配列を送りたい場合、
OpenCL Ctypedef struct { int A; double B; } TItem; kernel void Main( global TItem* Buffer ) { ・・・ }
以下のようにTCLBufferクラスを生成します。
Object PascalTItem = record A :Integer; B :Double; end; _Buffer := TCLBuffer<TItem>.Create( _Contex, _Queuer );
配列データは、Data[]プロパティを通して読み書きします。
ホストとデバイスの同期のため、配列データを使用する前に“マップ”し、終了後に“アンマップ”する必要があります。
Object Pascal_Buffer.Count := 3; // 要素数の設定 _Buffer.Data.Map; // メモリ領域を展開 _Buffer.Data[0] := TItem.Create( 1, 2.34 ); // 書き込み _Buffer.Data[1] := TItem.Create( 5, 6.78 ); // 書き込み _Buffer.Data[2] := TItem.Create( 9, 0.12 ); // 書き込み _Buffer.Data.Unmap; // メモリ領域を同期
▽ 2.5.1.2. イメージ
“イメージ”オブジェクト (TCLImager) は、1D~3Dにおけるピクセル配列を格納します。
3Dのボクセルデータもイメージの一種と見なされます。
TCLImagerクラスは抽象クラスであり、カラーチャンネルのレイアウトやビット数に応じて、様々なクラスが派生します。
TCLImager
┣TCLImager1D
┃ ┣TCLImager1DxBGRAxUInt8
┃ ┣TCLImager1DxBGRAxUFix8
┃ ┣TCLImager1DxRGBAxUInt32
┃ ┗TCLImager1DxRGBAxSFlo32
┣TCLImager2D
┃ ┣TCLImager2DxBGRAxUInt8
┃ ┣TCLImager2DxBGRAxUFix8
┃ ┣TCLImager2DxRGBAxUInt32
┃ ┗TCLImager2DxRGBAxSFlo32
┗TCLImager3D
┣TCLImager3DxBGRAxUInt8
┣TCLImager3DxBGRAxUFix8
┣TCLImager3DxRGBAxUInt32
┗TCLImager3DxRGBAxSFlo32
クラス名の1番目の部分は、画像の次元を表しています。
- TCLImager
1Dx*x*
- 次元:
1D- TCLImager
2Dx*x*
- 次元:
2D- TCLImager
3Dx*x*
- 次元:
3D
クラス名の2番目の部分は、カラーチャンネルの順番を表しています。
- TCLImager
*xBGRAx*
- カラーチャンネル順:
BGRA- TCLImager
*xRGBAx*
- カラーチャンネル順:
RGBA
クラス名の3番目の部分は、色のデータ型を表しています。
- TCLImager
*x*xUInt8
- デバイス側データ型:
uint8@ OpenCL C- ホスト側データ型:
UInt8 (Byte)@ Delphi- TCLImager
*x*xUFix8
- デバイス側データ型:
float@ OpenCL C- ホスト側データ型:
UInt8 (Byte)@ Delphi- TCLImager
*x*xUInt32
- デバイス側データ型:
uint@ OpenCL C- ホスト側データ型:
UInt32 (Cardinal)@ Delphi- TCLImager
*x*xSFlo32
- デバイス側データ型:
float@ OpenCL C- ホスト側データ型:
Single@ Delphi
X/Y/Z方向のピクセル数は、’CountX’/’Y’/’Z’ プロパティで設定できます。
Object Pascal_Imager := TCLDevIma3DxBGRAxUInt8.Create( _Contex, _Queuer ); _Imager.CountX := 100; // X方向ピクセル数 _Imager.CountY := 200; // Y方向ピクセル数 _Imager.CountZ := 300; // Z方向ピクセル数
▼ 2.5.2. サンプラー
サンプラーオブジェクト (TCLSamplr) は、ピクセル色を実数座標で得るための補間方法を定義します。
TCLSamplr クラスは、’TCLContex’クラスを引数として生成できます。
Object Pascal_Samplr := TCLSamplr.Create( _Contex );
⬤ 2.6. プログラム
“プログラム”オブジェクト (TCLProgra) は、ソースコードを読み込んで、実行可能なバイナリへビルドします。
TCLPrograクラスは、’TCLContex’クラスを引数として生成できます。
TCLPrograクラスは抽象クラスであり、ソースコードの種類に応じて、TCLLibrarクラスまたはTCLExecutクラスの基底クラスとして機能します。
▼ 2.6.1. ライブラリ
TCLLibrarクラスは、直接実行する関数を含まないプログラムです。
Object Pascal_Librar := TCLLibrar.Create( _Contex ); _Librar.Source.LoadFromFile( 'Librar.cl' ); // ソースコードのロード
▼ 2.6.2. エグゼキュータブル
TCLExecutクラスは、直接実行する関数(カーネル)を含んだプログラムです。
Object Pascal_Execut := TCLExecut.Create( _Contex ); _Execut.Source.LoadFromFile( 'Execut.cl' ); // ソースコードのロード
⬤ 2.7. ビルド
ビルド (TCLBuildr) はプログラムが行う“行為”ですが、このライブラリでは、ビルドはクラスとして明確に定義されています。
TCLBuildr クラスは、’TCLExecut’クラスと’TCLDevice’クラスを引数として生成できます。
Object Pascal_Buildr := TCLBuildr.Create( _Execut, _Device ); {or} _Buildr := _Execut.Buildrs[ _Device ]; {or} _Buildr := _Execut.BuildTo( _Device );
カーネルオブジェクト(2.8.章参照)は、実行時にTCLBuildrクラスを自動的に生成します。
しかし、カーネルの実行前にTCLBuildrクラスを作成することで、コンパイルとリンクのエラーを事前に確認することができます。
Object Pascal_Buildr.Handle; // ビルドの実行(ハンドルの生成) _Buildr.CompileStatus :T_cl_build_status // コンパイルのスタータス _Buildr.CompileLog :String // コンパイルのログ _Buildr.LinkStatus :T_cl_build_status // リンクのスタータス _Buildr.LinkLog :String // リンクのログ
⬤ 2.8. カーネル
カーネル”オブジェクト (TCLKernel) は、プログラム内の実行可能な関数を指します。
OpenCL Ckernel void Main( ・・・ ) { ・・・ }
TCLKernelクラスは、TCLExecutクラスとTCLQueuerクラスを引数にして生成できます。
Object Pascal_Kernel := TCLKernel.Create( _Execut, 'Main', _Queuer ); {or} _Kernel := _Execut.Kernels.Add( 'Main', _Queuer );
▼ 2.8.1. 仮引数
メモリオブジェクトは、TCLKernelクラスのParames[]プロパティを介して、ソースコード内の引数に関連付けられます。
Object Pascal_Kernel.Parames['Buffer'] := _Buffer; // バッファーの接続 _Kernel.Parames['Imager'] := _Imager; // イメージ の接続 _Kernel.Parames['Samplr'] := _Samplr; // サンプラーの接続
▼ 2.8.2. 反復回数
OpenCL のプログラムは、3重のループ構文のように繰り返し実行されます。
Object Pascal_Kernel.GloSizX := 100; // X方向のループ回数 _Kernel.GloSizY := 200; // Y方向のループ回数 _Kernel.GloSizZ := 300; // Z方向のループ回数
ループの最小および最大インデックスを指定することも可能です。
Object Pascal_Kernel.GloMinX := 0; // X方向の開始インデックス _Kernel.GloMinY := 0; // Y方向の開始インデックス _Kernel.GloMinZ := 0; // Z方向の開始インデックス _Kernel.GloMaxX := 100-1; // X方向の終了インデックス _Kernel.GloMaxY := 200-1; // Y方向の終了インデックス _Kernel.GloMaxZ := 300-1; // Z方向の終了インデックス
▼ 2.8.3. 実行
Object Pascal_Kernel.Run; // 実行
■ 3. 参考文献
⬤ 3.1. The Khronos Group Inc
⬤ 3.2. GitHub
- Delphi IDE @ Embarcadero
https://www.embarcadero.com/jp/products/delphi/starter