【问题标题】:Cuda and OpenGL InteropCuda 和 OpenGL 互操作
【发布时间】:2011-09-22 19:02:15
【问题描述】:

我一直在阅读 CUDA 文档,在我看来,每个需要与 OpenGL 接口的缓冲区都需要在 glBuffer 中创建。

根据 nvidia 编程指南,必须这样做:

GLuint positionsVBO;
struct cudaGraphicsResource* positionsVBO_CUDA;

int main() {

    // Explicitly set device
    cudaGLSetGLDevice(0);
    // Initialize OpenGL and GLUT
    ...
    glutDisplayFunc(display);
    // Create buffer object and register it with CUDA
    glGenBuffers(1, positionsVBO);
    glBindBuffer(GL_ARRAY_BUFFER, &vbo);
    unsigned int size = width * height * 4 * sizeof(float);
    glBufferData(GL_ARRAY_BUFFER, size, 0, GL_DYNAMIC_DRAW);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    cudaGraphicsGLRegisterBuffer(&positionsVBO_CUDA, positionsVBO, cudaGraphicsMapFlagsWriteDiscard);

    // Launch rendering loop
    glutMainLoop();
}
void display() {
    // Map buffer object for writing from CUDA
    float4* positions;
    cudaGraphicsMapResources(1, &positionsVBO_CUDA, 0);
    size_t num_bytes;
    cudaGraphicsResourceGetMappedPointer((void**)&positions, &num_bytes, positionsVBO_CUDA));
    // Execute kernel
    dim3 dimBlock(16, 16, 1);
    dim3 dimGrid(width / dimBlock.x, height / dimBlock.y, 1);
    createVertices<<<dimGrid, dimBlock>>>(positions, time, width, height);
    // Unmap buffer object
    cudaGraphicsUnmapResources(1, &positionsVBO_CUDA, 0);
    // Render from buffer object
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glBindBuffer(GL_ARRAY_BUFFER, positionsVBO);
    glVertexPointer(4, GL_FLOAT, 0, 0);
    glEnableClientState(GL_VERTEX_ARRAY);
    glDrawArrays(GL_POINTS, 0, width * height);
    glDisableClientState(GL_VERTEX_ARRAY);
    // Swap buffers
    glutSwapBuffers();
    glutPostRedisplay();
}
void deleteVBO() {
    cudaGraphicsUnregisterResource(positionsVBO_CUDA);
    glDeleteBuffers(1, &positionsVBO);
}

__global__ void createVertices(float4* positions, float time, unsigned int width, unsigned int height) { 
    // [....]
}

有没有办法将 cudaMalloc 创建的内存空间直接提供给 OpenGL?我已经在 cuda 上编写了工作代码,我想将我的 float4 数组直接放入 OpenGL。

如果已经有类似的代码,请说:

float4 *cd = (float4*) cudaMalloc(elements*sizeof(float4)). 
do_something<<<16,1>>>(cd);

我想通过 OpenGL 显示 do_something 的输出。

旁注:为什么 cudaGraphicsResourceGetMappedPointer 函数在每个时间步上运行?

【问题讨论】:

    标签: opengl cuda


    【解决方案1】:

    从 CUDA 4.0 开始,OpenGL 互操作是单向的。这意味着做你想做的事(运行一个将数据写入 GL 缓冲区或纹理图像的 CUDA 内核),你必须将缓冲区映射到一个设备指针,并将该指针传递给你的内核,如你的示例所示。

    至于您的旁注:每次调用 display() 时都会调用 cudaGraphicsResourceGetMappedPointer,因为每帧都会调用 cudaGraphicsMapResource。任何时候你重新映射一个资源,你都应该重新获取映射的指针,因为它可能已经改变了。为什么要重新映射每一帧?好吧,出于性能原因(尤其是在内存密集型 GL 应用程序中),OpenGL 有时会在内存中移动缓冲区对象。如果您始终保持资源映射,则它无法做到这一点,并且性能可能会受到影响。我相信 GL 虚拟化内存对象的能力和需要也是当前 GL 互操作 API 是单向的原因之一(不允许 GL 移动 CUDA 分配,因此您无法映射 CUDA 分配的设备指针到一个 GL 缓冲区对象中)。

    【讨论】:

    • 所以我想目前没有办法解决这个问题。让我们希望未来有更好的互操作性。
    • 我看不出有什么问题。是的,能够将设备指针传递给 OpenGL 以用作纹理或 VBO 会更方便,但这并不容易,我不明白为什么其他方式不起作用也是。您是否有不能让内核直接写入映射指针的用例?
    • 主要是速度问题。假设我想做一些 hpc,然后我想确定,在使用 OpenGL 缓冲区时没有任何额外的开销。而且编程会更容易:只要给 OpenGL 显卡上的地址,告诉它有多大。
    • 当指针被映射时,在使用它时不会有任何额外的开销——对于你的 CUDA 内核来说,它只是一个普通的设备指针。如果您遇到特定的速度问题,请在 NVIDIA CUDA 论坛上报告。
    • 你可能想参考这个实现:你不需要在每一帧都重新映射:github.com/nvpro-samples/gl_cuda_interop_pingpong_st
    【解决方案2】:

    有关如何使用 CUDA-GL 互操作而无需重新映射每一帧的示例,请参考此示例:

    https://github.com/nvpro-samples/gl_cuda_interop_pingpong_st

    【讨论】:

    • 链接失效
    猜你喜欢
    • 2013-04-30
    • 2011-12-03
    • 2013-10-15
    • 2013-04-04
    • 2016-01-25
    • 2011-07-23
    • 2014-05-11
    • 2015-08-03
    相关资源
    最近更新 更多