【OpenCL学习】在Visual Studios上永久配置OpenCL库环境(Intel)

要写并行的大作业,连VS都是头一次用的小白昨天花了一上午学习怎么配置OpenCL。_(:з」∠)_

可以说这篇教程是对新手蛮友好的~

(一)查看自己电脑的显卡配置支不支持OpenCL

我的电脑用的是intel的显卡,具体查看方式:桌面右键 → 英特尔显卡设置 → 选项与支持



(二)下载OpenCL

英特尔https://software.intel.com/en-us/intel-opencl/download

我这里下载安装完成后默认路径是C:\Intel\OpenCL


(三)配置OpenCL库环境

1. 打开Visual Studio2013 → 新建 → Win32控制台应用程序 → 命名opencl → 确定

2. 打开属性页

视图 → 其他窗口 → 属性管理器

在右侧的属性管理器窗口右键点击Microsoft.Cpp.Win32.user → 属性



3. 配置库文件

3.1 配置CL目录

将OpenCL的SDK的头文件包含到项目中:

C/C++ → 常规 → 附加包含目录 → 编辑 → 添加CL文件夹的目录

我的目录是C:\Intel\OpenCL\sdk\include





3.2 配置预处理器

C/C++ → 预处理器 → 预处理器定义 → 编辑 → 添加"_CRT_SECURE_NO_WARNINGS"

这是为了避免编译的时候对某些函数报错。



3.3 配置外部依赖OpenCL.lib目录

链接器 → 常规 → 附加库目录 → 编辑 → 添加OpenCL.lib所在的目录

这里需要注意的是,32位平台和64位平台的目录是不同的。

我这里的解决方案平台是Win32,目录是C:\Intel\OpenCL\sdk\lib\x86

如果是Win64,目录则是C:\Intel\OpenCL\sdk\lib\x64

同时将启用增量链接设置为否:

链接器 → 常规 → 启用增量链接 → 编辑 → 否



3.4 配置OpenCL.lib文件

链接器 → 输入 → 附加依赖项 → 编辑 → 添加“OpenCL.lib”



4. 保存

配置完成后,右键点击Microsoft.Cpp.Win32.user → 保存Microsoft.Cpp.Win32.user

保存成功之后,下次新建项目就不需要再配置OpenCL了。



(四)用OpenCL运行一个HelloWorld程序

1. 新建一个空项目:文件 → 新建 → 项目 → Visual C++ → 空项目



2. 新建两个文件:文件 → 新建 → 文件 → Visual C++ → C++ 文件(.cpp)

第一个是主函数文件(内容同附录1),存为.cpp格式

第二个是OpenCL核函数文件(内容同附录2),存为.cl格式

这里将主函数命名为源1.cpp,核函数命名为HelloWorld_Kernel.cl



3. 添加源文件

视图 → 解决方案资源管理器


在右侧的小窗口,

右键点击源文件 → 添加 → 现有项 → 源1.cpp

右键点击源文件 → 添加 → 现有项 HelloWorld_Kernel.cl



4. 编译运行

源1.cpp文件中点击“本地Windows调试器”编译运行。


5.运行结果



6.附录

附录1 源1.cpp

// OpenCl-1.cpp : Defines the entry point for the console application.
//
//#include "stdafx.h" 项目属性c/c++预编译头里本来就有
#include <tchar.h>
#include <CL/cl.h>
#include <iostream>
#include <fstream>
#include <stdio.h>
#include <stdlib.h>
#include <string>

using namespace std;

#pragma warning( disable : 4996 )//宏定义,避免报错。
                                 //因为在OpenCL2.0中clCreateCommandQueue()已经被弃用了 

cl_int ConvertToString(const char *pFileName, std::string &str);

int _tmain(int argc, _TCHAR* argv[])
{
	cl_int			iStatus = 0;				// 函数返回状态
	cl_uint			uiNumPlatforms = 0;				// 平台个数
	cl_platform_id	Platform = NULL;				// 选择的平台
	size_t			uiSize = 0;				// 平台版本名字字节数	
	cl_int			iErr = 0;				// 返回参数
	char			*pName = NULL;				// 平台版本名
	cl_uint			uiNumDevices = 0;				// 设备数量
	cl_device_id	*pDevices = NULL;				// 设备
	cl_context		Context = NULL;				// 设备环境
	cl_command_queue	CommandQueue = NULL;			// 命令队列
	const char		*pFileName = "HelloWorld_Kernel.cl";	// cl文件名
	string			strSource = "";				// 用于存储cl文件中的代码
	const char		*pSource;							// 代码字符串指针
	size_t			uiArrSourceSize[] = { 0 };			// 代码字符串长度
	cl_program		Program = NULL;				// 程序对象
	const char		*pInput = "gdkknvnqkc";		// 输入字符串
	size_t			uiStrlength = strlen(pInput);	// 输入字符串长度
	char			*pOutput = NULL;				// 输出字符串
	cl_mem			memInutBuffer = NULL;				// 输入内存对象
	cl_mem			memOutputBuffer = NULL;				// 输出内存对象
	cl_kernel		Kernel = NULL;				// 内核对象
	size_t			uiGlobal_Work_Size[1] = { 0 };		// 用于设定内核分布	


	//-------------------1. 获得并选择可用平台-----------------------------
	// 查询可用的平台个数,并返回状态
	iStatus = clGetPlatformIDs(0, NULL, &uiNumPlatforms);
	if (CL_SUCCESS != iStatus)
	{
		cout << "Error: Getting platforms error" << endl;
		return 0;
	}


	// 获得平台地址
	if (uiNumPlatforms > 0)  // 如果有可用平台
	{
		// 根据平台数为平台分配内存空间
		cl_platform_id *pPlatforms = (cl_platform_id *)malloc(uiNumPlatforms * sizeof(cl_platform_id));

		// 获得可用的平台
		iStatus = clGetPlatformIDs(uiNumPlatforms, pPlatforms, NULL);
		Platform = pPlatforms[0];	// 获得第一个平台的地址
		free(pPlatforms);			// 释放平台占用的内存空间
	}

	// 获得平台版本名
	// 获得平台版本名的字节数
	iErr = clGetPlatformInfo(Platform, CL_PLATFORM_VERSION, 0, NULL, &uiSize);

	// 根据字节数为平台版本名分配内存空间
	pName = (char *)alloca(uiSize * sizeof(char));

	// 获得平台版本名字
	iErr = clGetPlatformInfo(Platform, CL_PLATFORM_VERSION, uiSize, pName, NULL);
	cout << pName << endl;



	//--------------2. 查询GPU设备,并选择可用设备------------------------
	// 获得GPU设备数量
	iStatus = clGetDeviceIDs(Platform, CL_DEVICE_TYPE_GPU, 0, NULL, &uiNumDevices);
	if (0 == uiNumDevices)	// 如果没有GPU设备
	{
		cout << "No GPU device available." << endl;
		cout << "Choose CPU as default device." << endl;

		// 选择CPU作为设备,获得设备数
		iStatus = clGetDeviceIDs(Platform, CL_DEVICE_TYPE_CPU, 0, NULL, &uiNumDevices);

		// 为设备分配空间
		pDevices = (cl_device_id *)malloc(uiNumDevices * sizeof(cl_device_id));

		// 获得平台
		iStatus = clGetDeviceIDs(Platform, CL_DEVICE_TYPE_CPU, uiNumDevices, pDevices, NULL);
	}
	else
	{
		pDevices = (cl_device_id *)malloc(uiNumDevices * sizeof(cl_device_id));

		iStatus = clGetDeviceIDs(Platform, CL_DEVICE_TYPE_GPU, uiNumDevices, pDevices, NULL);
	}


	// -------------------3.创建设备环境---------------------------------
	// 创建设备环境
	Context = clCreateContext(NULL, 1, pDevices, NULL, NULL, NULL);
	if (NULL == Context)
	{
		cout << "Error: Can not create context" << endl;
		return 0;
	}

	// -------------------4.创建命令队列--------------------------------------
	// 创建第1个设备的命令队列
	CommandQueue = clCreateCommandQueue(Context, pDevices[0], 0, NULL);
	if (NULL == CommandQueue)
	{
		cout << "Error: Can not create CommandQueue" << endl;
		return 0;
	}


	// ----------------------5. 创建程序对象------------------------------
	// 将cl文件中的代码转为字符串
	iStatus = ConvertToString(pFileName, strSource);

	pSource = strSource.c_str();			// 获得strSource指针
	uiArrSourceSize[0] = strlen(pSource);	// 字符串大小

	// 创建程序对象
	Program = clCreateProgramWithSource(Context, 1, &pSource, uiArrSourceSize, NULL);
	if (NULL == Program)
	{
		cout << "Error: Can not create program" << endl;
		return 0;
	}


	// -----------------------------6. 编译程序--------------------------------
	// 编译程序
	iStatus = clBuildProgram(Program, 1, pDevices, NULL, NULL, NULL);
	if (CL_SUCCESS != iStatus)	// 编译错误
	{
		cout << "Error: Can not build program" << endl;
		char szBuildLog[16384];
		clGetProgramBuildInfo(Program, *pDevices, CL_PROGRAM_BUILD_LOG, sizeof(szBuildLog), szBuildLog, NULL);

		cout << "Error in Kernel: " << endl << szBuildLog;
		clReleaseProgram(Program);

		return 0;
	}

	//-------------------------7. 并创建输入输出内核内存对象--------------------------------

	// 创建输入内存对象
	memInutBuffer = clCreateBuffer(
		Context,
		CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR,  // 输入内存为只读,并可以从宿主机内存复制到设备内存
		(uiStrlength + 1) * sizeof(char),		  // 输入内存空间大小
		(void *)pInput,
		NULL);

	// 创建输出内存对象
	memOutputBuffer = clCreateBuffer(
		Context,
		CL_MEM_WRITE_ONLY,					// 输出内存只能写
		(uiStrlength + 1) * sizeof(char),	// 输出内存空间大小
		NULL,
		NULL);

	if ((NULL == memInutBuffer) || (NULL == memOutputBuffer))
	{
		cout << "Error creating memory objects" << endl;
		return 0;
	}

	//--------------------------8. 创建内核对象-------------------------------------
	Kernel = clCreateKernel(Program,
		"helloworld",  // cl文件中的入口函数
		NULL);
	if (NULL == Kernel)
	{
		cout << "Error: Can not create kernel" << endl;
		return 0;
	}



	//----------------------------9. 设置内核参数----------------------------------
	iStatus = clSetKernelArg(Kernel,
		0,		// 参数索引
		sizeof(cl_mem),
		(void *)&memInutBuffer);

	iStatus |= clSetKernelArg(Kernel, 1, sizeof(cl_mem), (void *)&memOutputBuffer);

	if (CL_SUCCESS != iStatus)
	{
		cout << "Error setting kernel arguments" << endl;
	}



	// --------------------------10.运行内核---------------------------------
	uiGlobal_Work_Size[0] = uiStrlength;  // 输入字符串大小

	// 利用命令队列使将再设备上执行的内核排队
	iStatus = clEnqueueNDRangeKernel(
		CommandQueue,
		Kernel,
		1,
		NULL,
		uiGlobal_Work_Size,  // 确定内核在设备上的多个处理单元间的分布
		NULL,				 // 确定内核在设备上的多个处理单元间的分布
		0,
		NULL,
		NULL);


	if (CL_SUCCESS != iStatus)
	{
		cout << "Error: Can not run kernel" << endl;
		return 0;
	}

	// ----------------------------11. 将输出读取到主机内存
	pOutput = (char *)malloc(uiStrlength + 1);  // uiStrlength 为 输入字符串长度

	iStatus = clEnqueueReadBuffer(
		CommandQueue,		// 命令队列
		memOutputBuffer,	// 输出内存对象
		CL_TRUE,			// 内核读取结束之前该函数不会返回
		0,
		uiStrlength * sizeof(char),
		pOutput,
		0,
		NULL,
		NULL);

	if (CL_SUCCESS != iStatus)
	{
		cout << "Error: Can not reading result buffer" << endl;
		return 0;
	}


	// ---------------------12--输出计算结果---------------
	pOutput[uiStrlength] = '\0';
	cout << "Input String:" << endl;
	cout << pInput << endl;
	cout << "Output String:" << endl;
	cout << pOutput << endl;


	// -------------------------------13. 释放资源--------------------------------
	iStatus = clReleaseKernel(Kernel);
	iStatus = clReleaseProgram(Program);
	iStatus = clReleaseMemObject(memInutBuffer);
	iStatus = clReleaseMemObject(memOutputBuffer);
	iStatus = clReleaseCommandQueue(CommandQueue);
	iStatus = clReleaseContext(Context);

	if (NULL != pOutput)
	{
		free(pOutput);
		pOutput = NULL;
	}

	if (NULL != pDevices)
	{
		free(pDevices);
		pDevices = NULL;
	}

	system("pause");//避免执行完闪退
	return 0;
}

// 将cl文件代码转为字符串
cl_int ConvertToString(const char *pFileName, std::string &Str)
{
	size_t		uiSize = 0;
	size_t		uiFileSize = 0;
	char		*pStr = NULL;
	std::fstream fFile(pFileName, (std::fstream::in | std::fstream::binary));


	if (fFile.is_open())
	{
		fFile.seekg(0, std::fstream::end);
		uiSize = uiFileSize = (size_t)fFile.tellg();  // 获得文件大小
		fFile.seekg(0, std::fstream::beg);
		pStr = new char[uiSize + 1];

		if (NULL == pStr)
		{
			fFile.close();
			return 0;
		}

		fFile.read(pStr, uiFileSize);				// 读取uiFileSize字节
		fFile.close();
		pStr[uiSize] = '\0';
		Str = pStr;

		delete[] pStr;

		return 0;
	}

	cout << "Error: Failed to open cl file\n:" << pFileName << endl;

	return -1;
}

附录2 HelloWorld_Kernel.cl

__kernel void helloworld(__global char *pIn, __global char *pOut)
{
	int iNum = get_global_id(0);
	pOut[iNum] = pIn[iNum] + 1;
}

  • 5
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值