目录
创建上下文
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