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);
}