cuda与OpenGL和DirectX的图形交互

OpenGL和Direct3D中的资源可以被映射到cuda的内存空间,以允许cuda读取,也允许cuda写入后供OpenGL和Direct3D使用。

在映射之前,需要对资源进行注册(register),会得到一个cudaGraphicsResource的指针。使用完成后,需要通过cudaGraphicsUnregisterResource注销资源。

一旦资源注册成功,就可以对资源进行映射cudaGraphicsMapResources和取消映射cudaGraphicsUnmapResource,映射可以根据需要是多次的。映射后的内存,可以被内核函数使用,通过cudaGraphicsResourceGetMappedPointer和cudaGraphicsSubResourceGetMappedArray得到设备内存地址的指针。

下面以Direct3D11为例:

#include <d3d11.h>
#include <cuda_runtime.h>

ID3D11Device *device = nullptr;
struct CUSTOMVERTEX {
    FLOAT x, y, z;
    DOWRD color;
};
ID3D11Buffer *vbBuffer = nullptr;
struct cudaGraphicsResource *vbCuda = nullptr;

int main()
{
    //省略初始化步骤

    unsigned int size = width * height * sizeof(CUSTOMVERTEX);
    D3D11_BUFFER_DESC bufferDesc = {};
    bufferDesc.Usage = D3D11_USAGE_DEFAULT;
    bufferDesc.ByteWidth = size;
    bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
    bufferDesc.CPUAccessFlags = 0;
    bufferDesc.MiscFlags = 0;
    device->CreateBuffer(&bufferDesc, 0, &vbBuffer);
    cudaGraphicsD3D11RegisterResource(&vbCuda, vbBuffer, cudaGraphicsRegisterFlagsNone);
    cudaGraphicsResourceSetMapFlags(vbCuda, cudaGraphicsMapFlagsWriteDiscard);

    //省略其他步骤
    Render();
    //省略其他步骤

    cudaGraphicsUnregisterResource(vbCuda);
    vbBuffer->Release();

    return 0;
}

void Render()
{
    float4 *pData = nullptr;
    cudaGraphicsMapResources(1, &vbCuda, 0);
    size_t numBytes;
    cudaGraphicsResourceGetMappedPointer((void**)&pData, &numBytes, vbCuda);

    dim3 threads(16, 16);
    dim3 blocks(width / threads.x, height /threads.y);
    createVertics<<<blocks, threads>>>(pData, time, width, height);

    cudaGraphicsUnmapResource(1, &vbCuda, 0);
}