全网第一个c++版本的opencl编程详解(gpu编程)

本文主要讲解opencl在windows下,使用cpp编程的基本过程,使用的IDE是Visual Studio 2017。

下面的代码连在一起就可以运行

step1:新建工程,导入头文件

在VS上新建一个工程,然后配置相关的头文件:视图->其它窗口->属性管理器,然后配置一些项,目的是将opencl的头文件导入这个cpp工程里面。(这里不介绍了,有很多现成的文章)

step2:导入头文件

#include <opencv2/opencv.hpp>  //我的核函数是用来处理图片的,如果不是可以去掉
#include <string>
#include <iostream>
#include <fstream>
#include <sstream>
#include <CL/cl2.hpp>  //cpp版本的opencl的头文件
using namespace cv;
using namespace std;
#pragma warning( disable : 4996 )  //去掉告警信息

step3:获取平台和上下文

cl::Platform platforms = cl::Platform::getDefault();
//我们获取的是gpu设备
cl::Context context = cl::Context(CL_DEVICE_TYPE_GPU,NULL);

 step4:获取设备和命令队列

这里的errNum帮助我们判断每一步是否出错,选中CL_SUCCESS,按F12,就可以看到这些错误码的具体定义

cl_int errNum = CL_SUCCESS;
std::vector<cl::Device> devices = context.getInfo<CL_CONTEXT_DEVICES>();
cl::CommandQueue cq = cl::CommandQueue(context, devices[0], CL_QUEUE_PROFILING_ENABLE, &errNum);	
if(errNum != CL_SUCCESS){
    printf("创建命令队列失败,错误码:%d\n, errNum);
}

step5:创建并且编译Program

main.cl是一个文件,放的是所有的核函数

//读取main.cl中核函数的内容
std::ifstream kernelFile("main.cl", std::ios::in);
std::ostringstream oss;
oss << kernelFile.rdbuf();
std::string srcStdStr = oss.str();
const char *srcStr = srcStdStr.c_str();
//创建Program
//这里要注意,传入的是核函数的内容,而不是核函数所在的文件的名字
program = cl::Program(context, srcStr, false, &errNum);
errNum = program.build(devices);  //编译Program

step6:编写核函数

这段代码放在main.cl文件中,我们这里的main.cl中只有一个核函数,当然,可以有多个

__kernel void kernel_func(__global unsigned char * rgbImage, __global * result)
{
    int x = get_global_id(0);
    int y = get_global_id(1);
    int index = x * height + y;
    result[index] = rgbImage[index];  //这里是输出
}

 step7:为核函数设置参数

Mat image = imread("D://b.jpg");  //存放自己图像的路径 
Mat dst;
cvtColor(image, dst, CV_BGR2GRAY);//图片转灰度图
int imgSize = dst.rows * dst.cols;

//输入的参数
cl::Buffer srcImg(context, CL_MEM_USE_HOST_PTR, sizeof(uchar) * 3 * imgSize, dst.data, &errNum);
//输出的参数
cl::Buffer memResult = cl::Buffer(context, CL_MEM_WRITE_ONLY, sizeof(int)*imgSize,NULL,NULL);
//设置参数
errNum = kernel.setArg(0, sizeof(cl_mem), &srcImg);
errNum = kernel.setArg(1, sizeof(cl_mem), &memResult);

step8:执行核函数

size_t globalThreads[2];
globalThreads[0] = dst.cols;
globalThreads[1] = dst.rows;
errNum = cq.enqueueNDRangeKernel(kernel, cl::NDRange(0), cl::NDRange(globalThreads[0], globalThreads[1]), cl::NullRange, NULL, NULL);

step9:获取执行结果

float * result = new float[imgSize];
errNum = cq.enqueueReadBuffer(memResult, true, 0, sizeof(float)*imgSize, result, NULL, NULL);

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章