以下の問題は、nvidia の新しいドライバー リリース 331.xx で修正されており、現在ベータ ドライバーとして利用できます。
コメントありがとうございます!
OpenGL テクスチャで多くのフラグメント操作と gpgpu を実行するマルチプラットフォーム アプリケーションがあります。アプリケーションは GL/CL 相互運用機能を多用し、各テクスチャは OpenCL イメージにバインドされ、CL カーネルを使用して操作されます。
問題は、アプリケーションが Linux と Windows の両方の AMD カードで高速に動作することです。NVIDIA カードでは、Linux では高速に動作しますが、Windows 7 では非常に遅くなります。問題は enqueueAcquireGLObjects と enqueueReleaseGLObjects のようです。最小限のサンプルを作成し、単純にパフォーマンスの低下を示しました。
- 2 つの OpenGL テクスチャの作成 (1600x1200 ピクセル、RGBA float)
- 2 つの OpenCL イメージを作成し、2 つのテクスチャを共有する
- 繰り返し (50 回) 取得、解放、終了
結果(取得、解放、終了の平均実行時間)
- AMD HD 6980、Linux: <0.1 ミリ秒
- AMD HD 6980、Win7: <0.1 ミリ秒
- NVIDIA GTX590、Linux: <0.1 ミリ秒
- NVIDIA GTX590、Win7 : 16.0 ミリ秒
古い295.73から現在のベータドライバー326.80まで、nvidiaのいくつかの異なるドライバーを試しましたが、すべて同じ動作を示しました。
私の質問は、nvidiaドライバーが深刻に壊れているのか、それともここで何か間違ったことをしているのですか? コードは Linux で高速に実行されるため、OpenCL の nvidia サポートに関する一般的な問題にはなりません。コードは 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
}
1 つの取得、リリース、終了サイクルに関連するコード
try {
queue_->enqueueAcquireGLObjects( &clImages_ );
queue_->enqueueReleaseGLObjects( &clImages_ );
queue_->finish();
} catch (cl::Error &e) {
std::cout << e.what() << std::endl;
}