对缓冲区资源使用无绑定描述符有意义吗?

Does it make sense to use bindless descriptors for buffer resources?

我正在我的 directx12 项目中尝试使用 bindless hlsl 资源绑定,我明白了为什么 bindless 对于绑定纹理很有用,因为您可以执行以下操作:

DescriptorTable(
    SRV(t0, space=0, numDescriptors=unbounded, offset=0),
    SRV(t0, space=1, numDescriptors=unbounded, offset=),
    SRV(t0, space=2, numDescriptors=unbounded, offset=0)
    visibility=SHADER_VISIBLITY_ALL)

Texture2D textures2d[8192] : register(t0, space0);
Texture3D textures3d[8192] : register(t0, space1);
TextureCube texturesCube[8192] : register(t0, space2);

但是绑定缓冲资源,比如StructuredBuffers呢?由于它们需要关联一个类型,例如 StructuredBuffer<some_struct>,您将如何在 HLSL 中声明它们?例如,假设您有许多不同类型的 StructuredBuffer,您是否必须将它们分别绑定到一个单独的 space?

struct point_light
{
    float3 position_ws;
    float falloff_start;
    float3 color;
    float falloff_end;
    float3 strenght;
    uint id;
};
RWStructuredBuffer<point_light> sb_point_lights : register(u0, space0);

struct spot_light
{
    float3 position_ws;
    float falloff_start;
    float3 color;
    float falloff_end;
    float3 strenght;
    float spot_power;
    float3 direction;
    uint id;
};
StructuredBuffer<spot_light> sb_spot_lights : register(u0, space1);

或者有没有办法做类似的事情(这不起作用):

struct point_light
{
    float3 position_ws;
    float falloff_start;
    float3 color;
    float falloff_end;
    float3 strenght;
    uint id;
};
RWStructuredBuffer<point_light> sb_point_lights : register(u0, space0);

struct spot_light
{
    float3 position_ws;
    float falloff_start;
    float3 color;
    float falloff_end;
    float3 strenght;
    float spot_power;
    float3 direction;
    uint id;
};
StructuredBuffer<spot_light> sb_spot_lights : register(u0 + offset_to_spotlights, space0);

如果你需要在相同类型的缓冲区之间切换,动态索引确实有用,但是正如你所说的你需要声明相同类型的资源(也就是说,它与纹理相同,我有共同的例如,Texture2d< uint > 之类的用例,因此它不限于 StructuredBuffer)。

是的,您必须为每个类型化缓冲区声明一个不同的数组,这不是很方便。

如果您想完全动态访问资源(无论类型),Shader Model 6.6 引入了对堆的直接访问(代号:ultimate bindless ;)

所以你有一个名为ResourceDescriptorHeap的全局变量(代表当前绑定的资源Heap)

和 SamplerDescriptorHeap(相同但用于采样器)。

现在你可以这样做(例如):

 int textureLocationInHeap =5;
 int bufferLocationInHeap = 6;
 
 Texture2D myTexture = ResourceDescriptorHeap[textureLocationInHeap];
 StructuredBuffer<float> myBuffer = ResourceDescriptorHeap[bufferLocationInHeap ];

然后您可以使用根常量或常量缓冲区(根据您的喜好)传递 textureLocationInHeap 和 bufferLocationInHeap。

您不再需要传递描述符 tables(当然您仍然可以混合使用 table/“直接访问”

当然请注意,如果您索引的资源类型不正确(或者您有一个空的堆槽),您将面临未定义的结果或驱动程序崩溃(第二种可能性更大)。

更多关于动态资源绑定的信息:

https://devblogs.microsoft.com/directx/in-the-works-hlsl-shader-model-6-6/