opencl_1

来源:互联网 发布:win10 专业版网络受限 编辑:程序博客网 时间:2024/06/10 02:45
在使用OpenCL API之前,和绝大部份所有其它的API一样,都需要include相关的header档案。由于在MacOS X 10.6下OpenCL的header档案命名方式和在其它作业系统下不同,因此,通常要使用一个#ifdef来进行区分。如下所示:

#ifdef __APPLE__
#include <OpenCL/opencl.h>
#else
#include <CL/cl.h>
#endif

这样就可以在MacOS X 10.6 下,以及其它的作业系统下,都可以include 正确的OpenCL header 档。

接着,要先取得系统上所有的OpenCL platform。在MacOS X 10.6 下,目前只有一个由Apple 提供的OpenCL platform,但是在其它系统上,可能会有不同厂商提供的多个不同的OpenCL platform,因此需要先取得platform 的数目:

cl_int err;
cl_uint num;
err = clGetPlatformIDs(0, 0, &num);
if(err != CL_SUCCESS) {
std::cerr << "Unable to get platforms\n";
return 0;
}

大部份的OpenCL API 会传回错误值。如果传回值是CL_SUCCESS 则表示执行成功,否则会传回某个错误值,表示失败的原因。

接着,再取得platform 的ID,这在建立OpenCL context 时会用到:

std::vector<cl_platform_id> platforms(num);
err = clGetPlatformIDs(num, &platforms[0], &num);
if(err != CL_SUCCESS) {
std::cerr << "Unable to get platform ID\n";
return 0;
}

在OpenCL 中,类似这样的模式很常出现:先呼叫第一次以取得数目,以便配置足够的记忆体量。接着,再呼叫第二次,取得实际的资料。

接下来,要建立一个OpenCL context。如下:

cl_context_properties prop[] = { CL_CONTEXT_PLATFORM, reinterpret_cast<cl_context_properties>(platforms[0]), 0 };
cl_context context = clCreateContextFromType(prop, CL_DEVICE_TYPE_DEFAULT, NULL, NULL, NULL);
if(context == 0) {
std::cerr << "Can't create OpenCL context\n";
return 0;


clReleaseContext(context);
return 0;

在上面的程式中,clCreateContextFromType 是一个OpenCL的API,它可以从指定的装置类别中,建立一个OpenCL context。第一个参数是指定context的property。在OpenCL中,是透过一个property的阵列,以「property种类」及「property内容」成对出现,并以0做为结束。例如,以上面的例子来说,要指定的property种类是CL_CONTEXT_PLATFORM,即要使用的platform ID,而property内容则是由之前取得的platform ID中的第一个(即platforms[0])。由于property的内容可能是不同的资料型态,因此需要使用reinterpret_cast 来进行强制转型。

第二个参数可以指定要使用的装置类别。目前可以使用的类别包括:
  • CL_DEVICE_TYPE_CPU:使用CPU 装置
  • CL_DEVICE_TYPE_GPU:使用显示晶片装置
  • CL_DEVICE_TYPE_ACCELERATOR:特定的OpenCL 加速装置,例如CELL
  • CL_DEVICE_TYPE_DEFAULT:系统预设的OpenCL 装置
  • CL_DEVICE_TYPE_ALL:所有系统中的OpenCL 装置
这里使用的是CL_DEVICE_TYPE_DEFAULT,也就是指定使用预设的装置。另外,在这里,直接使用了之前取得的OpenCL platform ID中的第一个ID(实际的程式中,可能会需要让使用者可以指定要使用哪一个platform)。

如果建立OpenCL context失败,会传回0。因此,要进行检查,并显示错误讯息。如果建立成功的话,在使用完后,要记得将context释放。这可以透过呼叫clReleaseContext来达成。
这个程式基本上已经可以编译执行了,但是当然它并没有真的做什么事情。

一个OpenCL context中可以包括一个或多个装置,所以接下来的工作是要取得装置的列表。要取得任何和OpenCL context相关的资料,可以使用clGetContextInfo函式。以下是取得装置列表的方式:

size_t cb;
clGetContextInfo(context, CL_CONTEXT_DEVICES, 0, NULL, &cb);
std::vector<cl_device_id> devices(cb / sizeof(cl_device_id));
clGetContextInfo(context, CL_CONTEXT_DEVICES, cb, &devices[0], 0);

CL_CONTEXT_DEVICES表示要取得装置的列表。和前面取得platform ID的情形相同,clGetContextInfo 被呼叫了两次:第一次是要取得需要存放装置列表所需的记忆体空间大小(也就是传入 &cb),然后第二次呼叫才真正取得所有装置的列表。

接下来,可能会想要确定倒底找到的OpenCL装置是什么。所以,可以透过OpenCL API取得装置的名称,并将它印出来。取得和装置相关的资料,是使用clGetDeviceInfo 函式,和前面的clGetContextInfo函式相当类似。以下是取得装置名称的方式:

clGetDeviceInfo(devices[0], CL_DEVICE_NAME, 0, NULL, &cb);
std::string devname;
devname.resize(cb);
clGetDeviceInfo(devices[0], CL_DEVICE_NAME, cb, &devname[0], 0);
std::cout << "Device: " << devname.c_str() << "\n";
// ConsoleApplication1.cpp : Defines the entry point for the console application.//#include "stdafx.h"#include <iostream>#include <string>#include <vector>#ifdef __APPLE__#include <OpenCL/opencl.h>#else#include <CL/cl.h>#endifint main(){cl_int err;cl_uint num;err = clGetPlatformIDs(0, 0, &num);if (err != CL_SUCCESS) {std::cerr << "Unable to get platforms\n";return 0;}std::vector<cl_platform_id> platforms(num);err = clGetPlatformIDs(num, &platforms[0], &num);if (err != CL_SUCCESS) {std::cerr << "Unable to get platform ID\n";return 0;}cl_context_properties prop[] = { CL_CONTEXT_PLATFORM, reinterpret_cast<cl_context_properties>(platforms[0]), 0 };cl_context context = clCreateContextFromType(prop, CL_DEVICE_TYPE_DEFAULT, NULL, NULL, NULL);if (context == 0) {std::cerr << "Can't create OpenCL context\n";return 0;}size_t cb;clGetContextInfo(context, CL_CONTEXT_DEVICES, 0, NULL, &cb);std::vector<cl_device_id> devices(cb / sizeof(cl_device_id));clGetContextInfo(context, CL_CONTEXT_DEVICES, cb, &devices[0], 0);clGetDeviceInfo(devices[0], CL_DEVICE_NAME, 0, NULL, &cb);std::string devname;devname.resize(cb);clGetDeviceInfo(devices[0], CL_DEVICE_NAME, cb, &devname[0], 0);std::cout << "Device: " << devname.c_str() << "\n";clReleaseContext(context);return 0;}