使用多个GPU的OpenCL/OpenGL交互操作

9
我在使用OpenCL/OpenGL互操作时遇到了多GPU的问题。我正在尝试编写一个应用程序,以呈现密集计算的结果。最终它将运行一个优化问题,并根据结果将某些内容渲染到屏幕上。作为一个测试案例,我从这个课程中开始使用粒子模拟示例代码:http://web.engr.oregonstate.edu/~mjb/sig13/ 示例代码创建了一个OpenGL上下文,然后创建了一个OpenCL上下文,共享状态,使用cl_khr_gl_sharing扩展。当我使用单个GPU时,一切正常。创建上下文的方式如下:
3. create an opencl context based on the opengl context:
  cl_context_properties props[ ] =
  {
      CL_GL_CONTEXT_KHR, (cl_context_properties) glXGetCurrentContext( ),
      CL_GLX_DISPLAY_KHR, (cl_context_properties) glXGetCurrentDisplay( ),
      CL_CONTEXT_PLATFORM, (cl_context_properties) Platform,
      0
  };

  cl_context Context = clCreateContext( props, 1, Device, NULL, NULL, &status );
  if( status != CL_SUCCESS) 
  {
      PrintCLError( status, "clCreateContext: " );
      exit(1);
  }

稍后,示例将使用clCreateFromGLBuffer创建共享的CL/GL缓冲区。
现在,我想从两个GPU设备创建上下文:
cl_context Context = clCreateContext( props, 2, Device, NULL, NULL, &status );

我已成功打开设备,并可以查询它们都支持cl_khr_gl_sharing,且单独工作良好。然而,在尝试像上面那样创建上下文时,出现了以下问题:

CL_INVALID_OPERATION 

这是由cl_khr_gl_sharing扩展添加的错误代码。在扩展描述(上面链接的)中,它说:
CL_INVALID_OPERATION如果为CGL、EGL、GLX或WGL之一指定了上下文或共享组对象,并且满足以下任何条件:
- OpenGL实现不支持指定上下文或共享组对象的窗口系统绑定API。 - CL_CGL_SHAREGROUP_KHR、CL_EGL_DISPLAY_KHR、CL_GLX_DISPLAY_KHR和CL_WGL_HDC_KHR属性中有多个属性设置为非默认值。 - CL_CGL_SHAREGROUP_KHR和CL_GL_CONTEXT_KHR两个属性都设置为非默认值。 - 参数中指定的任何设备都不能支持共享OpenGL对象数据存储的OpenCL对象,如第9.12节所述。
这个描述似乎不完全符合我的情况。无法使用多个GPU进行OpenCL/OpenGL互操作吗?还是我有异构硬件?我从枚举设备中打印出了一些参数。我只是拿到手的两个随机GPU。
PlatformID: 18483216
Num Devices: 2

-------- Device 00 ---------
CL_DEVICE_NAME: GeForce GTX 285
CL_DEVICE_VENDOR: NVIDIA Corporation
CL_DEVICE_VERSION: OpenCL 1.0 CUDA
CL_DRIVER_VERSION: 304.88
CL_DEVICE_MAX_COMPUTE_UNITS: 30
CL_DEVICE_MAX_CLOCK_FREQUENCY: 1476
CL_DEVICE_TYPE: CL_DEVICE_TYPE_GPU

-------- Device 01 ---------
CL_DEVICE_NAME: Quadro FX 580
CL_DEVICE_VENDOR: NVIDIA Corporation
CL_DEVICE_VERSION: OpenCL 1.0 CUDA
CL_DRIVER_VERSION: 304.88
CL_DEVICE_MAX_COMPUTE_UNITS: 4
CL_DEVICE_MAX_CLOCK_FREQUENCY: 1125
CL_DEVICE_TYPE: CL_DEVICE_TYPE_GPU

cl_khr_gl_sharing is supported on dev 0.
cl_khr_gl_sharing is supported on dev 1.

请注意,如果我创建上下文时没有使用Interop部分(使props数组看起来像下面这样),那么它可以成功地创建上下文,但显然无法与应用程序的OpenGL端共享缓冲区。
cl_context_properties props[ ] =
{
   CL_CONTEXT_PLATFORM, (cl_context_properties) Platform,
   0
};

你的 OpenCL 上下文是否包含两个 GPU?为了实现在两个 GPU 之间传输数据,你需要这样做,以便一个 GPU 的结果可以由另一个 GPU 渲染。 - chippies
1
@chippies 当我尝试创建OpenCL上下文时,出现了错误。在上面的代码中,Device是一个包含两个GPU的数组。 - matth
@CaptianObvious 我正在使用在rpmfusion打包的适用于Fedora的nvidia驱动程序,看起来是四月份的版本。我将尝试从nvidia网站下载更新版本,但我对三个月内有多少变化持怀疑态度。谢谢。 - matth
@CaptainObvious 是的,我尝试了325.08 -- 结果一样。 - matth
我不能告诉你是否可以在两个不同的GPU之间共享上下文,但你肯定可以在两个相同的GPU之间共享一个上下文。你甚至可以在两个GPU和一个CPU之间共享上下文。我成功地在我的两个Nvidia GTX 460上共享了它。但我从未有机会测试异构GPU。 - Tara
显示剩余2条评论
2个回答

2
几个相关的问题和例子:

    bool stageProducer::preExecution() 
    {
        if(!glContext::getInstance().makeCurrent(_rc))
        {
            window::getInstance().messageBoxWithLastError("wglMakeCurrent");
            return false;
        }
        glBindFramebuffer(GL_DRAW_FRAMEBUFFER, _fboID);
        return true;
    }

特定于OpenCL,但与此问题相关::

“如果您在queueA(deviceA)上对缓冲区进行写入,则OpenCL将使用该设备进行写入。但是,如果您在同一上下文中在queueB(deviceB)上使用缓冲区,则OpenCL将识别到deviceA具有最新的数据,并在使用之前将其移动到deviceB。简而言之,只要使用事件确保没有两个设备同时尝试访问同一内存对象,OpenCL将确保每次使用内存对象都具有最新数据,无论最后使用它的是哪个设备。”

我假设当您排除OpenGL时,在GPU之间共享内存会按预期工作?


1
当您调用这两行代码时:
CL_GL_CONTEXT_KHR,(cl_context_properties) glXGetCurrentContext( ), CL_GLX_DISPLAY_KHR,(cl_context_properties) glXGetCurrentDisplay( ),
这些调用需要来自一个新线程和一个新的OpenGL上下文。通常情况下,每个线程一次只能将一个OpenCL上下文与一个设备的一个OpenGL上下文关联起来。

感谢您抽出时间回答这个问题。我已经有一段时间没有使用OpenCL了,也没有简单的方法来测试它,但是您的答案听起来很有道理,所以我会接受它。 - matth

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接