CUDA纹理存储器的特性及其使用

2.3.5 纹理存储器

纹理存储器(texture memory)是一种只读存储器,由GPU用于纹理渲染的图形专用单元发展而来,因此也提供了一些特殊功能。纹理存储器中的数据位于显存,但可以通过纹理缓存加速读取。在纹理存储器中可以绑定的数据比在常量存储器可以声明的64K大很多,并且支持一维、二维或者三维纹理。在通用计算中,纹理存储器十分适合用于实现图像处理或查找表,并且对数据量较大时的随机数据访问或者非对齐访问也有良好的加速效果。

纹理存储器在硬件中并不对应一块专门的存储器,而实际上是牵涉到显存、两级纹理缓存、纹理抓取单元的纹理流水线。纹理存储器提供了地址映射、数据滤波、缓存等功能,这些功能都是围绕着纹理渲染的需求设计的。关于GPU纹理流水线的介绍可以参考本书3.3.3节。在CUDA编程模型中,纹理缓存是透明的,编程人员不用去了解它的实现机制。

CUDA的内核函数访问纹理存储器的操作被称为纹理拾取(texture fetching)。纹理拾取使用的坐标与数据在显存中的地址可以不同,两者通过纹理参照系(texture reference)约定从数据的地址到纹理坐标的映射方式。将显存中的数据与纹理参照系关联的操作,称为将数据与纹理绑定(texture binding)。显存中可以绑定到纹理的数据有两种,分别是普通的线性内存(Linear Memroy)和CUDA数组(CUDA Array)。CUDA数组则为纹理访问进行了优化,并且在Device端中只能通过纹理拾取访问。

绑定到纹理的线性内存和数组中的元素被称为像元(texels),是texture elements的缩写。像元的数据类型可以是其中的元素可以是CUDA中规定的12或者4元组(不能是3元组)的有符号或者无符号8-,16-32-bit整型或者16-bit(目前只能通过driver API支持)整型,以及32-bit浮点型数据。与CUDA数组绑定的纹理参照系中的元素使用的N-元组数据中的组件数量必须与CUDA数组相同。

纹理缓存有两个作用。首先,纹理缓存中的数据可以被重复利用,当一次访问需要的数据已经存在于纹理缓存中时,就可以避免对显存进行读取。数据重用过滤了一部分对显存的访问,节约了带宽,也不必按照显存对齐的要求读取。第二,纹理缓存可以缓存拾取坐标附近几个像元的数据,可以实现滤波模式,也能提高具有一定局部性的访问的效率。

纹理存储器是只读的,不需要关心缓存数据一致性问题。这意味着如果更改了绑定到纹理存储器的数据,纹理缓存中的数据可能并没有被更新,此时通过纹理拾取得到的数据可能是错误的。因此,在每次修改了绑定到纹理的数据以后,都需要对纹理进行重新绑定。由于不能从设备端修改CUDA数组,因此只有在对绑定到纹理的线性内存进行修改时才需要注意这一点。

线性内存中的数据只能与一维纹理绑定,并且纹理拾取坐标是定点型,坐标的值也与数据在线性内存中的偏移量相同;而CUDA数组可以与一维、二维或者三维纹理绑定,纹理拾取坐标是浮点型,并且支持许多特殊功能。纹理存储器的特殊功能有:

浮点型纹理拾取坐标:使用浮点型的纹理拾取坐标对纹理进行寻址,只对与CUDA数组绑定的存储器有效。地址映射的方式可以是归一化或者非归一化的:使用归一化纹理时,纹理在每个维度上的坐标被映射到浮点数[0.0, 1.0)范围内;使用非归一化纹理坐标时,各个维度上的坐标则被映射到浮点数[0.0, N)的范围内,其中N是纹理在该维度上像元的数量。由于在GPU中通常用浮点计算点的坐标,因此使用浮点数作为纹理拾取坐标更加自然;使用归一化的纹理拾取坐标可以不用关心纹理的实际尺寸,简化了渲染程序的编写。

       寻址模式:寻址模式规定了纹理拾取的输入坐标超出纹理寻址范围时的行为,有钳位模式和循环模式两种。使用钳位模式时,当输入的坐标超出了寻址范围,输入的值将被“钳位”到寻址范围的最大值或者最小值;循环模式只对归一化坐标有效,此时要对超出寻址范围的纹理坐标作求模等处理。例如,对映射到[0.0, 1.0)的归一化纹理坐标,输入拾取坐标1.25,钳位模式会将输入按照0.99999…处理,而循环模式会将输入0.25处理。

       类型转换:如果像元中的数据是8-bit或者16-bit定点型,类型转换功能对拾取的返回值进行类型转换,将其映射到归一化的浮点范围[0.0f, 1.0f](对无符号整型)或者[ -1.0f, 1.0f](对有符号整型)。

       滤波:如果将返回类型是浮点型的CUDA数组与纹理绑定,那么就可以对返回的值进行滤波。滤波模式可以是最近点取样模式或者线性滤波模式两种。最近点模式返回与浮点型的纹理抓取坐标最近像元的值,而线性滤波模式则会先取出附近几个像元,然后按照抓取坐标与这几个像元的距离进行线性插值,返回线性插值得到的值。线性滤波可以使纹理渲染得到的画面更加平滑自然。线性滤波需要的插值计算不需要可编程单元参与,提供了额外的浮点处理能力,但精度较低。使用线性滤波模式返回的值经过了插值处理,适合用于图像处理;使用最近点取样模式的返回值不会改变纹理中像元的值,适合用于实现查找表。

       关于纹理拾取模式的详细描述,可以参考附录F

       使用纹理存储器时,首先要在主机端声明需要绑定到纹理的线性存储器或CUDA数组,并设置好纹理参照系,然后将纹理参照系与线性内存或者CUDA数组绑定。在主机端完成配置工作后,就可以在内核函数中通过纹理抓取函数访问纹理存储器了。

3.2.4.1 CUDA数组

在显存中可以分配的空间有两种:CUDA 数组和线性内存。此外,常数存储器中通过缓存加速读取的数据实际也存在于显存中。CUDA数组和线性内存都可以与纹理参照系绑定,但CUDA数组对纹理拾取访问进行了优化,在设备端也只能通过纹理拾取访问。

声明CUDA数组之前,必须先以结构体channelDesc描述CUDA数组中的数据类型。

struct cudaChannelFormatDesc {

  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值