专栏首页10km的专栏opencl: C++ 接口(cl.hpp)创建kernel

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

版权声明:本文为博主原创文章,转载请注明源地址。 https://blog.csdn.net/10km/article/details/50755251

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_ */

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • opencl:改造C++接口增加对内存编译(compile)的支持

    版权声明:本文为博主原创文章,转载请注明源地址。 https://blog.csdn.net...

    用户1148648
  • C++11模板:如何判断类中是否有指定名称的成员变量?

    版权声明:本文为博主原创文章,转载请注明源地址。 https://blog.csdn.net...

    用户1148648
  • opencl/msvc:kernel因为指针对齐方式造成向量类型读写异常

    版权声明:本文为博主原创文章,转载请注明源地址。 https://blog.csdn.net...

    用户1148648
  • 使用Nginx转发TCP/UDP数据

    程序员同行者
  • Linux CFS调度器之pick_next_task_fair选择下一个被调度的进程--Linux进程的管理与调度(二十八)

    每个调度器类sched_class都必须提供一个pick_next_task函数用以在就绪队列中选择一个最优的进程来等待调度, 而我们的CFS调度器类中, 选择...

    233333
  • 对又一个epoll问题的全面分析

    该方法最主要的目的是,当客户端建立tcp连接到服务端时,服务端立即调用shutdown方法,关闭其send方向。

    wangyuntao
  • tomcat安全加固

    【加固方法】删除webapps/docs、examples、manager、ROOT、host-manager

    程序员同行者
  • AI辅助构建知识图谱:关系抽取

    文件标注工作基于brat软件,http://brat.nlplab.org/。其中.txt文件为原始文档,.ann文件为标注信息,标注实体以T开头,后接实体序...

    机器学习AI算法工程
  • 【面试算法题】水仙花算法题详解

    题目:打印出所有的 “水仙花数 “,所谓 “水仙花数 “是指一个三位数,其各位数字立方和等于该数本身。例如:153是一个 “水仙花数 “,因为153=1的三次方...

    Java编程指南
  • 短小精悍的多源最短路径算法—Floyd算法

    在图论中,在寻路最短路径中除了Dijkstra算法以外,还有Floyd算法也是非常经典,然而两种算法还是有区别的,Floyd主要计算多源最短路径。

    bigsai

扫码关注云+社区

领取腾讯云代金券