CUDA使用纹理内存

该博客探讨了CUDA中的纹理内存,指出其比全局内存访问速度快,因为有缓存机制。当缓存未命中时,仍能保持较低延迟。内容包括纹理内存的初始化、在kernel函数中的使用,以及结合PBO(像素缓冲对象)进行数据处理和绘制的示例。

纹理内存位于设备端,global memory也位于设备端,但是texture memory的访问速度较global memory要快。

因为纹理内存有cache, 只有当cache没有命中的时候才会去访问device memory,否则访问texture cache具有很小的延迟。

另外,texture cache的2D定位已经进行了优化,对于同一线程束的线程访问位置临近的texture memory时效率非常高。

还有,texture memory的stream fetching 也进行了优化,所以即使cache没有命中,对texture memory的访问延迟也不会很高。


初始化纹理内存:

texture<uchar, 3, cudaReadModeNormalizedFloat> tex;
cudaArray *d_volumeArray = 0;

extern "C"
void initCudaTexture(const uchar *h_volume, cudaExtent volumeSize)
{
	cudaChannelFormatDesc channelDesc = cudaCreateChannelDesc<uchar>();

	cutilSafeCall(cudaMalloc3DArray(&d_volumeArray, &channelDesc, volumeSize));

	cudaMemcpy3DParms copyParams = {0};
	copyParams.srcPtr = make_cudaPitchedPtr((void*)h_volume, volumeSize.width*sizeof(uchar), volumeSize.width, volumeSize.height);
	copyParams.dstArray = d_volumeArray;
	copyParams.extent   = volumeSize;
	copyParams.kind     = cudaMemcpyHostToDevice;
	cutilSafeCall(cudaMemcpy3D(©Params));

	tex.normalized = true;
	tex.filterMode = cudaFilterModeLinear;
	tex.addressMode[0] = cudaAddressModeWrap;
	tex.addressMode[1] = cudaAddressModeWrap;
	tex.addressMode[2] = cudaAddressModeWrap;

	cutilSafeCall(cudaBindTextureToArray(tex, d_volumeArray, channelDesc));
}


在上述代码中已经将h_volume中的数据拷贝到设备端的d_volumeArray中,然后又将其绑定到一个纹理内存。
下面在kernel函数中,对纹理进行访问,并将数据保存到PBO中,然后绘制。PBO的使用在前面已经写过了,可以参考之。

__global__ void kernel(uint *d_output, uint imageW, uint imageH, float w)
{
	uint x = __umul24(blockIdx.x, blockDim.x) + threadIdx.x;
	uint y = __umul24(blockIdx.y, blockDim.y) + threadIdx.y;

	float u = x / (float)imageW;
	float v = y / (float)imageH;

	float voxel = tex3D(tex, u, v, w);
	

	if ((x < imageW) && (y < imageH))
	{
		uint i = __umul24(y, imageW) + x;
		d_output[i] = vox
### CUDA纹理内存的大小限制与配置方法 在CUDA编程中,纹理内存(Texture Memory)是一种特殊的全局内存,具有缓存优化机制,适合用于具有空间局部性访问模式的应用场景[^4]。例如,在图像处理或科学计算中,如果相邻线程访问相邻的内存地址,纹理内存可以显著提高性能。 #### 纹理内存的大小限制 纹理内存的大小限制主要取决于GPU架构和设备的具体实现。通常情况下,纹理内存的最大容量为8GB,但这并不是绝对值。具体的大小限制可以通过查询`cudaDeviceProp`结构体中的`totalConstMem`字段来获取,尽管该字段实际上表示的是常量内存的大小,但类似的查询方法适用于纹理内存。此外,纹理内存使用不会直接影响全局内存的可用空间,因为它依赖于缓存机制。 #### 纹理内存的配置方法 纹理内存的配置需要通过声明纹理引用并绑定数据来完成。以下是配置纹理内存的基本步骤: 1. **声明纹理引用**:使用`texture<T>`类型声明一个纹理引用对象。 2. **分配设备内存**:为数据分配设备内存,并将主机数据拷贝到设备。 3. **绑定纹理引用**:将纹理引用绑定到设备内存,并设置必要的参数(如归一化坐标、寻址模式等)。 4. **核函数中访问**:在核函数中通过纹理引用访问数据。 以下是一个完整的代码示例,展示如何配置和使用纹理内存: ```cpp #include <cuda_runtime.h> #include <iostream> // 声明纹理引用 texture<float, 1, cudaReadModeElementType> texRef; __global__ void kernel(float* output) { int idx = threadIdx.x + blockIdx.x * blockDim.x; // 通过纹理引用访问数据 output[idx] = tex1Dfetch(texRef, idx); } int main() { const int N = 1024; size_t size = N * sizeof(float); // 分配主机内存 float* h_data = new float[N]; for (int i = 0; i < N; ++i) { h_data[i] = static_cast<float>(i); } // 分配设备内存 float* d_data; cudaMalloc((void**)&d_data, size); // 将主机数据拷贝到设备 cudaMemcpy(d_data, h_data, size, cudaMemcpyHostToDevice); // 绑定纹理引用到设备内存 cudaChannelFormatDesc desc = cudaCreateChannelDesc<float>(); cudaBindTexture(0, &texRef, d_data, desc, size); // 分配输出设备内存 float* d_output; cudaMalloc((void**)&d_output, size); // 启动核函数 kernel<<<N / 256, 256>>>(d_output); // 拷贝结果回主机 float* h_output = new float[N]; cudaMemcpy(h_output, d_output, size, cudaMemcpyDeviceToHost); // 打印部分结果 for (int i = 0; i < 10; ++i) { std::cout << h_output[i] << " "; } std::cout << std::endl; // 解绑纹理引用 cudaUnbindTexture(&texRef); // 释放资源 delete[] h_data; delete[] h_output; cudaFree(d_data); cudaFree(d_output); return 0; } ``` 上述代码展示了如何声明纹理引用、绑定数据以及在核函数中访问纹理内存。需要注意的是,纹理内存的访问模式对性能有显著影响,因此应尽量遵循其设计初衷,即利用空间局部性访问模式。 ### 总结 纹理内存的大小限制通常由GPU架构决定,最大可达8GB,但具体值需根据设备属性查询。纹理内存的配置涉及纹理引用的声明、数据绑定以及核函数中的访问操作[^4]。
评论 7
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值