arduino int转char_OpenCL练习(一):使用OpenCL+OpenCV进行RGB转灰度图

a123dfbe74d93b68ede9d5ba3df4e7d7.png

背景

最近在学OpenCL,用的书是《OpenCL异构并行编程实战》。怎么说呢,感觉这本书比较迷,讲的很乱,跟着看完的话可能学不到什么。好在之前学过CUDA,勉强能够理解并行计算的思路。因此这里写了一下用显卡进行RGB2Gray的程序,也算是自己能够使用OpenCL进行一些简单的显卡计算吧。

平台:Ubuntu18.04 + CUDA10.0 + MX150 + OpenCL 1.2
目标:从磁盘读取一张图片,送入OpenCL设备进行RGB转灰度图,再拷贝回来显示

使用OpenCL进行计算的流程

无论是OpenCL,还是CUDA,当利用显卡计算时,都需要经历如下步骤:
1. 设备初始化 2. 准备主机端数据(分配主机端内存+获取数据) 3. 分配设备端内存 4. 将主机端数据拷贝到设备端 5. 设备启动内核函数,进行运算,将结果写到设备端内存 6. 将设备端结果拷贝回主机端 7. 读取主机端内存,进行后续处理 8. 释放资源

对于OpenCL,具体的步骤是:
1. 设备初始化(获取平台和设备id,创建上下文和命令队列) 2. 编写并编译内核 3. 准备主机端数据并传入设备(准备主机端数据,创建设备端缓冲对象,传入数据) 4. 启动内核函数(传递参数,启动内核) 5. 将结果拷贝回主机端 6. 后续处理 7. 释放资源

设备初始化

获取平台id

cl_int error;
    cl_platform_id platform;

    error = clGetPlatformIDs(1, &platform, NULL);   //获取平台id

这里clGetPlatformIDs的函数原型为:

clGetPlatformIDs(cl_uint          /* num_entries */,
                 cl_platform_id * /* platforms */,
                 cl_uint *        /* num_platforms */)

本例是只读取一个平台。实际上可能有多个平台。因此实际上更为通用的使用方法为:

cl_uint numOfPlatforms;
cl_int error;

error = clGetPlatformIDs(0, NULL, &numOfPlatforms); //获取平台数量
if(error != CL_SUCCESS)
{
    
    perror("Cannot get platform ids");
    exit(1);
}
cl_platform_id *platforms = (cl_platform_id*)alloca(sizeof(cl_platform_id)*numOfPlatforms);
error = clGetPlatformIDs(numOfPlatforms, platforms, NULL);  //获取cl_platform_id实体

这里我们看到clGetPlatformIDs()函数被调用了两次,第一次是获取平台的数量numOfPlatforms,第二次是获取cl_platform_id的实体。OpenCL里有很多类似的API。

本例是为了偷个懒,只使用第一个平台。

获取设备id

获取完平台id后,要获取设备id。这里一样偷懒,只使用平台上第一个设备。实际上一个平台上可能有多个OpenCL设备(CPU、GPU)。

cl_device_id device;

error = clGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU, 1, &device, NULL); //获取设备id

函数原型为:

clGetDeviceIDs(cl_platform_id   /* platform */,
               cl_device_type   /* device_type */, 
               cl_uint          /* num_entries */, 
               cl_device_id *   /* devices */, 
               cl_uint *        /* num_devices */)

创建设备上下文

OpenCL使用上下文来管理设备,因此不论进行什么操作,都需要先创建上下文:

context = clCreateContext(NULL, 1, &device, NULL, NULL, &error);    //创建上下文

创建命令队列

命令队列和CUDA中的的概念相对应。主机程序在设备上创建命令队列,并向命令队列中压入操作(数据传输、内核执行)。 一个设备上可以创建多个命令队列。
与CUDA略有区别的是,OpenCL除了顺序执行命令队列中的任务之外,还可以不按顺序执行(创建队列时传入CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE标志位)。

创建命令队列时,需要传入设备id和上下文

cQ = clCreateCommandQueue(context, device, NULL, &error);

函数原型:

clCreateCommandQueue(cl_context                     /* context */,
                     cl_device_id                   /* device */,
                     cl_command_queue_properties    /* properties */,
                     cl_int *                       /* errcode_ret */)

编译内核

与CUDA不同的是,OpenCL需要在程序中显式编译内核。

内核函数

OpenCL工程一般将内核放在单独的*.cl文件中。本例的内核为:

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值