Vulkan使用location来绑定,而hlsl使用语义绑定,但SPIRV编译器通常会按输入的顺序来自动指定location,一个结构体如下:

struct InVertexAssembly
{
    float3 Position  : POSITION;
    float3 Normal    : NORMAL;
    float3 Tangent   : TANGENT;
    float4 Color     : COLOR0;
    float2 TexCoord0 : TEXCOORD0;
    float2 TexCoord1 : TEXCOORD1;
    float2 TexCoord2 : TEXCOORD2;
    float2 TexCoord3 : TEXCOORD3;
};

其中Position的location为隐式的0,Normal的location为隐式的1,可以通过spirv-dis工具来查看编译的字节码信息。

如果希望用户去自定义shader的输入方式,像unity中可以使用cg语言,通过语义绑定来允许用户不需要关注布局。如果使用以上方法调换变量位置则会出现数据传输的错误。要实现这种语义绑定,那让那我们可以在不修改编译器情况下来完成,定义一套自己的语义。

#ifdef PLATFORM_VULKAN
#define LAYOUT_LOCATION(index) [[vk::location(index)]]
#else
#define LAYOUT_LOCATION(index)  
#endif

#define EIS_POSITION  LAYOUT_LOCATION(0)
#define EIS_NORMAL    LAYOUT_LOCATION(1)
#define EIS_TANGENT   LAYOUT_LOCATION(2)
#define EIS_VERTCOLOR LAYOUT_LOCATION(3)
#define EIS_TEXCOORD0 LAYOUT_LOCATION(4)
#define EIS_TEXCOORD1 LAYOUT_LOCATION(5)
#define EIS_TEXCOORD2 LAYOUT_LOCATION(6)
#define EIS_TEXCOORD3 LAYOUT_LOCATION(7)

来修改一下结构体,这样就通过宏去给每个输入字段手动指定了一个location。

struct InVertexAssembly
{
    EIS_POSITION  float3 Position  : POSITION;
    EIS_NORMAL    float3 Normal    : NORMAL;
    EIS_TANGENT   float3 Tangent   : TANGENT;
    EIS_VERTCOLOR float4 Color     : COLOR0;
    EIS_TEXCOORD0 float2 TexCoord0 : TEXCOORD0;
    EIS_TEXCOORD1 float2 TexCoord1 : TEXCOORD1;
    EIS_TEXCOORD2 float2 TexCoord2 : TEXCOORD2;
    EIS_TEXCOORD3 float2 TexCoord3 : TEXCOORD3;
};

比如允许用户像unity一样,通过语义绑定自定义输入结构,前面的语义对应的location允许vk和gl使用,hlsl自身的语义d3d使用。

struct a2v
{
    EIS_NORMAL   Normal : NORMAL;
    EIS_POSITION Pos    : POSITION;
}