CUDA/OpenGL交互,使用CUDA将绘制内容输出到OpenGL纹理

18

我正在使用CUDA编写渲染系统,希望通过OpenGL快速显示结果,而不触及主内存。我的基本思路如下:

创建并初始化OpenGL纹理,并将其在CUDA中注册为cudaGraphicsResource。

GLuint viewGLTexture;
cudaGraphicsResource_t viewCudaResource;

void initialize() {
    glEnable(GL_TEXTURE_2D);
    glGenTextures(1, &viewGLTexture);

    glBindTexture(GL_TEXTURE_2D, viewGLTexture); 
    {
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, view.getWidth(), view.getHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
    } 
    glBindTexture(GL_TEXTURE_2D, 0);

    cudaGraphicsGLRegisterImage(&viewCudaResource, viewGLTexture, GL_TEXTURE_2D, cudaGraphicsRegisterFlagsWriteDiscard)
}

每当视图被调整大小时,我会相应地调整视口和纹理图像的大小:

void resize() {
    glViewport(0, 0, view.getWidth(), view.getHeight());

    glBindTexture(GL_TEXTURE_2D, viewGLTexture); 
    {
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, view.getWidth(), view.getHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
    } 
    glBindTexture(GL_TEXTURE_2D, 0);
}

然后我将graphicsResource映射为cudaArray上的cudaSurfaceObject,对其调用渲染内核,在渲染完成后取消映射并同步以便让OpenGL使用此纹理绘制全屏四边形:

void renderFrame() {
    cudaGraphicsMapResources(1, &viewCudaResource); 
    {
        cudaArray_t viewCudaArray;
        cudaGraphicsSubResourceGetMappedArray(&viewCudaArray, viewCudaResource, 0, 0);
        cudaResourceDesc viewCudaArrayResourceDesc;
        {
            viewCudaArrayResourceDesc.resType = cudaResourceTypeArray;
            viewCudaArrayResourceDesc.res.array.array = viewCudaArray;
        }
        cudaSurfaceObject_t viewCudaSurfaceObject;
        cudaCreateSurfaceObject(&viewCudaSurfaceObject, &viewCudaArrayResourceDesc); 
        {
            invokeRenderingKernel(viewCudaSurfaceObject);
        } 
        cudaDestroySurfaceObject(viewCudaSurfaceObject));
    } 
    cudaGraphicsUnmapResources(1, &viewCudaResource);

    cudaStreamSynchronize(0);

    glBindTexture(GL_TEXTURE_2D, viewGLTexture); 
    {
        glBegin(GL_QUADS); 
        {
            glTexCoord2f(0.0f, 0.0f); glVertex2f(-1.0f, -1.0f);
            glTexCoord2f(1.0f, 0.0f); glVertex2f(+1.0f, -1.0f);
            glTexCoord2f(1.0f, 1.0f); glVertex2f(+1.0f, +1.0f);
            glTexCoord2f(0.0f, 1.0f); glVertex2f(-1.0f, +1.0f);
        } 
        glEnd();
    }
    glBindTexture(GL_TEXTURE_2D, 0);

    glFinish();
}

问题是:每当视图被调整大小时,所有CUDA调用都开始喷出“未知错误”,并且在视觉上看来,纹理实际上没有被调整大小,只是跨越整个视图被拉伸。为什么会发生这种情况,我该如何解决?


cudaStreamSynchronize(0); 必要吗? - gpu
1个回答

16

似乎在Interop中,需要重新注册纹理以便在调整大小时使用。以下代码可以实现此功能:

void resize() {
    glViewport(0, 0, view.getWidth(), view.getHeight());

        // unregister
    cudaGraphicsUnregisterResource(viewCudaResource);
        // resize
    glBindTexture(GL_TEXTURE_2D, viewGLTexture);
    {
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, view.getWidth(), view.getHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
    }
    glBindTexture(GL_TEXTURE_2D, 0);
        // register back
    cudaGraphicsGLRegisterImage(&viewCudaResource, viewGLTexture, GL_TEXTURE_2D, cudaGraphicsRegisterFlagsWriteDiscard);
}

能否通过cudaSurface_t将数据写入OpenGL的默认后备缓冲区GL_BACK?谢谢! - gpu
应该使用cudaGraphicsRegisterFlagsWriteSurfaceLoadStore而不是cudaGraphicsRegisterFlagsWriteDiscard吗? - gpu
1
@gpu兄弟,已经快10年了,我自从没和cuda一起工作过。我不知道是否可以直接写入帧缓冲区。至于DiscardSurfaceLoadStore,我很确定对于我所需的用例(即每帧重新绘制整个纹理)使用discard是正确的。 - yuri kilochek
https://stackoverflow.com/questions/16765895/what-is-the-use-case-of-cudagraphicsregisterflagswritediscard-in-cudagraphicsglr - gpu
https://stackoverflow.com/questions/76532086/which-is-faster-glblitframebuffer-a-renderbuffer-or-render-a-fullscreen-texture - gpu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接