3.2.7 图形学互操作性
一些OpenGL和Direct3D的资源可被映射到CUDA地址空间,要么使CUDA可以读OpenGL或Direct3D写的数据,要么使CUDA写数据供OpenGL或Direct3D消费。
资源必须先在CUDA中注册,才能被3.2.7.1和3.2.7.2提到的函数映射。这些函数返回一个指向cudaGraphicsResource类型结构体的CUDA图形资源。资源注册是潜在高消耗的,因此通常每个资源只注册一次。可以使用cudaGraphicsUnregisterResource()解注册CUDA图形资源。
一旦资源被注册到CUDA,就可以按需要被任意次的映射和解映射,映射和解映射使用cudaGraphicsMapResources()和cudaGraphicsUnmapResources()。可以使用cudaGraphicsResourceSetMapFlags()来指定资源用处(只读,只写),CUDA驱动可以据此优化资源管理。
可以获得cudaGraphicsResourceGetMappedPointer()为缓冲区返回的设备地址空间和cudaGraphicsSubResourceGetMappedArray()为CUDA数组返回的设备地址空间,内核通过读写这些空间读写被映射资源。
通过OpenGL或Direct3D访问被映射到CUDA的OpenGL或Direct3D的资源,其结果未定义。
3.2.7.1和3.2.7.2节给出了每种图形API的特性和一些代码例子。
3.2.7.1 OpenGL互操作性
和OpenGL互操作要求在其它任何运行时函数调用前,使用cudaGLSetGLDevice()指定CUDA设备。注意cudaSetDevice()和cudaGLSetDevice()是相互排斥的。
可以被映射到CUDA地址空间的OpenGL资源有OpenGL缓冲区、纹理和渲染缓存对象。
使用cudaGraphicsGLRegisterBuffer()注册缓冲对象。在CUDA中,缓冲对象表现为设备指针,因此可以在内核中读写或通过cudaMemcpy()调用。
纹理或渲染缓存对象使用cudaGraphicsGLRegisterImage()注册。在CUDA中,它们表现为CUDA数组,可绑定到纹理参考,可被内核读写或通过cudaMemcpy2D()调用。cudaGraphicsGLRegisterImage()使用内置的float类型(例如,GL_RGBA_FLOAT32)和非归一化整数(例如GL_RGBA8UI)支持所有纹理格式。请注意,由于GL_RGBA8UI是OpenGL3.0纹理格式,只能被着色器写,不能被固定功能的管线写。
下面的代码使用内核动态的修改一个存储在顶点缓冲对象中的二维width*height顶点网格。
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,
{
// Map buffer object for writing from CUDA
float4* positions;
cudaGraphicsMapResources(1, &positionsVBO_CUDA, 0);
size_t num_bytes;
cudaGraphicsResourceGetMappedPointer((void**)&positions, &num_bytes,
在Windows系统上和对于Quadro显卡,可以用cudaWGLGetDevice()检索关联到wglEnumGpusNV()返回的句柄的CUDA设备。Quadro显卡与OpenGL的互操作性能比GeForce和Tesla要好。在一个多GPU的系统中,在Quadro GPU上运行OpenGL渲染,在其它的GPU进行CUDA计算。