1. 选择OpenCL平台并创建一个上下文
平台(Platform)是指主机和OpenCL管理框架下的若干个设备构成的可以运行OpenCL程序的完整硬件系统,这个是跑OpenCL程序的基础,所以第一步要选择一个可用的OpenCL品台。一台机器上可以有不止一个这样的品台,一个平台也可以有不止一个GPU。
clGetPlatformIDs() ,用于获取可用的平台;
//创建平台对象
status = clGetPlatformIDs( 1, &platform, NULL );
clGetDeviceIDs(),创建 GPU 设备
//创建 GPU 设备
status = clGetDeviceIDs( platform, CL_DEVICE_TYPE_GPU, 1, &device, NULL );
clCreateContext(), 创建一个OpenCL运行时山下文环境;
//创建context
context = clCreateContext( NULL, 1, &device, NULL, NULL, NULL );
2. 选择设备并创建命令队列
选择平台并创建好OpenCL上下文环境之后,要做的事选择运行时用到的设备,还要创建一个命令队列,命令队列里定义了设备要完成的操作,以及各个操作的运行次序。
主要涉及的函数:clCreateCommandQueue(),用于创建一个指定设备上的上下文环境,第二个参数定义了选择的设备。
//创建命令队列
commandQueue = clCreateCommandQueue( context, device, CL_QUEUE_PROFILING_ENABLE, NULL );
3. 创建和构建程序对象
程序对象用来存储与上下文相关联的设备的已编译可执行代码,同时也完成内核源代码的加载编译工作。
clCreateProgramWithSource(), 这个函数会创建一个程序对象,在创建的同时,把已经转化成字符串形式的内核源代码加载到该程序对象中。
//创建程序对象
program = clCreateProgramWithSource( context, 1, &source, sourceSize, NULL );
clBuildProgram()用于编译指定程序对象中的内核源代码,编译成功之后,再把编译代码存储在程序对象中
//编译程序对象
status = clBuildProgram(program, 1, &device, NULL, NULL, NULL);
clGetProgramBuildInfo()编译错误信息
clGetProgramBuildInfo(program, device, CL_PROGRAM_BUILD_LOG, 0x10000, tbuf, NULL);
4. 创建内核和内存对象
要执行程序对象中的已编译成功的内核运算,需要在内存中创建内核并分配内核函数的参数,在GPU上定义内存对象并分配存储空间。
clCreateBuffer(),分配内存对象的存储空间,这些对象可以由内核函数直接访问。
paramcl = clCreateBuffer(context, CL_MEM_READ_ONLY, sizeof(float) * 1024 * 500, NULL, NULL);
clCreateKernel(), 创建内核;
kernel = clCreateKernel(program, "function", NULL);
clSetKernelArg(),设置内核参数,想要执行内核,就必须设置内核参数。
status |= clSetKernelArg(kernel, 0, sizeof(cl_mem), (void *)¶mcl);
5. 设置内核数据并执行内核
创建内核和内存对象之后,接下来要设置核函数的数据,并将要执行的内核排队。
主要涉及的函数:clEnqueueNDRangeKernel(),用于设置内核函数的所有参与运算的数据。 利用命令队列对要在设备上执行的内核排队。需要注意的是,执行内核排队之后并不意味着这个内核一定会立即执行,只是排队到了执行队列中。
6. 读取执行结果并释放OpenCL资源
内核执行完成之后,需要把数据从GPU拷贝到CPU中,供主机进一步处理,所有者写工作完成之后需要释放所有的OpenCL资源。
主要涉及的函数:clEnqueueReadBuffer(),读取设备内存数据到主机内存;
clReleaseXXX(),释放OpenCL资源。