【问题标题】:OpenCL/OpenGL interop wasting CPUOpenCL/OpenGL 互操作浪费 CPU
【发布时间】:2019-11-05 16:21:19
【问题描述】:

我每次使用一个 OpenCL 内核调用在 OpenCL 中生成帧 60 次,并将它们写入 OpenGL 纹理,以便我可以在屏幕上显示它们。没有性能问题,帧率符合预期,但问题是它非常浪费,它至少保持一个 CPU 核心完全忙碌,即使它几乎没有什么可做的,比如以非常低的分辨率绘制空白帧.为了进行比较,当我不使用 OpenGL 互操作而是从 CL 内核写入通用缓冲区,然后将该缓冲区复制回主机然后以另一种方式显示它时,帧速率会下降一点(由于后面和互操作不必要的第四个开销),但是当无事可做时,CPU使用率要低得多。

这意味着我执行互操作的方式有问题,我认为必须创建某种繁忙的等待。

这是相关代码,这是我使用互操作时的代码,而不是我不使用它时的代码。在我循环的一个地方,我清除了 GL 纹理并让 OpenCL 获取它:

    uint32_t z = 0;
    glClearTexImage(fb.gltex, 0, GL_RGBA, GL_UNSIGNED_BYTE, &z);
    glFlush();
    glFinish();

    clEnqueueAcquireGLObjects(fb.clctx.command_queue, 1,  &fb.cl_srgb, 0, 0, NULL);

然后我将我的 OpenCL 内核的执行排入队列,该内核将写入纹理作为 cl_mem 对象 fb.cl_srgb,然后我将控制权交还给 OpenGL,以便在显示器上显示纹理:

    clEnqueueReleaseGLObjects(fb.clctx.command_queue, 1, &fb.cl_srgb, 0, 0, NULL);
    clFinish(fb.clctx.command_queue);   // this blocks until the kernel is done writing to the texture and releasing the texture

    // setting GL texture coordinates, probably not relevant to this question
    float hoff = 2. * (fb.h - fb.maxdim.y) / (double) fb.maxdim.y;
    glLoadIdentity();             // Reset the projection matrix
    glViewport(0, 0, fb.maxdim.x, fb.maxdim.y);

    glBegin(GL_QUADS);
    glTexCoord2f(0.f, 0.f); glVertex2f(-1., 1.+hoff);
    glTexCoord2f(1.f, 0.f); glVertex2f(1., 1.+hoff);
    glTexCoord2f(1.f, 1.f); glVertex2f(1., -1.+hoff);
    glTexCoord2f(0.f, 1.f); glVertex2f(-1., -1.+hoff);
    glEnd();

    SDL_GL_SwapWindow(fb.window);

我很难说出是什么原因造成的,因为高 CPU 使用率是在另一个由 nvopencl64.dll 运行的线程中(当我在带有 nVidia GPU 的 Windows 10 机器上运行它时,但我遇到了类似的问题)配备 Intel iGPU 的笔记本电脑,同样在 Windows 10 上)。

分析告诉我,大部分 CPU 时间由从 nvopencl64.dll 调用的 WaitForSingleObjectEx(独占 CPU 时间的 42%)、从 nvoglv64.dll 的 DrvPresentBuffers 调用的 WaitForMultipleObjects(21%)和RtlUserThreadStart (16%) 来自上述WaitForMultipleObjects 呼叫的呼叫。这适用于我的 nVidia GPU 机器,但在只有 Intel HD 5000 iGPU 的机器上情况看起来非常相似。因此,显然有一些非常低效的事情正在发生,可能是因为太多线程启动得太频繁了。

【问题讨论】:

  • 似乎 GPU 不希望你做你做的事。 clGetDeviceInfo(CL_DEVICE_PREFERRED_INTEROP_USER_SYNC) 是否返回 CL_FALSE?
  • 好的,所以您的 GPU 不需要手动同步。尝试删除 clEnqueueAcquireGLObjects 和 clEnqueueReleaseGLObjects 看看会发生什么。顺便说一句,您是否使用clCreateFromGLTexture 将 GL 纹理传递给 CL?
  • 现在这很好奇......明天的某个地方我会尝试在我的机器上执行你的代码,以亲自查看。
  • 谢谢!你开始构建代码了吗?也许我写的说明不是很清楚。无论如何,我只是尝试使用单个 clEnqueueAcquireGLObjects() 调用来跟踪 clCreateFromGLTexture() 调用,而没有进一步的互操作调用,这解决了问题,在仍然运行时只给了我大约 2% 的 CPU 使用率(而不是 1 或 2 个完整内核) 60 FPS,这似乎是最佳的。我想这就是CL_DEVICE_PREFERRED_INTEROP_USER_SYNC 给我们 0 时必须做的事情。既然您暗示了该解决方案并且有赏金,您应该写下答案。感谢您的帮助!
  • 不幸的是我昨天无法编译它。但无论如何,你似乎已经自己解决了这个问题,所以赏金不应该是我的。请回答您自己的问题(这是允许和鼓励的),以帮助任何可能正在寻找这个问题的答案的人=)

标签: opengl opencl


【解决方案1】:

似乎当CL_DEVICE_PREFERRED_INTEROP_USER_SYNC 为假时,不需要与clEnqueueAcquireGLObjects 和clEnqueueReleaseGLObjects 手动同步,除了在初始化OpenGL 纹理后调用clEnqueueAcquireGLObjects。在这种情况下,glFinish 似乎是唯一需要的同步形式。

【讨论】:

    猜你喜欢
    • 2013-07-27
    • 1970-01-01
    • 1970-01-01
    • 2012-04-12
    • 2013-07-31
    • 2016-08-18
    • 1970-01-01
    • 1970-01-01
    • 2016-10-31
    相关资源
    最近更新 更多