Support initializers on StorageClassOutput.
diff --git a/reference/opt/shaders-hlsl/asm/frag/storage-class-output-initializer.asm.frag b/reference/opt/shaders-hlsl/asm/frag/storage-class-output-initializer.asm.frag
new file mode 100644
index 0000000..1905b5e
--- /dev/null
+++ b/reference/opt/shaders-hlsl/asm/frag/storage-class-output-initializer.asm.frag
@@ -0,0 +1,23 @@
+static const float4 _20[2] = { float4(1.0f, 2.0f, 3.0f, 4.0f), 10.0f.xxxx };
+
+static float4 FragColors[2] = _20;
+static float4 FragColor = 5.0f.xxxx;
+
+struct SPIRV_Cross_Output
+{
+ float4 FragColors[2] : SV_Target0;
+ float4 FragColor : SV_Target2;
+};
+
+void frag_main()
+{
+}
+
+SPIRV_Cross_Output main()
+{
+ frag_main();
+ SPIRV_Cross_Output stage_output;
+ stage_output.FragColors = FragColors;
+ stage_output.FragColor = FragColor;
+ return stage_output;
+}
diff --git a/reference/opt/shaders-msl/asm/frag/storage-class-output-initializer.asm.frag b/reference/opt/shaders-msl/asm/frag/storage-class-output-initializer.asm.frag
new file mode 100644
index 0000000..1bafc69
--- /dev/null
+++ b/reference/opt/shaders-msl/asm/frag/storage-class-output-initializer.asm.frag
@@ -0,0 +1,24 @@
+#include <metal_stdlib>
+#include <simd/simd.h>
+
+using namespace metal;
+
+constant float4 _20[2] = { float4(1.0, 2.0, 3.0, 4.0), float4(10.0) };
+
+struct main0_out
+{
+ float4 FragColors_0 [[color(0)]];
+ float4 FragColors_1 [[color(1)]];
+ float4 FragColor [[color(2)]];
+};
+
+fragment main0_out main0()
+{
+ main0_out out = {};
+ float4 FragColors[2] = { float4(1.0, 2.0, 3.0, 4.0), float4(10.0) };
+ out.FragColor = float4(5.0);
+ out.FragColors_0 = FragColors[0];
+ out.FragColors_1 = FragColors[1];
+ return out;
+}
+
diff --git a/reference/opt/shaders/asm/frag/storage-class-output-initializer.asm.frag b/reference/opt/shaders/asm/frag/storage-class-output-initializer.asm.frag
new file mode 100644
index 0000000..2293587
--- /dev/null
+++ b/reference/opt/shaders/asm/frag/storage-class-output-initializer.asm.frag
@@ -0,0 +1,11 @@
+#version 450
+
+layout(location = 0) out vec4 FragColors[2];
+layout(location = 2) out vec4 FragColor;
+
+void main()
+{
+ FragColors = vec4[](vec4(1.0, 2.0, 3.0, 4.0), vec4(10.0));
+ FragColor = vec4(5.0);
+}
+
diff --git a/reference/shaders-hlsl/asm/frag/storage-class-output-initializer.asm.frag b/reference/shaders-hlsl/asm/frag/storage-class-output-initializer.asm.frag
new file mode 100644
index 0000000..1905b5e
--- /dev/null
+++ b/reference/shaders-hlsl/asm/frag/storage-class-output-initializer.asm.frag
@@ -0,0 +1,23 @@
+static const float4 _20[2] = { float4(1.0f, 2.0f, 3.0f, 4.0f), 10.0f.xxxx };
+
+static float4 FragColors[2] = _20;
+static float4 FragColor = 5.0f.xxxx;
+
+struct SPIRV_Cross_Output
+{
+ float4 FragColors[2] : SV_Target0;
+ float4 FragColor : SV_Target2;
+};
+
+void frag_main()
+{
+}
+
+SPIRV_Cross_Output main()
+{
+ frag_main();
+ SPIRV_Cross_Output stage_output;
+ stage_output.FragColors = FragColors;
+ stage_output.FragColor = FragColor;
+ return stage_output;
+}
diff --git a/reference/shaders-msl/asm/frag/storage-class-output-initializer.asm.frag b/reference/shaders-msl/asm/frag/storage-class-output-initializer.asm.frag
new file mode 100644
index 0000000..1bafc69
--- /dev/null
+++ b/reference/shaders-msl/asm/frag/storage-class-output-initializer.asm.frag
@@ -0,0 +1,24 @@
+#include <metal_stdlib>
+#include <simd/simd.h>
+
+using namespace metal;
+
+constant float4 _20[2] = { float4(1.0, 2.0, 3.0, 4.0), float4(10.0) };
+
+struct main0_out
+{
+ float4 FragColors_0 [[color(0)]];
+ float4 FragColors_1 [[color(1)]];
+ float4 FragColor [[color(2)]];
+};
+
+fragment main0_out main0()
+{
+ main0_out out = {};
+ float4 FragColors[2] = { float4(1.0, 2.0, 3.0, 4.0), float4(10.0) };
+ out.FragColor = float4(5.0);
+ out.FragColors_0 = FragColors[0];
+ out.FragColors_1 = FragColors[1];
+ return out;
+}
+
diff --git a/reference/shaders/asm/frag/storage-class-output-initializer.asm.frag b/reference/shaders/asm/frag/storage-class-output-initializer.asm.frag
new file mode 100644
index 0000000..2293587
--- /dev/null
+++ b/reference/shaders/asm/frag/storage-class-output-initializer.asm.frag
@@ -0,0 +1,11 @@
+#version 450
+
+layout(location = 0) out vec4 FragColors[2];
+layout(location = 2) out vec4 FragColor;
+
+void main()
+{
+ FragColors = vec4[](vec4(1.0, 2.0, 3.0, 4.0), vec4(10.0));
+ FragColor = vec4(5.0);
+}
+
diff --git a/shaders-hlsl/asm/frag/storage-class-output-initializer.asm.frag b/shaders-hlsl/asm/frag/storage-class-output-initializer.asm.frag
new file mode 100644
index 0000000..7763b7c
--- /dev/null
+++ b/shaders-hlsl/asm/frag/storage-class-output-initializer.asm.frag
@@ -0,0 +1,41 @@
+; SPIR-V
+; Version: 1.0
+; Generator: Khronos Glslang Reference Front End; 7
+; Bound: 25
+; Schema: 0
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %main "main" %FragColors %FragColor
+ OpExecutionMode %main OriginUpperLeft
+ OpSource GLSL 450
+ OpName %main "main"
+ OpName %FragColors "FragColors"
+ OpName %FragColor "FragColor"
+ OpDecorate %FragColors Location 0
+ OpDecorate %FragColor Location 2
+ %void = OpTypeVoid
+ %3 = OpTypeFunction %void
+ %float = OpTypeFloat 32
+ %v4float = OpTypeVector %float 4
+ %uint = OpTypeInt 32 0
+ %uint_2 = OpConstant %uint 2
+%_arr_v4float_uint_2 = OpTypeArray %v4float %uint_2
+%_ptr_Output__arr_v4float_uint_2 = OpTypePointer Output %_arr_v4float_uint_2
+ %float_1 = OpConstant %float 1
+ %float_2 = OpConstant %float 2
+ %float_3 = OpConstant %float 3
+ %float_4 = OpConstant %float 4
+ %17 = OpConstantComposite %v4float %float_1 %float_2 %float_3 %float_4
+ %float_10 = OpConstant %float 10
+ %19 = OpConstantComposite %v4float %float_10 %float_10 %float_10 %float_10
+ %20 = OpConstantComposite %_arr_v4float_uint_2 %17 %19
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+ %float_5 = OpConstant %float 5
+ %24 = OpConstantComposite %v4float %float_5 %float_5 %float_5 %float_5
+ %FragColors = OpVariable %_ptr_Output__arr_v4float_uint_2 Output %20
+ %FragColor = OpVariable %_ptr_Output_v4float Output %24
+ %main = OpFunction %void None %3
+ %5 = OpLabel
+ OpReturn
+ OpFunctionEnd
diff --git a/shaders-msl/asm/frag/storage-class-output-initializer.asm.frag b/shaders-msl/asm/frag/storage-class-output-initializer.asm.frag
new file mode 100644
index 0000000..7763b7c
--- /dev/null
+++ b/shaders-msl/asm/frag/storage-class-output-initializer.asm.frag
@@ -0,0 +1,41 @@
+; SPIR-V
+; Version: 1.0
+; Generator: Khronos Glslang Reference Front End; 7
+; Bound: 25
+; Schema: 0
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %main "main" %FragColors %FragColor
+ OpExecutionMode %main OriginUpperLeft
+ OpSource GLSL 450
+ OpName %main "main"
+ OpName %FragColors "FragColors"
+ OpName %FragColor "FragColor"
+ OpDecorate %FragColors Location 0
+ OpDecorate %FragColor Location 2
+ %void = OpTypeVoid
+ %3 = OpTypeFunction %void
+ %float = OpTypeFloat 32
+ %v4float = OpTypeVector %float 4
+ %uint = OpTypeInt 32 0
+ %uint_2 = OpConstant %uint 2
+%_arr_v4float_uint_2 = OpTypeArray %v4float %uint_2
+%_ptr_Output__arr_v4float_uint_2 = OpTypePointer Output %_arr_v4float_uint_2
+ %float_1 = OpConstant %float 1
+ %float_2 = OpConstant %float 2
+ %float_3 = OpConstant %float 3
+ %float_4 = OpConstant %float 4
+ %17 = OpConstantComposite %v4float %float_1 %float_2 %float_3 %float_4
+ %float_10 = OpConstant %float 10
+ %19 = OpConstantComposite %v4float %float_10 %float_10 %float_10 %float_10
+ %20 = OpConstantComposite %_arr_v4float_uint_2 %17 %19
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+ %float_5 = OpConstant %float 5
+ %24 = OpConstantComposite %v4float %float_5 %float_5 %float_5 %float_5
+ %FragColors = OpVariable %_ptr_Output__arr_v4float_uint_2 Output %20
+ %FragColor = OpVariable %_ptr_Output_v4float Output %24
+ %main = OpFunction %void None %3
+ %5 = OpLabel
+ OpReturn
+ OpFunctionEnd
diff --git a/shaders/asm/frag/storage-class-output-initializer.asm.frag b/shaders/asm/frag/storage-class-output-initializer.asm.frag
new file mode 100644
index 0000000..7763b7c
--- /dev/null
+++ b/shaders/asm/frag/storage-class-output-initializer.asm.frag
@@ -0,0 +1,41 @@
+; SPIR-V
+; Version: 1.0
+; Generator: Khronos Glslang Reference Front End; 7
+; Bound: 25
+; Schema: 0
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %main "main" %FragColors %FragColor
+ OpExecutionMode %main OriginUpperLeft
+ OpSource GLSL 450
+ OpName %main "main"
+ OpName %FragColors "FragColors"
+ OpName %FragColor "FragColor"
+ OpDecorate %FragColors Location 0
+ OpDecorate %FragColor Location 2
+ %void = OpTypeVoid
+ %3 = OpTypeFunction %void
+ %float = OpTypeFloat 32
+ %v4float = OpTypeVector %float 4
+ %uint = OpTypeInt 32 0
+ %uint_2 = OpConstant %uint 2
+%_arr_v4float_uint_2 = OpTypeArray %v4float %uint_2
+%_ptr_Output__arr_v4float_uint_2 = OpTypePointer Output %_arr_v4float_uint_2
+ %float_1 = OpConstant %float 1
+ %float_2 = OpConstant %float 2
+ %float_3 = OpConstant %float 3
+ %float_4 = OpConstant %float 4
+ %17 = OpConstantComposite %v4float %float_1 %float_2 %float_3 %float_4
+ %float_10 = OpConstant %float 10
+ %19 = OpConstantComposite %v4float %float_10 %float_10 %float_10 %float_10
+ %20 = OpConstantComposite %_arr_v4float_uint_2 %17 %19
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+ %float_5 = OpConstant %float 5
+ %24 = OpConstantComposite %v4float %float_5 %float_5 %float_5 %float_5
+ %FragColors = OpVariable %_ptr_Output__arr_v4float_uint_2 Output %20
+ %FragColor = OpVariable %_ptr_Output_v4float Output %24
+ %main = OpFunction %void None %3
+ %5 = OpLabel
+ OpReturn
+ OpFunctionEnd
diff --git a/spirv_cross.cpp b/spirv_cross.cpp
index ef3ec24..19bac30 100644
--- a/spirv_cross.cpp
+++ b/spirv_cross.cpp
@@ -701,6 +701,12 @@
InterfaceVariableAccessHandler handler(*this, variables);
traverse_all_reachable_opcodes(get<SPIRFunction>(ir.default_entry_point), handler);
+ // Make sure we preserve output variables which are only initialized, but never accessed by any code.
+ ir.for_each_typed_id<SPIRVariable>([&](uint32_t, const SPIRVariable &var) {
+ if (var.storage == StorageClassOutput && var.initializer != 0)
+ variables.insert(var.self);
+ });
+
// If we needed to create one, we'll need it.
if (dummy_sampler_id)
variables.insert(dummy_sampler_id);
diff --git a/spirv_glsl.cpp b/spirv_glsl.cpp
index e4d54e0..a0b826d 100644
--- a/spirv_glsl.cpp
+++ b/spirv_glsl.cpp
@@ -1743,6 +1743,15 @@
add_resource_name(var.self);
statement(layout_for_variable(var), to_qualifiers_glsl(var.self),
variable_decl(type, to_name(var.self), var.self), ";");
+
+ // If a StorageClassOutput variable has an initializer, we need to initialize it in main().
+ if (var.storage == StorageClassOutput && var.initializer)
+ {
+ auto &entry_func = this->get<SPIRFunction>(ir.default_entry_point);
+ entry_func.fixup_hooks_in.push_back([&]() {
+ statement(to_name(var.self), " = ", to_expression(var.initializer), ";");
+ });
+ }
}
}
}
diff --git a/spirv_msl.cpp b/spirv_msl.cpp
index 7f2d3c6..fd90160 100644
--- a/spirv_msl.cpp
+++ b/spirv_msl.cpp
@@ -851,10 +851,10 @@
// Update the original variable reference to include the structure reference
string qual_var_name = ib_var_ref + "." + mbr_name;
+ auto &entry_func = get<SPIRFunction>(ir.default_entry_point);
if (padded_output)
{
- auto &entry_func = get<SPIRFunction>(ir.default_entry_point);
entry_func.add_local_variable(var.self);
vars_needing_early_declaration.push_back(var.self);
@@ -866,6 +866,13 @@
else
ir.meta[var.self].decoration.qualified_alias = qual_var_name;
+ if (var.storage == StorageClassOutput && var.initializer != 0)
+ {
+ entry_func.fixup_hooks_in.push_back([=, &var]() {
+ statement(qual_var_name, " = ", to_expression(var.initializer), ";");
+ });
+ }
+
// Copy the variable location from the original variable to the member
if (get_decoration_bitset(var.self).get(DecorationLocation))
{
@@ -3383,10 +3390,13 @@
for (auto var_id : vars_needing_early_declaration)
{
auto &ed_var = get<SPIRVariable>(var_id);
- if (!ed_var.initializer)
- ed_var.initializer = ir.increase_bound_by(1);
+ uint32_t &initializer = ed_var.initializer;
+ if (!initializer)
+ initializer = ir.increase_bound_by(1);
- set<SPIRExpression>(ed_var.initializer, "{}", ed_var.basetype, true);
+ // Do not override proper initializers.
+ if (ir.ids[initializer].get_type() == TypeNone || ir.ids[initializer].get_type() == TypeExpression)
+ set<SPIRExpression>(ed_var.initializer, "{}", ed_var.basetype, true);
}
}