OpenCL 学习(4)---- OpenCL 上下文和程序对象

目录

创建上下文

OpenCL 上下文创建:

先查询支持的设备和平台信息,然后根据这些信息创建相应的 OpenCL 上下文对象

之后所有的 OpenCL 操作都是以该上下文对象(context)作为标识,相当于后续的并行计算也是在该设备上执行,

在实际的硬件产品中,PC 上的设备通常是一些显卡(Nvdia 独立显卡,或者 Intel 独立显卡),手机上是使用移动的 GPU (比如 ARM 的MALI)

c 复制代码
cl_context clCreateContext(
    const cl_context_properties *properties,  // 上下文创建属性
    cl_uint num_devices,                      // 运行的设备数量
    const cl_device_id *devices,              // 运行的 deviceId列表
    // 如果创建成功使用的回调函数
    void (CL_CALLBACK *pfn_notify)(const char *errinfo, const void *private_info, size_t cb,void *user_data), 
    void *user_data,                          // 回调函数使用的用户数据
    cl_int *errcode_ret);                     // 输出错误码
)

参数 properties 指定上下属性的属性名称及属性相应的值的列表,规定最后一个值为 0,

如下表,当实现自定义选择平台时,参数 properties 可以设置为 NULL

cl_context_properties 属性值 描述
CL_CONTEXT_PLATFORM cl_platform_id 指定使用的平台
CL_CONTEXT_INETROP_USER_SYNC cl_bool 指定用户是否负责 OpenCL 和其他 API 之间的同步,如果没有指定,默认值为 CL_FALSE

参数 pfn_notify 和 user_data 共同定义一个回调函数,这个回调函数报告上下文生命周期中出现的错误的有关信息,

要把 user_data 作为最后一个参数传递至回调函数,这两个参数都可以设置为 NULL
errcode_ret 是函数的返回状态值,成功为 CL_SUCCESS,否则值为对应的错误代码

创建程序对象

程序对象主要是用来加载、编译和处理 CL 代码的函数,这个处理流程跟 OpenGL 中处理 shader 语言代码几乎一样,

都是先将脚本语言加载、编译、链接,不同的是:
OpenCL 中的代码 GPU 的编程通常只在顶点着色器(VertexShader) 和片段着色器(FragementShader)中,

执行的时机依赖于渲染管线流程的顺序,不能直接通过 CPU 的代码控制Shader 的执行 ,

而 OpenCL 的脚本代码在 GPU 中执行,可以通过命令队列来控制,并且可以使用事件进行同步,这一点是 OpenGL 所没有的

c 复制代码
cl_program clCreateProgramWithSource(
    cl_context context,                 // 输入OpenCL上下文对象
    cl_uint count,                      // 输入CL代码的数量,一般设置为 1
    const char **strings,               // 输入CL代码字符串数组 
    const size_t *lengths,              // 输入CL代码字符串数量  
    cl_int *errcode_ret)                // 输出错误码,如果成功返回0
c 复制代码
clCreateProgramWithBinary(
    cl_context                     /* context */,
    cl_uint                        /* num_devices */,
    const cl_device_id *           /* device_list */,
    const size_t *                 /* lengths */,
    const unsigned char **         /* binaries */,
    cl_int *                       /* binary_status */,
    cl_int *                       /* errcode_ret */)

这里的 CL 代码就是 GPU 中执行的内置的开发语言,一般将这部分代码作为一个完整的字符串,提供给 clCreateProgramWithSource 进行编译
CL 代码通常都是实现的一个个独立的函数,称为内核函数,经过编译、加载运行后,最终在 GPU 中执行

利用编译好程序二进制来创建程序对象,第五个参数传入 binaries 的内容,第四个参数为二进制内容大小

先使用对应的 OpenCL 编译工具(不同的平台会有不同的实现)将 CL 脚本代码编译成二进制数据,之后使用 clCreateProgramWithBinary来加载

c 复制代码
cl_program clCreateProgramWithBinary( cl_context         context,
                                    cl_uint            num_devices,
                                    const cl_device_id *device_list,
                                    const size_t       *lengths,
                                    cosnt unsigned char **binaries,
                                    cl_int             *binary_status,
                                    cl_int             *errcode_ret )
编译程序对象

clBuildProgram 为指定的所有设备构建程序对象,实际上等价于在一个C程序上调用编译器和链接器,

第四个参数就是设置编译器选项

c 复制代码
cl_int clBuildProgram(
        cl_program program,                  // 要编译的程序对象
        cl_uint num_devices,                 // 指定运行的设备Id数量
        const cl_device_id *device_list,     // 指定要运行的设备Id列表
        const char *options,                 // 编译参数字符串
        void (CL_CALLBACK *pfn_notify) (cl_program program,void *user_data), // 编译成功的回调函数,如果NULL表示同步等待
        void *user_data)                     // 回调函数用户数据

编译器的选项可以分为下面几种类型

  • 预处理选项
  • 数学选项
  • 优化选项
  • 其他选项

这几个选项的详细情况,如下表所示:

需要关注的主要就是 option 编译参数字串,通常这个参数设置跟 GCC 的编译选项非常类似,当然也有些 CL 语言本身的一些编译参数

比如 CL 程序中如果是下面的代码:

c 复制代码
#ifdef __USE_FLOAT__
    #define ELM_TYPE    float
#else
    #define ELM_TYPE    int
#endif

ELM_TYPE    data[10];

那么使用 clBuildProgram 编译 .cl 代码的时候,如果带上 options = "-D __USE_FLOAT__" 参数的时候,
.cl 代码会编译成 float data[10]否则就会编译成 int data[10]

clGetProgramBuildInfo 用于获取编译信息,通常用于获取编译传递的错误信息

c 复制代码
cl_int clGetProgramBuildInfo(
    cl_program program,                    // 程序对象
    cl_device_id device,                   // 编译的设备Id
    cl_program_build_info param_name,      // 通常用 CL_PROGRAM_BUILD_LOG,表示输出编译日志
    size_t param_value_size,               // 输出缓冲区大小
    void *param_value,                     // 输出缓冲区
    size_t *param_value_size_ret)          // 返回错误代码,成功返回0
查询和管理程序对象

TBD

相关推荐
前进的李工3 小时前
Agent 学习笔记 05:系统提示词应该怎么写
笔记·学习·prompt·agent·个人开发·few-shot·ai应用开发
正在走向自律4 小时前
【3/5】人工智能训练师 三级/高级工 考证学习方向:从“独立执行”到“设计、归因与全链条负责”
人工智能·学习·人工智能训练师·注方案设计·数据质控负责人·模型评测与调优辅助·ai训练项目交付
CCIE-Yasuo6 小时前
网络安全-学习数据库-Mysql-2
数据库·学习·mysql
La Pulga7 小时前
【FreeRTOS源码学习笔记】任务切换
单片机·mcu·学习·嵌入式·freertos·实时操作系统
li星野7 小时前
【学习记录】逻辑分析仪完全入门:从品牌方案到采样率、存储深度的核心概念解析
学习
旖旎夜光8 小时前
【C++ 基础入门】类和对象(上):封装、对象模型与 this 指针
开发语言·c++·笔记·学习
WEI_YANG_JU9 小时前
初中数学教学中合作学习的研究与实践
学习
码农小韩9 小时前
FPGA学习(一)——LED点灯与开发流程
学习·fpga开发·入门·环境配置·仿真·点灯
李长渊哦9 小时前
Qoder 自定义子智能体(Subagent)学习笔记
chrome·笔记·学习
代码山河10 小时前
基本类型转换:自动类型转换与强制类型转换
java·学习·架构·教程·面向对象·项目