HLSL
+ -

6.5资源对象

2024-06-26 33 0

HLSL提供了几种类型的资源对象,允许HLSL着色器程序与D3D11中可用的各种资源类型进行交互。每个对象类型都通过一组方法公开资源的功能,这些方法可以在该类型的声明对象上调用。当给定地址或索引时,这些方法中的大多数提供了从资源读取数据的方法,而有些方法还提供了有关资源本身的信息。在读/写资源的情况下,还公开了用于写入资源数据的方法。

所有只读资源对象都对应于一种类型的着色器资源视图,而读/写资源对象则对应于一个类型的无序访问视图。与常量缓冲区一样,编译器将资源对象的每个声明映射到一个寄存器索引,该索引对应于传递给SSetShaderResources、OMSetRenderTargetsAndUnorderedAccessViews或CSSetUnorderedAccess Views的插槽。

与常量缓冲区一样,在声明资源对象时,可以使用register关键字手动指定寄存器。对于着色器资源视图,寄存器为t0到tl27,而对于无序访问视图,寄存器则为u0到u7。有关资源以及资源如何绑定到管道的更多信息,请参阅第2章。

6.5.1缓冲区

缓冲区资源对象对应于为ID3D11Buffer资源创建的着色器资源视图。在大多数情况下,它们有一个非常简单的接口,其中包括用于获取资源大小的方法、用于在给定地址时读取值的Load方法和用于在给定索引时读取数值的数组运算符。在缓冲区可以包含不同类型的情况下,Load方法或数组运算符返回的数据类型是使用类似模板的语法指定的。

清单6.16演示了一个标准Buffer对象的声明,该对象具有float4返回类型,对应于DXGI_FORMAT_R32B32A32_FLOAT。

Buffer<float4> Float4Buffer : register(t0);
  • 着色器资源视图 -t
  • 无序访问视图 -u

Buffer

Buffer对象是HLSL中最简单的资源对象类型。Buffer通过Load方法和数组运算符提供对其数据的只读访问,这两种方法都返回指定索引处的数据。它还提供了GetDimensions方法,用于查询以字节为单位的缓冲区大小。

ByteAddressBuffer

ByteAddressBuffer类型允许使用字节偏移量而不是索引来访问缓冲区。此功能通过Load、Load2、Load3和Load4方法公开,这些方法分别返回1、2、3或4 uint值。由于这些方法只返回uint类型,因此包含其他类型数据的缓冲区必须使用转换/强制转换内部函数之一手动转换返回值。

StructuredBuffer

StructuredBuffer提供对包含由结构定义的元素的缓冲区的只读访问,而常规缓冲区类型只能访问与DXGI_FORMAT值对应的类型。结构必须在HLSL中声明为结构,并且在声明StructuredBuffer对象时必须将该类型指定为模板参数。

Read/Write Buffers

读/写缓冲区允许对缓冲区资源进行随机存取读写。由于设备不会自动同步读取和写入,因此必须使用同步内部或原子来控制跨线程的内存访问。默认情况下,同步内在只会导致写入在该线程组中刷新。为了在整个GPU上刷新写入,缓冲区声明必须使用globallycoherent前缀。

三种类型的读/写缓冲区是RWBuffer、RWByteAddressBuffer和RWStructuredBuf。对于读取,它们的行为与只读缓冲区完全相同,并使用相同的方法。对于写入内存,数组运算符可用于RWBuffer和RWStructuredBuffer,而RWByteAddressBuffer提供Store、Store2、Store3和Store4方法。RWByteAddressBuffer还提供了一组互锁方法,允许对资源的内容执行原子操作。对于包含隐藏计数器的RWStructuredBuffer(使用D3D11_buffer_UAV_FLAG_C0UNTER标志创建的结构化缓冲区资源就是这种情况),它可以使用IncrementCounter和DecrementCounters递增或递减。有关结构化缓冲资源的更多详细信息,请参阅第2章

6.5.2 附加/使用缓冲区Append/Consume Buffers

附加和消耗缓冲区允许在像素或计算着色器中添加和移除资源中的值。添加和删除操作是在缓冲区的末尾完成的,这使它的行为有点像堆栈。然而,与传统堆栈不同的是,添加和删除的顺序并不能得到保证,因为资源是由多个线程同时访问的。值的添加是使用AppendStructuredBuffer类型的Append方法完成的,而删除是使用ConsumeStructunedBuffer型的Consume方法完成的。顾名思义,这两种类型都是结构化缓冲区资源。

6.5.3输出流缓冲

流输出缓冲区是一个简单的资源对象,由几何体着色器用于发射基本体顶点数据。与其他资源类型不同,它不是全局声明的,也没有映射到寄存器。相反,它被用作几何体着色器入口点函数的inout参数。可以声明三种类型的流输出缓冲区,每种缓冲区都对应于不同的基元类型。它们是PointStream、LineStream和TriangleStream,分别对应于点带、直线带和三角形带。参数声明还应包括一个类型作为模板参数,它指示顶点的数据格式。通常,此类型是包含所有顶点数据的结构,这些数据需要传递给像素着色器,或者将由流输出阶段输出。向条形图添加顶点是使用Append方法完成的,而RestartStrip则会剪切当前条形图并开始新的条形图。如果在附加最小数量的顶点之前剪切条带,则会丢弃不完整的基本体。

6.5.4输入输出补丁Patches

HLSL包括两种面片类型,用于访问外壳着色器和域着色器中的控制点数据数组,也可作为几何着色器的输入。2 InputPatch包含一个点数组,可以声明为外壳着色器、面片常量函数和几何着色器的输入属性。OutputPatch包含一个点数组,该数组被声明为域着色器的输入。这两种类型都使用数组运算符进行访问,并公开Length属性以确定它们所包含的元素数.

6.5.5纹理

纹理是渲染管道中最常用的资源之一,并在图形硬件中使用专门的纹理采样单元。因此,HLSL公开了一个用于采样纹理数据的大型接口,以允许着色器程序充分利用硬件的功能。HLSL包括只读纹理资源对象类型,对应于D3D11中的各种纹理资源类型。这些类型的完整列表如表6.4所示

Intrinsic Description
Texture1D One-dimensional texture
Texture1DArray Array of one-dimensional textures
Texture2D Two-dimensional texture
Texture2DArray Array of two-dimensional textures
Texture2DMS Two-dimensional texture with multisampling
Texture2DMSAr>ray Array of two-dimensional textures with multisampling
Texture3D Three-dimensional texture
Texture3DArray Array of three-dimensional textures
TextuneCube Array of six 2D textures, representing faces of a cube
TextureCubeArray Array of cube textures

每个纹理资源对象类型都支持所有纹理操作的子集,因此,每个对象类型都有自己的接口。请参阅HLSL文档,查看给定纹理对象类型是否支持某个方法。以下部分描述了如何使用每种方法来访问纹理对象。

采样方式

传统的纹理采样操作是使用纹理对象上可用的采样族方法执行的。这些方法都采用一组浮点纹理坐标来表示要采样的内存位置,其中每个分量都被归一化到[0,1]的范围。组件的数量取决于纹理类型。例如,TexturelD只接受一个浮动,而Texture2D接受两个浮动,Texture3D接受三个浮动。如果使用纹理数组,则会传递一个额外的浮点组件,指示要使用的数组的索引。

Sample方法允许根据给定的采样器状态执行硬件纹理过滤(缩小、放大和mip贴图插值)。采样器状态必须声明为HLSL中的SamplerState对象,它被映射到采样器寄存器(s0到s15),就像常量缓冲区和资源对象被映射到它们的寄存器类型一样。寄存器的索引对应于传递给设备上下文上可用的SSetSamplers方法的槽。然后,可以将声明的SamplerState对象传递给Sample方法,该方法将使用指定的采样器状态进行过滤。

SamplerState LinearSampler : register(s0);
Texture2D ColorTexture : register(t0);
float4 PSMain( in float2 TexCoord : TEXCOORD ) : SV_Target
{
    return ColorTexture.Sample( LinearSampler, TexCoord );
}

当对包含多个mipmap级别的纹理调用Sample时,会根据纹理坐标的屏幕空间导数(也称为渐变)自动选择mipmap等级。这就是为什么“采样”仅在像素着色器中可用,并且仅在动态循环或分支构造之外可用。若要在其他着色器阶段或在像素着色器的动态分支/循环内部使用纹理采样,可以使用Sample方法的其他变体,这些变体允许显式指定渐变或mip级别。它们分别是SampleGrad和SampleLevel。第三种方法SampleBias的工作原理类似于添加了偏移值的Samplelevel。

示例方法的返回类型取决于在创建绑定到纹理对象的着色器资源视图时指定的DXGI_FORMAT。因此,DXGI_FORMAT_R32G32B32A32_FLOAT将返回一个float4,DXGI-FORMAT_R32G32_UINT将返回uint2,并且DXGI_F0RMAT_R8G8B8_UN0RM将返回float4。

采样比较方法SampleCmp Methods

SampleCmp不是直接返回纹理值,而是返回将采样值与作为CompareValue参数传递给方法的值进行比较的结果。如果比较通过,则返回的值等于1.0,如果比较失败,则返回值等于0.0。这使得该方法非常自然地用于实现阴影映射技术。

比较中使用的不等式在D3D11_SAMPLER_DESC结构的ComparisonFunc成员中指定,该结构用于创建传递给该方法的采样器状态。请注意,为采样器状态指定的筛选器必须是D3D11_filter枚举的“比较”值之一。此外,如果要将HLSL中声明的采样器状态传递给SampleCmp,则它必须具有SamplerComparisonState类型。如果为采样器状态指定了线性滤波模式,则纹理将被采样多次,并与比较值进行比较。最后的返回值是所有比较的过滤结果。这可以用于有效地实现阴影贴图的百分比接近过滤。

聚合方法Gather Methods

当给定单个纹理坐标时,Gather方法族返回四个值。这些值来自2x2四元组的纹素,使用的位置与双线性过滤所用的位置相同。GatherRed返回纹素的四个红色分量,GatherGreen返回四个绿色分量,Gather blue返回四个蓝色分量,GathereAlpha返回四个alpha分量。Gather返回四个红色组件,使其在功能上等效于GatherRed。由于该方法返回2x2四边形,因此它只能用于Texture2D和Texture2DArray资源对象。GatherCmp方法也可用,其工作方式与SampleCmp类似。

Gather方法的一个更有用的情况是在执行图像处理的像素着色器中。通常,为2x2四元纹素收集rgb值需要四个采样操作,每个纹素一个采样操作。通过调用GatherRed、GatherGreen和GatherBlue仅在三条指令中检索相同的数据,可以提高效率。Gather指令的另一个有用案例是实现自定义阴影贴图过滤内核,这可以通过GatherCmp有效地完成

加载方法

Load方法以类似于我们在缓冲区类型中看到的方式,提供对纹理数据的直接、不变的只读访问。与Buffer Load方法一样,它采用int索引参数,而不是[0,1]纹理地址。由于它是访问纹理数据的最基本手段,因此在所有纹理资源类型和所有阶段都可以使用。阵列运算符也可用,它提供了类似的功能。对于多采样纹理,“加载”提供对像素的各个子采样的访问。此功能可用于实现自定义MSAA解析,或将MSAA集成到延迟渲染管道中。与Buffer对象的Load方法一样,返回类型由声明纹理对象时用作模板参数的类型决定。

获取方法GetMethods

纹理资源对象实现了几种方法来查询有关底层资源的信息。所有纹理资源对象类型都实现GetDimenslons,它返回大小、mip级别数、采样数(对于多采样纹理)和元素数(对于纹理阵列)。Texture2DMS对象还支持GetSamplePosition方法,该方法返回给定采样索引的像素内MSAA采样点的位置。

Cube Textures

立方体纹理是纹理阵列的一种特殊情况,用于表示立方体的六个边,通常用于反射或环境贴图。虽然它们可以像普通纹理阵列一样通过Texture2DArray类型进行访问,但也可以声明为TextureCube类型。在TextureCube上调用Sample方法时,传入的纹理坐标是标准化的三分量方向向量。然后通过选择方向向量指向的纹素来对纹理进行采样。这种用法将在第2章的立方体纹理部分中进一步描述。

Read/Write Textures

读/写纹理的功能与读/写缓冲区资源类似。通过数组运算符支持随机访问读取和写入,并且可以调用GetDimensions来查询资源的大小。HLSL中支持的读/写资源对象类型有RWTexturelD、RWTextureDArray、RWTextures 2D、RWTexture 2DArray和RWTexture3D.

0 篇笔记 写笔记

作者信息
站长漫谈
取消
感谢您的支持,我会继续努力的!
扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

您的支持,是我们前进的动力!