【问题标题】:Handling Multiple OpenCL Versions and Platforms处理多个 OpenCL 版本和平台
【发布时间】:2014-09-11 19:26:59
【问题描述】:

英特尔最近将其 OpenCL SDK 更新为 2.0 规范。 AMD 仍在 1.2 上,Nvidia 在 1.1 上。从本质上讲,这意味着每个 GPU 平台现在都有自己的版本。

就弃用的工作方式而言,OpenCL 的设计方式似乎与 OpenGL 不同。据我所知,无法请求兼容版本,英特尔甚至在其 SDK 中包含构建错误,阻止您调用已弃用的函数。

如果我想使用最低版本(最有可能是 1.1)支持每个平台,我需要什么?

【问题讨论】:

  • 如果您只想要 OpenCL 1.1,请使用 Nvidia SDK。也许您指的是驱动程序之间的不兼容? SDK 和 OpenCL 驱动程序不是一回事。 SDK 用于主机上的编译时代码。 OpenCL 设备驱动程序 (ICD) 用于设备上的运行时(尽管设备会编译代码然后运行)。
  • @zboson 我知道区别,我只是希望它以 gl 标头的工作方式工作 - 您在运行时请求版本,而不是编译时。 CL 似乎正好相反。我现在唯一的问题是:我可以在 1.2 或 2.0 驱动程序上使用 1.1 API 吗?

标签: opencl


【解决方案1】:

不幸的是,如果您有多个平台,并且它们支持不同的 OpenCL 版本,那么只制作 ifdef 语句将不起作用。比如安装在 CPU 上的 POCL 支持 2.0,所以你需要有 2.0 的 OpenCL 头文件,但大多数 GPU 和开源驱动程序只支持 OpenCL 1.1 或 1.2。

最好的选择似乎是获取 OpenCL 平台版本信息,并以此为基础调用什么命令。不幸的是,它是一个 char[],所以可能必须将它解析出来。

这是一个如何获取平台信息字符串的示例。

clGetPlatformInfo(platforms[platform_indexFinger], CL_PLATFORM_VERSION, INFO_LENGTH, &platformInfo, &realSize);

版本信息通常采用以下形式:“OpenCL 1.2 implementation name”

这是我用来诊断当前opencl编号的一个小函数

浮动诊断OpenCLnumber(cl_platform_id平台){ #define VERSION_LENGTH 64 字符完整版本[VERSION_LENGTH]; size_t 实际尺寸 = 0; clGetPlatformInfo(平台,CL_PLATFORM_VERSION,VERSION_LENGTH, &complete_version, &realSize); 字符版本[4]; 版本[3] = 0; memcpy(版本, &complete_version[7], 3); // printf("V %s %f\n", version, version_float); float version_float = atof(version); 返回版本浮动; }

然后可以像这样使用它,例如与为 2.0 修改的命令队列功能一起使用

float version_float = 诊断OpenCLnumber(platform_id); if (version_float >= 2.0) { command_waiting_line = clCreateCommandQueueWithProperties(context, device_id, 0, &return_number); 别的 { #pragma GCC 诊断推送 #pragma GCC 诊断忽略“-Wdeprecated-declarations” command_waiting_line = clCreateCommandQueue(context, device_id, 0, &return_number); #pragma GCC 诊断弹出 }

【讨论】:

    【解决方案2】:

    AFAIK 已弃用的函数不必实现,因此代码应检查 OpenCL 平台版本号并避免在该平台上调用已弃用的函数。请参阅之前的讨论:http://www.khronos.org/message_boards/showthread.php/8514-clCreateImage-2D-3D-vs-the-ICD-loader。目前,在 AMD 或 Intel 平台 (OpenCL 1.2) 上调用已弃用的 OpenCL 1.1 函数仍然有效,但不能保证将来或在其他平台上仍然如此。我想一旦支持那些已弃用的功能对实现的维护者来说太麻烦了,它们就会被删除。

    诚然,我很顽皮,因为我只是忽略了这个问题并继续使用 OpenCL 1.1 功能。但是,如果您正在开始一个新项目(并且有时间),那么宁愿将不推荐使用的函数包装在某种通用函数中,该函数具有每个版本的 OpenCL 的路径——在我看来,现在比以后更快。 http://www.khronos.org/opencl/resources 有一个框架和库列表。也许你会发现其中一个已经足够好地解决了这个问题。如果没有,并且如果您有足够的时间,那么您可以构建一个框架,将大部分 OpenCL 函数从您的程序中隐藏起来。然后,随着越来越多的功能被弃用,您希望只需要更改您的框架,而不是使用它的程序。目前,我不知道有任何框架可以在 C++ 中执行此操作。

    【讨论】:

    • Boost.Compute 为 C++ 执行此操作。它在编译时查看头文件支持的 OpenCL 版本,在运行时查看设备支持的 OpenCL 版本,并将调用适当的函数。
    • @KyleLutz 很高兴听到您确实透明地处理了这个问题。我只是快速浏览了 API 文档,对您添加的函数数量印象深刻。我唯一没有看到的是 OpenCL 图像对象。目前是否支持,或者将来会支持?
    • 是的,图像对象受支持,但尚未完全记录。请参阅image2d 类。此外,example 目录下还有一些使用图像 API 的示例。
    【解决方案3】:

    在头文件 cl.h 中,您会找到如下定义列表:

    ...
    #define CL_VERSION_1_0   1
    #define CL_VERSION_1_1   1
    #define CL_VERSION_1_2   1
    #define CL_VERSION_2_0   1
    ...
    

    就我而言,如果我使用 OpenCL 2.0 进行构建,我会收到关于已弃用函数的烦人警告。所以我的快速/肮脏的解决方案是做

    #ifdef CL_VERSION_2_0 
        //call 2.0 Function
    #else
        //call deprecated Function
    #endif
    

    虽然这可能需要在您的代码中进行多次修复,但如果您想基于可用的 opencl 库进行编译,这对我来说是一种方式。
    请注意,如果您使用的是 opencl 1.2,您将获得所有先前版本的定义(就像上面示例中的 CL_VERSION_1_1 和 CL_VERSION_1_0 也将被定义)
    希望这会有所帮助

    【讨论】: