变量语法

使用以下语法规则声明 HLSL 变量。

[Storage_Class][Type_Modifier] 类型 Name[Index] [: Semantic] [: Packoffset] [: Register];[批注][= Initial_Value]

parameters

Storage_Class

为编译器提供有关变量范围和生存期的提示的可选存储类修饰符;修饰符可以按任意顺序指定。

说明
extern 将全局变量标记为着色器的外部输入;这是所有全局变量的默认标记。 不能与 静态结合使用。
nointerpolation 在将顶点着色器的输出传递到像素着色器之前,请勿内插这些输出。
精确 应用于变量时的精确关键字 (keyword) 将通过以下方式限制用于生成分配给该变量的值的任何计算:
  • 单独的操作保持独立。 例如,如果 mul 和 add 操作可能已融合到疯狂操作中, 则精确 强制操作保持独立。 相反,你必须显式使用疯狂的内部函数。
  • 维护操作顺序。 在可能已对指令顺序进行洗牌以提高性能的情况下, 精确 确保编译器保留写入的顺序。
  • IEEE 不安全操作受到限制。 编译器可能使用了不考虑 NaN (非数字) 和 INF (无限) 值的快速数学运算, 精确 强制遵守有关 NaN 和 INF 值的 IEEE 要求。 如果不 精确,这些优化和数学运算就不是 IEEE 安全的。
  • 精确限定变量不会使使用该变量的操作变得精确。 由于 精确 仅传播到分配给 精确限定变量的值的运算,因此,正确实现所需计算 可能 很棘手,因此建议直接在声明着色器输出的位置标记着色器输出 无论是在结构字段上,还是在输出参数上,还是输入函数的返回类型。 以这种方式控制优化的能力通过禁用可能影响最终结果的优化来保持修改后的输出变量的结果不变性,这些优化可能会因累积精度差异的差异而影响最终结果。 当希望用于细化的着色器以保持紧水补丁接缝或匹配多个通道的深度值时,它非常有用。 示例代码:
    HLSLmatrix g_mWorldViewProjection;
    void main (in float3 InPos: Position, out precise float4 OutPos : SV_Position)
    {
    操作是精确的,因为它有助于精确的参数 OutPos
    OutPos = mul ( float4 ( InPos, 1.0 ) , g_mWorldViewProjection ) ;
    }
shared 标记变量以在效果之间共享;这是编译器的提示。
groupshared 为计算着色器标记线程组共享内存的变量。 在 D3D10 中,具有组共享存储类的所有变量的最大总大小为 16kb,在 D3D11 中,最大大小为 32kb。 请参阅示例。
static 标记局部变量,使其初始化一次,并在函数调用之间保留。 如果声明不包含初始值设定项,则该值设置为零。 标记为 静态 的全局变量对应用程序不可见。
uniform 标记一个变量,该变量的数据在整个着色器 ((例如顶点着色器) 中的材料颜色)的执行过程中是恒定的;默认情况下,全局变量被视为 一致
volatile 标记频繁更改的变量;这是编译器的提示。 此存储类修饰符仅适用于局部变量。
注意: HLSL 编译器当前忽略此存储类修饰符。

Type_Modifier

可选的变量类型修饰符。

说明
const 标记着色器无法更改的变量,因此必须在变量声明中对其进行初始化。 默认情况下,全局变量被视为 常量 , (通过将 /Gec 标志提供给编译器) 来抑制此行为。
row_major 标记一个将四个组件存储在单个行中的变量,以便它们可以存储在单个常量寄存器中。
column_major 标记一个变量,该变量将 4 个分量存储在单个列中以优化矩阵数学。

注意

如果未指定类型修饰符值,编译器将使用 column_major 作为默认值。

Type

数据类型中列出的任何 HLSL 类型 (DirectX HLSL)

Name[Index]

唯一标识着色器变量的 ASCII 字符串。 若要定义可选数组,请使用 数组大小的索引 ,即正整数 = 1。

语义

可选参数使用情况信息,由编译器用来链接着色器输入和输出。 顶点着色器和像素着色器有多个预定义 语义 。 编译器会忽略语义,除非它们在全局变量上声明,或者传递给着色器的参数。

Packoffset

可选关键字 (keyword) ,用于手动打包着色器常量。 请参阅 packoffset (DirectX HLSL)

注册

用于手动将着色器变量分配给特定寄存器的可选关键字 (keyword) 。 请参阅 注册 (DirectX HLSL)

批注 ()

以字符串形式附加到全局变量的可选元数据。 注释由效果框架使用,并由 HLSL 忽略;若要查看更详细的语法,请参阅 批注语法

Initial_Value

可选初始值 (s) ;值数应与 Type 中的组件数匹配。 每个标记为 extern 的全局变量都必须使用文本值进行初始化;每个标记为 静态 的变量都必须使用常量进行初始化。

未标记为 静态外部的 全局变量不会编译到着色器中。 编译器不会自动设置全局变量的默认值,也不能在优化中使用它们。 若要初始化此类全局变量,请使用反射获取其值,然后将值复制到常量缓冲区。 例如,可以使用 ID3D11ShaderReflection::GetVariableByName 方法获取变量,使用 ID3D11ShaderReflectionVariable::GetDesc 方法获取着色器变量说明,并从 D3D11_SHADER_VARIABLE_DESC 结构的 DefaultValue 成员获取初始值。 若要将值复制到常量缓冲区,必须确保创建缓冲区时具有 CPU 写入访问权限 (D3D11_CPU_ACCESS_WRITE) 。 有关如何创建常量缓冲区的详细信息,请参阅 如何:创建常量缓冲区

还可以使用 效果框架 自动处理反射和设置初始值。 例如,可以使用 ID3DX11EffectPass::Apply 方法。

示例

下面是着色器变量声明的几个示例。

float fVar;
float4 color;
float fVar = 3.1f;

int iVar[3];

int iVar[3] = {1,2,3};

uniform float4 position : SV_POSITION; 
const float4 lightDirection = {0,0,1};
      

组共享

HLSL 使计算着色器的线程能够通过共享内存交换值。 HLSL 提供屏障基元(如 GroupMemoryBarrierWithGroupSync 等),以确保对着色器中的共享内存进行正确的读取和写入顺序,并避免数据争用。

注意

硬件在) (扭曲或波形前方 (组中执行线程,当仅同步属于同一组的线程正确时,有时可以省略屏障同步以提高性能。 但是,出于以下原因,我们强烈建议不要遗漏此内容:

  • 此省略会导致不可移植的代码,这些代码可能不适用于某些硬件,并且不适用于通常以较小组执行线程的软件光栅器。
  • 与使用全线程屏障相比,由于此遗漏而可能实现的性能改进很小。

在 Direct3D 10 中,写入 组共享时没有线程同步,因此这意味着每个线程仅限于数组中的单个位置进行写入。 写入时,使用 SV_GroupIndex 系统值为此数组编制索引,以确保没有两个线程可以发生冲突。 在读取方面,所有线程都有权访问整个数组进行读取。

struct GSData
{
    float4 Color;
    float Factor;
}

groupshared GSData data[5*5*1];

[numthreads(5,5,1)]
void main( uint index : SV_GroupIndex )
{
    data[index].Color = (float4)0;
    data[index].Factor = 2.0f;
    GroupMemoryBarrierWithGroupSync();
    ...
}

打包

打包其大小足以防止跨越寄存器边界的向量和标量子组件。 例如,这些都有效:

cbuffer MyBuffer
{
    float4 Element1 : packoffset(c0);
    float1 Element2 : packoffset(c1);
    float1 Element3 : packoffset(c1.y);
}
        

不能混合打包类型。

与寄存器关键字 (keyword) 一样,packoffset 可以是特定于目标的。 子组件打包仅适用于 packoffset 关键字 (keyword) ,而寄存器关键字 (keyword) 不可用。 在 cbuffer 声明中,对于 Direct3D 10 目标,将忽略寄存器关键字 (keyword) ,因为它假定为跨平台兼容性。

打包的元素可能会重叠,编译器不会提供任何错误或警告。 在此示例中,Element2 和 Element3 将与 Element1.x 和 Element1.y 重叠。

cbuffer MyBuffer
{
    float4 Element1 : packoffset(c0);
    float1 Element2 : packoffset(c0);
    float1 Element3 : packoffset(c0.y);
}
        

使用 packoffset 的示例为: HLSLWithoutFX10 示例

(DirectX HLSL) 变量