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 float2 vTex;
|
||||
|
||||
struct InputFrag
|
||||
struct SPIRV_Cross_Input
|
||||
{
|
||||
float4 vColor : TEXCOORD0;
|
||||
float2 vTex : TEXCOORD1;
|
||||
};
|
||||
|
||||
struct OutputFrag
|
||||
struct SPIRV_Cross_Output
|
||||
{
|
||||
float4 FragColor : COLOR;
|
||||
float4 FragColor : SV_Target0;
|
||||
};
|
||||
|
||||
void frag_main()
|
||||
@ -20,12 +20,12 @@ void frag_main()
|
||||
FragColor = vColor * tex2D(uTex, vTex);
|
||||
}
|
||||
|
||||
OutputFrag main(InputFrag input)
|
||||
SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input)
|
||||
{
|
||||
vColor = input.vColor;
|
||||
vTex = input.vTex;
|
||||
vColor = stage_input.vColor;
|
||||
vTex = stage_input.vTex;
|
||||
frag_main();
|
||||
OutputFrag output;
|
||||
output.FragColor = FragColor;
|
||||
return output;
|
||||
SPIRV_Cross_Output stage_output;
|
||||
stage_output.FragColor = FragColor;
|
||||
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;
|
||||
};
|
||||
uniform float4 gl_HalfPixel;
|
||||
|
||||
static float4 gl_Position;
|
||||
static float4 aVertex;
|
||||
static float3 vNormal;
|
||||
static float3 aNormal;
|
||||
|
||||
struct InputVert
|
||||
struct SPIRV_Cross_Input
|
||||
{
|
||||
float3 aNormal : TEXCOORD0;
|
||||
float4 aVertex : TEXCOORD1;
|
||||
};
|
||||
|
||||
struct OutputVert
|
||||
struct SPIRV_Cross_Output
|
||||
{
|
||||
float4 gl_Position : SV_Position;
|
||||
float3 vNormal : TEXCOORD0;
|
||||
float4 gl_Position : POSITION;
|
||||
};
|
||||
|
||||
void vert_main()
|
||||
@ -32,15 +31,13 @@ void vert_main()
|
||||
vNormal = aNormal;
|
||||
}
|
||||
|
||||
OutputVert main(InputVert input)
|
||||
SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input)
|
||||
{
|
||||
aVertex = input.aVertex;
|
||||
aNormal = input.aNormal;
|
||||
aVertex = stage_input.aVertex;
|
||||
aNormal = stage_input.aNormal;
|
||||
vert_main();
|
||||
OutputVert output;
|
||||
output.gl_Position = gl_Position;
|
||||
output.vNormal = vNormal;
|
||||
output.gl_Position.x = output.gl_Position.x - gl_HalfPixel.x * output.gl_Position.w;
|
||||
output.gl_Position.y = output.gl_Position.y + gl_HalfPixel.y * output.gl_Position.w;
|
||||
return output;
|
||||
SPIRV_Cross_Output stage_output;
|
||||
stage_output.gl_Position = gl_Position;
|
||||
stage_output.vNormal = vNormal;
|
||||
return stage_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.use_initializer_list = true;
|
||||
|
||||
update_active_builtins();
|
||||
|
||||
uint32_t pass_count = 0;
|
||||
do
|
||||
{
|
||||
|
129
spirv_cross.cpp
129
spirv_cross.cpp
@ -136,7 +136,7 @@ bool Compiler::block_is_pure(const SPIRBlock &block)
|
||||
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)
|
||||
{
|
||||
@ -491,7 +491,7 @@ bool Compiler::InterfaceVariableAccessHandler::handle(Op opcode, const uint32_t
|
||||
|
||||
case OpCopyMemory:
|
||||
{
|
||||
if (length < 3)
|
||||
if (length < 2)
|
||||
return false;
|
||||
|
||||
auto *var = compiler.maybe_get<SPIRVariable>(args[0]);
|
||||
@ -2865,7 +2865,7 @@ void Compiler::analyze_variable_scope(SPIRFunction &entry)
|
||||
|
||||
case OpCopyMemory:
|
||||
{
|
||||
if (length < 3)
|
||||
if (length < 2)
|
||||
return false;
|
||||
|
||||
uint32_t lhs = args[0];
|
||||
@ -3116,3 +3116,126 @@ bool Compiler::get_common_basic_type(const SPIRType &type, SPIRType::BaseType &b
|
||||
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> 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_hidden_variable(const SPIRVariable &var, bool include_builtins = false) 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);
|
||||
};
|
||||
|
||||
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 SPIRFunction &block, OpcodeHandler &handler) const;
|
||||
// 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> 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.
|
||||
find_static_extensions();
|
||||
fixup_image_load_store_access();
|
||||
update_active_builtins();
|
||||
|
||||
uint32_t pass_count = 0;
|
||||
do
|
||||
@ -3331,8 +3332,12 @@ string CompilerGLSL::access_chain_internal(uint32_t base, const uint32_t *indice
|
||||
|
||||
const auto *type = &expression_type(base);
|
||||
|
||||
// For resolving array accesses, etc, keep a local copy for poking.
|
||||
SPIRType temp;
|
||||
// Start traversing type hierarchy at the proper non-pointer types.
|
||||
while (type->pointer)
|
||||
{
|
||||
assert(type->parent_type);
|
||||
type = &get<SPIRType>(type->parent_type);
|
||||
}
|
||||
|
||||
bool access_chain_is_arrayed = false;
|
||||
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 += "]";
|
||||
|
||||
// We have to modify the type, so keep a local copy.
|
||||
if (&temp != type)
|
||||
temp = *type;
|
||||
type = &temp;
|
||||
temp.array.pop_back();
|
||||
assert(type->parent_type);
|
||||
type = &get<SPIRType>(type->parent_type);
|
||||
|
||||
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 += "]";
|
||||
|
||||
// We have to modify the type, so keep a local copy.
|
||||
if (&temp != type)
|
||||
temp = *type;
|
||||
type = &temp;
|
||||
temp.columns = 1;
|
||||
type = &get<SPIRType>(type->parent_type);
|
||||
}
|
||||
// Vector -> Scalar
|
||||
else if (type->vecsize > 1)
|
||||
@ -3441,11 +3439,7 @@ string CompilerGLSL::access_chain_internal(uint32_t base, const uint32_t *indice
|
||||
expr += "]";
|
||||
}
|
||||
|
||||
// We have to modify the type, so keep a local copy.
|
||||
if (&temp != type)
|
||||
temp = *type;
|
||||
type = &temp;
|
||||
temp.vecsize = 1;
|
||||
type = &get<SPIRType>(type->parent_type);
|
||||
}
|
||||
else
|
||||
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);
|
||||
|
||||
// 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.
|
||||
// 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.
|
||||
|
@ -357,8 +357,8 @@ protected:
|
||||
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 *format_to_glsl(spv::ImageFormat format);
|
||||
std::string layout_for_member(const SPIRType &type, uint32_t index);
|
||||
std::string to_interpolation_qualifiers(uint64_t flags);
|
||||
virtual std::string layout_for_member(const SPIRType &type, uint32_t index);
|
||||
virtual std::string to_interpolation_qualifiers(uint64_t flags);
|
||||
uint64_t combined_decoration_for_member(const SPIRType &type, uint32_t index);
|
||||
std::string layout_for_variable(const SPIRVariable &variable);
|
||||
std::string to_combined_image_sampler(uint32_t image_id, uint32_t samp_id);
|
||||
|
692
spirv_hlsl.cpp
692
spirv_hlsl.cpp
@ -22,24 +22,6 @@ using namespace spv;
|
||||
using namespace spirv_cross;
|
||||
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)
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
auto &execution = get_entry_point();
|
||||
|
||||
add_resource_name(var.self);
|
||||
|
||||
if (execution.model == ExecutionModelVertex && var.storage == StorageClassInput && is_builtin_variable(var))
|
||||
{
|
||||
}
|
||||
else if (execution.model == ExecutionModelVertex && var.storage == StorageClassOutput && is_builtin_variable(var))
|
||||
{
|
||||
statement("static float4 gl_Position;");
|
||||
}
|
||||
else
|
||||
{
|
||||
statement("static ", variable_decl(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;
|
||||
auto old_flags = flags;
|
||||
flags = 0;
|
||||
statement("static ", variable_decl(var), ";");
|
||||
flags = old_flags;
|
||||
}
|
||||
|
||||
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 "";
|
||||
}
|
||||
|
||||
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 &type = get<SPIRType>(var.basetype);
|
||||
|
||||
const char *binding = "TEXCOORD";
|
||||
string binding;
|
||||
bool use_binding_number = true;
|
||||
bool legacy = options.shader_model <= 30;
|
||||
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))
|
||||
|
||||
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.");
|
||||
};
|
||||
|
||||
auto &m = meta[var.self].decoration;
|
||||
auto name = to_name(var.self);
|
||||
if (use_binding_number)
|
||||
{
|
||||
if (options.shader_model <= 30)
|
||||
{
|
||||
binding = "POSITION";
|
||||
}
|
||||
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 = "SV_POSITION";
|
||||
}
|
||||
use_binding_number = false;
|
||||
}
|
||||
binding_number = get_vacant_location();
|
||||
|
||||
bool is_no_builtin = !is_builtin_variable(var) && !var.remapped_variable;
|
||||
|
||||
if ((is_no_builtin && !builtins) || (!is_no_builtin && builtins))
|
||||
{
|
||||
auto &m = meta[var.self].decoration;
|
||||
if (use_binding_number)
|
||||
if (type.columns > 1)
|
||||
{
|
||||
if (type.vecsize == 4 && type.columns == 4)
|
||||
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++)
|
||||
{
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
std::stringstream name;
|
||||
name << m.alias << "_" << i;
|
||||
SPIRType newtype = type;
|
||||
newtype.columns = 1;
|
||||
statement(variable_decl(newtype, name.str()), " : ", binding, binding_number++, ";");
|
||||
}
|
||||
--binding_number;
|
||||
}
|
||||
else
|
||||
{
|
||||
statement(variable_decl(type, m.alias), " : ", binding, binding_number, ";");
|
||||
SPIRType newtype = type;
|
||||
newtype.columns = 1;
|
||||
statement(to_interpolation_qualifiers(get_decoration_mask(var.self)),
|
||||
variable_decl(newtype, join(name, "_", i)), " : TEXCOORD", binding_number, ";");
|
||||
active_locations.insert(binding_number++);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (execution.model == ExecutionModelVertex)
|
||||
{
|
||||
statement("float4 gl_Position", " : ", binding, ";");
|
||||
}
|
||||
else
|
||||
{
|
||||
statement(variable_decl(type, m.alias), " : ", binding, ";");
|
||||
}
|
||||
statement(to_interpolation_qualifiers(get_decoration_mask(var.self)), variable_decl(type, name),
|
||||
" : TEXCOORD", binding_number, ";");
|
||||
|
||||
// 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
|
||||
statement(variable_decl(type, name), " : ", binding, ";");
|
||||
}
|
||||
|
||||
if (is_no_builtin)
|
||||
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++)
|
||||
{
|
||||
++binding_number;
|
||||
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 (type)
|
||||
statement("static ", type, " ", builtin_to_glsl(builtin), ";");
|
||||
}
|
||||
}
|
||||
|
||||
@ -250,10 +412,6 @@ void CompilerHLSL::emit_resources()
|
||||
{
|
||||
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
|
||||
// when such variables are instantiated.
|
||||
for (auto &id : ids)
|
||||
@ -334,17 +492,25 @@ void CompilerHLSL::emit_resources()
|
||||
statement("");
|
||||
emitted = false;
|
||||
|
||||
// Emit builtin input and output variables here.
|
||||
emit_builtin_variables();
|
||||
|
||||
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 != StorageClassFunction && !var.remapped_variable && type.pointer &&
|
||||
(var.storage == StorageClassInput || var.storage == StorageClassOutput) &&
|
||||
// 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.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))
|
||||
{
|
||||
// Only emit non-builtins which are not blocks here. Builtin variables are handled separately.
|
||||
emit_interface_block_globally(var);
|
||||
emitted = true;
|
||||
}
|
||||
@ -355,81 +521,114 @@ void CompilerHLSL::emit_resources()
|
||||
statement("");
|
||||
emitted = false;
|
||||
|
||||
if (execution.model == ExecutionModelVertex)
|
||||
{
|
||||
statement("struct InputVert");
|
||||
}
|
||||
else
|
||||
{
|
||||
statement("struct InputFrag");
|
||||
}
|
||||
begin_scope();
|
||||
uint32_t binding_number = 0;
|
||||
std::vector<SPIRVariable *> variables;
|
||||
require_input = false;
|
||||
require_output = false;
|
||||
unordered_set<uint32_t> active_inputs;
|
||||
unordered_set<uint32_t> active_outputs;
|
||||
vector<SPIRVariable *> input_variables;
|
||||
vector<SPIRVariable *> output_variables;
|
||||
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 != StorageClassFunction && !var.remapped_variable && type.pointer &&
|
||||
var.storage == StorageClassInput && interface_variable_exists_in_entry_point(var.self))
|
||||
if (var.storage != StorageClassInput && var.storage != StorageClassOutput)
|
||||
continue;
|
||||
|
||||
// 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))
|
||||
{
|
||||
if (execution.model == ExecutionModelVertex && is_builtin_variable(var))
|
||||
continue;
|
||||
variables.push_back(&var);
|
||||
if (var.storage == StorageClassInput)
|
||||
input_variables.push_back(&var);
|
||||
else
|
||||
output_variables.push_back(&var);
|
||||
}
|
||||
|
||||
// Reserve input and output locations for block variables as necessary.
|
||||
if (block && !is_builtin_variable(var) && interface_variable_exists_in_entry_point(var.self))
|
||||
{
|
||||
auto &active = var.storage == StorageClassInput ? active_inputs : active_outputs;
|
||||
for (uint32_t i = 0; i < uint32_t(type.member_types.size()); i++)
|
||||
{
|
||||
if (has_member_decoration(type.self, i, DecorationLocation))
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
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)
|
||||
{
|
||||
statement("struct OutputVert");
|
||||
}
|
||||
else
|
||||
{
|
||||
statement("struct OutputFrag");
|
||||
}
|
||||
begin_scope();
|
||||
binding_number = 0;
|
||||
variables.clear();
|
||||
for (auto &id : ids)
|
||||
{
|
||||
if (id.get_type() == TypeVariable)
|
||||
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)
|
||||
{
|
||||
auto &var = id.get<SPIRVariable>();
|
||||
auto &type = get<SPIRType>(var.basetype);
|
||||
|
||||
if (var.storage != StorageClassFunction && !var.remapped_variable && type.pointer &&
|
||||
var.storage == StorageClassOutput && interface_variable_exists_in_entry_point(var.self))
|
||||
{
|
||||
variables.push_back(&var);
|
||||
}
|
||||
return get_decoration(a->self, DecorationLocation) < get_decoration(b->self, DecorationLocation);
|
||||
}
|
||||
}
|
||||
sort(variables.begin(), variables.end(), VariableComparator(meta));
|
||||
for (auto var : variables)
|
||||
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)
|
||||
{
|
||||
emit_interface_block_in_struct(*var, binding_number, false);
|
||||
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();
|
||||
statement("");
|
||||
}
|
||||
for (auto var : variables)
|
||||
|
||||
if (!output_variables.empty() || active_output_builtins)
|
||||
{
|
||||
emit_interface_block_in_struct(*var, binding_number, true);
|
||||
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("");
|
||||
}
|
||||
end_scope_decl();
|
||||
statement("");
|
||||
|
||||
// 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)
|
||||
{
|
||||
auto &type = get<SPIRType>(var.basetype);
|
||||
@ -541,97 +745,198 @@ void CompilerHLSL::emit_function_prototype(SPIRFunction &func, uint64_t return_f
|
||||
|
||||
void CompilerHLSL::emit_hlsl_entry_point()
|
||||
{
|
||||
auto &execution = get_entry_point();
|
||||
const char *post = "Frag";
|
||||
if (execution.model == ExecutionModelVertex)
|
||||
{
|
||||
post = "Vert";
|
||||
}
|
||||
vector<string> arguments;
|
||||
|
||||
statement("Output", post, " main(Input", post, " input)");
|
||||
begin_scope();
|
||||
if (require_input)
|
||||
arguments.push_back("SPIRV_Cross_Input stage_input");
|
||||
|
||||
// Add I/O blocks as separate arguments with appropriate storage qualifier.
|
||||
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 != StorageClassFunction && !var.remapped_variable && type.pointer &&
|
||||
var.storage == StorageClassInput && interface_variable_exists_in_entry_point(var.self))
|
||||
if (var.storage != StorageClassInput && var.storage != StorageClassOutput)
|
||||
continue;
|
||||
|
||||
if (block && !is_builtin_variable(var) && interface_variable_exists_in_entry_point(var.self))
|
||||
{
|
||||
if (execution.model == ExecutionModelVertex && is_builtin_variable(var))
|
||||
continue;
|
||||
|
||||
auto &m = meta[var.self].decoration;
|
||||
auto &mtype = get<SPIRType>(var.basetype);
|
||||
if (mtype.vecsize == 4 && mtype.columns == 4)
|
||||
if (var.storage == StorageClassInput)
|
||||
{
|
||||
statement(m.alias, "[0] = input.", m.alias, "_0;");
|
||||
statement(m.alias, "[1] = input.", m.alias, "_1;");
|
||||
statement(m.alias, "[2] = input.", m.alias, "_2;");
|
||||
statement(m.alias, "[3] = input.", m.alias, "_3;");
|
||||
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);
|
||||
if (mtype.columns > 1)
|
||||
{
|
||||
// Unroll matrices.
|
||||
for (uint32_t col = 0; col < mtype.columns; col++)
|
||||
statement(name, "[", col, "] = stage_input.", name, "_0;");
|
||||
}
|
||||
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)
|
||||
{
|
||||
statement("vert_main();");
|
||||
}
|
||||
else
|
||||
{
|
||||
else if (execution.model == ExecutionModelFragment)
|
||||
statement("frag_main();");
|
||||
}
|
||||
|
||||
statement("Output", post, " output;");
|
||||
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 != StorageClassFunction && !var.remapped_variable && type.pointer &&
|
||||
var.storage == StorageClassOutput && interface_variable_exists_in_entry_point(var.self))
|
||||
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 &m = meta[var.self].decoration;
|
||||
bool is_no_builtin = !is_builtin_variable(var) && !var.remapped_variable;
|
||||
if (is_no_builtin)
|
||||
statement("output.", m.alias, " = ", m.alias, ";");
|
||||
else if (execution.model == ExecutionModelVertex)
|
||||
{
|
||||
statement("output.gl_Position = gl_Position;");
|
||||
}
|
||||
auto name = to_name(var.self);
|
||||
statement("stage_output", name, " = ", name, ";");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (execution.model == ExecutionModelVertex)
|
||||
// Copy stage outputs.
|
||||
if (require_output)
|
||||
{
|
||||
if (options.shader_model <= 30)
|
||||
{
|
||||
statement("output.gl_Position.x = output.gl_Position.x - gl_HalfPixel.x * output.gl_Position.w;");
|
||||
statement("output.gl_Position.y = output.gl_Position.y + gl_HalfPixel.y * output.gl_Position.w;");
|
||||
}
|
||||
if (options.flip_vert_y)
|
||||
{
|
||||
statement("output.gl_Position.y = -output.gl_Position.y;");
|
||||
}
|
||||
if (options.fixup_clipspace)
|
||||
{
|
||||
statement("output.gl_Position.z = (output.gl_Position.z + output.gl_Position.w) * 0.5;");
|
||||
}
|
||||
}
|
||||
statement("SPIRV_Cross_Output stage_output;");
|
||||
|
||||
statement("return 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)
|
||||
{
|
||||
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;
|
||||
|
||||
if (!block && var.storage != StorageClassFunction && !var.remapped_variable && type.pointer &&
|
||||
!is_builtin_variable(var) && interface_variable_exists_in_entry_point(var.self))
|
||||
{
|
||||
auto name = to_name(var.self);
|
||||
statement("stage_output.", name, " = ", name, ";");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (execution.model == ExecutionModelVertex)
|
||||
{
|
||||
// Do various mangling on the gl_Position.
|
||||
if (options.shader_model <= 30)
|
||||
{
|
||||
statement("stage_output.gl_Position.x = stage_output.gl_Position.x - gl_HalfPixel.x * "
|
||||
"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)
|
||||
{
|
||||
statement("stage_output.gl_Position.y = -stage_output.gl_Position.y;");
|
||||
}
|
||||
if (options.fixup_clipspace)
|
||||
{
|
||||
statement(
|
||||
"stage_output.gl_Position.z = (stage_output.gl_Position.z + stage_output.gl_Position.w) * 0.5;");
|
||||
}
|
||||
}
|
||||
|
||||
statement("return stage_output;");
|
||||
}
|
||||
|
||||
end_scope();
|
||||
}
|
||||
@ -993,6 +1298,7 @@ string CompilerHLSL::compile()
|
||||
// Do not deal with ES-isms like precision, older extensions and such.
|
||||
CompilerGLSL::options.es = false;
|
||||
CompilerGLSL::options.version = 450;
|
||||
CompilerGLSL::options.vulkan_semantics = true;
|
||||
backend.float_literal_suffix = true;
|
||||
backend.double_literal_suffix = false;
|
||||
backend.long_long_literal_suffix = true;
|
||||
@ -1002,10 +1308,12 @@ string CompilerHLSL::compile()
|
||||
backend.swizzle_is_function = false;
|
||||
backend.shared_is_implied = true;
|
||||
backend.flexible_member_array_supported = false;
|
||||
backend.explicit_struct_type = true;
|
||||
backend.explicit_struct_type = false;
|
||||
backend.use_initializer_list = true;
|
||||
backend.use_constructor_splatting = false;
|
||||
|
||||
update_active_builtins();
|
||||
|
||||
uint32_t pass_count = 0;
|
||||
do
|
||||
{
|
||||
|
@ -57,7 +57,9 @@ private:
|
||||
void emit_header() override;
|
||||
void emit_resources();
|
||||
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_instruction(const Instruction &instruction) override;
|
||||
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_push_constant_block(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;
|
||||
|
||||
Options options;
|
||||
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();
|
||||
struct_member_padding.clear();
|
||||
|
||||
update_active_builtins();
|
||||
|
||||
// Preprocess OpCodes to extract the need to output additional header content
|
||||
set_enabled_interface_variables(get_active_interface_variables());
|
||||
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
|
||||
// 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))
|
||||
{
|
||||
|
@ -136,7 +136,7 @@ protected:
|
||||
std::string constant_expression(const SPIRConstant &c) 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_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,
|
||||
bool has_array_offsets, bool has_offset, bool has_grad, bool has_lod,
|
||||
bool has_dref) override;
|
||||
|
@ -107,7 +107,7 @@ def cross_compile_hlsl(shader):
|
||||
os.close(hlsl_f)
|
||||
subprocess.check_call(['glslangValidator', '-V', '-o', spirv_path, shader])
|
||||
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])
|
||||
|
||||
validate_shader_hlsl(hlsl_path)
|
||||
|
Loading…
Reference in New Issue
Block a user