OpenCL/OpenGL 互操作浪费 CPU

6
我每秒使用一个OpenCL内核调用生成帧,并将它们写入OpenGL纹理以在屏幕上显示。没有性能问题,帧率在预期范围内,但问题在于它非常浪费资源,即使是像在低分辨率绘制空白帧这样的轻负载任务也会使至少一个CPU核心保持高负载。相比之下,当我不使用OpenGL interop而直接从CL内核将内容写入通用缓冲区,然后将该缓冲区复制回主机以另一种方式显示时,帧率会略微降低(由于来回传输的开销),但是小工作量情况下CPU使用率要低得多。
这意味着我做interop的方式有问题,可能会创建某种繁忙等待。以下是相关代码,当我使用interop时出现,当我不使用时则不存在。在循环中的一个位置,我会清除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使用率,因为高CPU使用率在由nvopencl64.dll运行的另一个线程中(当我在我的Windows 10机器上使用nVidia GPU运行它时,但我也遇到了类似的问题在一个只有Intel iGPU的笔记本电脑上,在Windows 10上)。

性能分析告诉我,大部分CPU时间都被WaitForSingleObjectEx (独占42%的CPU时间)从nvopencl64.dll调用,WaitForMultipleObjects (21%)从nvoglv64.dll的 DrvPresentBuffers 调用,并且RtlUserThreadStart(16%)调用即上述WaitForMultipleObjects调用的起点。对于我的nVidia GPU机器来说,情况看起来非常类似于只有Intel HD 5000 iGPU的机器。因此,显然存在一些非常低效的问题,可能会经常启动许多线程。


2
似乎GPU不想讓你做你所做的事情。 clGetDeviceInfo(CL_DEVICE_PREFERRED_INTEROP_USER_SYNC) 返回CL_FALSE嗎? - hidefromkgb
2
好的,那么您的GPU不需要手动同步。尝试删除clEnqueueAcquireGLObjectsclEnqueueReleaseGLObjects,看看会发生什么。顺便说一下,您是否正在使用clCreateFromGLTexture将GL纹理传递给CL? - hidefromkgb
2
现在这真是很奇怪...大约明天我会尝试在我的电脑上执行你的代码,以便自己验证。 - hidefromkgb
2
谢谢!你有构建代码吗?也许我写的指令不是很清楚。无论如何,我只是尝试使用单个clEnqueueAcquireGLObjects()调用跟随clCreateFromGLTexture()调用,这样可以修复问题,同时仅使用约2%的CPU使用率(而不是1或2个完整核心),同时仍以60 FPS运行,这似乎是最佳的。我猜这就是当CL_DEVICE_PREFERRED_INTEROP_USER_SYNC给我们0时必须完成的工作。由于你暗示了这个解决方案并且有赏金,所以你应该写出答案。感谢你的帮助! - Michel Rouzic
2
很遗憾,昨天我无法编译它。但是无论如何,你似乎已经自己解决了问题,所以赏金不属于我。请回答你自己的问题(这是允许和鼓励的),以便任何可能在寻找这个问题的答案而感到苦恼的人受益 =) - hidefromkgb
显示剩余7条评论
1个回答

3

看起来当CL_DEVICE_PREFERRED_INTEROP_USER_SYNC为false时,除了在OpenGL纹理初始化之后需要一次clEnqueueAcquireGLObjects调用外,不需要手动同步clEnqueueAcquireGLObjectsclEnqueueReleaseGLObjects。在这种情况下,似乎glFinish是唯一需要的同步形式。


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