这里继续CUDA编程的学习,今天学习了设备纹理内存的使用,这里分享给大家!
纹理内存,是设备中一种只读存储器,在设备内存中也有对应的缓冲器Cache来加速IO操作。纹理内存对于程序中有空间邻近性访问的数据很高效。这里的空间邻近性是指每个线程的读取位置和其他线程的读取位置邻近,这在图像处理中非常有用,因为图像处理中经常需要进行邻域比较,比如4邻域和8邻域。
当然全局内存也可以进行这种有空间邻近性特性数据的存储与访问,但是速度上要慢很多,需要进行大量的显存读取操作。但是纹理内存则只需要从显存读取一次就可以(不理解这种说法,书中这么说的),纹理内存支持2维和3维纹理读取操作。
这里以一个简单的例子:从纹理内存中读取数据并赋值。
纹理内存需要和“纹理引用”与CUDA数组配套使用来实现。
纹理引用通过 t e x t u r e < p a r a m 1 , p a r a m 2 , p a r a m 3 > texture
注意,纹理引用变量要确保被定义为全局静态变量(个人理解,这样才能在内核函数中使用),同时还要确保这个变量不能作为参数传递给任何其他函数。
下面的例子中通过纹理引用读取线程ID作为索引位置的数据,然后复制到d_out指针指向全局内存中。
在main函数中则使用CUDA数组 c u d a A r r a y cudaArray cudaArray并通过 c u d a M e m c p y T o A r r a y ( p a r a m 1 , p a r a m 2 , p a r a m 3 , p a r a m 4 , p a r a m 5 , p a r a m 6 ) cudaMemcpyToArray(param1, param2, param3, param4, param5, param6) cudaMemcpyToArray(param1,param2,param3,param4,param5,param6)对CUDA数组进行赋值,param1表示目标CUDA数组变量, param2和param3表示将主机数据赋值到CUDA数组横向和纵向的偏移量,(0, 0)表示CUDA数组的左上角开始赋值。
使用 c u d a B i n d T e x t u r e T o A r r a y ( ) cudaBindTextureToArray() cudaBindTextureToArray()函数将纹理引用和CUDA数组绑定,这样就可以通过访问纹理引用来获取纹理内存中存储的CUDA数组数据。这里使用texture相应的函数进行访问。当使用完纹理内存后,要执行解除纹理引用与CUDA数组的绑定的代码,即调用 c u d a U n b i n d T e x t u r e ( ) cudaUnbindTexture() cudaUnbindTexture()。
详细代码如下所示:
#include
#include
#include
#include
#include
#include
#ifndef __CUDACC__
#define __CUDACC__
#endif
#include //texture<> depend head file
#include //tex1D() depend head file
#define NUM_THREADS 10
#define N 10
//定义1维的纹理引用
texture<float, 1, cudaReadModeElementType> textureRef;
//textureReference textureRef;
//定义内核函数:从纹理内存中获取数据并赋值给设备内存
__global__ void gpu_texture_memory(int n, float* d_out)
{
int idx = blockIdx.x *blockDim.x + threadIdx.x;
if (idx < n)
{
float temp = tex1D(textureRef, float(idx));
d_out[idx] = temp;
}
}
int main()
{
int num_blocks = N / NUM_THREADS + ((N % NUM_THREADS) ? 1 : 0);
float* d_out;
cudaMalloc(&d_out, sizeof(float) * N);
float* h_out = (float*)malloc(sizeof(float) * N);
float h_in[N];
for (int i = 0; i < N; i++)
{
h_in[i] = float(i);
}
//定义CUDA数组
cudaArray *cu_Array;
cudaMallocArray(&cu_Array, &textureRef.channelDesc, N, 1);
cudaMemcpyToArray(cu_Array, 0, 0, h_in, sizeof(float)*N, cudaMemcpyHostToDevice);
//绑定CUDA数组到纹理引用变量
cudaBindTextureToArray(&textureRef, cu_Array, &textureRef.channelDesc);
//调用内核函数
gpu_texture_memory << <num_blocks, NUM_THREADS >> > (N, d_out);
//拷贝结果到主机
cudaMemcpy(h_out, d_out, sizeof(float)*N, cudaMemcpyDeviceToHost);
printf("在GPU上使用纹理内存:\n");
//打印结果
for (int i = 0; i < N; i++)
{
printf("%f\n", h_out[i]);
}
//回收分配的资源
free(h_out);
cudaFree(d_out);
cudaFreeArray(cu_Array);
cudaUnbindTexture(&textureRef);
system("pause");
return 0;
}
说实话,这里还是无法体会到纹理内存的提速,这里只是简单介绍了纹理内存的用法,由于这里只是记录个人的学习笔记,所以如果有误,还请原谅,如果能够指正,万分感谢!
《基于GPU加速的计算机视觉编程》