Merge pull request #136 from KhronosGroup/hlsl-builtin
Rewrite HLSL backend handling of inputs and outputs.
This commit is contained in:
commit
ba09b0e1a0
@ -4,15 +4,15 @@ static float4 FragColor;
|
|||||||
static float4 vColor;
|
static float4 vColor;
|
||||||
static float2 vTex;
|
static float2 vTex;
|
||||||
|
|
||||||
struct InputFrag
|
struct SPIRV_Cross_Input
|
||||||
{
|
{
|
||||||
float4 vColor : TEXCOORD0;
|
float4 vColor : TEXCOORD0;
|
||||||
float2 vTex : TEXCOORD1;
|
float2 vTex : TEXCOORD1;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct OutputFrag
|
struct SPIRV_Cross_Output
|
||||||
{
|
{
|
||||||
float4 FragColor : COLOR;
|
float4 FragColor : SV_Target0;
|
||||||
};
|
};
|
||||||
|
|
||||||
void frag_main()
|
void frag_main()
|
||||||
@ -20,12 +20,12 @@ void frag_main()
|
|||||||
FragColor = vColor * tex2D(uTex, vTex);
|
FragColor = vColor * tex2D(uTex, vTex);
|
||||||
}
|
}
|
||||||
|
|
||||||
OutputFrag main(InputFrag input)
|
SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input)
|
||||||
{
|
{
|
||||||
vColor = input.vColor;
|
vColor = stage_input.vColor;
|
||||||
vTex = input.vTex;
|
vTex = stage_input.vTex;
|
||||||
frag_main();
|
frag_main();
|
||||||
OutputFrag output;
|
SPIRV_Cross_Output stage_output;
|
||||||
output.FragColor = FragColor;
|
stage_output.FragColor = FragColor;
|
||||||
return output;
|
return stage_output;
|
||||||
}
|
}
|
||||||
|
33
reference/shaders-hlsl/frag/builtins.frag
Normal file
33
reference/shaders-hlsl/frag/builtins.frag
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
static float4 gl_FragCoord;
|
||||||
|
static float gl_FragDepth;
|
||||||
|
static float4 FragColor;
|
||||||
|
static float4 vColor;
|
||||||
|
|
||||||
|
struct SPIRV_Cross_Input
|
||||||
|
{
|
||||||
|
float4 gl_FragCoord : SV_Position;
|
||||||
|
float4 vColor : TEXCOORD0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SPIRV_Cross_Output
|
||||||
|
{
|
||||||
|
float gl_FragDepth : SV_Depth;
|
||||||
|
float4 FragColor : SV_Target0;
|
||||||
|
};
|
||||||
|
|
||||||
|
void frag_main()
|
||||||
|
{
|
||||||
|
FragColor = gl_FragCoord + vColor;
|
||||||
|
gl_FragDepth = 0.5f;
|
||||||
|
}
|
||||||
|
|
||||||
|
SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input)
|
||||||
|
{
|
||||||
|
gl_FragCoord = stage_input.gl_FragCoord;
|
||||||
|
vColor = stage_input.vColor;
|
||||||
|
frag_main();
|
||||||
|
SPIRV_Cross_Output stage_output;
|
||||||
|
stage_output.gl_FragDepth = gl_FragDepth;
|
||||||
|
stage_output.FragColor = FragColor;
|
||||||
|
return stage_output;
|
||||||
|
}
|
28
reference/shaders-hlsl/frag/io-block.frag
Normal file
28
reference/shaders-hlsl/frag/io-block.frag
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
static float4 FragColor;
|
||||||
|
|
||||||
|
struct VertexOut
|
||||||
|
{
|
||||||
|
float4 a : TEXCOORD1;
|
||||||
|
float4 b : TEXCOORD2;
|
||||||
|
};
|
||||||
|
|
||||||
|
static VertexOut _12;
|
||||||
|
|
||||||
|
struct SPIRV_Cross_Output
|
||||||
|
{
|
||||||
|
float4 FragColor : SV_Target0;
|
||||||
|
};
|
||||||
|
|
||||||
|
void frag_main()
|
||||||
|
{
|
||||||
|
FragColor = _12.a + _12.b;
|
||||||
|
}
|
||||||
|
|
||||||
|
SPIRV_Cross_Output main(in VertexOut stage_input_12)
|
||||||
|
{
|
||||||
|
_12 = stage_input_12;
|
||||||
|
frag_main();
|
||||||
|
SPIRV_Cross_Output stage_output;
|
||||||
|
stage_output.FragColor = FragColor;
|
||||||
|
return stage_output;
|
||||||
|
}
|
31
reference/shaders-hlsl/frag/mrt.frag
Normal file
31
reference/shaders-hlsl/frag/mrt.frag
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
static float4 RT0;
|
||||||
|
static float4 RT1;
|
||||||
|
static float4 RT2;
|
||||||
|
static float4 RT3;
|
||||||
|
|
||||||
|
struct SPIRV_Cross_Output
|
||||||
|
{
|
||||||
|
float4 RT0 : SV_Target0;
|
||||||
|
float4 RT1 : SV_Target1;
|
||||||
|
float4 RT2 : SV_Target2;
|
||||||
|
float4 RT3 : SV_Target3;
|
||||||
|
};
|
||||||
|
|
||||||
|
void frag_main()
|
||||||
|
{
|
||||||
|
RT0 = float4(1.0f, 1.0f, 1.0f, 1.0f);
|
||||||
|
RT1 = float4(2.0f, 2.0f, 2.0f, 2.0f);
|
||||||
|
RT2 = float4(3.0f, 3.0f, 3.0f, 3.0f);
|
||||||
|
RT3 = float4(4.0f, 4.0f, 4.0f, 4.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
SPIRV_Cross_Output main()
|
||||||
|
{
|
||||||
|
frag_main();
|
||||||
|
SPIRV_Cross_Output stage_output;
|
||||||
|
stage_output.RT0 = RT0;
|
||||||
|
stage_output.RT1 = RT1;
|
||||||
|
stage_output.RT2 = RT2;
|
||||||
|
stage_output.RT3 = RT3;
|
||||||
|
return stage_output;
|
||||||
|
}
|
8
reference/shaders-hlsl/frag/no-return.frag
Normal file
8
reference/shaders-hlsl/frag/no-return.frag
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
void frag_main()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
frag_main();
|
||||||
|
}
|
17
reference/shaders-hlsl/frag/no-return2.frag
Normal file
17
reference/shaders-hlsl/frag/no-return2.frag
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
static float4 vColor;
|
||||||
|
|
||||||
|
struct SPIRV_Cross_Input
|
||||||
|
{
|
||||||
|
float4 vColor : TEXCOORD0;
|
||||||
|
};
|
||||||
|
|
||||||
|
void frag_main()
|
||||||
|
{
|
||||||
|
float4 v = vColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
void main(SPIRV_Cross_Input stage_input)
|
||||||
|
{
|
||||||
|
vColor = stage_input.vColor;
|
||||||
|
frag_main();
|
||||||
|
}
|
@ -7,23 +7,22 @@ cbuffer UBO
|
|||||||
{
|
{
|
||||||
_UBO _16;
|
_UBO _16;
|
||||||
};
|
};
|
||||||
uniform float4 gl_HalfPixel;
|
|
||||||
|
|
||||||
static float4 gl_Position;
|
static float4 gl_Position;
|
||||||
static float4 aVertex;
|
static float4 aVertex;
|
||||||
static float3 vNormal;
|
static float3 vNormal;
|
||||||
static float3 aNormal;
|
static float3 aNormal;
|
||||||
|
|
||||||
struct InputVert
|
struct SPIRV_Cross_Input
|
||||||
{
|
{
|
||||||
float3 aNormal : TEXCOORD0;
|
float3 aNormal : TEXCOORD0;
|
||||||
float4 aVertex : TEXCOORD1;
|
float4 aVertex : TEXCOORD1;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct OutputVert
|
struct SPIRV_Cross_Output
|
||||||
{
|
{
|
||||||
|
float4 gl_Position : SV_Position;
|
||||||
float3 vNormal : TEXCOORD0;
|
float3 vNormal : TEXCOORD0;
|
||||||
float4 gl_Position : POSITION;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void vert_main()
|
void vert_main()
|
||||||
@ -32,15 +31,13 @@ void vert_main()
|
|||||||
vNormal = aNormal;
|
vNormal = aNormal;
|
||||||
}
|
}
|
||||||
|
|
||||||
OutputVert main(InputVert input)
|
SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input)
|
||||||
{
|
{
|
||||||
aVertex = input.aVertex;
|
aVertex = stage_input.aVertex;
|
||||||
aNormal = input.aNormal;
|
aNormal = stage_input.aNormal;
|
||||||
vert_main();
|
vert_main();
|
||||||
OutputVert output;
|
SPIRV_Cross_Output stage_output;
|
||||||
output.gl_Position = gl_Position;
|
stage_output.gl_Position = gl_Position;
|
||||||
output.vNormal = vNormal;
|
stage_output.vNormal = vNormal;
|
||||||
output.gl_Position.x = output.gl_Position.x - gl_HalfPixel.x * output.gl_Position.w;
|
return stage_output;
|
||||||
output.gl_Position.y = output.gl_Position.y + gl_HalfPixel.y * output.gl_Position.w;
|
|
||||||
return output;
|
|
||||||
}
|
}
|
||||||
|
29
reference/shaders-hlsl/vert/instancing.vert
Normal file
29
reference/shaders-hlsl/vert/instancing.vert
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
static float4 gl_Position;
|
||||||
|
static int gl_VertexIndex;
|
||||||
|
static int gl_InstanceIndex;
|
||||||
|
struct SPIRV_Cross_Input
|
||||||
|
{
|
||||||
|
uint gl_VertexIndex : SV_VertexID;
|
||||||
|
uint gl_InstanceIndex : SV_InstanceID;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SPIRV_Cross_Output
|
||||||
|
{
|
||||||
|
float4 gl_Position : SV_Position;
|
||||||
|
};
|
||||||
|
|
||||||
|
void vert_main()
|
||||||
|
{
|
||||||
|
float _19 = float(gl_VertexIndex + gl_InstanceIndex);
|
||||||
|
gl_Position = float4(_19, _19, _19, _19);
|
||||||
|
}
|
||||||
|
|
||||||
|
SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input)
|
||||||
|
{
|
||||||
|
gl_VertexIndex = int(stage_input.gl_VertexIndex);
|
||||||
|
gl_InstanceIndex = int(stage_input.gl_InstanceIndex);
|
||||||
|
vert_main();
|
||||||
|
SPIRV_Cross_Output stage_output;
|
||||||
|
stage_output.gl_Position = gl_Position;
|
||||||
|
return stage_output;
|
||||||
|
}
|
75
reference/shaders-hlsl/vert/locations.vert
Normal file
75
reference/shaders-hlsl/vert/locations.vert
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
struct Foo
|
||||||
|
{
|
||||||
|
float3 a;
|
||||||
|
float3 b;
|
||||||
|
float3 c;
|
||||||
|
};
|
||||||
|
|
||||||
|
static float4 gl_Position;
|
||||||
|
static float4 Input2;
|
||||||
|
static float4 Input4;
|
||||||
|
static float4 Input0;
|
||||||
|
static float vLocation0;
|
||||||
|
static float vLocation1;
|
||||||
|
static float vLocation2[2];
|
||||||
|
static Foo vLocation4;
|
||||||
|
static float vLocation9;
|
||||||
|
|
||||||
|
struct VertexOut
|
||||||
|
{
|
||||||
|
float3 color : TEXCOORD7;
|
||||||
|
float3 foo : TEXCOORD8;
|
||||||
|
};
|
||||||
|
|
||||||
|
static VertexOut vout;
|
||||||
|
|
||||||
|
struct SPIRV_Cross_Input
|
||||||
|
{
|
||||||
|
float4 Input2 : TEXCOORD2;
|
||||||
|
float4 Input4 : TEXCOORD4;
|
||||||
|
float4 Input0 : TEXCOORD0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SPIRV_Cross_Output
|
||||||
|
{
|
||||||
|
float4 gl_Position : SV_Position;
|
||||||
|
float vLocation0 : TEXCOORD0;
|
||||||
|
float vLocation1 : TEXCOORD1;
|
||||||
|
float vLocation2[2] : TEXCOORD2;
|
||||||
|
Foo vLocation4 : TEXCOORD4;
|
||||||
|
float vLocation9 : TEXCOORD9;
|
||||||
|
};
|
||||||
|
|
||||||
|
void vert_main()
|
||||||
|
{
|
||||||
|
gl_Position = ((float4(1.0f, 1.0f, 1.0f, 1.0f) + Input2) + Input4) + Input0;
|
||||||
|
vLocation0 = 0.0f;
|
||||||
|
vLocation1 = 1.0f;
|
||||||
|
vLocation2[0] = 2.0f;
|
||||||
|
vLocation2[1] = 2.0f;
|
||||||
|
Foo foo;
|
||||||
|
foo.a = float3(1.0f, 1.0f, 1.0f);
|
||||||
|
foo.b = float3(1.0f, 1.0f, 1.0f);
|
||||||
|
foo.c = float3(1.0f, 1.0f, 1.0f);
|
||||||
|
vLocation4 = foo;
|
||||||
|
vLocation9 = 9.0f;
|
||||||
|
vout.color = float3(2.0f, 2.0f, 2.0f);
|
||||||
|
vout.foo = float3(4.0f, 4.0f, 4.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input, out VertexOut stage_outputvout)
|
||||||
|
{
|
||||||
|
Input2 = stage_input.Input2;
|
||||||
|
Input4 = stage_input.Input4;
|
||||||
|
Input0 = stage_input.Input0;
|
||||||
|
vert_main();
|
||||||
|
stage_outputvout = vout;
|
||||||
|
SPIRV_Cross_Output stage_output;
|
||||||
|
stage_output.gl_Position = gl_Position;
|
||||||
|
stage_output.vLocation0 = vLocation0;
|
||||||
|
stage_output.vLocation1 = vLocation1;
|
||||||
|
stage_output.vLocation2 = vLocation2;
|
||||||
|
stage_output.vLocation4 = vLocation4;
|
||||||
|
stage_output.vLocation9 = vLocation9;
|
||||||
|
return stage_output;
|
||||||
|
}
|
18
reference/shaders-hlsl/vert/no-input.vert
Normal file
18
reference/shaders-hlsl/vert/no-input.vert
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
static float4 gl_Position;
|
||||||
|
struct SPIRV_Cross_Output
|
||||||
|
{
|
||||||
|
float4 gl_Position : SV_Position;
|
||||||
|
};
|
||||||
|
|
||||||
|
void vert_main()
|
||||||
|
{
|
||||||
|
gl_Position = float4(1.0f, 1.0f, 1.0f, 1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
SPIRV_Cross_Output main()
|
||||||
|
{
|
||||||
|
vert_main();
|
||||||
|
SPIRV_Cross_Output stage_output;
|
||||||
|
stage_output.gl_Position = gl_Position;
|
||||||
|
return stage_output;
|
||||||
|
}
|
50
reference/shaders-hlsl/vert/qualifiers.vert
Normal file
50
reference/shaders-hlsl/vert/qualifiers.vert
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
static float4 gl_Position;
|
||||||
|
static float vFlat;
|
||||||
|
static float vCentroid;
|
||||||
|
static float vSample;
|
||||||
|
static float vNoperspective;
|
||||||
|
|
||||||
|
struct Block
|
||||||
|
{
|
||||||
|
nointerpolation float vFlat : TEXCOORD4;
|
||||||
|
centroid float vCentroid : TEXCOORD5;
|
||||||
|
sample float vSample : TEXCOORD6;
|
||||||
|
noperspective float vNoperspective : TEXCOORD7;
|
||||||
|
};
|
||||||
|
|
||||||
|
static Block vout;
|
||||||
|
|
||||||
|
struct SPIRV_Cross_Output
|
||||||
|
{
|
||||||
|
float4 gl_Position : SV_Position;
|
||||||
|
nointerpolation float vFlat : TEXCOORD0;
|
||||||
|
centroid float vCentroid : TEXCOORD1;
|
||||||
|
sample float vSample : TEXCOORD2;
|
||||||
|
noperspective float vNoperspective : TEXCOORD3;
|
||||||
|
};
|
||||||
|
|
||||||
|
void vert_main()
|
||||||
|
{
|
||||||
|
gl_Position = float4(1.0f, 1.0f, 1.0f, 1.0f);
|
||||||
|
vFlat = 0.0f;
|
||||||
|
vCentroid = 1.0f;
|
||||||
|
vSample = 2.0f;
|
||||||
|
vNoperspective = 3.0f;
|
||||||
|
vout.vFlat = 0.0f;
|
||||||
|
vout.vCentroid = 1.0f;
|
||||||
|
vout.vSample = 2.0f;
|
||||||
|
vout.vNoperspective = 3.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
SPIRV_Cross_Output main(out Block stage_outputvout)
|
||||||
|
{
|
||||||
|
vert_main();
|
||||||
|
stage_outputvout = vout;
|
||||||
|
SPIRV_Cross_Output stage_output;
|
||||||
|
stage_output.gl_Position = gl_Position;
|
||||||
|
stage_output.vFlat = vFlat;
|
||||||
|
stage_output.vCentroid = vCentroid;
|
||||||
|
stage_output.vSample = vSample;
|
||||||
|
stage_output.vNoperspective = vNoperspective;
|
||||||
|
return stage_output;
|
||||||
|
}
|
11
shaders-hlsl/frag/builtins.frag
Normal file
11
shaders-hlsl/frag/builtins.frag
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#version 310 es
|
||||||
|
precision mediump float;
|
||||||
|
|
||||||
|
layout(location = 0) out vec4 FragColor;
|
||||||
|
layout(location = 0) in vec4 vColor;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
FragColor = gl_FragCoord + vColor;
|
||||||
|
gl_FragDepth = 0.5;
|
||||||
|
}
|
16
shaders-hlsl/frag/io-block.frag
Normal file
16
shaders-hlsl/frag/io-block.frag
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#version 310 es
|
||||||
|
#extension GL_EXT_shader_io_blocks : require
|
||||||
|
precision mediump float;
|
||||||
|
|
||||||
|
layout(location = 1) in VertexOut
|
||||||
|
{
|
||||||
|
vec4 a;
|
||||||
|
vec4 b;
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(location = 0) out vec4 FragColor;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
FragColor = a + b;
|
||||||
|
}
|
15
shaders-hlsl/frag/mrt.frag
Normal file
15
shaders-hlsl/frag/mrt.frag
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#version 310 es
|
||||||
|
precision mediump float;
|
||||||
|
|
||||||
|
layout(location = 0) out vec4 RT0;
|
||||||
|
layout(location = 1) out vec4 RT1;
|
||||||
|
layout(location = 2) out vec4 RT2;
|
||||||
|
layout(location = 3) out vec4 RT3;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
RT0 = vec4(1.0);
|
||||||
|
RT1 = vec4(2.0);
|
||||||
|
RT2 = vec4(3.0);
|
||||||
|
RT3 = vec4(4.0);
|
||||||
|
}
|
5
shaders-hlsl/frag/no-return.frag
Normal file
5
shaders-hlsl/frag/no-return.frag
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#version 310 es
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
}
|
9
shaders-hlsl/frag/no-return2.frag
Normal file
9
shaders-hlsl/frag/no-return2.frag
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#version 310 es
|
||||||
|
precision mediump float;
|
||||||
|
|
||||||
|
layout(location = 0) in vec4 vColor;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
vec4 v = vColor;
|
||||||
|
}
|
6
shaders-hlsl/vert/instancing.vert
Normal file
6
shaders-hlsl/vert/instancing.vert
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#version 310 es
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
gl_Position = vec4(float(gl_VertexIndex + gl_InstanceIndex));
|
||||||
|
}
|
51
shaders-hlsl/vert/locations.vert
Normal file
51
shaders-hlsl/vert/locations.vert
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
#version 310 es
|
||||||
|
#extension GL_EXT_shader_io_blocks : require
|
||||||
|
|
||||||
|
struct Foo
|
||||||
|
{
|
||||||
|
vec3 a;
|
||||||
|
vec3 b;
|
||||||
|
vec3 c;
|
||||||
|
};
|
||||||
|
|
||||||
|
// This will lock to input location 2.
|
||||||
|
layout(location = 2) in vec4 Input2;
|
||||||
|
// This will lock to input location 4.
|
||||||
|
layout(location = 4) in vec4 Input4;
|
||||||
|
// This will pick first available, which is 0.
|
||||||
|
in vec4 Input0;
|
||||||
|
|
||||||
|
// Locks output 0.
|
||||||
|
layout(location = 0) out float vLocation0;
|
||||||
|
// Locks output 1.
|
||||||
|
layout(location = 1) out float vLocation1;
|
||||||
|
// Picks first available two locations, so, 2 and 3.
|
||||||
|
out float vLocation2[2];
|
||||||
|
// Picks first available location, 4.
|
||||||
|
out Foo vLocation4;
|
||||||
|
// Picks first available location 9.
|
||||||
|
out float vLocation9;
|
||||||
|
|
||||||
|
// Locks location 7 and 8.
|
||||||
|
layout(location = 7) out VertexOut
|
||||||
|
{
|
||||||
|
vec3 color;
|
||||||
|
vec3 foo;
|
||||||
|
} vout;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
gl_Position = vec4(1.0) + Input2 + Input4 + Input0;
|
||||||
|
vLocation0 = 0.0;
|
||||||
|
vLocation1 = 1.0;
|
||||||
|
vLocation2[0] = 2.0;
|
||||||
|
vLocation2[1] = 2.0;
|
||||||
|
Foo foo;
|
||||||
|
foo.a = vec3(1.0);
|
||||||
|
foo.b = vec3(1.0);
|
||||||
|
foo.c = vec3(1.0);
|
||||||
|
vLocation4 = foo;
|
||||||
|
vLocation9 = 9.0;
|
||||||
|
vout.color = vec3(2.0);
|
||||||
|
vout.foo = vec3(4.0);
|
||||||
|
}
|
6
shaders-hlsl/vert/no-input.vert
Normal file
6
shaders-hlsl/vert/no-input.vert
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#version 310 es
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
gl_Position = vec4(1.0);
|
||||||
|
}
|
27
shaders-hlsl/vert/qualifiers.vert
Normal file
27
shaders-hlsl/vert/qualifiers.vert
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
#version 450
|
||||||
|
|
||||||
|
layout(location = 0) flat out float vFlat;
|
||||||
|
layout(location = 1) centroid out float vCentroid;
|
||||||
|
layout(location = 2) sample out float vSample;
|
||||||
|
layout(location = 3) noperspective out float vNoperspective;
|
||||||
|
|
||||||
|
layout(location = 4) out Block
|
||||||
|
{
|
||||||
|
flat float vFlat;
|
||||||
|
centroid float vCentroid;
|
||||||
|
sample float vSample;
|
||||||
|
noperspective float vNoperspective;
|
||||||
|
} vout;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
gl_Position = vec4(1.0);
|
||||||
|
vFlat = 0.0;
|
||||||
|
vCentroid = 1.0;
|
||||||
|
vSample = 2.0;
|
||||||
|
vNoperspective = 3.0;
|
||||||
|
vout.vFlat = 0.0;
|
||||||
|
vout.vCentroid = 1.0;
|
||||||
|
vout.vSample = 2.0;
|
||||||
|
vout.vNoperspective = 3.0;
|
||||||
|
}
|
@ -297,6 +297,8 @@ string CompilerCPP::compile()
|
|||||||
backend.explicit_struct_type = true;
|
backend.explicit_struct_type = true;
|
||||||
backend.use_initializer_list = true;
|
backend.use_initializer_list = true;
|
||||||
|
|
||||||
|
update_active_builtins();
|
||||||
|
|
||||||
uint32_t pass_count = 0;
|
uint32_t pass_count = 0;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
|
129
spirv_cross.cpp
129
spirv_cross.cpp
@ -136,7 +136,7 @@ bool Compiler::block_is_pure(const SPIRBlock &block)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
string Compiler::to_name(uint32_t id, bool allow_alias)
|
string Compiler::to_name(uint32_t id, bool allow_alias) const
|
||||||
{
|
{
|
||||||
if (allow_alias && ids.at(id).get_type() == TypeType)
|
if (allow_alias && ids.at(id).get_type() == TypeType)
|
||||||
{
|
{
|
||||||
@ -491,7 +491,7 @@ bool Compiler::InterfaceVariableAccessHandler::handle(Op opcode, const uint32_t
|
|||||||
|
|
||||||
case OpCopyMemory:
|
case OpCopyMemory:
|
||||||
{
|
{
|
||||||
if (length < 3)
|
if (length < 2)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
auto *var = compiler.maybe_get<SPIRVariable>(args[0]);
|
auto *var = compiler.maybe_get<SPIRVariable>(args[0]);
|
||||||
@ -2865,7 +2865,7 @@ void Compiler::analyze_variable_scope(SPIRFunction &entry)
|
|||||||
|
|
||||||
case OpCopyMemory:
|
case OpCopyMemory:
|
||||||
{
|
{
|
||||||
if (length < 3)
|
if (length < 2)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
uint32_t lhs = args[0];
|
uint32_t lhs = args[0];
|
||||||
@ -3116,3 +3116,126 @@ bool Compiler::get_common_basic_type(const SPIRType &type, SPIRType::BaseType &b
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Compiler::ActiveBuiltinHandler::handle(spv::Op opcode, const uint32_t *args, uint32_t length)
|
||||||
|
{
|
||||||
|
const auto add_if_builtin = [&](uint32_t id) {
|
||||||
|
// Only handles variables here.
|
||||||
|
// Builtins which are part of a block are handled in AccessChain.
|
||||||
|
auto *var = compiler.maybe_get<SPIRVariable>(id);
|
||||||
|
if (var && compiler.meta[id].decoration.builtin)
|
||||||
|
{
|
||||||
|
auto &type = compiler.get<SPIRType>(var->basetype);
|
||||||
|
auto &flags =
|
||||||
|
type.storage == StorageClassInput ? compiler.active_input_builtins : compiler.active_output_builtins;
|
||||||
|
flags |= 1ull << compiler.meta[id].decoration.builtin_type;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (opcode)
|
||||||
|
{
|
||||||
|
case OpStore:
|
||||||
|
if (length < 1)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
add_if_builtin(args[0]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OpCopyMemory:
|
||||||
|
if (length < 2)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
add_if_builtin(args[0]);
|
||||||
|
add_if_builtin(args[1]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OpCopyObject:
|
||||||
|
case OpLoad:
|
||||||
|
if (length < 3)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
add_if_builtin(args[2]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OpFunctionCall:
|
||||||
|
{
|
||||||
|
if (length < 3)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
uint32_t count = length - 3;
|
||||||
|
args += 3;
|
||||||
|
for (uint32_t i = 0; i < count; i++)
|
||||||
|
add_if_builtin(args[i]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case OpAccessChain:
|
||||||
|
case OpInBoundsAccessChain:
|
||||||
|
{
|
||||||
|
if (length < 4)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Only consider global variables, cannot consider variables in functions yet, or other
|
||||||
|
// access chains as they have not been created yet.
|
||||||
|
auto *var = compiler.maybe_get<SPIRVariable>(args[2]);
|
||||||
|
if (!var)
|
||||||
|
break;
|
||||||
|
|
||||||
|
auto *type = &compiler.get<SPIRType>(var->basetype);
|
||||||
|
|
||||||
|
// Start traversing type hierarchy at the proper non-pointer types.
|
||||||
|
while (type->pointer)
|
||||||
|
{
|
||||||
|
assert(type->parent_type);
|
||||||
|
type = &compiler.get<SPIRType>(type->parent_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto &flags =
|
||||||
|
type->storage == StorageClassInput ? compiler.active_input_builtins : compiler.active_output_builtins;
|
||||||
|
|
||||||
|
uint32_t count = length - 3;
|
||||||
|
args += 3;
|
||||||
|
for (uint32_t i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
// Arrays
|
||||||
|
if (!type->array.empty())
|
||||||
|
{
|
||||||
|
type = &compiler.get<SPIRType>(type->parent_type);
|
||||||
|
}
|
||||||
|
// Structs
|
||||||
|
else if (type->basetype == SPIRType::Struct)
|
||||||
|
{
|
||||||
|
uint32_t index = compiler.get<SPIRConstant>(args[i]).scalar();
|
||||||
|
|
||||||
|
if (index < uint32_t(compiler.meta[type->self].members.size()))
|
||||||
|
{
|
||||||
|
auto &decorations = compiler.meta[type->self].members[index];
|
||||||
|
if (decorations.builtin)
|
||||||
|
flags |= 1ull << decorations.builtin_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
type = &compiler.get<SPIRType>(type->member_types[index]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// No point in traversing further. We won't find any extra builtins.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Compiler::update_active_builtins()
|
||||||
|
{
|
||||||
|
active_input_builtins = 0;
|
||||||
|
active_output_builtins = 0;
|
||||||
|
ActiveBuiltinHandler handler(*this);
|
||||||
|
traverse_all_reachable_opcodes(get<SPIRFunction>(entry_point), handler);
|
||||||
|
}
|
||||||
|
@ -411,7 +411,7 @@ protected:
|
|||||||
std::unordered_set<uint32_t> selection_merge_targets;
|
std::unordered_set<uint32_t> selection_merge_targets;
|
||||||
std::unordered_set<uint32_t> multiselect_merge_targets;
|
std::unordered_set<uint32_t> multiselect_merge_targets;
|
||||||
|
|
||||||
virtual std::string to_name(uint32_t id, bool allow_alias = true);
|
virtual std::string to_name(uint32_t id, bool allow_alias = true) const;
|
||||||
bool is_builtin_variable(const SPIRVariable &var) const;
|
bool is_builtin_variable(const SPIRVariable &var) const;
|
||||||
bool is_hidden_variable(const SPIRVariable &var, bool include_builtins = false) const;
|
bool is_hidden_variable(const SPIRVariable &var, bool include_builtins = false) const;
|
||||||
bool is_immutable(uint32_t id) const;
|
bool is_immutable(uint32_t id) const;
|
||||||
@ -577,6 +577,17 @@ protected:
|
|||||||
void register_combined_image_sampler(SPIRFunction &caller, uint32_t texture_id, uint32_t sampler_id);
|
void register_combined_image_sampler(SPIRFunction &caller, uint32_t texture_id, uint32_t sampler_id);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ActiveBuiltinHandler : OpcodeHandler
|
||||||
|
{
|
||||||
|
ActiveBuiltinHandler(Compiler &compiler_)
|
||||||
|
: compiler(compiler_)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool handle(spv::Op opcode, const uint32_t *args, uint32_t length) override;
|
||||||
|
Compiler &compiler;
|
||||||
|
};
|
||||||
|
|
||||||
bool traverse_all_reachable_opcodes(const SPIRBlock &block, OpcodeHandler &handler) const;
|
bool traverse_all_reachable_opcodes(const SPIRBlock &block, OpcodeHandler &handler) const;
|
||||||
bool traverse_all_reachable_opcodes(const SPIRFunction &block, OpcodeHandler &handler) const;
|
bool traverse_all_reachable_opcodes(const SPIRFunction &block, OpcodeHandler &handler) const;
|
||||||
// This must be an ordered data structure so we always pick the same type aliases.
|
// This must be an ordered data structure so we always pick the same type aliases.
|
||||||
@ -591,6 +602,11 @@ protected:
|
|||||||
|
|
||||||
std::unordered_set<uint32_t> forced_temporaries;
|
std::unordered_set<uint32_t> forced_temporaries;
|
||||||
std::unordered_set<uint32_t> forwarded_temporaries;
|
std::unordered_set<uint32_t> forwarded_temporaries;
|
||||||
|
|
||||||
|
uint64_t active_input_builtins = 0;
|
||||||
|
uint64_t active_output_builtins = 0;
|
||||||
|
// Traverses all reachable opcodes and sets active_builtins to a bitmask of all builtin variables which are accessed in the shader.
|
||||||
|
void update_active_builtins();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -310,6 +310,7 @@ string CompilerGLSL::compile()
|
|||||||
// Scan the SPIR-V to find trivial uses of extensions.
|
// Scan the SPIR-V to find trivial uses of extensions.
|
||||||
find_static_extensions();
|
find_static_extensions();
|
||||||
fixup_image_load_store_access();
|
fixup_image_load_store_access();
|
||||||
|
update_active_builtins();
|
||||||
|
|
||||||
uint32_t pass_count = 0;
|
uint32_t pass_count = 0;
|
||||||
do
|
do
|
||||||
@ -3331,8 +3332,12 @@ string CompilerGLSL::access_chain_internal(uint32_t base, const uint32_t *indice
|
|||||||
|
|
||||||
const auto *type = &expression_type(base);
|
const auto *type = &expression_type(base);
|
||||||
|
|
||||||
// For resolving array accesses, etc, keep a local copy for poking.
|
// Start traversing type hierarchy at the proper non-pointer types.
|
||||||
SPIRType temp;
|
while (type->pointer)
|
||||||
|
{
|
||||||
|
assert(type->parent_type);
|
||||||
|
type = &get<SPIRType>(type->parent_type);
|
||||||
|
}
|
||||||
|
|
||||||
bool access_chain_is_arrayed = false;
|
bool access_chain_is_arrayed = false;
|
||||||
bool row_major_matrix_needs_conversion = is_non_native_row_major_matrix(base);
|
bool row_major_matrix_needs_conversion = is_non_native_row_major_matrix(base);
|
||||||
@ -3351,11 +3356,8 @@ string CompilerGLSL::access_chain_internal(uint32_t base, const uint32_t *indice
|
|||||||
expr += to_expression(index);
|
expr += to_expression(index);
|
||||||
expr += "]";
|
expr += "]";
|
||||||
|
|
||||||
// We have to modify the type, so keep a local copy.
|
assert(type->parent_type);
|
||||||
if (&temp != type)
|
type = &get<SPIRType>(type->parent_type);
|
||||||
temp = *type;
|
|
||||||
type = &temp;
|
|
||||||
temp.array.pop_back();
|
|
||||||
|
|
||||||
access_chain_is_arrayed = true;
|
access_chain_is_arrayed = true;
|
||||||
}
|
}
|
||||||
@ -3414,11 +3416,7 @@ string CompilerGLSL::access_chain_internal(uint32_t base, const uint32_t *indice
|
|||||||
expr += to_expression(index);
|
expr += to_expression(index);
|
||||||
expr += "]";
|
expr += "]";
|
||||||
|
|
||||||
// We have to modify the type, so keep a local copy.
|
type = &get<SPIRType>(type->parent_type);
|
||||||
if (&temp != type)
|
|
||||||
temp = *type;
|
|
||||||
type = &temp;
|
|
||||||
temp.columns = 1;
|
|
||||||
}
|
}
|
||||||
// Vector -> Scalar
|
// Vector -> Scalar
|
||||||
else if (type->vecsize > 1)
|
else if (type->vecsize > 1)
|
||||||
@ -3441,11 +3439,7 @@ string CompilerGLSL::access_chain_internal(uint32_t base, const uint32_t *indice
|
|||||||
expr += "]";
|
expr += "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
// We have to modify the type, so keep a local copy.
|
type = &get<SPIRType>(type->parent_type);
|
||||||
if (&temp != type)
|
|
||||||
temp = *type;
|
|
||||||
type = &temp;
|
|
||||||
temp.vecsize = 1;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
SPIRV_CROSS_THROW("Cannot subdivide a scalar value!");
|
SPIRV_CROSS_THROW("Cannot subdivide a scalar value!");
|
||||||
@ -3686,6 +3680,13 @@ std::pair<std::string, uint32_t> CompilerGLSL::flattened_access_chain_offset(uin
|
|||||||
{
|
{
|
||||||
const auto *type = &expression_type(base);
|
const auto *type = &expression_type(base);
|
||||||
|
|
||||||
|
// Start traversing type hierarchy at the proper non-pointer types.
|
||||||
|
while (type->pointer)
|
||||||
|
{
|
||||||
|
assert(type->parent_type);
|
||||||
|
type = &get<SPIRType>(type->parent_type);
|
||||||
|
}
|
||||||
|
|
||||||
// This holds the type of the current pointer which we are traversing through.
|
// This holds the type of the current pointer which we are traversing through.
|
||||||
// We always start out from a struct type which is the block.
|
// We always start out from a struct type which is the block.
|
||||||
// This is primarily used to reflect the array strides and matrix strides later.
|
// This is primarily used to reflect the array strides and matrix strides later.
|
||||||
|
@ -357,8 +357,8 @@ protected:
|
|||||||
virtual const char *to_storage_qualifiers_glsl(const SPIRVariable &var);
|
virtual const char *to_storage_qualifiers_glsl(const SPIRVariable &var);
|
||||||
const char *flags_to_precision_qualifiers_glsl(const SPIRType &type, uint64_t flags);
|
const char *flags_to_precision_qualifiers_glsl(const SPIRType &type, uint64_t flags);
|
||||||
const char *format_to_glsl(spv::ImageFormat format);
|
const char *format_to_glsl(spv::ImageFormat format);
|
||||||
std::string layout_for_member(const SPIRType &type, uint32_t index);
|
virtual std::string layout_for_member(const SPIRType &type, uint32_t index);
|
||||||
std::string to_interpolation_qualifiers(uint64_t flags);
|
virtual std::string to_interpolation_qualifiers(uint64_t flags);
|
||||||
uint64_t combined_decoration_for_member(const SPIRType &type, uint32_t index);
|
uint64_t combined_decoration_for_member(const SPIRType &type, uint32_t index);
|
||||||
std::string layout_for_variable(const SPIRVariable &variable);
|
std::string layout_for_variable(const SPIRVariable &variable);
|
||||||
std::string to_combined_image_sampler(uint32_t image_id, uint32_t samp_id);
|
std::string to_combined_image_sampler(uint32_t image_id, uint32_t samp_id);
|
||||||
|
648
spirv_hlsl.cpp
648
spirv_hlsl.cpp
@ -22,24 +22,6 @@ using namespace spv;
|
|||||||
using namespace spirv_cross;
|
using namespace spirv_cross;
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
struct VariableComparator
|
|
||||||
{
|
|
||||||
VariableComparator(const std::vector<Meta> &m)
|
|
||||||
: meta(m)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator()(SPIRVariable *var1, SPIRVariable *var2)
|
|
||||||
{
|
|
||||||
return meta[var1->self].decoration.alias.compare(meta[var2->self].decoration.alias) < 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::vector<Meta> &meta;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
string CompilerHLSL::type_to_glsl(const SPIRType &type)
|
string CompilerHLSL::type_to_glsl(const SPIRType &type)
|
||||||
{
|
{
|
||||||
// Ignore the pointer type since GLSL doesn't have pointers.
|
// Ignore the pointer type since GLSL doesn't have pointers.
|
||||||
@ -148,21 +130,15 @@ void CompilerHLSL::emit_header()
|
|||||||
|
|
||||||
void CompilerHLSL::emit_interface_block_globally(const SPIRVariable &var)
|
void CompilerHLSL::emit_interface_block_globally(const SPIRVariable &var)
|
||||||
{
|
{
|
||||||
auto &execution = get_entry_point();
|
|
||||||
|
|
||||||
add_resource_name(var.self);
|
add_resource_name(var.self);
|
||||||
|
|
||||||
if (execution.model == ExecutionModelVertex && var.storage == StorageClassInput && is_builtin_variable(var))
|
// The global copies of I/O variables should not contain interpolation qualifiers.
|
||||||
{
|
// These are emitted inside the interface structs.
|
||||||
}
|
auto &flags = meta[var.self].decoration.decoration_flags;
|
||||||
else if (execution.model == ExecutionModelVertex && var.storage == StorageClassOutput && is_builtin_variable(var))
|
auto old_flags = flags;
|
||||||
{
|
flags = 0;
|
||||||
statement("static float4 gl_Position;");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
statement("static ", variable_decl(var), ";");
|
statement("static ", variable_decl(var), ";");
|
||||||
}
|
flags = old_flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *CompilerHLSL::to_storage_qualifiers_glsl(const SPIRVariable &var)
|
const char *CompilerHLSL::to_storage_qualifiers_glsl(const SPIRVariable &var)
|
||||||
@ -178,71 +154,257 @@ const char *CompilerHLSL::to_storage_qualifiers_glsl(const SPIRVariable &var)
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
void CompilerHLSL::emit_interface_block_in_struct(const SPIRVariable &var, uint32_t &binding_number, bool builtins)
|
void CompilerHLSL::emit_builtin_outputs_in_struct()
|
||||||
|
{
|
||||||
|
bool legacy = options.shader_model <= 30;
|
||||||
|
for (uint32_t i = 0; i < 64; i++)
|
||||||
|
{
|
||||||
|
if (!(active_output_builtins & (1ull << i)))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const char *type = nullptr;
|
||||||
|
const char *semantic = nullptr;
|
||||||
|
auto builtin = static_cast<BuiltIn>(i);
|
||||||
|
switch (builtin)
|
||||||
|
{
|
||||||
|
case BuiltInPosition:
|
||||||
|
type = "float4";
|
||||||
|
semantic = legacy ? "POSITION" : "SV_Position";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BuiltInFragDepth:
|
||||||
|
type = "float";
|
||||||
|
semantic = legacy ? "DEPTH" : "SV_Depth";
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
SPIRV_CROSS_THROW("Unsupported builtin in HLSL.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type && semantic)
|
||||||
|
statement(type, " ", builtin_to_glsl(builtin), " : ", semantic, ";");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CompilerHLSL::emit_builtin_inputs_in_struct()
|
||||||
|
{
|
||||||
|
bool legacy = options.shader_model <= 30;
|
||||||
|
for (uint32_t i = 0; i < 64; i++)
|
||||||
|
{
|
||||||
|
if (!(active_input_builtins & (1ull << i)))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const char *type = nullptr;
|
||||||
|
const char *semantic = nullptr;
|
||||||
|
auto builtin = static_cast<BuiltIn>(i);
|
||||||
|
switch (builtin)
|
||||||
|
{
|
||||||
|
case BuiltInFragCoord:
|
||||||
|
type = "float4";
|
||||||
|
semantic = legacy ? "VPOS" : "SV_Position";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BuiltInVertexIndex:
|
||||||
|
if (legacy)
|
||||||
|
SPIRV_CROSS_THROW("Vertex index not supported in SM 3.0 or lower.");
|
||||||
|
type = "uint";
|
||||||
|
semantic = "SV_VertexID";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BuiltInInstanceIndex:
|
||||||
|
if (legacy)
|
||||||
|
SPIRV_CROSS_THROW("Instance index not supported in SM 3.0 or lower.");
|
||||||
|
type = "uint";
|
||||||
|
semantic = "SV_InstanceID";
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
SPIRV_CROSS_THROW("Unsupported builtin in HLSL.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type && semantic)
|
||||||
|
statement(type, " ", builtin_to_glsl(builtin), " : ", semantic, ";");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t CompilerHLSL::type_to_consumed_locations(const SPIRType &type) const
|
||||||
|
{
|
||||||
|
// TODO: Need to verify correctness.
|
||||||
|
uint32_t elements = 0;
|
||||||
|
|
||||||
|
if (type.basetype == SPIRType::Struct)
|
||||||
|
{
|
||||||
|
for (uint32_t i = 0; i < uint32_t(type.member_types.size()); i++)
|
||||||
|
elements += type_to_consumed_locations(get<SPIRType>(type.member_types[i]));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
uint32_t array_multiplier = 1;
|
||||||
|
for (uint32_t i = 0; i < uint32_t(type.array.size()); i++)
|
||||||
|
{
|
||||||
|
if (type.array_size_literal[i])
|
||||||
|
array_multiplier *= type.array[i];
|
||||||
|
else
|
||||||
|
array_multiplier *= get<SPIRConstant>(type.array[i]).scalar();
|
||||||
|
}
|
||||||
|
elements += array_multiplier * type.columns;
|
||||||
|
}
|
||||||
|
return elements;
|
||||||
|
}
|
||||||
|
|
||||||
|
string CompilerHLSL::to_interpolation_qualifiers(uint64_t flags)
|
||||||
|
{
|
||||||
|
string res;
|
||||||
|
//if (flags & (1ull << DecorationSmooth))
|
||||||
|
// res += "linear ";
|
||||||
|
if (flags & (1ull << DecorationFlat))
|
||||||
|
res += "nointerpolation ";
|
||||||
|
if (flags & (1ull << DecorationNoPerspective))
|
||||||
|
res += "noperspective ";
|
||||||
|
if (flags & (1ull << DecorationCentroid))
|
||||||
|
res += "centroid ";
|
||||||
|
if (flags & (1ull << DecorationPatch))
|
||||||
|
res += "patch "; // Seems to be different in actual HLSL.
|
||||||
|
if (flags & (1ull << DecorationSample))
|
||||||
|
res += "sample ";
|
||||||
|
if (flags & (1ull << DecorationInvariant))
|
||||||
|
res += "invariant "; // Not supported?
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CompilerHLSL::emit_io_block(const SPIRVariable &var)
|
||||||
|
{
|
||||||
|
auto &type = get<SPIRType>(var.basetype);
|
||||||
|
add_resource_name(type.self);
|
||||||
|
|
||||||
|
statement("struct ", to_name(type.self));
|
||||||
|
begin_scope();
|
||||||
|
type.member_name_cache.clear();
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < uint32_t(type.member_types.size()); i++)
|
||||||
|
{
|
||||||
|
string semantic;
|
||||||
|
if (has_member_decoration(type.self, i, DecorationLocation))
|
||||||
|
{
|
||||||
|
uint32_t location = get_member_decoration(type.self, i, DecorationLocation);
|
||||||
|
semantic = join(" : TEXCOORD", location);
|
||||||
|
}
|
||||||
|
|
||||||
|
add_member_name(type, i);
|
||||||
|
|
||||||
|
auto &membertype = get<SPIRType>(type.member_types[i]);
|
||||||
|
statement(to_interpolation_qualifiers(get_member_decoration_mask(type.self, i)),
|
||||||
|
variable_decl(membertype, to_member_name(type, i)), semantic, ";");
|
||||||
|
}
|
||||||
|
|
||||||
|
end_scope_decl();
|
||||||
|
statement("");
|
||||||
|
|
||||||
|
statement("static ", variable_decl(var), ";");
|
||||||
|
statement("");
|
||||||
|
}
|
||||||
|
|
||||||
|
void CompilerHLSL::emit_interface_block_in_struct(const SPIRVariable &var, unordered_set<uint32_t> &active_locations)
|
||||||
{
|
{
|
||||||
auto &execution = get_entry_point();
|
auto &execution = get_entry_point();
|
||||||
auto &type = get<SPIRType>(var.basetype);
|
auto &type = get<SPIRType>(var.basetype);
|
||||||
|
|
||||||
const char *binding = "TEXCOORD";
|
string binding;
|
||||||
bool use_binding_number = true;
|
bool use_binding_number = true;
|
||||||
|
bool legacy = options.shader_model <= 30;
|
||||||
if (execution.model == ExecutionModelFragment && var.storage == StorageClassOutput)
|
if (execution.model == ExecutionModelFragment && var.storage == StorageClassOutput)
|
||||||
{
|
{
|
||||||
binding = "COLOR";
|
binding = join(legacy ? "COLOR" : "SV_Target", get_decoration(var.self, DecorationLocation));
|
||||||
use_binding_number = false;
|
|
||||||
}
|
|
||||||
else if (execution.model == ExecutionModelVertex && var.storage == StorageClassOutput && is_builtin_variable(var))
|
|
||||||
{
|
|
||||||
if (options.shader_model <= 30)
|
|
||||||
{
|
|
||||||
binding = "POSITION";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
binding = "SV_POSITION";
|
|
||||||
}
|
|
||||||
use_binding_number = false;
|
use_binding_number = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_no_builtin = !is_builtin_variable(var) && !var.remapped_variable;
|
const auto get_vacant_location = [&]() -> uint32_t {
|
||||||
|
for (uint32_t i = 0; i < 64; i++)
|
||||||
|
if (!active_locations.count(i))
|
||||||
|
return i;
|
||||||
|
SPIRV_CROSS_THROW("All locations from 0 to 63 are exhausted.");
|
||||||
|
};
|
||||||
|
|
||||||
if ((is_no_builtin && !builtins) || (!is_no_builtin && builtins))
|
|
||||||
{
|
|
||||||
auto &m = meta[var.self].decoration;
|
auto &m = meta[var.self].decoration;
|
||||||
|
auto name = to_name(var.self);
|
||||||
if (use_binding_number)
|
if (use_binding_number)
|
||||||
{
|
{
|
||||||
if (type.vecsize == 4 && type.columns == 4)
|
uint32_t binding_number;
|
||||||
|
|
||||||
|
// If an explicit location exists, use it with TEXCOORD[N] semantic.
|
||||||
|
// Otherwise, pick a vacant location.
|
||||||
|
if (m.decoration_flags & (1ull << DecorationLocation))
|
||||||
|
binding_number = m.location;
|
||||||
|
else
|
||||||
|
binding_number = get_vacant_location();
|
||||||
|
|
||||||
|
if (type.columns > 1)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < 4; ++i)
|
if (!type.array.empty())
|
||||||
|
SPIRV_CROSS_THROW("Arrays of matrices used as input/output. This is not supported.");
|
||||||
|
|
||||||
|
// Unroll matrices.
|
||||||
|
for (uint32_t i = 0; i < type.columns; i++)
|
||||||
{
|
{
|
||||||
std::stringstream name;
|
|
||||||
name << m.alias << "_" << i;
|
|
||||||
SPIRType newtype = type;
|
SPIRType newtype = type;
|
||||||
newtype.columns = 1;
|
newtype.columns = 1;
|
||||||
statement(variable_decl(newtype, name.str()), " : ", binding, binding_number++, ";");
|
statement(to_interpolation_qualifiers(get_decoration_mask(var.self)),
|
||||||
}
|
variable_decl(newtype, join(name, "_", i)), " : TEXCOORD", binding_number, ";");
|
||||||
--binding_number;
|
active_locations.insert(binding_number++);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
statement(variable_decl(type, m.alias), " : ", binding, binding_number, ";");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (execution.model == ExecutionModelVertex)
|
statement(to_interpolation_qualifiers(get_decoration_mask(var.self)), variable_decl(type, name),
|
||||||
{
|
" : TEXCOORD", binding_number, ";");
|
||||||
statement("float4 gl_Position", " : ", binding, ";");
|
|
||||||
|
// Structs and arrays should consume more locations.
|
||||||
|
uint32_t consumed_locations = type_to_consumed_locations(type);
|
||||||
|
for (uint32_t i = 0; i < consumed_locations; i++)
|
||||||
|
active_locations.insert(binding_number + i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
statement(variable_decl(type, name), " : ", binding, ";");
|
||||||
|
}
|
||||||
|
|
||||||
|
void CompilerHLSL::emit_builtin_variables()
|
||||||
|
{
|
||||||
|
// Emit global variables for the interface variables which are statically used by the shader.
|
||||||
|
for (uint32_t i = 0; i < 64; i++)
|
||||||
{
|
{
|
||||||
statement(variable_decl(type, m.alias), " : ", binding, ";");
|
if (!((active_input_builtins | active_output_builtins) & (1ull << i)))
|
||||||
}
|
continue;
|
||||||
}
|
|
||||||
|
const char *type = nullptr;
|
||||||
|
auto builtin = static_cast<BuiltIn>(i);
|
||||||
|
|
||||||
|
switch (builtin)
|
||||||
|
{
|
||||||
|
case BuiltInFragCoord:
|
||||||
|
case BuiltInPosition:
|
||||||
|
type = "float4";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BuiltInFragDepth:
|
||||||
|
type = "float";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BuiltInVertexIndex:
|
||||||
|
case BuiltInInstanceIndex:
|
||||||
|
type = "int";
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
SPIRV_CROSS_THROW(join("Unsupported builtin in HLSL: ", unsigned(builtin)));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_no_builtin)
|
if (type)
|
||||||
{
|
statement("static ", type, " ", builtin_to_glsl(builtin), ";");
|
||||||
++binding_number;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -250,10 +412,6 @@ void CompilerHLSL::emit_resources()
|
|||||||
{
|
{
|
||||||
auto &execution = get_entry_point();
|
auto &execution = get_entry_point();
|
||||||
|
|
||||||
// Emit PLS blocks if we have such variables.
|
|
||||||
if (!pls_inputs.empty() || !pls_outputs.empty())
|
|
||||||
emit_pls();
|
|
||||||
|
|
||||||
// Output all basic struct types which are not Block or BufferBlock as these are declared inplace
|
// Output all basic struct types which are not Block or BufferBlock as these are declared inplace
|
||||||
// when such variables are instantiated.
|
// when such variables are instantiated.
|
||||||
for (auto &id : ids)
|
for (auto &id : ids)
|
||||||
@ -334,17 +492,25 @@ void CompilerHLSL::emit_resources()
|
|||||||
statement("");
|
statement("");
|
||||||
emitted = false;
|
emitted = false;
|
||||||
|
|
||||||
|
// Emit builtin input and output variables here.
|
||||||
|
emit_builtin_variables();
|
||||||
|
|
||||||
for (auto &id : ids)
|
for (auto &id : ids)
|
||||||
{
|
{
|
||||||
if (id.get_type() == TypeVariable)
|
if (id.get_type() == TypeVariable)
|
||||||
{
|
{
|
||||||
auto &var = id.get<SPIRVariable>();
|
auto &var = id.get<SPIRVariable>();
|
||||||
auto &type = get<SPIRType>(var.basetype);
|
auto &type = get<SPIRType>(var.basetype);
|
||||||
|
bool block = (meta[type.self].decoration.decoration_flags & (1ull << DecorationBlock)) != 0;
|
||||||
|
|
||||||
if (var.storage != StorageClassFunction && !var.remapped_variable && type.pointer &&
|
// Do not emit I/O blocks here.
|
||||||
(var.storage == StorageClassInput || var.storage == StorageClassOutput) &&
|
// I/O blocks can be arrayed, so we must deal with them separately to support geometry shaders
|
||||||
|
// and tessellation down the line.
|
||||||
|
if (!block && var.storage != StorageClassFunction && !var.remapped_variable && type.pointer &&
|
||||||
|
(var.storage == StorageClassInput || var.storage == StorageClassOutput) && !is_builtin_variable(var) &&
|
||||||
interface_variable_exists_in_entry_point(var.self))
|
interface_variable_exists_in_entry_point(var.self))
|
||||||
{
|
{
|
||||||
|
// Only emit non-builtins which are not blocks here. Builtin variables are handled separately.
|
||||||
emit_interface_block_globally(var);
|
emit_interface_block_globally(var);
|
||||||
emitted = true;
|
emitted = true;
|
||||||
}
|
}
|
||||||
@ -355,81 +521,114 @@ void CompilerHLSL::emit_resources()
|
|||||||
statement("");
|
statement("");
|
||||||
emitted = false;
|
emitted = false;
|
||||||
|
|
||||||
if (execution.model == ExecutionModelVertex)
|
require_input = false;
|
||||||
{
|
require_output = false;
|
||||||
statement("struct InputVert");
|
unordered_set<uint32_t> active_inputs;
|
||||||
}
|
unordered_set<uint32_t> active_outputs;
|
||||||
else
|
vector<SPIRVariable *> input_variables;
|
||||||
{
|
vector<SPIRVariable *> output_variables;
|
||||||
statement("struct InputFrag");
|
|
||||||
}
|
|
||||||
begin_scope();
|
|
||||||
uint32_t binding_number = 0;
|
|
||||||
std::vector<SPIRVariable *> variables;
|
|
||||||
for (auto &id : ids)
|
for (auto &id : ids)
|
||||||
{
|
{
|
||||||
if (id.get_type() == TypeVariable)
|
if (id.get_type() == TypeVariable)
|
||||||
{
|
{
|
||||||
auto &var = id.get<SPIRVariable>();
|
auto &var = id.get<SPIRVariable>();
|
||||||
auto &type = get<SPIRType>(var.basetype);
|
auto &type = get<SPIRType>(var.basetype);
|
||||||
|
bool block = (meta[type.self].decoration.decoration_flags & (1ull << DecorationBlock)) != 0;
|
||||||
|
|
||||||
if (var.storage != StorageClassFunction && !var.remapped_variable && type.pointer &&
|
if (var.storage != StorageClassInput && var.storage != StorageClassOutput)
|
||||||
var.storage == StorageClassInput && interface_variable_exists_in_entry_point(var.self))
|
|
||||||
{
|
|
||||||
if (execution.model == ExecutionModelVertex && is_builtin_variable(var))
|
|
||||||
continue;
|
continue;
|
||||||
variables.push_back(&var);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sort(variables.begin(), variables.end(), VariableComparator(meta));
|
|
||||||
for (auto var : variables)
|
|
||||||
{
|
|
||||||
emit_interface_block_in_struct(*var, binding_number, false);
|
|
||||||
}
|
|
||||||
for (auto var : variables)
|
|
||||||
{
|
|
||||||
emit_interface_block_in_struct(*var, binding_number, true);
|
|
||||||
}
|
|
||||||
end_scope_decl();
|
|
||||||
statement("");
|
|
||||||
|
|
||||||
if (execution.model == ExecutionModelVertex)
|
// Do not emit I/O blocks here.
|
||||||
|
// I/O blocks can be arrayed, so we must deal with them separately to support geometry shaders
|
||||||
|
// and tessellation down the line.
|
||||||
|
if (!block && !var.remapped_variable && type.pointer && !is_builtin_variable(var) &&
|
||||||
|
interface_variable_exists_in_entry_point(var.self))
|
||||||
{
|
{
|
||||||
statement("struct OutputVert");
|
if (var.storage == StorageClassInput)
|
||||||
}
|
input_variables.push_back(&var);
|
||||||
else
|
else
|
||||||
{
|
output_variables.push_back(&var);
|
||||||
statement("struct OutputFrag");
|
|
||||||
}
|
}
|
||||||
begin_scope();
|
|
||||||
binding_number = 0;
|
|
||||||
variables.clear();
|
|
||||||
for (auto &id : ids)
|
|
||||||
{
|
|
||||||
if (id.get_type() == TypeVariable)
|
|
||||||
{
|
|
||||||
auto &var = id.get<SPIRVariable>();
|
|
||||||
auto &type = get<SPIRType>(var.basetype);
|
|
||||||
|
|
||||||
if (var.storage != StorageClassFunction && !var.remapped_variable && type.pointer &&
|
// Reserve input and output locations for block variables as necessary.
|
||||||
var.storage == StorageClassOutput && interface_variable_exists_in_entry_point(var.self))
|
if (block && !is_builtin_variable(var) && interface_variable_exists_in_entry_point(var.self))
|
||||||
{
|
{
|
||||||
variables.push_back(&var);
|
auto &active = var.storage == StorageClassInput ? active_inputs : active_outputs;
|
||||||
}
|
for (uint32_t i = 0; i < uint32_t(type.member_types.size()); i++)
|
||||||
}
|
|
||||||
}
|
|
||||||
sort(variables.begin(), variables.end(), VariableComparator(meta));
|
|
||||||
for (auto var : variables)
|
|
||||||
{
|
{
|
||||||
emit_interface_block_in_struct(*var, binding_number, false);
|
if (has_member_decoration(type.self, i, DecorationLocation))
|
||||||
}
|
|
||||||
for (auto var : variables)
|
|
||||||
{
|
{
|
||||||
emit_interface_block_in_struct(*var, binding_number, true);
|
uint32_t location = get_member_decoration(type.self, i, DecorationLocation);
|
||||||
|
active.insert(location);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Emit the block struct and a global variable here.
|
||||||
|
emit_io_block(var);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto variable_compare = [&](const SPIRVariable *a, const SPIRVariable *b) -> bool {
|
||||||
|
// Sort input and output variables based on, from more robust to less robust:
|
||||||
|
// - Location
|
||||||
|
// - Variable has a location
|
||||||
|
// - Name comparison
|
||||||
|
// - Variable has a name
|
||||||
|
// - Fallback: ID
|
||||||
|
bool has_location_a = has_decoration(a->self, DecorationLocation);
|
||||||
|
bool has_location_b = has_decoration(b->self, DecorationLocation);
|
||||||
|
|
||||||
|
if (has_location_a && has_location_b)
|
||||||
|
{
|
||||||
|
return get_decoration(a->self, DecorationLocation) < get_decoration(b->self, DecorationLocation);
|
||||||
|
}
|
||||||
|
else if (has_location_a && !has_location_b)
|
||||||
|
return true;
|
||||||
|
else if (!has_location_a && has_location_b)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const auto &name1 = to_name(a->self);
|
||||||
|
const auto &name2 = to_name(b->self);
|
||||||
|
|
||||||
|
if (name1.empty() && name2.empty())
|
||||||
|
return a->self < b->self;
|
||||||
|
else if (name1.empty())
|
||||||
|
return true;
|
||||||
|
else if (name2.empty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return name1.compare(name2) < 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!input_variables.empty() || active_input_builtins)
|
||||||
|
{
|
||||||
|
require_input = true;
|
||||||
|
statement("struct SPIRV_Cross_Input");
|
||||||
|
|
||||||
|
begin_scope();
|
||||||
|
sort(input_variables.begin(), input_variables.end(), variable_compare);
|
||||||
|
emit_builtin_inputs_in_struct();
|
||||||
|
for (auto var : input_variables)
|
||||||
|
emit_interface_block_in_struct(*var, active_inputs);
|
||||||
end_scope_decl();
|
end_scope_decl();
|
||||||
statement("");
|
statement("");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!output_variables.empty() || active_output_builtins)
|
||||||
|
{
|
||||||
|
require_output = true;
|
||||||
|
statement("struct SPIRV_Cross_Output");
|
||||||
|
|
||||||
|
begin_scope();
|
||||||
|
// FIXME: Use locations properly if they exist.
|
||||||
|
sort(output_variables.begin(), output_variables.end(), variable_compare);
|
||||||
|
emit_builtin_outputs_in_struct();
|
||||||
|
for (auto var : output_variables)
|
||||||
|
emit_interface_block_in_struct(*var, active_outputs);
|
||||||
|
end_scope_decl();
|
||||||
|
statement("");
|
||||||
|
}
|
||||||
|
|
||||||
// Global variables.
|
// Global variables.
|
||||||
for (auto global : global_variables)
|
for (auto global : global_variables)
|
||||||
@ -456,6 +655,11 @@ void CompilerHLSL::emit_resources()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string CompilerHLSL::layout_for_member(const SPIRType &, uint32_t)
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
void CompilerHLSL::emit_buffer_block(const SPIRVariable &var)
|
void CompilerHLSL::emit_buffer_block(const SPIRVariable &var)
|
||||||
{
|
{
|
||||||
auto &type = get<SPIRType>(var.basetype);
|
auto &type = get<SPIRType>(var.basetype);
|
||||||
@ -541,56 +745,154 @@ void CompilerHLSL::emit_function_prototype(SPIRFunction &func, uint64_t return_f
|
|||||||
|
|
||||||
void CompilerHLSL::emit_hlsl_entry_point()
|
void CompilerHLSL::emit_hlsl_entry_point()
|
||||||
{
|
{
|
||||||
auto &execution = get_entry_point();
|
vector<string> arguments;
|
||||||
const char *post = "Frag";
|
|
||||||
if (execution.model == ExecutionModelVertex)
|
|
||||||
{
|
|
||||||
post = "Vert";
|
|
||||||
}
|
|
||||||
|
|
||||||
statement("Output", post, " main(Input", post, " input)");
|
if (require_input)
|
||||||
begin_scope();
|
arguments.push_back("SPIRV_Cross_Input stage_input");
|
||||||
|
|
||||||
|
// Add I/O blocks as separate arguments with appropriate storage qualifier.
|
||||||
for (auto &id : ids)
|
for (auto &id : ids)
|
||||||
{
|
{
|
||||||
if (id.get_type() == TypeVariable)
|
if (id.get_type() == TypeVariable)
|
||||||
{
|
{
|
||||||
auto &var = id.get<SPIRVariable>();
|
auto &var = id.get<SPIRVariable>();
|
||||||
auto &type = get<SPIRType>(var.basetype);
|
auto &type = get<SPIRType>(var.basetype);
|
||||||
|
bool block = (meta[type.self].decoration.decoration_flags & (1ull << DecorationBlock)) != 0;
|
||||||
|
|
||||||
if (var.storage != StorageClassFunction && !var.remapped_variable && type.pointer &&
|
if (var.storage != StorageClassInput && var.storage != StorageClassOutput)
|
||||||
var.storage == StorageClassInput && interface_variable_exists_in_entry_point(var.self))
|
|
||||||
{
|
|
||||||
if (execution.model == ExecutionModelVertex && is_builtin_variable(var))
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
auto &m = meta[var.self].decoration;
|
if (block && !is_builtin_variable(var) && interface_variable_exists_in_entry_point(var.self))
|
||||||
|
{
|
||||||
|
if (var.storage == StorageClassInput)
|
||||||
|
{
|
||||||
|
arguments.push_back(join("in ", variable_decl(type, join("stage_input", to_name(var.self)))));
|
||||||
|
}
|
||||||
|
else if (var.storage == StorageClassOutput)
|
||||||
|
{
|
||||||
|
arguments.push_back(join("out ", variable_decl(type, join("stage_output", to_name(var.self)))));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto &execution = get_entry_point();
|
||||||
|
statement(require_output ? "SPIRV_Cross_Output " : "void ", "main(", merge(arguments), ")");
|
||||||
|
begin_scope();
|
||||||
|
bool legacy = options.shader_model <= 30;
|
||||||
|
|
||||||
|
// Copy builtins from entry point arguments to globals.
|
||||||
|
for (uint32_t i = 0; i < 64; i++)
|
||||||
|
{
|
||||||
|
if (!(active_input_builtins & (1ull << i)))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
auto builtin = builtin_to_glsl(static_cast<BuiltIn>(i));
|
||||||
|
switch (static_cast<BuiltIn>(i))
|
||||||
|
{
|
||||||
|
case BuiltInFragCoord:
|
||||||
|
// VPOS in D3D9 is sampled at integer locations, apply half-pixel offset to be consistent.
|
||||||
|
// TODO: Do we need an option here? Any reason why a D3D9 shader would be used
|
||||||
|
// on a D3D10+ system with a different rasterization config?
|
||||||
|
if (legacy)
|
||||||
|
statement(builtin, " = stage_input.", builtin, " + float4(0.5f, 0.5f, 0.0f, 0.0f);");
|
||||||
|
else
|
||||||
|
statement(builtin, " = stage_input.", builtin, ";");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BuiltInVertexIndex:
|
||||||
|
case BuiltInInstanceIndex:
|
||||||
|
// D3D semantics are uint, but shader wants int.
|
||||||
|
statement(builtin, " = int(stage_input.", builtin, ");");
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
statement(builtin, " = stage_input.", builtin, ";");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy from stage input struct to globals.
|
||||||
|
for (auto &id : ids)
|
||||||
|
{
|
||||||
|
if (id.get_type() == TypeVariable)
|
||||||
|
{
|
||||||
|
auto &var = id.get<SPIRVariable>();
|
||||||
|
auto &type = get<SPIRType>(var.basetype);
|
||||||
|
bool block = (meta[type.self].decoration.decoration_flags & (1ull << DecorationBlock)) != 0;
|
||||||
|
|
||||||
|
if (var.storage != StorageClassInput)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!block && !var.remapped_variable && type.pointer && !is_builtin_variable(var) &&
|
||||||
|
interface_variable_exists_in_entry_point(var.self))
|
||||||
|
{
|
||||||
|
auto name = to_name(var.self);
|
||||||
auto &mtype = get<SPIRType>(var.basetype);
|
auto &mtype = get<SPIRType>(var.basetype);
|
||||||
if (mtype.vecsize == 4 && mtype.columns == 4)
|
if (mtype.columns > 1)
|
||||||
{
|
{
|
||||||
statement(m.alias, "[0] = input.", m.alias, "_0;");
|
// Unroll matrices.
|
||||||
statement(m.alias, "[1] = input.", m.alias, "_1;");
|
for (uint32_t col = 0; col < mtype.columns; col++)
|
||||||
statement(m.alias, "[2] = input.", m.alias, "_2;");
|
statement(name, "[", col, "] = stage_input.", name, "_0;");
|
||||||
statement(m.alias, "[3] = input.", m.alias, "_3;");
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
statement(m.alias, " = input.", m.alias, ";");
|
statement(name, " = stage_input.", name, ";");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// I/O blocks don't use the common stage input/output struct, but separate outputs.
|
||||||
|
if (block && !is_builtin_variable(var) && interface_variable_exists_in_entry_point(var.self))
|
||||||
|
{
|
||||||
|
auto name = to_name(var.self);
|
||||||
|
statement(name, " = stage_input", name, ";");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Run the shader.
|
||||||
if (execution.model == ExecutionModelVertex)
|
if (execution.model == ExecutionModelVertex)
|
||||||
{
|
|
||||||
statement("vert_main();");
|
statement("vert_main();");
|
||||||
}
|
else if (execution.model == ExecutionModelFragment)
|
||||||
else
|
|
||||||
{
|
|
||||||
statement("frag_main();");
|
statement("frag_main();");
|
||||||
|
else
|
||||||
|
SPIRV_CROSS_THROW("Unsupported shader stage.");
|
||||||
|
|
||||||
|
// Copy block outputs.
|
||||||
|
for (auto &id : ids)
|
||||||
|
{
|
||||||
|
if (id.get_type() == TypeVariable)
|
||||||
|
{
|
||||||
|
auto &var = id.get<SPIRVariable>();
|
||||||
|
auto &type = get<SPIRType>(var.basetype);
|
||||||
|
bool block = (meta[type.self].decoration.decoration_flags & (1ull << DecorationBlock)) != 0;
|
||||||
|
|
||||||
|
if (var.storage != StorageClassOutput)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// I/O blocks don't use the common stage input/output struct, but separate outputs.
|
||||||
|
if (block && !is_builtin_variable(var) && interface_variable_exists_in_entry_point(var.self))
|
||||||
|
{
|
||||||
|
auto name = to_name(var.self);
|
||||||
|
statement("stage_output", name, " = ", name, ";");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
statement("Output", post, " output;");
|
// Copy stage outputs.
|
||||||
|
if (require_output)
|
||||||
|
{
|
||||||
|
statement("SPIRV_Cross_Output stage_output;");
|
||||||
|
|
||||||
|
// Copy builtins from globals to return struct.
|
||||||
|
for (uint32_t i = 0; i < 64; i++)
|
||||||
|
{
|
||||||
|
if (!(active_output_builtins & (1ull << i)))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
auto builtin = builtin_to_glsl(static_cast<BuiltIn>(i));
|
||||||
|
statement("stage_output.", builtin, " = ", builtin, ";");
|
||||||
|
}
|
||||||
|
|
||||||
for (auto &id : ids)
|
for (auto &id : ids)
|
||||||
{
|
{
|
||||||
@ -598,40 +900,43 @@ void CompilerHLSL::emit_hlsl_entry_point()
|
|||||||
{
|
{
|
||||||
auto &var = id.get<SPIRVariable>();
|
auto &var = id.get<SPIRVariable>();
|
||||||
auto &type = get<SPIRType>(var.basetype);
|
auto &type = get<SPIRType>(var.basetype);
|
||||||
|
bool block = (meta[type.self].decoration.decoration_flags & (1ull << DecorationBlock)) != 0;
|
||||||
|
|
||||||
if (var.storage != StorageClassFunction && !var.remapped_variable && type.pointer &&
|
if (var.storage != StorageClassOutput)
|
||||||
var.storage == StorageClassOutput && interface_variable_exists_in_entry_point(var.self))
|
continue;
|
||||||
|
|
||||||
|
if (!block && var.storage != StorageClassFunction && !var.remapped_variable && type.pointer &&
|
||||||
|
!is_builtin_variable(var) && interface_variable_exists_in_entry_point(var.self))
|
||||||
{
|
{
|
||||||
auto &m = meta[var.self].decoration;
|
auto name = to_name(var.self);
|
||||||
bool is_no_builtin = !is_builtin_variable(var) && !var.remapped_variable;
|
statement("stage_output.", name, " = ", name, ";");
|
||||||
if (is_no_builtin)
|
|
||||||
statement("output.", m.alias, " = ", m.alias, ";");
|
|
||||||
else if (execution.model == ExecutionModelVertex)
|
|
||||||
{
|
|
||||||
statement("output.gl_Position = gl_Position;");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (execution.model == ExecutionModelVertex)
|
if (execution.model == ExecutionModelVertex)
|
||||||
{
|
{
|
||||||
|
// Do various mangling on the gl_Position.
|
||||||
if (options.shader_model <= 30)
|
if (options.shader_model <= 30)
|
||||||
{
|
{
|
||||||
statement("output.gl_Position.x = output.gl_Position.x - gl_HalfPixel.x * output.gl_Position.w;");
|
statement("stage_output.gl_Position.x = stage_output.gl_Position.x - gl_HalfPixel.x * "
|
||||||
statement("output.gl_Position.y = output.gl_Position.y + gl_HalfPixel.y * output.gl_Position.w;");
|
"stage_output.gl_Position.w;");
|
||||||
|
statement("stage_output.gl_Position.y = stage_output.gl_Position.y + gl_HalfPixel.y * "
|
||||||
|
"stage_output.gl_Position.w;");
|
||||||
}
|
}
|
||||||
if (options.flip_vert_y)
|
if (options.flip_vert_y)
|
||||||
{
|
{
|
||||||
statement("output.gl_Position.y = -output.gl_Position.y;");
|
statement("stage_output.gl_Position.y = -stage_output.gl_Position.y;");
|
||||||
}
|
}
|
||||||
if (options.fixup_clipspace)
|
if (options.fixup_clipspace)
|
||||||
{
|
{
|
||||||
statement("output.gl_Position.z = (output.gl_Position.z + output.gl_Position.w) * 0.5;");
|
statement(
|
||||||
|
"stage_output.gl_Position.z = (stage_output.gl_Position.z + stage_output.gl_Position.w) * 0.5;");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
statement("return output;");
|
statement("return stage_output;");
|
||||||
|
}
|
||||||
|
|
||||||
end_scope();
|
end_scope();
|
||||||
}
|
}
|
||||||
@ -993,6 +1298,7 @@ string CompilerHLSL::compile()
|
|||||||
// Do not deal with ES-isms like precision, older extensions and such.
|
// Do not deal with ES-isms like precision, older extensions and such.
|
||||||
CompilerGLSL::options.es = false;
|
CompilerGLSL::options.es = false;
|
||||||
CompilerGLSL::options.version = 450;
|
CompilerGLSL::options.version = 450;
|
||||||
|
CompilerGLSL::options.vulkan_semantics = true;
|
||||||
backend.float_literal_suffix = true;
|
backend.float_literal_suffix = true;
|
||||||
backend.double_literal_suffix = false;
|
backend.double_literal_suffix = false;
|
||||||
backend.long_long_literal_suffix = true;
|
backend.long_long_literal_suffix = true;
|
||||||
@ -1002,10 +1308,12 @@ string CompilerHLSL::compile()
|
|||||||
backend.swizzle_is_function = false;
|
backend.swizzle_is_function = false;
|
||||||
backend.shared_is_implied = true;
|
backend.shared_is_implied = true;
|
||||||
backend.flexible_member_array_supported = false;
|
backend.flexible_member_array_supported = false;
|
||||||
backend.explicit_struct_type = true;
|
backend.explicit_struct_type = false;
|
||||||
backend.use_initializer_list = true;
|
backend.use_initializer_list = true;
|
||||||
backend.use_constructor_splatting = false;
|
backend.use_constructor_splatting = false;
|
||||||
|
|
||||||
|
update_active_builtins();
|
||||||
|
|
||||||
uint32_t pass_count = 0;
|
uint32_t pass_count = 0;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
|
@ -57,7 +57,9 @@ private:
|
|||||||
void emit_header() override;
|
void emit_header() override;
|
||||||
void emit_resources();
|
void emit_resources();
|
||||||
void emit_interface_block_globally(const SPIRVariable &type);
|
void emit_interface_block_globally(const SPIRVariable &type);
|
||||||
void emit_interface_block_in_struct(const SPIRVariable &type, uint32_t &binding_number, bool builtins);
|
void emit_interface_block_in_struct(const SPIRVariable &type, std::unordered_set<uint32_t> &active_locations);
|
||||||
|
void emit_builtin_inputs_in_struct();
|
||||||
|
void emit_builtin_outputs_in_struct();
|
||||||
void emit_texture_op(const Instruction &i) override;
|
void emit_texture_op(const Instruction &i) override;
|
||||||
void emit_instruction(const Instruction &instruction) override;
|
void emit_instruction(const Instruction &instruction) override;
|
||||||
void emit_glsl_op(uint32_t result_type, uint32_t result_id, uint32_t op, const uint32_t *args,
|
void emit_glsl_op(uint32_t result_type, uint32_t result_id, uint32_t op, const uint32_t *args,
|
||||||
@ -65,11 +67,21 @@ private:
|
|||||||
void emit_buffer_block(const SPIRVariable &type) override;
|
void emit_buffer_block(const SPIRVariable &type) override;
|
||||||
void emit_push_constant_block(const SPIRVariable &var) override;
|
void emit_push_constant_block(const SPIRVariable &var) override;
|
||||||
void emit_uniform(const SPIRVariable &var) override;
|
void emit_uniform(const SPIRVariable &var) override;
|
||||||
|
std::string layout_for_member(const SPIRType &type, uint32_t index) override;
|
||||||
|
std::string to_interpolation_qualifiers(uint64_t flags) override;
|
||||||
|
|
||||||
const char *to_storage_qualifiers_glsl(const SPIRVariable &var) override;
|
const char *to_storage_qualifiers_glsl(const SPIRVariable &var) override;
|
||||||
|
|
||||||
Options options;
|
Options options;
|
||||||
bool requires_op_fmod = false;
|
bool requires_op_fmod = false;
|
||||||
|
|
||||||
|
void emit_builtin_variables();
|
||||||
|
bool require_output = false;
|
||||||
|
bool require_input = false;
|
||||||
|
|
||||||
|
uint32_t type_to_consumed_locations(const SPIRType &type) const;
|
||||||
|
|
||||||
|
void emit_io_block(const SPIRVariable &var);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,6 +68,8 @@ string CompilerMSL::compile()
|
|||||||
non_stage_in_input_var_ids.clear();
|
non_stage_in_input_var_ids.clear();
|
||||||
struct_member_padding.clear();
|
struct_member_padding.clear();
|
||||||
|
|
||||||
|
update_active_builtins();
|
||||||
|
|
||||||
// Preprocess OpCodes to extract the need to output additional header content
|
// Preprocess OpCodes to extract the need to output additional header content
|
||||||
set_enabled_interface_variables(get_active_interface_variables());
|
set_enabled_interface_variables(get_active_interface_variables());
|
||||||
preprocess_op_codes();
|
preprocess_op_codes();
|
||||||
@ -1792,7 +1794,7 @@ string CompilerMSL::argument_decl(const SPIRFunction::Parameter &arg)
|
|||||||
|
|
||||||
// If we're currently in the entry point function, and the object
|
// If we're currently in the entry point function, and the object
|
||||||
// has a qualified name, use it, otherwise use the standard name.
|
// has a qualified name, use it, otherwise use the standard name.
|
||||||
string CompilerMSL::to_name(uint32_t id, bool allow_alias)
|
string CompilerMSL::to_name(uint32_t id, bool allow_alias) const
|
||||||
{
|
{
|
||||||
if (current_function && (current_function->self == entry_point))
|
if (current_function && (current_function->self == entry_point))
|
||||||
{
|
{
|
||||||
|
@ -136,7 +136,7 @@ protected:
|
|||||||
std::string constant_expression(const SPIRConstant &c) override;
|
std::string constant_expression(const SPIRConstant &c) override;
|
||||||
size_t get_declared_struct_member_size(const SPIRType &struct_type, uint32_t index) const override;
|
size_t get_declared_struct_member_size(const SPIRType &struct_type, uint32_t index) const override;
|
||||||
std::string to_func_call_arg(uint32_t id) override;
|
std::string to_func_call_arg(uint32_t id) override;
|
||||||
std::string to_name(uint32_t id, bool allow_alias = true) override;
|
std::string to_name(uint32_t id, bool allow_alias = true) const override;
|
||||||
std::string to_function_name(uint32_t img, const SPIRType &imgtype, bool is_fetch, bool is_gather, bool is_proj,
|
std::string to_function_name(uint32_t img, const SPIRType &imgtype, bool is_fetch, bool is_gather, bool is_proj,
|
||||||
bool has_array_offsets, bool has_offset, bool has_grad, bool has_lod,
|
bool has_array_offsets, bool has_offset, bool has_grad, bool has_lod,
|
||||||
bool has_dref) override;
|
bool has_dref) override;
|
||||||
|
@ -107,7 +107,7 @@ def cross_compile_hlsl(shader):
|
|||||||
os.close(hlsl_f)
|
os.close(hlsl_f)
|
||||||
subprocess.check_call(['glslangValidator', '-V', '-o', spirv_path, shader])
|
subprocess.check_call(['glslangValidator', '-V', '-o', spirv_path, shader])
|
||||||
spirv_cross_path = './spirv-cross'
|
spirv_cross_path = './spirv-cross'
|
||||||
subprocess.check_call([spirv_cross_path, '--entry', 'main', '--output', hlsl_path, spirv_path, '--hlsl'])
|
subprocess.check_call([spirv_cross_path, '--entry', 'main', '--output', hlsl_path, spirv_path, '--hlsl', '--shader-model', '50'])
|
||||||
subprocess.check_call(['spirv-val', spirv_path])
|
subprocess.check_call(['spirv-val', spirv_path])
|
||||||
|
|
||||||
validate_shader_hlsl(hlsl_path)
|
validate_shader_hlsl(hlsl_path)
|
||||||
|
Loading…
Reference in New Issue
Block a user