1,336
社区成员




这篇文章最初发表在 NVIDIA 技术博客上。有关此类的更多内容,请参阅最新的 模拟/建模/设计 新闻和教程。
OpenCL 正在改进与其他 API (如 Vulkan )的互操作方式。本文向您介绍了最新的 OpenCL 互操作风格,最新的 NVIDIA 驱动程序已经支持这种风格。我们提供了可下载的示例代码,所以您今天可以尝试这个新功能。
开发人员通常将 OpenCL for compute 与其他 API (如 OpenGL )一起使用,以访问包括图形渲染在内的功能。 OpenCL 长期以来一直支持通过扩展与 OpenGL 、 OpenGL ES 、 EGL 、 Direct3D 10 和 Direct3D 11 共享隐式缓冲区和图像对象:
新一代 GPU API (如 Vulkan )使用对外部内存的显式引用以及信号量来协调对共享资源的访问。到目前为止,还没有 OpenCL 扩展来支持外部内存和信号量与这类新的 API 共享。
OpenCL 和 Vulkan 之间的互操作在移动和桌面平台上都有很强的需求。 NVIDIA 与 Khronos OpenCL 工作组密切合作,发布了一套临时跨供应商的 KHR 扩展。这些扩展使应用程序能够在 OpenCL 和 Vulkan 等 API 之间高效地共享数据,与使用隐式资源的前一代互操作 API 相比,灵活性显著提高。
这组新的外部内存和信号量共享扩展提供了一个通用框架,使 OpenCL 能够使用 Vulkan 开发人员熟悉的方法导入外部 API 导出的外部内存和信号量句柄。然后, OpenCL 使用这些信号量来同步外部运行时,协调共享内存的使用。
图 1 。 OpenCL 与 Vulkan 软件的互操作关系
然后可以添加特定于 API 的外部互操作扩展,以处理与特定 API 交互的细节。 Vulkan 互操作现在可用,并计划使用其他 API ,如 DirectX 12 。
OpenCL 新的外部信号量和内存共享功能包括单独的一组精心构造的扩展。
这组扩展增加了从操作系统特定的信号量句柄创建 OpenCL 信号量对象的能力。
以下扩展使用特定于句柄类型的行为扩展cl_khr_external_semaphore:
这些扩展增加了从操作系统特定的内存句柄创建 OpenCL 内存对象的能力。它们的设计与 Vulkan 外部存储器扩展 VK_KHR_external_memory . 类似
以下扩展使用特定于句柄类型的行为扩展cl_khr_external_memory:
典型的互操作用例包括以下步骤。
检查所需的支持是否可用:
导入外部信号量需要cl_khr_external_semaphore。如果支持cl_khr_external_semaphore_opaque_fd,则可以使用clCreateSemaphoreWithPropertiesKHR和 OpenCL 中的 FD 句柄导入 Vulkan 导出的外部信号量。
// Get cl_devices of the platform. clGetDeviceIDs(..., &devices, &deviceCount); // Create cl_context with just first device clCreateContext(..., 1, devices, ...); // Obtain fd/win32 or similar handle for external semaphore to be imported from the other API. int fd = getFdForExternalSemaphore();// Create clSema of type cl_semaphore_khr usable on the only available device assuming the semaphore was imported from the same device. cl_semaphore_properties_khr sema_props[] = {(cl_semaphore_properties_khr)CL_SEMAPHORE_TYPE_KHR, (cl_semaphore_properties_khr)CL_SEMAPHORE_TYPE_BINARY_KHR, (cl_semaphore_properties_khr)CL_SEMAPHORE_HANDLE_OPAQUE_FD_KHR, (cl_semaphore_properties_khr)fd, 0}; int errcode_ret = 0; cl_semaphore_khr clSema = clCreateSemaphoreWithPropertiesKHR(context, sema_props, &errcode_ret);
导入图像需要cl_khr_external_memory和对图像的支持。在 OpenCL 中,通过clCreateSemaphoreWithPropertiesKHR使用 Win32 句柄导入 Vulkan 导出的外部信号量。
// Get cl_devices of the platform. clGetDeviceIDs(..., &devices, &deviceCount); // Create cl_context with just first device clCreateContext(..., 1, devices, ...); // Obtain fd/win32 or similar handle for external semaphore to be imported from the other API. void *handle = getWin32HandleForExternalSemaphore(); // Create clSema of type cl_semaphore_khr usable on the only available device assuming the semaphore was imported from the same device. cl_semaphore_properties_khr sema_props[] = {(cl_semaphore_properties_khr)CL_SEMAPHORE_TYPE_KHR, (cl_semaphore_properties_khr)CL_SEMAPHORE_TYPE_BINARY_KHR, (cl_semaphore_properties_khr)CL_SEMAPHORE_HANDLE_OPAQUE_WIN32_KHR, (cl_semaphore_properties_khr)handle, 0}; int errcode_ret = 0; cl_semaphore_khr clSema = clCreateSemaphoreWithPropertiesKHR(context, sema_props, &errcode_ret);
在 OpenCL 中,使用 FD 句柄将 Vulkan 导出的外部内存作为缓冲内存与clCreateBufferWithProperties一起导入。
// Get cl_devices of the platform.
clGetDeviceIDs(..., &devices, &deviceCount);
// Create cl_context with just first device
clCreateContext(..., 1, devices, ...);
// Obtain fd/win32 or similar handle for external memory to be imported from other API.
int fd = getFdForExternalMemory();
// Create extMemBuffer of type cl_mem from fd.
cl_mem_properties_khr extMemProperties[] =
{ (cl_mem_properties_khr)CL_EXTERNAL_MEMORY_HANDLE_OPAQUE_FD_KHR,
(cl_mem_properties_khr)fd,
0
};
cl_mem extMemBuffer = clCreateBufferWithProperties(/*context*/ clContext,
/*properties*/ extMemProperties,
/*flags*/ 0,
/*size*/ size,
/*host_ptr*/ NULL,
/*errcode_ret*/ &errcode_ret);
在 OpenCL 中,使用clCreateImageWithProperties将 Vulkan 导出的外部内存作为图像内存导入。
// Create img of type cl_mem. Obtain fd/win32 or similar handle for external memory to be imported from other API. int fd = getFdForExternalMemory(); // Set cl_image_format based on external image info cl_image_format clImgFormat = { }; clImageFormat.image_channel_order = CL_RGBA; clImageFormat.image_channel_data_type = CL_UNORM_INT8; // Set cl_image_desc based on external image info size_t clImageFormatSize; cl_image_desc image_desc = { }; image_desc.image_type = CL_MEM_OBJECT_IMAGE2D_ARRAY; image_desc.image_width = width; image_desc.image_height = height; image_desc.image_depth = depth; cl_mem_properties_khr extMemProperties[] = { (cl_mem_properties_khr)CL_EXTERNAL_MEMORY_HANDLE_OPAQUE_FD_KHR, (cl_mem_properties_khr)fd, 0 }; cl_mem img = clCreateImageWithProperties(/*context*/ clContext, /*properties*/ extMemProperties, /*flags*/ 0, /*image_format*/ &clImgFormat, /*image_desc*/ &image_desc, /*errcode_ret*/ &errcode_ret)
使用信号量 wait 和 signal 在 OpenCL 和 Vulkan 之间同步。
// Create clSema using one of the above examples of external semaphore creation. int errcode_ret = 0; cl_semaphore_khr clSema = clCreateSemaphoreWithPropertiesKHR(context, sema_props, &errcode_ret); while (true) { // (not shown) Signal the semaphore from the other API, // Wait for the semaphore in OpenCL clEnqueueWaitSemaphoresKHR( /*command_queue*/ command_queue, /*num_sema_objects*/ 1, /*sema_objects*/ &clSema, /*num_events_in_wait_list*/ 0, /*event_wait_list*/ NULL, /*event*/ NULL); clEnqueueNDRangeKernel(command_queue, ...); clEnqueueSignalSemaphoresKHR(/*command_queue*/ command_queue, /*num_sema_objects*/ 1, /*sema_objects*/ &clSema, /*num_events_in_wait_list*/ 0, /*event_wait_list*/ NULL, /*event*/ NULL); // (not shown) Launch work in the other API that waits on 'clSema'
您可以使用可下载的 sample code 以及 NVIDIA R510 (或更高版本)驱动程序,尝试新的 NVIDIA OpenCL 实现 Vulkan 互操作:
有关更多信息,请参阅 Khronos 发布了用于神经网络推理和 OpenCL / Vulkan 互操作的 OpenCL 3.0 扩展 .