【VS2013】OpenCl环境搭建&helloworld

参考资料:

OpenCL编程的开发环境与API(视频)

OpenCL例程1-HelloWorld(博客)(源代码,部分修改)

OpenCL “速成”冲刺【第一天】(博客)

前面几步都比较简单,最后一步需要如下3小步:

1.项目属性->VC++目录->包含目录(include),C:\Program Files (x86)\AMD APP SDK\2.9\include。

2.项目属性->链接器->常规->附加库目录,C:\Program Files (x86)\AMD APP SDK\2.9\lib\x86。

3.项目属性->链接器->输入->附加依赖项,opencl.lib

(1设置include,错误则编译错;2、3设置lib,错误则调试运行报错:1error LNK2019: 无法解析的外部符号 _clGetPlatformIDs@12,SDK,lib目录下有32bit和64bit,选择不对也会报错


修改:

1."stdafx.h"无法包含

2._TCHAR找不到,#include <tchar.h>

3._tmain的return前加system("pause");//避免执行窗口完闪退

// 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;

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;
}


HelloWorld_Kernel.cl文件,在上面的源文件开头变量声明里有(28)const char*pFileName = "HelloWorld_Kernel.cl"; // cl文件名

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

运行结果:



阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/hermittt/article/details/50668850
个人分类: OpenCl
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭