本文在Windows 10 64位系统上搭建OpenCL开发环境,笔记本显卡的类型(使用英特尔® 驱动程序和支持助理查询):
NVIDIA GeForce 820M | Intel® HD Graphics Family | |
---|---|---|
Adapter Compatibility | NVIDIA | Intel Corporation |
Video Processor | GeForce 820M | Intel® HD Graphics Family |
Driver Provider | NVIDIA | Intel Corporation |
Driver Version | 23.21.13.8857 | 20.19.15.4549 |
Driver Date | 2017/12/4 | 2016/11/10 |
Adapter DAC Type | Integrated RAMDAC | Internal |
Adapter RAM | 2.00 GB | 1.00 GB |
Availability | Offline | Running at full power |
Location | PCI bus 4, device 0, function 0 | PCI bus 0, device 2, function 0 |
Device Id | PCI\VEN_10DE&DEV_1140&SUBSYS_228A1043&REV_A1\4&3A7A1238&0&00E4 | PCI\VEN_8086&DEV_0A16&SUBSYS_228A1043&REV_09\3&11583659&0&10 |
以及Intel® HD Graphics Family的一些参数Resolution:1366 x 768, Bits Per Pixel:32,Number of Colors:4294967296,Refresh Rate - Current、 Refresh Rate - Maximum、Refresh Rate - Minimum:60 Hz。
Windows 驱动中自动包含了OpenCL驱动,VS2012-VS2017任意版本(这里使用的是VS2017)。下载Intel SDK for OpenCL applications,注意选择Windows平台,然后注册帐号后即可下载。下载测试程序,解压后打开CapsBasic目录下的sln文件(高版本自动升级项目)。
添加一个新文件HelloOpenCL.cpp,在文件中添加如下代码:
#include
#include
#include
#include
#include
#include
#define OCLBASIC_PRINT_TEXT_PROPERTY(NAME) \
{ /* 获得属性信息长度 */ \
size_t property_length = 0; \
err = clGetDeviceInfo(device,NAME,0,0,&property_length); \
char* property_value = new char[property_length]; \
/* 获得属性信息 */ \
err = clGetDeviceInfo(device,NAME,property_length,property_value,0); \
std::cout << " " << #NAME << ": " << property_value << std::endl; \
delete[] property_value; \
}
int main()
{
// Discover and initialize the platforms
cl_int err = CL_SUCCESS;
cl_uint num_of_platforms = 0;
// get total number of available platforms 获得可用平台总数
err = clGetPlatformIDs(0, NULL, &num_of_platforms);
std::cout << "Number of available platforms: " << num_of_platforms << std::endl;
cl_platform_id* platforms = new cl_platform_id[num_of_platforms];
// get IDs for all platforms
err = clGetPlatformIDs(num_of_platforms, platforms, 0);
// List all platforms
for (cl_uint i = 0; i < num_of_platforms; ++i)
{
// Get the length for the i-th platform name 获得平台名长度
size_t platform_name_length = 0;
err = clGetPlatformInfo(platforms[i], CL_PLATFORM_NAME, 0, 0, &platform_name_length);
// Get the name itself for the i-th platform 获得平台名字
char* platform_name = new char[platform_name_length]; //为存储平台名分配空间
err = clGetPlatformInfo(platforms[i], CL_PLATFORM_NAME, platform_name_length, platform_name, 0);
// Output platform name
std::cout << " [" << i << "] " << platform_name << std::endl;
delete[] platform_name;
}
cl_platform_id platform = platforms[1]; // 选择Intel核显
// Discover the number of devices which are provided for the selected platform.
struct {
cl_device_type type;
const char* name;
cl_uint count;
} devices[] =
{
{ CL_DEVICE_TYPE_CPU, "CL_DEVICE_TYPE_CPU", 0 },
{ CL_DEVICE_TYPE_GPU, "CL_DEVICE_TYPE_GPU", 0 },
{ CL_DEVICE_TYPE_ACCELERATOR, "CL_DEVICE_TYPE_ACCELERATOR", 0 }
};
const int NUM_OF_DEVICE_TYPES = sizeof(devices) / sizeof(devices[0]);
std::cout << "Number of devices available for each type in selected platform:\n";
// iterate over all device types 获得每种设备的数量
for (int i = 0; i < NUM_OF_DEVICE_TYPES; ++i)
{
err = clGetDeviceIDs(platform, devices[i].type, 0, 0, &devices[i].count);
if (CL_DEVICE_NOT_FOUND == err)
{
devices[i].count = 0;
err = CL_SUCCESS;
}
std::cout << " " << devices[i].name << ": " << devices[i].count << std::endl;
}
// get useful capabilities information for each device
std::cout << "\n*** Detailed information for each device ***\n";
for (int type_index = 0; type_index < NUM_OF_DEVICE_TYPES; ++type_index)
{
cl_uint cur_num_of_devices = devices[type_index].count;
if (cur_num_of_devices == 0)
{
continue; // there is no devices of this type; move to the next type
}
// Retrieve a list of device IDs with type selected by type_index 检索设备ID列表
cl_device_id* devices_of_type = new cl_device_id[cur_num_of_devices];
err = clGetDeviceIDs(platform,devices[type_index].type,cur_num_of_devices,devices_of_type,0);
// Iterate over all devices of the current device type
for (cl_uint device_index = 0; device_index < cur_num_of_devices; ++device_index)
{
std::cout << "\n" << devices[type_index].name << "[" << device_index << "]\n";
cl_device_id device = devices_of_type[device_index];
#define OCLBASIC_PRINT_NUMERIC_PROPERTY(NAME, TYPE) \
{ \
TYPE property_value; \
size_t property_length = 0; \
err = clGetDeviceInfo( \
device, \
NAME, \
sizeof(property_value), \
&property_value, \
&property_length \
); \
assert(property_length == sizeof(property_value)); \
std::cout \
<< " " << #NAME << ": " \
<< property_value << std::endl; \
}
OCLBASIC_PRINT_TEXT_PROPERTY(CL_DEVICE_NAME);
OCLBASIC_PRINT_NUMERIC_PROPERTY(CL_DEVICE_AVAILABLE, cl_bool);
OCLBASIC_PRINT_TEXT_PROPERTY(CL_DEVICE_VENDOR);
OCLBASIC_PRINT_TEXT_PROPERTY(CL_DEVICE_PROFILE);
OCLBASIC_PRINT_TEXT_PROPERTY(CL_DEVICE_VERSION);
OCLBASIC_PRINT_TEXT_PROPERTY(CL_DRIVER_VERSION);
OCLBASIC_PRINT_TEXT_PROPERTY(CL_DEVICE_OPENCL_C_VERSION);
OCLBASIC_PRINT_NUMERIC_PROPERTY(CL_DEVICE_MAX_COMPUTE_UNITS, cl_uint);
OCLBASIC_PRINT_NUMERIC_PROPERTY(CL_DEVICE_MAX_CLOCK_FREQUENCY, cl_uint);
OCLBASIC_PRINT_NUMERIC_PROPERTY(CL_DEVICE_MAX_WORK_GROUP_SIZE, size_t);
OCLBASIC_PRINT_NUMERIC_PROPERTY(CL_DEVICE_ADDRESS_BITS, cl_uint);
OCLBASIC_PRINT_NUMERIC_PROPERTY(CL_DEVICE_MEM_BASE_ADDR_ALIGN, cl_uint);
OCLBASIC_PRINT_NUMERIC_PROPERTY(CL_DEVICE_MAX_MEM_ALLOC_SIZE, cl_ulong);
OCLBASIC_PRINT_NUMERIC_PROPERTY(CL_DEVICE_GLOBAL_MEM_SIZE, cl_ulong);
OCLBASIC_PRINT_NUMERIC_PROPERTY(CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE, cl_ulong);
OCLBASIC_PRINT_NUMERIC_PROPERTY(CL_DEVICE_GLOBAL_MEM_CACHE_SIZE, cl_ulong);
OCLBASIC_PRINT_NUMERIC_PROPERTY(CL_DEVICE_GLOBAL_MEM_CACHELINE_SIZE, cl_uint);
OCLBASIC_PRINT_NUMERIC_PROPERTY(CL_DEVICE_LOCAL_MEM_SIZE, cl_ulong);
OCLBASIC_PRINT_NUMERIC_PROPERTY(CL_DEVICE_PROFILING_TIMER_RESOLUTION, size_t);
OCLBASIC_PRINT_NUMERIC_PROPERTY(CL_DEVICE_IMAGE_SUPPORT, cl_bool);
OCLBASIC_PRINT_NUMERIC_PROPERTY(CL_DEVICE_ERROR_CORRECTION_SUPPORT, cl_bool);
OCLBASIC_PRINT_NUMERIC_PROPERTY(CL_DEVICE_HOST_UNIFIED_MEMORY, cl_bool);
OCLBASIC_PRINT_TEXT_PROPERTY(CL_DEVICE_EXTENSIONS);
OCLBASIC_PRINT_NUMERIC_PROPERTY(CL_DEVICE_PREFERRED_VECTOR_WIDTH_INT, cl_uint);
OCLBASIC_PRINT_NUMERIC_PROPERTY(CL_DEVICE_PREFERRED_VECTOR_WIDTH_LONG, cl_uint);
OCLBASIC_PRINT_NUMERIC_PROPERTY(CL_DEVICE_PREFERRED_VECTOR_WIDTH_FLOAT, cl_uint);
OCLBASIC_PRINT_NUMERIC_PROPERTY(CL_DEVICE_PREFERRED_VECTOR_WIDTH_DOUBLE, cl_uint);
OCLBASIC_PRINT_NUMERIC_PROPERTY(CL_DEVICE_NATIVE_VECTOR_WIDTH_INT, cl_uint);
OCLBASIC_PRINT_NUMERIC_PROPERTY(CL_DEVICE_NATIVE_VECTOR_WIDTH_LONG, cl_uint);
OCLBASIC_PRINT_NUMERIC_PROPERTY(CL_DEVICE_NATIVE_VECTOR_WIDTH_FLOAT, cl_uint);
OCLBASIC_PRINT_NUMERIC_PROPERTY(CL_DEVICE_NATIVE_VECTOR_WIDTH_DOUBLE, cl_uint);
}
delete[] devices_of_type;
}
delete[] platforms;
return 0;
}
API函数clGetPlatformIDs()用来获取指定系统上可用的计算平台:
cl_int clGetPlatformIDs(cl_uint num_entries, cl_platform_id *platforms, cl_uint *num_platforms)
该函数通常由应用程序调用两次。首次调用时,将cl_uint指针和NULL传递给num_platforms和platforms参数。num_platforms即为可用平台的数量。第二次调用,将num_entries平台分配足够空间夫人地址传递给函数的cl_platform_id指针。
clGetPlatformInfo
API函数clGetDeviceIDs()获取指定平台上设备的数量。
cl_int clGetDeviceIDs(cl_platorm_id platform, cl_device_type device_type, cl_device_id *devices, cl_uint *num_devices)
从示例代码中看出cl_device_type的类型有:CL_DEVICE_TYPE_CPU、CL_DEVICE_TYPE_GPU、CL_DEVICE_TYPE_ACCELERATOR。
三个平台:NVIDIA CUDA、Intel® OpenCL、Experimental OpenCL 2.1 CPU Only Platform
对于Intel® OpenCL的详细设备情况:有一个CPU和一个GPU。
对于NVIDIA CUDA的详细设备情况:一个GPU。
对于Experimental OpenCL 2.1 CPU Only Platform的详细设备情况:只有一个CPU
错误处理:
#define CAPSBASIC_CHECK_ERRORS(ERR) \
if(ERR != CL_SUCCESS) \
{ \
cerr \
<< "OpenCL error with code " << ERR \
<< " happened in file " << __FILE__ \
<< " at line " << __LINE__ \
<< ". Exiting...\n"; \
exit(1); \
}
通过宏定义对错误代码,文件和行数进行输出,并退出。
#define OCLBASIC_PRINT_TEXT_PROPERTY(NAME) \
{ \
/* When we query for string properties, first we */ \
/* need to get string length: */ \
size_t property_length = 0; \
err = clGetDeviceInfo( \
device, \
NAME, \
0, \
0, \
&property_length \
); \
CAPSBASIC_CHECK_ERRORS(err); \
/* Then allocate buffer. No need to add 1 symbol */ \
/* to store terminating zero; OpenCL takes care */ \
/* about it: */ \
char* property_value = new char[property_length]; \
err = clGetDeviceInfo( \
device, \
NAME, \
property_length, \
property_value, \
0 \
); \
CAPSBASIC_CHECK_ERRORS(err); \
cout \
<< " " << #NAME << ": " \
<< property_value << endl; \
delete [] property_value; \
}
使用宏函数:
#define OCLBASIC_PRINT_NUMERIC_PROPERTY(NAME, TYPE) \
{ \
TYPE property_value; \
size_t property_length = 0; \
err = clGetDeviceInfo( \
device, \
NAME, \
sizeof(property_value), \
&property_value, \
&property_length \
); \
assert(property_length == sizeof(property_value)); \
CAPSBASIC_CHECK_ERRORS(err); \
cout \
<< " " << #NAME << ": " \
<< property_value << endl; \
}
这里输入的TYPE是变量的类型,用于在宏定义代码中申明代码。