shader-slang / slang

Making it easier to work with shaders
MIT License
2.07k stars 177 forks source link

SPIR-V Validation error - Fragment stage integer Input decorated Flat multiple times #4315

Closed Darianopolis closed 3 months ago

Darianopolis commented 3 months ago

I have run into an issue with slang spirv output failing spirv validation checks in newly updated source builds of slang and the vulkan validation layers:

slang commit: https://github.com/shader-slang/slang/commit/9a23a9aab3721828526c921db1e779008e133e8f validation layers commit: https://github.com/KhronosGroup/Vulkan-ValidationLayers/commit/f34c751cbffb7287101e8d8682305a9b805892e3

The following shader

struct VertexOutput
{
    nointerpolation int a : SOME_VALUE;
    float4              b : SV_Position;
};

[shader("vertex")]
VertexOutput Vertex()
{
    VertexOutput out;
    out.a = 0;
    out.b = float4(0, 0, 0, 1);
    return out;
}

[shader("fragment")]
float4 Fragment(in VertexOutput vo)
{
    return float4(float(vo.a), 0, 0, 1);
}

produces the following validation error

Validation Error: [ VUID-VkShaderModuleCreateInfo-pCode-08737 ] | MessageID = 0xa5625282 | vkCreateShaderModule(): pCreateInfo->pCode (spirv-val produced an error):
ID '36' decorated with Flat multiple times is not allowed.
  %vo_a = OpVariable %_ptr_Input_int Input
. The Vulkan spec states: If pCode is a pointer to SPIR-V code, pCode must adhere to the validation rules described by the Validation Rules within a Module section of the SPIR-V Environment appendix (https://www.khronos.org/registry/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-VkShaderModuleCreateInfo-pCode-08737)

Note: This only occurs when a is an integer (I tried with int and uint). No double annotation or spirv error occurs when a is a float.

Inspecting spirv-assembly generated using the same compile options led to the following output

slangc 
  -lang slang 
  -matrix-layout-column-major 
  -force-glsl-scalar-layout 
  -target spirv-assembly 
  -fvk-use-entrypoint-name 
  -emit-spirv-directly
; SPIR-V
; Version: 1.5
; Generator: Khronos; 40
; Bound: 40
; Schema: 0
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Vertex %Vertex "Vertex" %entryPointParam_Vertex_a %gl_Position
OpEntryPoint Fragment %Fragment "Fragment" %entryPointParam_Fragment %vo_a
OpExecutionMode %Fragment OriginUpperLeft

; Debug Information
OpSource Slang 1
OpName %entryPointParam_Vertex_a "entryPointParam_Vertex.a"  ; id %25
OpName %Vertex "Vertex"  ; id %2
OpName %vo_a "vo.a"  ; id %36
OpName %entryPointParam_Fragment "entryPointParam_Fragment"  ; id %39
OpName %Fragment "Fragment"  ; id %32

; Annotations
OpDecorate %entryPointParam_Vertex_a Location 0
OpDecorate %entryPointParam_Vertex_a Flat
OpDecorate %gl_Position BuiltIn Position
OpDecorate %vo_a Location 0
OpDecorate %vo_a Flat
OpDecorate %entryPointParam_Fragment Location 0
OpDecorate %vo_a Flat

; Types, variables and constants
%void = OpTypeVoid
%3 = OpTypeFunction %void
%int = OpTypeInt 32 1
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%int_0 = OpConstant %int 0
%float_0 = OpConstant %float 0
%float_1 = OpConstant %float 1
%18 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_1
%_ptr_Output_int = OpTypePointer Output %int
%_ptr_Output_v4float = OpTypePointer Output %v4float
%_ptr_Input_int = OpTypePointer Input %int
%entryPointParam_Vertex_a = OpVariable %_ptr_Output_int Output
%gl_Position = OpVariable %_ptr_Output_v4float Output
%vo_a = OpVariable %_ptr_Input_int Input
%entryPointParam_Fragment = OpVariable %_ptr_Output_v4float Output

; Function Vertex
%Vertex = OpFunction %void None %3
%4 = OpLabel
OpStore %entryPointParam_Vertex_a %int_0
OpStore %gl_Position %18
OpReturn
OpFunctionEnd

; Function Fragment
%Fragment = OpFunction %void None %3
%33 = OpLabel
%34 = OpLoad %int %vo_a
%37 = OpConvertSToF %float %34
%38 = OpCompositeConstruct %v4float %37 %float_0 %float_0 %float_1
OpStore %entryPointParam_Fragment %38
OpReturn
OpFunctionEnd

where Flat is being applied twice

OpDecorate %vo_a Location 0
OpDecorate %vo_a Flat
OpDecorate %entryPointParam_Fragment Location 0
OpDecorate %vo_a Flat

The same double annotations occurs with the more minimal set of compile options building just the Fragment entry point

slangc 
  -lang slang 
  -target spirv-assembly
  -emit-spirv-directly
  -entry Fragment

Note: This only occurs when code is generated for the Fragment entry point. Generating Vertex results in only a single Flat decoration. Note: After commit https://github.com/shader-slang/slang/commit/f1de1817ca10e34ec6a844100f10f0de3340c9f2 this repro works without -emit-spirv-directly as it is now selected by default.

The first validation layers commit that started catching this was https://github.com/KhronosGroup/Vulkan-ValidationLayers/commit/a9b3f651c1b8a6515ec876f25a570f6572dc2516 which updated the SPIRV-Tools dependency to commit https://github.com/KhronosGroup/SPIRV-Tools/commit/02470f606fe1571de808cb773d8c521ab201aaff in which * Disallow duplicate decorations generally would be relevant here.

A recent commit (latest as of this issue being made) https://github.com/shader-slang/slang/commit/9a23a9aab3721828526c921db1e779008e133e8f seems to address some duplicate decorations, but not OpDecorate ... Flat

From bisecting, I believe the first commit that introduced this double decoration was https://github.com/shader-slang/slang/commit/6f8a20688e0c4b989db152b4d06aeab04fac0567 (which was made before the validation check was added to spirv-val)

Happy to provide any more context if necessary.

jkwak-work commented 3 months ago

I start getting this type of errors a lot after upgrading Vulkan SDK from 1.3.268.0 to 1.3.283.0. We may need to check the version we are using on CI.