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

目录

创建上下文

OpenCL 上下文创建:

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

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

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

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_notifyuser_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

相关推荐
西岸行者11 天前
学习笔记:SKILLS 能帮助更好的vibe coding
笔记·学习
悠哉悠哉愿意11 天前
【单片机学习笔记】串口、超声波、NE555的同时使用
笔记·单片机·学习
别催小唐敲代码11 天前
嵌入式学习路线
学习
毛小茛11 天前
计算机系统概论——校验码
学习
babe小鑫11 天前
大专经济信息管理专业学习数据分析的必要性
学习·数据挖掘·数据分析
winfreedoms11 天前
ROS2知识大白话
笔记·学习·ros2
在这habit之下11 天前
Linux Virtual Server(LVS)学习总结
linux·学习·lvs
我想我不够好。11 天前
2026.2.25监控学习
学习
im_AMBER11 天前
Leetcode 127 删除有序数组中的重复项 | 删除有序数组中的重复项 II
数据结构·学习·算法·leetcode
CodeJourney_J11 天前
从“Hello World“ 开始 C++
c语言·c++·学习