以下问题已在 nvidia 的新驱动程序版本 331.xx 中得到修复,目前可作为测试版驱动程序使用。
谢谢你们的评论!
我有一个多平台应用程序,可以在 OpenGL 纹理上执行许多片段操作和 gpgpu 内容。该应用程序大量使用 GL/CL 互操作,每个纹理都可以绑定到 OpenCL 图像并使用 CL 内核进行操作。
问题是,该应用程序在 Linux 和 Windows 的 AMD 卡上运行速度很快。在 NVIDIA 卡上,它在 Linux 上运行速度很快,但在 Windows 7 上运行速度很慢。问题似乎是 enqueueAcquireGLObjects 和 enqueueReleaseGLObjects。我创建了一个最小的样本,简单地展示了糟糕的性能:
- 创建 2 个 OpenGL 纹理(1600x1200 像素,RGBA 浮点数)
- 创建 2 个 OpenCL 图像,共享 2 个纹理
- 反复(50 次)获取、释放、完成
结果(执行获取、发布、完成的平均时间)
- AMD HD 6980,Linux:<0.1 毫秒
- AMD HD 6980、Win7:<0.1 毫秒
- NVIDIA GTX590,Linux:<0.1 毫秒
- 英伟达 GTX590,Win7:16.0 毫秒
我尝试了几个来自 nvidia 的不同驱动程序,从旧的 295.73 到当前的 beta 驱动程序 326.80,都显示出相同的行为。
我现在的问题是,nvidia 驱动程序严重损坏还是我在这里做错了什么?该代码在 linux 上运行速度很快,因此它不会是 nvidia 对 OpenCL 支持的普遍问题。该代码在 AMD+Win 上运行速度很快,因此我的代码没有针对 Windows 进行优化不会是问题。例如,通过将 cl 图像更改为只读/只写来优化代码是没有意义的,因为性能损失几乎是 30 倍!
您可以在下面找到我的测试用例的相关代码,我也可以提供完整的源代码。
上下文创建的相关代码
{ // initialize GLEW
glewInit();
}
{ // initialize CL Context, sharing GL Contet
std::vector<cl::Platform> platforms;
cl::Platform::get(&platforms);
cl_context_properties cps[] = {
CL_GL_CONTEXT_KHR,(cl_context_properties)wglGetCurrentContext(),
CL_WGL_HDC_KHR,(cl_context_properties)wglGetCurrentDC(),
CL_CONTEXT_PLATFORM, (cl_context_properties)(platforms[0]()),
0};
std::vector<cl::Device> devices;
platforms[0].getDevices((cl_device_type)CL_DEVICE_TYPE_GPU, &devices);
context_ = new cl::Context(devices, cps, NULL, this);
queue_ = new cl::CommandQueue(*context_, devices[0]);
}
用于创建纹理和共享 CL 图像的相关代码
width_ = 1600;
height_ = 1200;
float *data = new float[ 1600*1200*4 ];
textures_.resize(2);
glGenTextures(2, textures_.data());
for (int i=0;i<2;i++) {
glBindTexture(GL_TEXTURE_2D, textures_[i]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// "data" pointer holds random/uninitialized data, do not care in this example
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F_ARB, width_,height_, 0, GL_RGBA, GL_FLOAT, data);
}
delete data;
{ // create shared CL Images
#ifdef CL_VERSION_1_2
clImages_.push_back(cl::ImageGL(*context_, CL_MEM_READ_WRITE, GL_TEXTURE_2D, 0, textures_[0]));
clImages_.push_back(cl::ImageGL(*context_, CL_MEM_READ_WRITE, GL_TEXTURE_2D, 0, textures_[1]));
#else
clImages_.push_back(cl::Image2DGL(*context_, CL_MEM_READ_WRITE, GL_TEXTURE_2D, 0, textures_[0]));
clImages_.push_back(cl::Image2DGL(*context_, CL_MEM_READ_WRITE, GL_TEXTURE_2D, 0, textures_[1]));
#endif
}
一个获取、发布、完成周期的相关代码
try {
queue_->enqueueAcquireGLObjects( &clImages_ );
queue_->enqueueReleaseGLObjects( &clImages_ );
queue_->finish();
} catch (cl::Error &e) {
std::cout << e.what() << std::endl;
}