我每次使用一个OpenCL内核调用以每秒60次的速度在OpenCL中生成帧,并将它们写入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);
我很难说出是什么原因造成的,因为nvopencl64.dll在另一个线程中运行了CPU占用率很高(当我在装有nVidia GPU的Windows 10机器上运行它时,但是我也遇到了类似的问题装有Intel iGPU的笔记本电脑(也适用于Windows 10)。
分析告诉我,大部分CPU时间由nvopencl64.dll调用的WaitForSingleObjectEx
(占CPU时间的42%),nvoglv64.dll的WaitForMultipleObjects
(占21%)占用的时间{1}}和发起上述DrvPresentBuffers
调用的RtlUserThreadStart
(16%)调用。那是给我的nVidia GPU机器使用的,但是在只有Intel HD 5000 iGPU的机器上情况看起来很相似。因此,显然发生了一些效率很低的事情,可能是因为太多的线程启动得太频繁了。
答案 0 :(得分:2)
似乎CL_DEVICE_PREFERRED_INTEROP_USER_SYNC
为false时,不需要进行与clEnqueueAcquireGLObjects
和clEnqueueReleaseGLObjects
的手动同步,除了在初始化OpenGL纹理后进行一次clEnqueueAcquireGLObjects
调用之外。在那种情况下,glFinish
似乎是唯一需要的同步形式。