【GPU】基于VS2012 的NVIDA OpenCL安装与配置
本博客涉及图像处理任务的加速问题,使用通用图像处理单元GPGPUs(General Purpose Graphics Processing Units),或简而言之,带并行处理的GPU,GPU本质上是一个专门为图形处理或浮点运算而设计的协处理器,目标是改善诸如视频游戏和交互三维图形之类的应用程序性能。当图形在GPU上执行时,CPU可以用来进行其他计算(如游戏中的人工智能部分)。
OPENCV库中包含了对OPENCL和CUDA GPU架构的支持,但是OPENCL得到更多设备的支持,甚至包含在一些NVIDIA图形卡中。
最近在学习OpenCL,想着搭建OpenCL的编码环境,自己编几个程序练习练习。要编程,那第一步就是要搭建编程环境了。
我的PC上安装过VS2012,配置好了OPENCV,这个节省了不少时间。使用OpenCL编程,不可避免地要使用到图像处理,OpenCV是最佳选择了。
1、 检测PC对OpenCL的支持情况
2008年,苹果公司向Khronos Group提交了一份关于跨平台计算框架的草案,该草案由苹果公司开发,并与AMD、IBM、Intel和NVIDIA公司合作逐步完善。这个跨平台计算框架就是OpenCL(Open Computing Language,开放计算语言)。2008年12月8日,OpenCL 1.0技术规范发布。2010年6月14日,OpenCL 1.1发布。2011年11月19日,OpenCL 1.2发布。2013年11月19日,OpenCL 2.0发布。
从OpenCL技术规范的发布历史看,2008年以前的PC一定是不支持OpenCL的。之后的芯片,也会因为年份不同、厂商不同,对OpenCL的版本支持不同。
怎么能准确地知道自己PC对OpenCL及OpenGL的支持情况呢?我们可以利用GPU-Z的工具来查看:它可以很详细地检测到你的PC的GPU情况,以及对OpenCL/OpenGL/CUDA/Vulkan的支持。这是我主机配置截图:
可以看到我的主机显卡是NVIDA GetForce GTX750,在最下面一栏Computing中显示支持OpenCL,CUDA。
2、OpenCL安装及环境配置
根据我的PC上GPU的型号,我下载NVIDIA的OpenCL驱动。在下面的网页上下载了cuda_8.0.61.exe:
https://developer.nvidia.com/cuda-downloads
安装时默认安装到了C盘(安装所占内存较大,可以安装在其他盘,安装在其他盘的话,也会在c盘生成如下路径C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v8.0,我们要配置的东西就在这里),具体目录为:
C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v8.0
测试CUDA安装成功与否
打开VS2015(VS2012),选择新建一个项目,可以看到,已安装模板下边多了一个NVIDIA选项,说明安装成功!
接下来,在VS2012中建立新工程,配置OpenCL的相关路径,对OpenCL安装是否成功做了检测。具体步骤如下:
首先,创建了Visual C++下的Win32控制台应用程序opencl_test。接着配置OpenCL的路径。在工程属性页的“VC++ 目录”下,配置它的“包含目录”和“库目录”。
(1)“包含目录”中选择路径:
C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v8.0\include
(2)“库目录”中选择路径:
C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v8.0\lib\Win32
需要注意的是,因为我创建的是Win32控制台应用程序,必须选择lib下的Win32目录,而不能选择x64目录。
(3)接下来对“链接器”的“输入”页面进行配置。在它的“附加依赖项”中添加库OpenCL.lib即可3、经过以上步骤,OpenCL编译环境就已经配置好了,可以把属性页“OpenCL.props”保存起来,下次直接这个属性页就可以了,不用每次都重复配置。以下是测试程序:
- #include <stdio.h>
- #include <stdlib.h>
- #include <iostream>
- #include <CL/cl.h>
- int main()
- {
- //cl_platform 表示一个OpenCL的执行平台,关联到GPU硬件,如N卡,AMD卡
- cl_platform_id *platforms;
- //OpenCL中定义的跨平台的usigned int和int类型
- cl_uint num_platforms;
- cl_int i, err, platform_index = -1;
- char* ext_data;
- size_t ext_size;
- const char icd_ext[] = "cl_khr_icd";
- //要使platform工作,需要两个步骤。1 需要为cl_platform_id结构分配内存空间。2 需要调用clGetPlatformIDs初始化这些数据结构。一般还需要步骤0:询问主机上有多少platforms
- //查询计算机上有多少个支持OpenCL的设备
- err = clGetPlatformIDs(5, NULL, &num_platforms);
- if (err < 0)
- {
- perror("Couldn't find any platforms.");
- exit(1);
- }
- printf("本机上支持OpenCL的环境数量: %d\n", num_platforms);
- //为platforms分配空间
- platforms = (cl_platform_id*)
- malloc(sizeof(cl_platform_id) * num_platforms);
- clGetPlatformIDs(num_platforms, platforms, NULL);
- //获取GPU平台的详细信息
- for (i = 0; i < num_platforms; i++)
- {
- //获取缓存大小
- err = clGetPlatformInfo(platforms[i],
- CL_PLATFORM_EXTENSIONS, 0, NULL, &ext_size);
- if (err < 0)
- {
- perror("Couldn't read extension data.");
- exit(1);
- }
- printf("缓存大小: %d\n", ext_size);
- ext_data = (char*)malloc(ext_size);
- //获取支持的扩展功能
- clGetPlatformInfo(platforms[i], CL_PLATFORM_EXTENSIONS,
- ext_size, ext_data, NULL);
- printf("平台 %d 支持的扩展功能: %s\n", i, ext_data);
- //获取显卡的名称
- char *name = (char*)malloc(ext_size);
- clGetPlatformInfo(platforms[i], CL_PLATFORM_NAME,
- ext_size, name, NULL);
- printf("平台 %d 是: %s\n", i, name);
- //获取显卡的生产商名称
- char *vendor = (char*)malloc(ext_size);
- clGetPlatformInfo(platforms[i], CL_PLATFORM_VENDOR,
- ext_size, vendor, NULL);
- printf("平台 %d 的生产商是: %s\n", i, vendor);
- //获取平台版本
- char *version = (char*)malloc(ext_size);
- clGetPlatformInfo(platforms[i], CL_PLATFORM_VERSION,
- ext_size, version, NULL);
- printf("平台 %d 的版本信息: %s\n", i, version);
- //查询显卡是独立的还是嵌入的
- char *profile = (char*)malloc(ext_size);
- clGetPlatformInfo(platforms[i], CL_PLATFORM_PROFILE,
- ext_size, profile, NULL);
- printf("平台 %d 是独立的(full profile)还是嵌入式的(embeded profile)?: %s\n", i, profile);
- //查询是否支持ICD扩展
- if (strstr(ext_data, icd_ext) != NULL)
- platform_index = i;
- std::cout << "平台ID = " << platform_index << std::endl;
- /* Display whether ICD extension is supported */
- if (platform_index > -1)
- printf("平台 %d 支持ICD扩展: %s\n",
- platform_index, icd_ext);
- std::cout << std::endl;
- //释放空间
- free(ext_data);
- free(name);
- free(vendor);
- free(version);
- free(profile);
- }
- if (platform_index <= -1)
- printf("No platforms support the %s extension.\n", icd_ext);
- getchar();
- //释放资源
- free(platforms);
- return 0;
- }
在本机上执行输出: