Cuda与OpenGL互操作

Cuda与OpenGL互操作,opengl,cuda,Opengl,Cuda,我一直在阅读CUDA文档,在我看来,每个需要与OpenGL接口的缓冲区都需要在glBuffer中创建 根据英伟达编程指南,必须这样做: GLuint positionsVBO; struct cudaGraphicsResource* positionsVBO_CUDA; int main() { // Explicitly set device cudaGLSetGLDevice(0); // Initialize OpenGL and GLUT ...

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

根据英伟达编程指南,必须这样做:

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) { 
    // [....]
}
GLuint位置svbo;
结构cudaGraphicsResource*位置SVBO_CUDA;
int main(){
//显式设置设备
cudaGLSetGLDevice(0);
//初始化OpenGL和GLUT
...
glutDisplayFunc(显示器);
//创建缓冲区对象并向CUDA注册
glGenBuffers(1,位置svbo);
glBindBuffer(GL_数组_缓冲区和vbo);
无符号整数大小=宽度*高度*4*sizeof(浮点);
glBufferData(GL\ U数组\ U缓冲区,大小,0,GL\ U动态\ U绘图);
glBindBuffer(GL_数组_BUFFER,0);
cudaGraphicsGLRegisterBuffer(&positionsVBO_CUDA,positionsVBO,cudaGraphicsMapFlagsWriteDiscard);
//启动渲染循环
glutMainLoop();
}
无效显示(){
//用于从CUDA写入的映射缓冲区对象
4*个职位;
cudaGraphicsMapResources(1,和positionsVBO_CUDA,0);
大小\u t数量\u字节;
cudaGraphicsResourceGetMappedPointer((void**)和positions,&num_字节,positionsVBO_CUDA));
//执行内核
dim3 dimBlock(16,16,1);
dim3 dimGrid(宽度/dimBlock.x,高度/dimBlock.y,1);
创建顶点(位置、时间、宽度、高度);
//取消映射缓冲区对象
CudAgraphic SunMapResources(1,和positionsVBO_CUDA,0);
//从缓冲区对象渲染
glClear(GL_颜色_缓冲_位| GL_深度_缓冲_位);
glBindBuffer(GL_数组_BUFFER,positionsVBO);
glvertexofinter(4,GL_FLOAT,0,0);
glEnableClientState(GL_顶点_数组);
glDrawArrays(GLU点,0,宽度*高度);
glDisableClientState(GL_顶点_数组);
//交换缓冲区
glutSwapBuffers();
再发现();
}
void deleteVBO(){
cudaGraphicsUnregisterResource(位置为Bo_CUDA);
glDeleteBuffers(1和位置SVBO);
}
__全局\uuuuvoid createVertices(浮点4*位置、浮点时间、无符号整数宽度、无符号整数高度){
// [....]
}
有没有办法将Cudamaloc创建的内存空间直接提供给OpenGL?我已经在cuda上编写了工作代码,我想把我的float4数组直接放到OpenGL中

如果您已经有如下代码:

float4 *cd = (float4*) cudaMalloc(elements*sizeof(float4)). 
do_something<<<16,1>>>(cd);
float4*cd=(float4*)cudamaloc(elements*sizeof(float4))。
做点什么(cd);
我想通过OpenGL显示do_something的输出


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

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


至于您的旁注:每次调用display()时都会调用cudaGraphicsResourceGetMappedPointer,因为每一帧都会调用CudaGraphicsPresource。无论何时重新映射资源,都应该重新获取映射的指针,因为它可能已更改。为什么要重新映射每个帧?由于性能原因,OpenGL有时会在内存中移动缓冲区对象(特别是在内存密集型GL应用程序中)。如果您一直保持资源映射,它就无法做到这一点,性能可能会受到影响。我相信GL虚拟化内存对象的能力和需要也是当前GL interop API是单向的原因之一(GL不允许移动CUDA分配,因此您无法将CUDA分配的设备指针映射到GL缓冲区对象).

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


所以我想目前没有办法解决这个问题。让我们期待未来更好的互操作。我看不出有什么问题。是的,也可以将设备指针传递到OpenGL以用作纹理或VBO,这会更方便,但这并不是那么容易,我不明白为什么另一种方法不起作用。您是否有不能让内核直接写入映射指针的用例?这主要是一个速度问题。假设我想做一些hpc,然后我想确定,在使用OpenGL缓冲区时没有任何额外的开销。编程也会更容易:只需给OpenGL图形卡上的地址并告诉它它有多大。虽然指针被映射,但在使用它时不会有任何额外的开销——对于CUDA内核来说,它只是一个常规的设备指针。如果你遇到了一个特定的速度问题,请在英伟达CUDA论坛上报告。你可能想引用这个实现:你不需要在每一帧重新映射:链接被破坏了。