当处理较大数据量的时候,往往会用GPU进行运算,比如OpenGL或者CUDA。在实际的操作中,往往CUDA实现并行计算会比OpenGL更加方便,而OpenGL在进行后期渲染更具有优势。由于CUDA中的运算结果存储在GPU中,如果将数据download到CPU,然后再将CPU中的数据上传到GPU,使用OpenGL进行渲染,中间的GPU与CPU的交互会很耗时,毕竟使用GPU的目的就是为了加速,这样的数据传输会降低效率。
接下来简要说一下如何使CUDA和OpenGL互操作来实现GPU中数据的交互传输,而不用通过主机的CPU。
一、首先是在OpenGL中声明这样一个buffer。
cudaGraphicsResource_t cudaBuffer;
然后将Buffer注册给纹理texture(假定已经提前声明一个纹理texture)
cudaGraphicsGLRegisterImage(&cudaBuffer, texture, GL_TEXTURE_2D, cudaGraphicsRegisterFlagsWriteDiscard);
二、好了,这样我们只需要把CUDA计算出来的数据写入cudaBuffer中就行了。如下:
利用Cuda中的两个API设置cudaBuffer为映射Map,并将一个cuda数组cudaArray绑定到cudaBuffer。
cudaError_t err; err = cudaGraphicsMapResources(1, cudaBuffer, 0); err = cudaGraphicsSubResourceGetMappedArray(&cudaArray, cudaBuffer, 0, 0);
那么接下来的就是把数据写入cudaArray中的事情了,假设我有一个数据指针pResult指向GPU中的一段内存,这段内存中保存的就是CUDA的运算结果(一幅4通道图像),我只需要将其copy到cudaArray就行了。注意是cudaMemcpyDeviceToDevice,这个很快的。
创建cudaArray
uchar* cudaArray=NULL; cudaChannelFormatDesc cuDesc = cudaCreateChannelDesc<uchar4>(); cudaMallocArray(&cudaArray, &cuDesc, imgWidth, imgHeight);
将结果数据拷贝至cudaArray
err=cudaMemcpyToArray(cudaArray, 0, 0, pResult, imgWidth*imgHeight * sizeof(uchar4), cudaMemcpyDeviceToDevice);
copy完后要解除映射Map
cudaGraphicsUnmapResources(1, &cudaBuffer, 0);
这样在OpenGL中就可以直接将buffer中的数据注册到纹理然后进行渲染了,so easy~