Why does spirv-remap give different outputs depending on out variable name?

94 Views Asked by At

I'm trying to understand what spirv-remap does, so I created a simple fragment shader with a simple layout(location=0) out vec4 fragColor;, compiled with glslang -V shader.frag -o shader.frag.spv and then spirv-remap --do-everything -i shader.frag.spv -o finalSpirV. As expected, changing variable names inside a uniform block does not change the final data in finalSpirV, after all, it's just data and offsets. To my surprise, renaming fragColor changed it. I thought that variable name was completely internal to the shader, and meaningless to the "outside world". What is my misunderstanding about spirv and spirv-remap?

Example:

shader1.frag

#version 460
layout(location=0) out vec4 fragColor;
void main()
{
    fragColor = vec4(1,0,0,1);
}

shader2.frag

#version 460
layout(location=0) out vec4 outout;
void main()
{
    outout = vec4(1,0,0,1);
}

after running glslang -V shader1.frag -o shader1.frag.spv && spirv-remap --do-everything -i shader1.frag.spv -o finalSpirV1, glslang -V shader2.frag -o shader2.frag.spv && spirv-remap --do-everything -i shader2.frag.spv -o finalSpirV2, spirv-dis finalSpirV1 -o orgFrag1.frag and spirv-dis finalSpirV2 -o orgFrag2.frag gives:

orgFrag1.frag

; SPIR-V
; Version: 1.0
; Generator: Khronos Glslang Reference Front End; 11
; Bound: 9012
; Schema: 0
               OpCapability Shader
          %1 = OpExtInstImport "GLSL.std.450"
               OpMemoryModel Logical GLSL450
               OpEntryPoint Fragment %5663 "main" %3647
               OpExecutionMode %5663 OriginUpperLeft
               OpDecorate %3647 Location 0
       %void = OpTypeVoid
       %1282 = OpTypeFunction %void
      %float = OpTypeFloat 32
    %v4float = OpTypeVector %float 4
%_ptr_Output_v4float = OpTypePointer Output %v4float
       %3647 = OpVariable %_ptr_Output_v4float Output
    %float_1 = OpConstant %float 1
    %float_0 = OpConstant %float 0
       %1416 = OpConstantComposite %v4float %float_1 %float_0 %float_0 %float_1
       %5663 = OpFunction %void None %1282
       %9011 = OpLabel
               OpStore %3647 %1416
               OpReturn
               OpFunctionEnd

orgFrag2.frag

; SPIR-V
; Version: 1.0
; Generator: Khronos Glslang Reference Front End; 11
; Bound: 9012
; Schema: 0
               OpCapability Shader
          %1 = OpExtInstImport "GLSL.std.450"
               OpMemoryModel Logical GLSL450
               OpEntryPoint Fragment %5663 "main" %3067
               OpExecutionMode %5663 OriginUpperLeft
               OpDecorate %3067 Location 0
       %void = OpTypeVoid
       %1282 = OpTypeFunction %void
      %float = OpTypeFloat 32
    %v4float = OpTypeVector %float 4
%_ptr_Output_v4float = OpTypePointer Output %v4float
       %3067 = OpVariable %_ptr_Output_v4float Output
    %float_1 = OpConstant %float 1
    %float_0 = OpConstant %float 0
       %1416 = OpConstantComposite %v4float %float_1 %float_0 %float_0 %float_1
       %5663 = OpFunction %void None %1282
       %9011 = OpLabel
               OpStore %3067 %1416
               OpReturn
               OpFunctionEnd

Cleary some id differs. Maybe SPIRV specification requires unique identifiers for out variables, and spirv-remap uses some kind of hash on the string name instead of a (more reasonable) sequential assignment of internal ids?

2

There are 2 best solutions below

1
Powereleven On

I figured it out. The problem is indeed the ID remapping, which I can't find much documentation about. Running spirv-remap only with flags --dce all --opt all --strip all gives consistent outputs.

I still don't understand what's possibly the benefit of ID remapping, maybe someone can explain in the comments.

5
Nicol Bolas On

Result IDs in SPIR-V are arbitrary; much like names in most programming languages, they are just placeholders. As such, a compiler can generate these IDs however they like. Compilers are in no way required to generate the same result IDs if you give it code that is only different based on the names.

Essentially, you cannot assume that if two SPIR-V binaries are un-equal, that they represent different shaders.