OpenCL 学习(5)---- OpenCL 内核和内核参数

目录

创建内核函数

OpenCL 中,使用 cl_kernel 数据结构来表示内核对象,OpenCL 使用如下函数来创建内核对象

c 复制代码
cl_kernel clCreateKernel(
      cl_program program,           // 程序对象
      const char *kernel_name,      // 内核函数名,CL代码中要执行的函数名 如上例子,使用的内核函数名就是 "image_filter"
      cl_int *errcode_ret);         // 输出错误码,如果成功返回 0

函数 clCreateKernel,参数 programOpenCL 编译的 Program 对象中构建的程序对象,里面包含了多个内核对象

参数 kernel_name 为程序对象中用 __kernel 地址限定符的内核对象名称,参数 errcode_ret 是函数的执行返回状态

c 复制代码
clCreateKernelsInProgram(cl_program     /* program */,
                         cl_uint        /* num_kernels */,
                         cl_kernel *    /* kernels */,
                         cl_uint *      /* num_kernels_ret */) ;

函数 clCreateKernelsInProgram,参数 program 是构建的程序对象,参数 kernels 为返回的内核对象列表,参数 num_kernels 为内核对象列表中内核的个数,参数 num_kernels_ret 为程序对象中内核个数,如果为 NULL 就忽略这个参数

如果程序中有多个对象,使用 clCreateKernelsInProgram 创建内核对象,但是注意内核列表中的内核函数名称顺序并不是根据 cl 文件中的内核书写顺序,而是依赖于实现

设置内核参数

为了执行一个具体的内核,需要向内核函数传递参数,OpenCL 使用下面函数来设置内核参数:

c 复制代码
clSetKernelArg(cl_kernel    /* kernel */,
               cl_uint      /* arg_index */,
               size_t       /* arg_size */,
               const void * /* arg_value */);

参数 kernel 为内核对象,参数 arg_index 为内核函数参数的索引,按照从左到右的顺序,第一个(最左边的)参数索引为 0, 第二个参数索引为 1,以此类推:

参数 arg_size 表示参数的大小,分为下面几种情况:

  • 如果参数为内存对象,那么 arg_size 为内存对象类型的大小(例如: sizeof(cl_mem))
  • 如果参数用 local修饰符声明,则 arg_size 用来存储参数的缓冲区所需的字节数
  • 如果参数为 sampler_t 类型,则 arg_size 大小必须扽与 sizeof(cl_sampler)
  • 如果参数为 queue_t 类型,则 arg_size 大小必须等于 sizeof(cl_command_queue)
  • 如果参数为其他类型,arg_size 大小为该类型参数大小(例如: 对一个 cl_int 类型参数,大小为 sizeof(cl_int))

参数的 arg_value 为传入内核参数的一个指针:

  • 如果参数为内存对象(cl_mem),则指针指向合适的缓冲、管道、图像或者图像数组对象
  • 如果参数用 local 修饰符声明,arg_value 必须为 NULL
  • 如果参数为 sampler_t, arg_value 必须指向采样器对象
  • 如果参数为 queue 类型,arg_value 必须指向设备队列对象
内核参数设置举例

比如一个内核函数实现如下:

c 复制代码
__kernel void image_filter(
  const __global uchar*   in_img_data,            
  const int               pxl_bytes,
  const int               img_line_bytes, 
  const __global double*  in_coeff,
  const int               coeff_wnd_size,
  __global uchar*         out_img_data  )

设置内核函数参数,有下面的对应关系:

  • 对于 cl 代码中,形如charfloatint 等基本类型的参数,在 C 语言中有 cl_charcl_intcl_float 等基本的数据类型对应,设置参数时使用这些基本的数据类型即可

  • 对于 cl 代码中,形如 const __global uchar* const__global double* 等指针类型的参数,在 C 语言中统一使用 cl_mem 缓冲区对象来传递下去

  • 对于 cl 代码中,形如 image2d_t srcImage,sampler_t sampler 等图像对象、采样器对象的参数,在 C 语言中统一使用 cl_memcl_sampler 等对象传递下去

所以对上述的 imagefilter 核函数设置参数:

c 复制代码
// 这里的 image_filter 是内核函数名称
kernel_filter_ = clCreateKernel(program_, "image_filter", &err_code);
CHK_CLERR(err_code);

// 给 image_filter 中各个参数设置参数值,从索引 0 开始
err_code = clSetKernelArg(kernel_filter_, 0, sizeof(cl_mem), (void*)&mem_in_img);
CHK_CLERR(err_code);
err_code = clSetKernelArg(kernel_filter_, 1, sizeof(cl_int), (void*)&pxl_bytes);
CHK_CLERR(err_code);
err_code = clSetKernelArg(kernel_filter_, 2, sizeof(cl_int), (void*)&line_bytes);
CHK_CLERR(err_code);
err_code = clSetKernelArg(kernel_filter_, 3, sizeof(cl_mem), (void*)&mem_in_coeff);
CHK_CLERR(err_code);
err_code = clSetKernelArg(kernel_filter_, 4, sizeof(cl_int), (void*)&coeff_wnd_size);
CHK_CLERR(err_code);
err_code = clSetKernelArg(kernel_filter_, 5, sizeof(cl_mem), (void*)&mem_out_img);
CHK_CLERR(err_code);
clReleaseKernel(kernel); 
查询内核信息

一旦创建了内核对象,开发人员如果想知道内核对象的一些属性信息,可以使用如下函数查询内核对象的属性信息

c 复制代码
clGetKernelInfo(cl_kernel       /* kernel */,
                cl_kernel_info  /* param_name */,
                size_t          /* param_value_size */,
                void *          /* param_value */,
                size_t *        /* param_value_size_ret */);

参数 param_name 为查询内核对象的属性名称,可以接受的参数如下表,参数 param_value 为存储结果的位置指针,

参数 param_value_size 为参数 param_value 的字节数,参数 param_value_size_ret 为实际写入的字节数

cl_kernel_work_group_info 返回值 描述
CL_KERNEL_GLOBAL_WORK_SIZE size_t[3] 指定设备上执行内核最大可用的工作项大小
CL_KERNEL_WORK_GROUP_SIZE size_t 指定设备上执行内核最大可用工作组大小
CL_KERNEL_COMPILE_WORK_SIZE size_t[3] TBD
CL_KERNEL_LOCAL_MEM_SIZE cl_ulong 返回内核函数使用的局部内存量
CL_KERNEL_PERFERRED_WORK_GROUP_SIZE_MULTIPLE size_t 给出一个最优工作组大小倍数
CL_KERNEL_PERFERRED_PRIVATE_MEM_SIZE cl_ulong 返回各工作项使用的最小私有内存量

函数 clGetkernelInfo 不能查询特定于某个设备的内核对象信息,例如:如何将一个并行负载分派到执行内核的一个或者多个不同设备上,那么 该如何处理?

OpenCL 中提供了如下函数可以查询特定于某个设备的内核对象属性信息

c 复制代码
clGetKernelWorkGroupInfo(cl_kernel                  /* kernel */,
                         cl_device_id               /* device */,
                         cl_kernel_work_group_info  /* param_name */,
                         size_t                     /* param_value_size */,
                         void *                     /* param_value */,
                         size_t *                   /* param_value_size_ret */);

参数 device 为内核对象关联的设备列表中的一个特定设备,参数 param_name 为查询内核工作组的属性信息,可以接受参数如下表,其他参数

类似于 clGetKernelInfo

下面例子用来查询工作组信息:

TBD

相关推荐
01二进制代码漫游日记2 小时前
自定义类型:联合和枚举(一)
c语言·开发语言·学习·算法
非凡ghost2 小时前
小X分身APP(手机分身类工具)
android·windows·学习·智能手机·软件需求
weixin_458872612 小时前
东华复试OJ每日3题打卡·复盘82~84
学习
昌兵鼠鼠3 小时前
LeetCode Hot100 哈希
学习·算法·leetcode·哈希算法
旖旎夜光3 小时前
哈希(14)(下)
数据结构·c++·学习
2401_848009725 小时前
Redis零基础入门学习
数据库·redis·学习
如果你想拥有什么先让自己配得上拥有5 小时前
全等三角形的判定条件思考
学习·总结
zenpluck6 小时前
RTAB-Map学习记录(1)--论文阅读
c++·论文阅读·学习·机器人
小宋加油啊7 小时前
多模态方法学习
学习·多模态