GLSL: Implement switch on ESSL 1.0.

Cannot use switch on legacy ESSL, fallback to plain branches.
This commit is contained in:
Hans-Kristian Arntzen 2020-06-29 13:23:13 +02:00
parent bae76d7915
commit 4d79d634f5
5 changed files with 244 additions and 15 deletions

View File

@ -0,0 +1,77 @@
#version 100
precision mediump float;
precision highp int;
varying highp float vIndexF;
void main()
{
int _13 = int(vIndexF);
highp vec4 _65;
highp vec4 _66;
highp vec4 _68;
for (int SPIRV_Cross_Dummy = 0; SPIRV_Cross_Dummy < 1; SPIRV_Cross_Dummy++)
{
if (_13 == 2)
{
_68 = vec4(0.0, 2.0, 3.0, 4.0);
break;
}
else if ((_13 == 4) || (_13 == 5))
{
_68 = vec4(1.0, 2.0, 3.0, 4.0);
break;
}
else if ((_13 == 8) || (_13 == 9))
{
_68 = vec4(40.0, 20.0, 30.0, 40.0);
break;
}
else if (_13 == 10)
{
_65 = vec4(10.0);
highp vec4 _45 = _65 + vec4(1.0);
_66 = _45;
highp vec4 _48 = _66 + vec4(2.0);
_68 = _48;
break;
}
else if (_13 == 11)
{
_65 = vec4(0.0);
highp vec4 _45 = _65 + vec4(1.0);
_66 = _45;
highp vec4 _48 = _66 + vec4(2.0);
_68 = _48;
break;
}
else if (_13 == 12)
{
_66 = vec4(0.0);
highp vec4 _48 = _66 + vec4(2.0);
_68 = _48;
break;
}
else
{
_68 = vec4(10.0, 20.0, 30.0, 40.0);
break;
}
}
highp vec4 _70;
for (int SPIRV_Cross_Dummy = 0; SPIRV_Cross_Dummy < 1; SPIRV_Cross_Dummy++)
{
if ((_13 == 10) || (_13 == 20))
{
_70 = vec4(40.0);
break;
}
else
{
_70 = vec4(20.0);
break;
}
}
gl_FragData[0] = _68 + _70;
}

View File

@ -17,14 +17,6 @@ void frag_main()
int j; int j;
int _30; int _30;
int _31; int _31;
if (vIndex != 0 && vIndex != 1 && vIndex != 11 && vIndex != 2 && vIndex != 3 && vIndex != 4 && vIndex != 5)
{
_30 = 2;
}
if (vIndex == 1 || vIndex == 11)
{
_31 = 1;
}
switch (vIndex) switch (vIndex)
{ {
case 0: case 0:
@ -37,6 +29,7 @@ void frag_main()
} }
default: default:
{ {
_30 = 2;
j = _30; j = _30;
_31 = 0; _31 = 0;
j = _31; j = _31;
@ -45,6 +38,7 @@ void frag_main()
case 1: case 1:
case 11: case 11:
{ {
_31 = 1;
j = _31; j = _31;
break; break;
} }

View File

@ -0,0 +1,78 @@
#version 100
precision mediump float;
precision highp int;
varying highp float vIndexF;
void main()
{
int vIndex = int(vIndexF);
highp vec4 v = vec4(0.0);
for (int SPIRV_Cross_Dummy = 0; SPIRV_Cross_Dummy < 1; SPIRV_Cross_Dummy++)
{
if (vIndex == 2)
{
v = vec4(0.0, 2.0, 3.0, 4.0);
break;
}
else if ((vIndex == 4) || (vIndex == 5))
{
v = vec4(1.0, 2.0, 3.0, 4.0);
break;
}
else if ((vIndex == 8) || (vIndex == 9))
{
v = vec4(40.0, 20.0, 30.0, 40.0);
break;
}
else if (vIndex == 10)
{
v = vec4(10.0);
highp vec4 _43 = v;
highp vec4 _44 = vec4(1.0);
highp vec4 _45 = _43 + _44;
v = _45;
highp vec4 _46 = v;
highp vec4 _47 = vec4(2.0);
highp vec4 _48 = _46 + _47;
v = _48;
break;
}
else if (vIndex == 11)
{
highp vec4 _43 = v;
highp vec4 _44 = vec4(1.0);
highp vec4 _45 = _43 + _44;
v = _45;
highp vec4 _46 = v;
highp vec4 _47 = vec4(2.0);
highp vec4 _48 = _46 + _47;
v = _48;
break;
}
else if (vIndex == 12)
{
highp vec4 _46 = v;
highp vec4 _47 = vec4(2.0);
highp vec4 _48 = _46 + _47;
v = _48;
break;
}
else
{
v = vec4(10.0, 20.0, 30.0, 40.0);
break;
}
}
highp vec4 w = vec4(20.0);
for (int SPIRV_Cross_Dummy = 0; SPIRV_Cross_Dummy < 1; SPIRV_Cross_Dummy++)
{
if ((vIndex == 10) || (vIndex == 20))
{
w = vec4(40.0);
break;
}
}
gl_FragData[0] = v + w;
}

View File

@ -0,0 +1,43 @@
#version 450
layout(location = 0) out vec4 FragColor;
layout(location = 0) in float vIndexF;
void main()
{
int vIndex = int(vIndexF);
vec4 v = vec4(0.0);
switch (vIndex)
{
case 2:
v = vec4(0, 2, 3, 4);
break;
case 4:
case 5:
v = vec4(1, 2, 3, 4);
break;
case 8:
case 9:
v = vec4(40, 20, 30, 40);
break;
case 10:
v = vec4(10.0);
case 11:
v += 1.0;
case 12:
v += 2.0;
break;
default:
v = vec4(10, 20, 30, 40);
break;
}
vec4 w = vec4(20.0);
switch (vIndex)
{
case 10:
case 20:
w = vec4(40.0);
}
FragColor = v + w;
}

View File

@ -539,6 +539,9 @@ string CompilerGLSL::compile()
backend.supports_extensions = true; backend.supports_extensions = true;
backend.use_array_constructor = true; backend.use_array_constructor = true;
if (is_legacy_es())
backend.support_case_fallthrough = false;
// Scan the SPIR-V to find trivial uses of extensions. // Scan the SPIR-V to find trivial uses of extensions.
fixup_type_alias(); fixup_type_alias();
reorder_type_alias(); reorder_type_alias();
@ -13272,6 +13275,8 @@ void CompilerGLSL::emit_block_chain(SPIRBlock &block)
// Order does not matter. // Order does not matter.
if (!injected_block) if (!injected_block)
block_declaration_order.push_back(block.default_block); block_declaration_order.push_back(block.default_block);
else if (is_legacy_es())
SPIRV_CROSS_THROW("Default case label fallthrough to other case label is not supported in ESSL 1.0.");
case_constructs[block.default_block] = {}; case_constructs[block.default_block] = {};
} }
@ -13282,12 +13287,25 @@ void CompilerGLSL::emit_block_chain(SPIRBlock &block)
return is_unsigned_case ? convert_to_string(literal) : convert_to_string(int32_t(literal)); return is_unsigned_case ? convert_to_string(literal) : convert_to_string(int32_t(literal));
}; };
const auto to_legacy_case_label = [&](uint32_t condition, const SmallVector<uint32_t> &labels, const char *suffix) -> string {
string ret;
size_t count = labels.size();
for (size_t i = 0; i < count; i++)
{
if (i)
ret += " || ";
ret += join(count > 1 ? "(" : "", to_enclosed_expression(condition), " == ", labels[i], suffix,
count > 1 ? ")" : "");
}
return ret;
};
// We need to deal with a complex scenario for OpPhi. If we have case-fallthrough and Phi in the picture, // We need to deal with a complex scenario for OpPhi. If we have case-fallthrough and Phi in the picture,
// we need to flush phi nodes outside the switch block in a branch, // we need to flush phi nodes outside the switch block in a branch,
// and skip any Phi handling inside the case label to make fall-through work as expected. // and skip any Phi handling inside the case label to make fall-through work as expected.
// This kind of code-gen is super awkward and it's a last resort. Normally we would want to handle this // This kind of code-gen is super awkward and it's a last resort. Normally we would want to handle this
// inside the case label if at all possible. // inside the case label if at all possible.
for (size_t i = 1; i < num_blocks; i++) for (size_t i = 1; backend.support_case_fallthrough && i < num_blocks; i++)
{ {
if (flush_phi_required(block.self, block_declaration_order[i]) && if (flush_phi_required(block.self, block_declaration_order[i]) &&
flush_phi_required(block_declaration_order[i - 1], block_declaration_order[i])) flush_phi_required(block_declaration_order[i - 1], block_declaration_order[i]))
@ -13341,7 +13359,7 @@ void CompilerGLSL::emit_block_chain(SPIRBlock &block)
// This is buggy on FXC, so just emit the logical equivalent of a do { } while(false), which is more idiomatic. // This is buggy on FXC, so just emit the logical equivalent of a do { } while(false), which is more idiomatic.
bool degenerate_switch = block.default_block != block.merge_block && block.cases.empty(); bool degenerate_switch = block.default_block != block.merge_block && block.cases.empty();
if (degenerate_switch) if (degenerate_switch || is_legacy_es())
{ {
// ESSL 1.0 is not guaranteed to support do/while. // ESSL 1.0 is not guaranteed to support do/while.
if (is_legacy_es()) if (is_legacy_es())
@ -13365,8 +13383,21 @@ void CompilerGLSL::emit_block_chain(SPIRBlock &block)
{ {
// Default case. // Default case.
if (!degenerate_switch) if (!degenerate_switch)
{
if (is_legacy_es())
statement("else");
else
statement("default:"); statement("default:");
} }
}
else
{
if (is_legacy_es())
{
statement((i ? "else " : ""), "if (",
to_legacy_case_label(block.condition, literals, label_suffix),
")");
}
else else
{ {
for (auto &case_literal : literals) for (auto &case_literal : literals)
@ -13375,6 +13406,7 @@ void CompilerGLSL::emit_block_chain(SPIRBlock &block)
statement("case ", to_case_label(case_literal, unsigned_case), label_suffix, ":"); statement("case ", to_case_label(case_literal, unsigned_case), label_suffix, ":");
} }
} }
}
auto &case_block = get<SPIRBlock>(target_block); auto &case_block = get<SPIRBlock>(target_block);
if (backend.support_case_fallthrough && i + 1 < num_blocks && if (backend.support_case_fallthrough && i + 1 < num_blocks &&
@ -13407,7 +13439,12 @@ void CompilerGLSL::emit_block_chain(SPIRBlock &block)
statement("case ", to_case_label(case_literal, unsigned_case), label_suffix, ":"); statement("case ", to_case_label(case_literal, unsigned_case), label_suffix, ":");
if (block.default_block == block.next_block) if (block.default_block == block.next_block)
{
if (is_legacy_es())
statement("else");
else
statement("default:"); statement("default:");
}
begin_scope(); begin_scope();
flush_phi(block.self, block.next_block); flush_phi(block.self, block.next_block);