1

我在访问 CUDA 缓冲区时遇到问题:我注册了一个 OpenGL 缓冲区以将其与 CUDA 一起使用,cudaGraphicsGLRegisterBuffer() 没有返回错误(即 cudasucess),但是当我想用 cudaGraphicsMapResources() 映射我的 PBO 时,我得到“cudaErrorMapBufferObjectFailed”。

这是我的代码(简化但包含相关部分):

在 .h 文件中

GLuint bufferID;
struct cudaGraphicsResource* PBO_CUDA_Widget;

在 .cpp 文件中

void HDR_GLWidget::initializeGL()
{
    cutilSafeCall(cudaGLSetGLDevice(cutGetMaxGflopsDeviceId()));

        // create pixel buffer object
    glGenBuffersARB(1, &bufferID);
    glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, bufferID);
    glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, width * height * 4, NULL, GL_STREAM_DRAW_ARB);
    glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0);

    cudaError_t error_test = cudaGraphicsGLRegisterBuffer(&PBO_CUDA_Widget, bufferID, cudaGraphicsMapFlagsWriteDiscard); //no cuda error here
}

void HDR_GLWidget::uploadBuffer
{
    cudaError_t error_test = cudaGraphicsMapResources(1, &PBO_CUDA_Widget, 0); //crash here

        [...]
}

这是我得到的错误:

First-chance exception at 0x000007fefd47bccd in IHM_Qt_TM_cuda.exe: Microsoft C++ exception: cudaError_enum at memory location 0x073ff200..

我在 GTX580 上装有 Windows 7、CUDA 4.2 的 x64 机器上。

编辑:这是修改后的代码

在 .h 文件中

cudaGraphicsResource* PBO_CUDA_Widget;
GLuint bufferID;

在 .cpp 文件中

void HDR_GLWidget::initializeGL()
{
    cutilSafeCall(cudaGLSetGLDevice(cutGetMaxGflopsDeviceId()));
    GLenum err = glewInit();
    glGenBuffers(1, &bufferID);
    glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, bufferID);
    glBufferData(GL_PIXEL_UNPACK_BUFFER_ARB, width * height * 4, NULL, GL_STREAM_DRAW);
    glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, 0);

    cutilSafeCall(cudaMalloc((void**) PBO_CUDA_Widget, width * height * sizeof(uchar4)));
    cudaError_t error_reg = cudaGraphicsGLRegisterBuffer((cudaGraphicsResource **)PBO_CUDA_Widget, bufferID, cudaGraphicsMapFlagsWriteDiscard);
}

void HDR_GLWidget::uploadBuffer()
{
    cudaError_t error_map = cudaGraphicsMapResources(1, (cudaGraphicsResource_t*)PBO_CUDA_Widget, 0); //error here
[...]
cudaError_t flag_unmap = cudaGraphicsUnmapResources(1, (cudaGraphicsResource_t*)PBO_CUDA_Widget, 0);
}
4

1 回答 1

3

cudaGraphisMapResources 将指针作为第二个参数。不是指向指针的指针。您的PBO_CUDA_Widget变量已经是一个指针。调用应该是(不带地址,即省略'&'):

cudaError_t error_test = cudaGraphicsMapResources(1, PBO_CUDA_Widget, 0);

请记住在启动访问资源的 CUDA 内核之前取消 PBO 与 OpenGL 的绑定。

顺便说一句:自 OpenGL-1.5 以来,OpenGL 缓冲区对象一直是核心 OpenGL 的一部分。任何支持 CUDA 的 GPU 也比 OpenGL-2 支持得更好 => 不要使用ARB后缀。


更新示例代码:

这是我的一个项目中经过实际测试的代码。从技术上讲,它分布在几个函数上,变量名称略有不同。但是将它合并到一个函数中,它的工作原理就是这样。

void example(void)
{
    GLuint pbo_ID;
    size_t pbo_size = ...;

    // note the type, there's no '*' and it's initialized to 0
    cudaGraphicsResource_t cgr = 0;

    glGenBuffers(1, &pbo_ID);
    glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo_ID);
    glBufferData(GL_PIXEL_UNPACK_BUFFER, pbo_size, NULL, GL_DYNAMIC_DRAW);
    glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);

    cudaGraphicsGLRegisterBuffer(&cgr, pbo_ID, cudaGraphicsRegisterFlagsWriteDiscard);

    cudaGraphicsMapResources(1, &cgr, 0);

    void *ptr;
    size_t mapped_size;
    cudaGraphicsResourceGetMappedPointer(
        &ptr, &mapped_size, cgr);

    cudaArray_t array;
    cudaGraphicsSubResourceGetMappedArray(
    &array,
    cgr,
    0, 0 );

    call_CUDA_kernel();
    
    cudaGraphicsUnmapResources(1, &cgr, 0);
}

现在我的意思是让cudaGrapicsResource你成为一个你会malloc的指针。那么这样:

cudaGraphicsResource_t *p_cuda_gr_resources =
    malloc(count * sizeof cudaGraphicsResource_t);

/* do some stuff */

free(p_cuda_gr_resources);

如果您有一大堆资源,这很有用,其中的数量不是预定的。在通常情况下,您不需要动态分配。

于 2013-06-27T16:25:14.240 回答