opencl: C++ 接口(cl.hpp)创建kernel

OpenCL不仅提供了标准C接口,同时提供C++的接口(cl.hpp),其实就是基于C接口的进一步封装。有了这个C++接口,对于C++项目来说,就大大提高了使用的便利性,本人涉及的这个项目对OpenCL的调用全部都是基于OpenCL的C++接口来完成的。

本文讲述如何用OpenCL 1.2的C++接口来从cl原文件创建kernel。

在cl.hpp中对cl_kernel被封装成了cl::Kernel对象,当然cl_program也被封装成了cl::Program对象。创建Kernel基本上主要涉及的就是这两个对象。

要创建cl::Kernel,先要创建cl::Program,下面的代码片段从一个std::string字符串源码中创建cl::Program

/* 通过source提供的源码创建 cl::Program  */
cl::Program facecl_context::createProgram(std::string source,const char* name) {
	try {
		// 执行clCreateProgramWithSource创建对象
		// m_context为cl::Context上下文件对象
		cl::Program program(m_context, source); 
		try{
			program.build(); //代码编译 执行clBuildProgram
#ifndef NDEBUG
			// 获取编译日志
			auto log=cl_utilits::getBuildInfo<CL_PROGRAM_BUILD_LOG>(program);
			// 显示编译日志
			showBuildLog(log,name);
#endif
			return program;
		}
#ifdef CL_VERSION_2_0 //当OpenCL版本为2.0以上时,编译错误抛出cl::BuildError异常
// 当然要让Opencl出错时抛出异常而不是返回错误码,需要在的代码中增加__CL_ENABLE_EXCEPTIONS宏定义
		catch(cl::BuildError &e){
			auto log=e.getBuildLog();
			showBuildLog(log,name);
			// 将cl::BuildError封装成自定义异常face_cl_build_exception抛出
			throw face_cl_build_exception(e,log);
		}
#else //当OpenCL版本为1.1,1.2时,编译错误抛出cl::Error异常
		catch(cl::Error& e){
			auto log=cl_utilits::getBuildInfo<CL_PROGRAM_BUILD_LOG>(program);
			showBuildLog(log,name);
			// 将cl::Error封装成自定义异常face_cl_build_exception抛出
			throw face_cl_build_exception(e,log);
		}
#endif		
	} catch (cl::Error& e) {
		// 将cl::Error 封装成自定义异常face_cl_exception抛出
		throw face_cl_exception(e);
	}
}

有了cl::Program对象,创建cl::Kernel就更简单了

/* 通过file提供的源码创建 cl::Kernel,并将cl::Kernel命名为name加入m_kernels映射表中  */
cl::Kernel facecl_context::createKernel(const char* name, const char *file) {
	auto scaling = load_string(file); // 从文本文件file读取所有内存到转成std::string
	auto program = createProgram(scaling,name); // 创建cl::Program对象
	cl::Kernel kernel(program, name);
	this->m_kernels.emplace(name, kernel);
	// m_kernels类型为std::unordered_map<std::string,cl::Kernel>
	return kernel;
}

facecl_context 类完整的源码如下

/*
 * platforms.h
 *
 *  Created on: 2016年2月21日
 *      Author: guyadong
 */

#ifndef FACEDETECT_FACECL_CONTEXT_H_
#define FACEDETECT_FACECL_CONTEXT_H_
#include "mycl.h"
#include <iostream>
#include <unordered_map>
#include "cl_utilits.h"
#include "assert_macros.h"

using namespace std;


typedef enum {
	image_scaling
}facecl_kernel;
#define KERNEL_NAME(n) #n
#define KERNEL_FILE_NAME(n) #n".cl"
class facecl_context {
	cl::Context m_context;
	cl::ImageFormat m_gray_format;
	std::unordered_map<std::string,cl::Kernel> m_kernels;
	cl::CommandQueue m_command_queue;
	/* 初始化上下文(context),优先获取GPU设备 */
	cl::Context _initContext(){
	try {
		return cl::Context(CL_DEVICE_TYPE_GPU);
	} catch (cl::Error &e) {
		if (CL_DEVICE_NOT_FOUND != e.err())
			throw e;
		try {
			return cl::Context(CL_DEVICE_TYPE_CPU);
		} catch (cl::Error &e1) {
			if (CL_DEVICE_NOT_FOUND != e1.err())
				throw e1;
			return cl::Context(CL_DEVICE_TYPE_DEFAULT);
		}
	}
}
public:
	void showSupportedImageFormats(cl_mem_flags flags,
			cl_mem_object_type type = CL_MEM_OBJECT_IMAGE2D,
			std::ostream& stream = cout) {
		return cl_utilits::showSupportedImageFormats(m_context, flags, type, cout);
	}
	const cl::Context& getContext()const{
		return m_context;
	}
	const cl::ImageFormat& getGrayFormat()const{
		return m_gray_format;
	}
	const cl::Kernel& getKernel(const char* name)const{
		auto itor=m_kernels.find(std::string(name));
		if(itor==m_kernels.end())
			throw face_cl_exception(ERROR_STR("can't found kernel:").append(name));
		return  itor->second;
	}
	cl::CommandQueue &getCommandQueue(){
		return m_command_queue;
	}
	cl::Program createProgram(std::string src,const char* name=nullptr) {
		try {
			cl::Program program(m_context, source);
			try{
				program.build();
	#ifndef NDEBUG
				auto log=cl_utilits::getBuildInfo<CL_PROGRAM_BUILD_LOG>(program);
				showBuildLog(log,name);
	#endif
				return program;
			}
	#ifdef CL_VERSION_2_0 //当OpenCL版本为2.0以上时,编译错误抛出cl::BuildError异常
			catch(cl::BuildError &e){
				auto log=e.getBuildLog();
				showBuildLog(log,name);
				throw face_cl_build_exception(e,log);
			}
	#else //当OpenCL版本为1.1,1.2时,编译错误抛出cl::Error异常
			catch(cl::Error& e){
				auto log=cl_utilits::getBuildInfo<CL_PROGRAM_BUILD_LOG>(program);
				showBuildLog(log,name);
				throw face_cl_build_exception(e,log);
			}
	#endif
		} catch (cl::Error& e) {
			throw face_cl_exception(e);
		}
	}
	cl::Kernel createKernel(const char* name, const char* file){
		auto scaling = load_string(file);
		auto program = createProgram(scaling,name);
		cl::Kernel kernel(program, name);
		this->m_kernels.emplace(name, kernel);
		return kernel;
	}
	void showBuildLog(build_log_type& build_log, const char* name = nullptr, std::ostream& stream=cout) {
		if (name)
			stream<<"--------------" << "source name:" << name<<"------------------" << endl;
		cl_utilits::showBuildLog(build_log, stream);
	}
	facecl_context(){
		try{
			m_context = _initContext();
			auto devices = m_context.getInfo<CL_CONTEXT_DEVICES>();
			m_command_queue=cl::CommandQueue(m_context);
			cl_utilits::showDevices(devices);
			m_gray_format = cl_utilits::getFittedImageFormatForGray(m_context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR);
			cout << "select format:" << cl_utilits::imageFormatToString(m_gray_format) << endl;
			auto k=createKernel(KERNEL_NAME(image_scaling),KERNEL_FILE_NAME(image_scaling));
		}catch(exception&e){
			cout<<e.what()<<endl;
			throw e;
		}
	}
	virtual ~facecl_context()=default;

};
extern facecl_context global_facecl_context;



#endif /* FACEDETECT_FACECL_CONTEXT_H_ */

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 20
    评论
评论 20
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

10km

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值