win7 64位下VS2012搭建OpenCL开发环境(Intel显卡)[win8.1下VS2013亲测同样可行]

  1. 下载配置所需的所有文件(内含Intel OpenCL的SDK(Win7及Win8.1))
    点击获取 访问密码e085因网盘失效及版本过久,建议自行前往官网下载);

  2. 解压intel_sdk_for_ocl_applications_2013.64050.zip到本地,双击setup.exe开始安装(安装后可将整个文件夹删除),记住安装路径(可以自定义安装)。win8.1直接双击intel_sdk_for_ocl_applications_2014_x64_setup.msi进行安装;

  3. 打开VS2012->文件->Visual C++->Win32->Win32 控制台应用程序->输入工程名,选择工程存放路径->确定->下一步->完成,这样就成功新建一个VS控制台程序工程;
  4. 按照以下步骤配置工程,搭建OpenCL开发环境(主要是导入库文件和链入动态库);
      - 项目名->右键属性进入设置窗口。
      - C/C++ -> 常规 -> 选中附加包含目录 -> 点击右测下拉框 编辑 -> 通过(插入新行->选择文件夹)把安装目录下与bin同级目录的include文件夹的路径添加进去
      - 类似的,链接器->常规->附加库目录,把lib/x86目录也加进去(64位系统也选择x86文件夹)。链接器->输入->附加依赖项,输入OpenCL.lib(存放在lib/x86目录下)
      - 最后,就可以:应用->确定保存设置;
    此处还需要注意的是后面helloWorld程序调用到fopen函数,但编译时会产生vs2012 error c4996: This functionor variable may be unsafe对于这个错误,需要按照上述方式在C/C++ -> 预处理器->预处理器定义中加入_CRT_SECURE_NO_WARNINGS(其他选项之后处加入)。
  5. 拷贝以下内容,覆盖整个工程.cpp文件,保存后CTRL+F5编译运行,便可以查看到电脑中支持OpenCL的硬件nvidia或intel或AMD等信息。如果发生错误,请按照上述步骤检查,重新进行配置;

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    // 
    // 本程序是读取电脑中的支持OpenCL的硬件nvidia或intel或AMD等信息,然后显示在屏幕上
    #include "stdafx.h"
    #include <iostream>
    #include <CL/cl.h>
    using namespace std;

    //根据参数,判断设备类别。是CPU、GPU、ACCELERATOR或其他设备
    const char* GetDeviceType(cl_device_type it)
    {
    if (it == CL_DEVICE_TYPE_CPU)
    return "CPU";
    else if (it == CL_DEVICE_TYPE_GPU)
    return "GPU";
    else if (it == CL_DEVICE_TYPE_ACCELERATOR)
    return "ACCELERATOR";
    else
    return "DEFAULT";
    }

    int main()
    {
    char dname[512];
    cl_device_id devices[20];
    cl_platform_id* platform_id = NULL;
    cl_uint num_devices;
    cl_device_type int_type;
    cl_ulong long_entries;
    cl_uint num_platform;
    cl_int err;

    //查询系统上可用的计算平台,可以理解为初始化
    err = clGetPlatformIDs(0, NULL, &num_platform);

    if (err != CL_SUCCESS)
    {
    cout << "clGetPlatformIDs error" << endl;
    return 0;
    }

    cout << "PlatForm num:" << num_platform << endl;

    unsigned int st = 0;

    platform_id = new cl_platform_id[num_platform];

    err = clGetPlatformIDs(num_platform, platform_id, NULL);

    if (err != CL_SUCCESS)
    {
    cout << "clGetPlatformIDs error" << endl;
    return 0;
    }

    // 检查系统上可用平台
    for (st = 0; st<num_platform; st++)
    {
    cout << endl << "----------------------------------" << endl;
    cout << "Platform " << st + 1 << endl;

    //获取可用计算平台的名称
    clGetPlatformInfo(platform_id[st], CL_PLATFORM_NAME, 512, dname, NULL);
    cout << "CL_PLATFORM_NAME:" << dname << endl;

    //获取可用计算平台的版本号,即OpenCL的版本号
    clGetPlatformInfo(platform_id[st], CL_PLATFORM_VENDOR, 512, dname, NULL);
    cout << "CL_PLATFORM_VERSION:" << dname << endl;

    //获取可用计算平台的设备数目
    clGetDeviceIDs(platform_id[st], CL_DEVICE_TYPE_ALL, 20, devices, &num_devices);
    cout << "Device num:" << num_devices << endl << endl;

    unsigned int n = 0;

    //检测当前平台下所有设备的属性
    for (n = 0; n<num_devices; ++n)
    {
    cout << endl << "Device " << n + 1 << endl;
    //获取设备名称
    clGetDeviceInfo(devices[n], CL_DEVICE_NAME, 512, dname, NULL);
    cout << "Device :" << dname << endl;

    //获取设备类别
    clGetDeviceInfo(devices[n], CL_DEVICE_TYPE, sizeof(cl_device_type), &int_type, NULL);
    cout << "Device Type:" << GetDeviceType(int_type) << endl;

    //获取设备版本号
    clGetDeviceInfo(devices[n], CL_DRIVER_VERSION, 512, dname, NULL);
    cout << "Device version:" << dname << endl;

    //获取设备全局内存大小
    clGetDeviceInfo(devices[n], CL_DEVICE_GLOBAL_MEM_SIZE, sizeof(cl_ulong), &long_entries, NULL);
    cout << "Device global mem(MB):" << long_entries / 1024 / 1024 << endl;

    //获取设备CACHE内存大小
    clGetDeviceInfo(devices[n], CL_DEVICE_GLOBAL_MEM_CACHE_SIZE, sizeof(cl_ulong), &long_entries, NULL);
    cout << "Device global mem cache(KB):" << long_entries / 1024 << endl;

    //获取本地内存大小
    clGetDeviceInfo(devices[n], CL_DEVICE_LOCAL_MEM_SIZE, sizeof(cl_ulong), &long_entries, NULL);
    cout << "Device Locale mem(KB) :" << long_entries / 1024 << endl;

    //获取设备频率
    clGetDeviceInfo(devices[n], CL_DEVICE_MAX_CLOCK_FREQUENCY, sizeof(cl_ulong), &long_entries, NULL);
    cout << "Device Max clock(MHz) :" << long_entries << endl;

    //获取最大工作组数
    clGetDeviceInfo(devices[n], CL_DEVICE_MAX_WORK_GROUP_SIZE, sizeof(cl_ulong), &long_entries, NULL);
    cout << "Device Max Group size :" << long_entries << endl;

    //获取最大计算核心数
    clGetDeviceInfo(devices[n], CL_DEVICE_MAX_COMPUTE_UNITS, sizeof(cl_ulong), &long_entries, NULL);
    cout << "Device Max parallel cores:" << long_entries << endl;

    // 获取扩展信息
    cl_uint addr_data;
    clGetDeviceInfo(devices[n], CL_DEVICE_ADDRESS_BITS, sizeof(addr_data), &addr_data, NULL);

    char ext_data[4096];
    clGetDeviceInfo(devices[n], CL_DEVICE_EXTENSIONS, sizeof(ext_data), ext_data, NULL);

    printf("ADDRESS_WIDTH: %u\nEXTENSIONS: %s\n\n", addr_data, ext_data);
    }
    }

    return 0;
    }
  6. 以后新建OpenCL工程时,需要遵照步骤4进行设置;

  7. 新建工程,工程名为helloWorld ,并进行相应配置。拷贝以下内容,覆盖整个helloWorld.cpp文件,新建main.cl文件到工程目录下的/helloWorld下,内容如下,保存后CTRL+F5编译运行,即可看到Hello World!字样。
helloWorld.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
#include "stdafx.h"
#include "stdlib.h"
#include <CL/cl.h>

#pragma warning( disable : 4996 )

#define MEM_SIZE (128)
#define MAX_SOURCE_SIZE (0x100000)

/**
opencl编码流程(摘自opencl异构计算):
(1)初始化opencl 平台(调用两次clGetPlatformIDs函数)
第一次获取可用的平台数量,第二次获取一个可用的平台。
(2)选择设备(调用两次clGetDeviceIDs函数)
第一次获取可用的设备数量,第二次获取一个可用的设备。
(3)创建上下文(调用clCreateContext函数)
Context:环境上下文,一个Context包含几个device(单个Cpu或GPU),
一个Context就是这些device的一个联系纽带,
只有在一个Context上的那些Device才能彼此交流工作,
你的机器上可以同时存在很多Context。
你可以用一个CPU创建context,也可以用一个CPU和一个GPU创建一个。
(4)创建命令队列(调用clCreateCommandQueue函数)
(5)创建数据缓冲区(调用clCreateBuffer函数)
(6)将host数据写进设备缓冲区(调用clEnqueueWriteBuffer函数)
(7)创建程序对象(调用clCreateProgramWithSource函数)
并编译内核源码(调用clBuildProgram函数,
如果编译成功,则把编译代码存储在程序对象中)
(8)创建kernel(调用clCreateKernel函数)
(9)设置内核参数(调用clSetKernelArg函数)
(10)Configure the work-item structure(设置worksize)
//只在分组的时候用到,只调用全局id的时候不要设置
(11)内核入队执行(调用clEnqueueNDRangeKernel函数)
(12)取回计算结果。(调用clEnqueueReadBuffer函数) \
(13)Release OpenCL resources(至此结束整个运行过程)
*/
int main()
{
cl_device_id device_id = NULL;
cl_context context = NULL;
cl_command_queue command_queue = NULL;
cl_mem memobj = 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 string[MEM_SIZE];

FILE *fp;
char fileName[] = "main.ir";
char *source_str;
size_t source_size;

/* Load the source code containing the kernel*/
fp = fopen(fileName, "r");
if (!fp) {
fprintf(stderr, "Failed to load kernel.\n");
exit(1);
}
source_str = (char*)malloc(MAX_SOURCE_SIZE);
source_size = fread(source_str, 1, MAX_SOURCE_SIZE, fp);
fclose(fp);

/* Get Platform and Device Info 初始化opencl 平台(调用两次clGetPlatformIDs函数) */
ret = clGetPlatformIDs(1, &platform_id, &ret_num_platforms);
ret = clGetDeviceIDs(platform_id, CL_DEVICE_TYPE_GPU, 1, &device_id, &ret_num_devices);

/* Create OpenCL context 创建上下文(调用clCreateContext函数) */
context = clCreateContext(NULL, 1, &device_id, NULL, NULL, &ret);

/* Create Command Queue 创建命令队列(调用clCreateCommandQueue函数) */
command_queue = clCreateCommandQueue(context, device_id, 0, &ret);

/* Create Memory Buffer 创建数据缓冲区(调用clCreateBuffer函数) */
memobj = clCreateBuffer(context, CL_MEM_READ_WRITE, MEM_SIZE * sizeof(char), NULL, &ret);
/* Create Kernel Program from the source 创建程序对象(调用clCreateProgramWithSource函数) */
//program = clCreateProgramWithSource(context, 1, (const char **)&source_str, (const size_t *)&source_size, &ret);
cl_int binary_status;
program =
clCreateProgramWithBinary(context, 1, &device_id, (const size_t *)&source_size, (const unsigned char **)&source_str, &binary_status, &ret);

printf("binary_status = %d\n", binary_status);
printf("binary_status = %d\n", CL_INVALID_BINARY);
/* Build Kernel Program 编译内核源码(调用clBuildProgram函数,如果编译成功,则把编译代码存储在程序对象中) */
ret = clBuildProgram(program, 1, &device_id, NULL, NULL, NULL);
const int MAX_INFO_SIZE = (0x10000);
if (ret != CL_SUCCESS)
{
fprintf(stderr, "clBuild failed:%d\n", ret);
char info_buf[MAX_INFO_SIZE];
clGetProgramBuildInfo(program, device_id, CL_PROGRAM_BUILD_LOG, MAX_INFO_SIZE, info_buf, NULL);
//fprintf(stderr, "\n%s\n", info_buf);
exit(-1);
}
else{
char info_buf[MAX_INFO_SIZE];
clGetProgramBuildInfo(program, device_id, CL_PROGRAM_BUILD_LOG, MAX_INFO_SIZE, info_buf, NULL);
printf("Kernel Build Success\n%s\n", info_buf);
}

/* Create OpenCL Kernel 创建kernel(调用clCreateKernel函数) */
kernel = clCreateKernel(program, "hello", &ret);

/* Set OpenCL Kernel Parameters 设置内核参数(调用clSetKernelArg函数)*/
ret = clSetKernelArg(kernel, 0, sizeof(cl_mem), (void *)&memobj);

/* Execute OpenCL Kernel 内核入队执行(调用clEnqueueNDRangeKernel函数) */
ret = clEnqueueTask(command_queue, kernel, 0, NULL, NULL);

/* Copy results from the memory buffer 取回计算结果。Read the output buffer back to the host(调用clEnqueueReadBuffer函数) */
ret = clEnqueueReadBuffer(command_queue, memobj, CL_TRUE, 0, MEM_SIZE * sizeof(char), string, 0, NULL, NULL);

/* Display Result */
//puts(string);

/* Finalization */
ret = clFlush(command_queue);
ret = clFinish(command_queue);
ret = clReleaseKernel(kernel);
ret = clReleaseProgram(program);
ret = clReleaseMemObject(memobj);
ret = clReleaseCommandQueue(command_queue);
ret = clReleaseContext(context);

/* Release OpenCL resources(至此结束整个运行过程) */
free(source_str);

return 0;

}
main.cl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// kernel function

__kernel void hello(__global char* string)
{
string[0] = 'H';
string[1] = 'e';
string[2] = 'l';
string[3] = 'l';
string[4] = 'o';
string[5] = ',';
string[6] = ' ';
string[7] = 'T';
string[8] = 'a';
string[9] = 'r';
string[10] = 'a';
string[11] = 'n';
string[12] = 't';
string[13] = 'u';
string[14] = 'l';
string[15] = 'a';
string[16] = '!';
string[17] = '\0';
}

注意:

  • win8.1 下 VS2013 搭建 OpenCL 开发环境只需改变安装的 SDK 即可;
  • 此外还需要注意的是,由于该SDK使用的是OpenCL 2.0规范,某些函数在cl.h里被声明为弃用,需要在#include <CL/cl.h>包含头文件之后添加#pragma warning( disable : 4996)启用这些函数,这样才能继续使用OpenCL 1.2的函数)
文章目录