【问题标题】:DirectCompute shader (HLSL) has strange array sizeDirectCompute 着色器 (HLSL) 具有奇怪的数组大小
【发布时间】:2019-12-11 15:37:23
【问题描述】:

计算着色器存储 uint 数组的方式让我很苦恼。 我有以下着色器代码(重现问题的简单示例):

cbuffer TCstParams : register(b0)
{
    int    IntValue1;
    uint   UIntArray[10];    // <== PROBLEM IS HERE
    int    IntValue2;
}

RWTexture2D<float4>                Output         : register(u0);

[numthreads(1, 1, 1)]
void CSMain()
{
    if (IntValue1 == 0)
        Output[uint2(0, 0)] = float4(1, 1, 1, 1);
}

编译后,我检查编译器的输出以了解常量缓冲区项的偏移量和大小。项目“uint UIntArray[10];”令人惊讶的大小为 148 字节。这很奇怪,因为 uint 是 4 个字节。所以我希望数组大小为 40 字节。

这是编译器的输出:

Microsoft (R) Direct3D Shader Compiler 6.3.9600.16384
Copyright (C) 2013 Microsoft. All rights reserved.

//
// Generated by Microsoft (R) HLSL Shader Compiler 6.3.9600.16384
//
//
// Buffer Definitions: 
//
// cbuffer TCstParams
// {
//
//   int IntValue1;                     // Offset:    0 Size:     4
//   uint UIntArray[10];                // Offset:   16 Size:   148 [unused]    // <== PROBLEM IS HERE
//   int IntValue2;                     // Offset:  164 Size:     4 [unused]
//
// }
//
//
// Resource Bindings:
//
// Name                                 Type  Format         Dim Slot Elements
// ------------------------------ ---------- ------- ----------- ---- --------
// Output                                UAV  float4          2d    0        1
// TCstParams                        cbuffer      NA          NA    0        1
//
//
//
// Input signature:
//
// Name                 Index   Mask Register SysValue  Format   Used
// -------------------- ----- ------ -------- -------- ------- ------
// no Input
//
// Output signature:
//
// Name                 Index   Mask Register SysValue  Format   Used
// -------------------- ----- ------ -------- -------- ------- ------
// no Output
cs_5_0
dcl_globalFlags refactoringAllowed | skipOptimization
dcl_constantbuffer cb0[1], immediateIndexed
dcl_uav_typed_texture2d (float,float,float,float) u0
dcl_temps 2
dcl_thread_group 1, 1, 1

#line 13 "E:\Development\Projects\Test Projects\DirectCompute\TestShader1.hlsl"
if_z cb0[0].x
  mov r0.xyzw, l(0,0,0,0)
  itof r1.xyzw, l(1, 1, 1, 1)
  store_uav_typed u0.xyzw, r0.xyzw, r1.xyzw
endif 
ret 
// Approximately 6 instruction slots used

我检查了各种数组大小,结果很奇怪:元素数量变化时每个元素的大小不同!

我做错了什么或者我想念什么? 谢谢。

【问题讨论】:

    标签: directx hlsl directcompute


    【解决方案1】:

    引用Microsoft Docs:

    默认情况下,数组不打包在 HLSL 中。为了避免强制着色器为偏移计算承担 ALU 开销,数组中的每个元素都存储在一个四分量向量中。

    所以uint UIntArray[10]; 实际上存储为uint4 UIntArray[10];,除了最后三个填充 uint 不包括在大小计算中(即使它们仍然计入偏移计算)。

    如果您想要更紧凑的包装,您可以将数组声明为uint4 UInt4Array[4];,然后将其转换为:static uint UInt1Array[16] = (uint[16])TCstParams.UInt4Array;(没有检查该代码是否正确,但应该类似)。强制转换本身不会造成任何开销 - 但是,在 UInt1Array 中访问元素将引入额外的指令来计算实际偏移量。

    【讨论】:

    • 感谢您指向我的文档。为了有更紧密的包装,我必须将大小除以 4 并使用 uint4。我明白那个。但我根本不明白如何使用你展示的演员表。在使用数组的实际代码中,我必须单独访问每个 uint。使用强制转换,我可以避免在基于等效 uintarray 索引的某个索引处计算自己正确的 uint4 组件吗?
    • 是的,转换只是告诉编译器自动计算正确的索引和组件。这只是使访问紧密封装数组中的值更加方便的一种简写方式。
    • 嗯,我知道演员表是什么。我不明白如何应用您显示的那一行,这只是一个带有初始化的变量声明。目前要访问一个数组元素,我使用这个: MyFunct(UInt4Array[Index>>2][Index&3]);如果我理解得很好,使用演员表会变成 M​​yFunct(((uint[16])UIntArray)[Index]) 。没有太多可读性。
    • 这个想法是在单独的行中使用演员表,然后调用MyFunct(UIntArray[index])。无论您是否使用演员阵容都取决于您,说明最终应该是相同的,所以使用您更好的套件
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多