CUDA GL interop - 从另一个进程读取映射的缓冲区纹理

时间:2014-05-05 02:05:52

标签: opengl cuda ipc

我想在渲染过程中渲染GL缓冲区纹理,然后在另一个进程中通过CUDA读取它。目前我不希望将这两个进程合并为一个。这是我的代码的样子:

//Note: this code runs under Linux
int svMain();
int main() {
    //Tons of variable definitions vomited
    float* dptr;    //pointer to mapped device mem
    size_t map_size;    //size of mapped mem
    cudaGraphicsResource_t cuda_res;
    cudaIpcMemHandle_t memhdl;
    if( !fork() )
        return svMain();
    else {
        initGL();
        genGLBufferTextureAndUploadSomeData();
        cudaGLSetGLDevice(0);
        cudaGraphicsGLRegisterBuffer( &cuda_res, buf_id, cudaGraphicsRegisterFlagsNone );
        cudaGraphicsMapResources( 1, &cuda_res, &map_size, 0 );
        cudaGraphicsGetMappedPointer( (void**)&dptr, &map_size, cuda_res );
        cudaIpcGetMemHandle( &memhdl, dptr );
        sendToServerProcViaSocket( memhdl );
    }
    return 0;
}
int svMain() {
    cudaIpcMemHandle_t memhdl;
    float* dptr;
    cudaGLSetGLDevice(0);
    recvFromClientProc( memhdl );
    if( cudaSuccess != cudaIpcOpenMemHandle( (void**)&dptr, memhdl ) ) {
        fprintf( stderr, "SV: cannot open CUDA mem handle!\n" );
        return -1;
    } else
        launchSomeKernel( dptr );
    return 0;
}

问题是cudaIpcOpenMemHandle总是返回错误。但是,如果我通过cudaMalloc分配设备内存(不涉及GL)然后发送相应的内存句柄,则上述代码可以正常工作。如果我在一个过程中完成所有工作(涉及GL,不涉及IPC),它也可以工作。

我的操作系统是Ubuntu 13.04 LTS

CUDA工具包中的“simpleIPC”示例在我的系统中运行正常。 这是我的设备查询输出的一部分:

Device 0: "GeForce GT 650M"
  CUDA Driver Version / Runtime Version          6.0 / 5.5
  CUDA Capability Major/Minor version number:    3.0
  Total amount of global memory:                 2048 MBytes (2147287040 bytes)
  ( 2) Multiprocessors, (192) CUDA Cores/MP:     384 CUDA Cores
  Texture alignment:                             512 bytes
  Concurrent copy and kernel execution:          Yes with 1 copy engine(s)
  Run time limit on kernels:                     Yes
  Integrated GPU sharing Host Memory:            No
  Support host page-locked memory mapping:       Yes
  Alignment requirement for Surfaces:            Yes
  Device has ECC support:                        Disabled
  Device supports Unified Addressing (UVA):      Yes
  Device PCI Bus ID / PCI location ID:           1 / 0
  Compute Mode:
     < Default (multiple host threads can use ::cudaSetDevice() with device simultaneously) >

那么,从另一个进程访问GL缓冲区纹理的正确方法是什么?

1 个答案:

答案 0 :(得分:4)

OpenGL上下文与创建它们的进程相关联。您不能在进程之间共享CUDA映射的OpenGL对象,因为OpenGL上下文排序是数据的“所有者”,当您将其映射到CUDA时,您只是将其借出。 OpenGL在幕后进行了大量的簿记和更高级别的管理。

OpenGL中存在某些内部结构,并且在使用OpenGL CUDA互操作时必须遵守约束。例如,您不能主动使用当前映射到CUDA的OpenGL对象作为数据源或目标。例如,对glTexImage2DglBufferData的调用可以重复使用前面的ID,但使用与不同内部ID相关联的不同缓冲区。 glTexSubImage2DglBufferSubData可能需要创建原位副本以满足同步点要求等。如果某个OpenGL状态跟踪器无法访问的进程确实将其内存填满,那么事情就会破裂。

通常的OpenGL CUDA互操作序列是

  1. 在OpenGL中执行某些操作
  2. 取消绑定OpenGL中的活动使用对象
  3. 将对象映射到CUDA
  4. 在CUDA做点什么
  5. 取消CUDA中的对象
  6. 回到1
  7. 现在你必须做的是,创建一个在进程之间共享的代理内存区域,而不是OpenGL对象的进程间映射。在使用OpenGL执行某些操作后,将OpenGL对象映射到CUDA,使用cudaMemcpy将数据复制到代理内存中并取消绑定OpenGL对象。