C++でOpenCL(環境構築編)

# 目指すところ
OpenCLとは何かみたいな話は他のサイトに譲って、使いましょう。楽しいから。

# プログラム全文
[github](https://github.com/vl2hmmp/detect-line)からクローンできます。

# 環境構築
## この記事で作った環境
Visual Studioがちょっと古いですが、ビルド設定はそんなに差はないと思います。
・Windows 10
・Visual Studio 2015
・Intel SDK for OpenCL 7.0.0.2519

## OpenCL SDKの入手
OpenCLは[Khronos Group](https://www.khronos.org/)が仕様を策定して、各ベンダーが仕様に基づいた実装を行っています。そのため、所有する機器のベンダーからOpenCLのSDKを入手する必要があります。

インテル製CPU/GPUの場合、[Intel® SDK for OpenCL™ Applications](https://software.intel.com/en-us/intel-opencl)からIntel向けOpenCL SDKを入手します。SDKの入手にはメールアドレスを入力してデベロッパーに登録したりする必要があり、ちょっと面倒かも。
インストールはインストーラに言われるがままにやるだけなので割愛です。

## ビルド設定(Visual Studio)
インストールが完了したらVisual Studioを起動して、とりあえず新規プロジェクトを作りましょう。困ったときのwin32コンソールアプリケーションを選択、面倒なので空のプロジェクトにして作ります。
プロジェクトを作ったら、ビルド設定を変更してOpenCLを利用できるようにします。
まずは[VC++ ディレクトリ]の中の[インクルード ディレクトリ]にincludeフォルダを指定します。IntelSDKを何も考えずに突っ込んだ場合はC:\Intel\OpenCL\sdk\includeというパスになりました。
このとき、includeの中にあるCLというフォルダにパスを通さないように気を付けます。*CLの中に通してしまうと、大事なものがいろいろ見つからなくなります*
![image.png](https://qiita-image-store.s3.amazonaws.com/0/124881/54d9fc7a-fdfd-b162-7501-cf8affec5bbc.png)

続いて、[リンカー]→[全般]の中の[追加のライブラリ ディレクトリ]にlibフォルダを指定します。libフォルダの中にはx64向けとx86向けのそれぞれのフォルダがあるので、必要な方にパスを通してください。今回はC:\Intel\OpenCL\sdk\lib\x86にパスを通しました。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/124881/45164edc-e6eb-54d8-924c-bd6034fe7013.png)

最後に、[リンカー]→[入力]の中の[追加の依存ファイル]にOpenCL.libを指定します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/124881/7cede6f6-7089-7b25-fd9c-eace9f3add28.png)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/124881/5f49b2b8-038d-e1ab-917d-25ddad6b9387.png)

# プラットフォームとデバイスを調べる
Congratulations!これで楽しいOpenCLライフが満喫できます！！いいえ、まだです！！
OpenCLを実際に使うときには、OpenCLに対応したデバイスのうちどれを使うのか、インデックスを用いて指定する必要があります。そこで、自分の機器にどんなOpenCLデバイスがあるのか調べてみましょう。ソースファイルにmain.cを追加して、以下のプログラムを書いて実行してみましょう。

```c
#include <stdio.h>
#include <CL/cl.h>

int main(int argc, char **argv)
{

	// プラットフォーム取得
	cl_uint platformNumber = 0;
	cl_platform_id platformIds[8];
	clGetPlatformIDs(8, platformIds, &platformNumber);

	char string[256];
	cl_device_type type;
	cl_uint value;
	size_t sizes[3];
	cl_ulong ulvalue;
	for (int i = 0; i < platformNumber; i++)
	{
		printf("platform idx : %d\n", i);
		cl_platform_id platform = platformIds[i];
		clGetPlatformInfo(platform, CL_PLATFORM_VENDOR, 256, string, NULL);
		printf("platform vendor : %s\n", string);
		clGetPlatformInfo(platform, CL_PLATFORM_NAME, 256, string, NULL);
		printf("platform name : %s\n", string);
		clGetPlatformInfo(platform, CL_PLATFORM_VERSION, 256, string, NULL);
		printf("platform version : %s\n", string);

		// デバイス取得
		cl_uint deviceNumber = 0;
		cl_device_id deviceIds[8];
		clGetDeviceIDs(platform, CL_DEVICE_TYPE_ALL, 8, deviceIds, &deviceNumber);
		for (int j = 0; j < deviceNumber; j++)
		{
			printf("	device idx : %d\n", j);
			cl_device_id device = deviceIds[j];
			clGetDeviceInfo(device, CL_DEVICE_NAME, 256, string, NULL);
			printf("	device name : %s\n", string);
			clGetDeviceInfo(device, CL_DEVICE_TYPE, sizeof(cl_device_type), &type, NULL);
			if (type == CL_DEVICE_TYPE_CPU) printf("	device type : CPU\n");
			if (type == CL_DEVICE_TYPE_GPU) printf("	device type : GPU\n");
			if (type == CL_DEVICE_TYPE_ACCELERATOR) printf("	device type : ACCELERATOR\n");
			clGetDeviceInfo(device, CL_DEVICE_MAX_COMPUTE_UNITS, sizeof(cl_uint), &value, NULL);
			printf("	device max compute units : %d\n", value);
			clGetDeviceInfo(device, CL_DEVICE_MAX_WORK_ITEM_SIZES, sizeof(size_t) * 3, sizes, NULL);
			printf("	device max work item sizes : [%d][%d][%d]\n", sizes[0], sizes[1], sizes[2]);
			clGetDeviceInfo(device, CL_DEVICE_MAX_WORK_GROUP_SIZE, sizeof(cl_uint), &value, NULL);
			printf("	device max work group size : %d\n", value);
			clGetDeviceInfo(device, CL_DEVICE_MAX_MEM_ALLOC_SIZE, sizeof(cl_ulong), &ulvalue, NULL);
			printf("	device max mem alloc size : %d\n", ulvalue);
			clGetDeviceInfo(device, CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE, sizeof(cl_ulong), &ulvalue, NULL);
			printf("	device max constant buffer size : %d\n", ulvalue);
		}
	}

}
```

実行してみると、私の環境では以下のように表示されました。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/124881/5732585c-3438-2de0-704f-a3371a9eba61.png)
この表示を見ながらどの機器を使用するのか検討して、使用する機器のplatform idxとdevice idxを用いてOpenCL環境を初期化します。

# 続く
次は実際に簡単なカーネルプログラムを作って、OpenCLの基本的な使い方を知る[C++でOpenCL(使ってみよう編)](https://qiita.com/Kiribayashi_Hayate/items/acf04e5fbbc6dabde1bc)をやります。