全網第一個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);

 

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