|
|
@@ -3565,6 +3565,11 @@ void CompilerGLSL::emit_resources()
|
|
|
(var.storage == StorageClassInput || var.storage == StorageClassOutput) &&
|
|
|
interface_variable_exists_in_entry_point(var.self) && !is_hidden)
|
|
|
{
|
|
|
+ if (options.es && get_execution_model() == ExecutionModelVertex && var.storage == StorageClassInput &&
|
|
|
+ type.array.size() == 1)
|
|
|
+ {
|
|
|
+ SPIRV_CROSS_THROW("OpenGL ES doesn't support array input variables in vertex shader.");
|
|
|
+ }
|
|
|
emit_interface_block(var);
|
|
|
emitted = true;
|
|
|
}
|
|
|
@@ -14768,13 +14773,13 @@ void CompilerGLSL::emit_block_chain(SPIRBlock &block)
|
|
|
case SPIRBlock::MultiSelect:
|
|
|
{
|
|
|
auto &type = expression_type(block.condition);
|
|
|
- bool unsigned_case =
|
|
|
- type.basetype == SPIRType::UInt || type.basetype == SPIRType::UShort || type.basetype == SPIRType::UByte;
|
|
|
+ bool unsigned_case = type.basetype == SPIRType::UInt || type.basetype == SPIRType::UShort ||
|
|
|
+ type.basetype == SPIRType::UByte || type.basetype == SPIRType::UInt64;
|
|
|
|
|
|
if (block.merge == SPIRBlock::MergeNone)
|
|
|
SPIRV_CROSS_THROW("Switch statement is not structured");
|
|
|
|
|
|
- if (type.basetype == SPIRType::UInt64 || type.basetype == SPIRType::Int64)
|
|
|
+ if (!backend.support_64bit_switch && (type.basetype == SPIRType::UInt64 || type.basetype == SPIRType::Int64))
|
|
|
{
|
|
|
// SPIR-V spec suggests this is allowed, but we cannot support it in higher level languages.
|
|
|
SPIRV_CROSS_THROW("Cannot use 64-bit switch selectors.");
|
|
|
@@ -14783,6 +14788,10 @@ void CompilerGLSL::emit_block_chain(SPIRBlock &block)
|
|
|
const char *label_suffix = "";
|
|
|
if (type.basetype == SPIRType::UInt && backend.uint32_t_literal_suffix)
|
|
|
label_suffix = "u";
|
|
|
+ else if (type.basetype == SPIRType::Int64 && backend.support_64bit_switch)
|
|
|
+ label_suffix = "l";
|
|
|
+ else if (type.basetype == SPIRType::UInt64 && backend.support_64bit_switch)
|
|
|
+ label_suffix = "ul";
|
|
|
else if (type.basetype == SPIRType::UShort)
|
|
|
label_suffix = backend.uint16_t_literal_suffix;
|
|
|
else if (type.basetype == SPIRType::Short)
|
|
|
@@ -14795,9 +14804,9 @@ void CompilerGLSL::emit_block_chain(SPIRBlock &block)
|
|
|
statement("bool _", block.self, "_ladder_break = false;");
|
|
|
|
|
|
// Find all unique case constructs.
|
|
|
- unordered_map<uint32_t, SmallVector<uint32_t>> case_constructs;
|
|
|
+ unordered_map<uint32_t, SmallVector<uint64_t>> case_constructs;
|
|
|
SmallVector<uint32_t> block_declaration_order;
|
|
|
- SmallVector<uint32_t> literals_to_merge;
|
|
|
+ SmallVector<uint64_t> literals_to_merge;
|
|
|
|
|
|
// If a switch case branches to the default block for some reason, we can just remove that literal from consideration
|
|
|
// and let the default: block handle it.
|
|
|
@@ -14806,21 +14815,17 @@ void CompilerGLSL::emit_block_chain(SPIRBlock &block)
|
|
|
auto &cases = get_case_list(block);
|
|
|
for (auto &c : cases)
|
|
|
{
|
|
|
- // It's safe to cast to uint32_t since we actually do a check
|
|
|
- // previously that we're not using uint64_t as the switch selector.
|
|
|
- auto case_value = static_cast<uint32_t>(c.value);
|
|
|
-
|
|
|
if (c.block != block.next_block && c.block != block.default_block)
|
|
|
{
|
|
|
if (!case_constructs.count(c.block))
|
|
|
block_declaration_order.push_back(c.block);
|
|
|
- case_constructs[c.block].push_back(case_value);
|
|
|
+ case_constructs[c.block].push_back(c.value);
|
|
|
}
|
|
|
else if (c.block == block.next_block && block.default_block != block.next_block)
|
|
|
{
|
|
|
// We might have to flush phi inside specific case labels.
|
|
|
// If we can piggyback on default:, do so instead.
|
|
|
- literals_to_merge.push_back(case_value);
|
|
|
+ literals_to_merge.push_back(c.value);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -14865,11 +14870,22 @@ void CompilerGLSL::emit_block_chain(SPIRBlock &block)
|
|
|
|
|
|
size_t num_blocks = block_declaration_order.size();
|
|
|
|
|
|
- const auto to_case_label = [](uint32_t literal, bool is_unsigned_case) -> string {
|
|
|
- return is_unsigned_case ? convert_to_string(literal) : convert_to_string(int32_t(literal));
|
|
|
+ const auto to_case_label = [](uint64_t literal, uint32_t width, bool is_unsigned_case) -> string
|
|
|
+ {
|
|
|
+ if (is_unsigned_case)
|
|
|
+ return convert_to_string(literal);
|
|
|
+
|
|
|
+ // For smaller cases, the literals are compiled as 32 bit wide
|
|
|
+ // literals so we don't need to care for all sizes specifically.
|
|
|
+ if (width <= 32)
|
|
|
+ {
|
|
|
+ return convert_to_string(int64_t(int32_t(literal)));
|
|
|
+ }
|
|
|
+
|
|
|
+ return convert_to_string(int64_t(literal));
|
|
|
};
|
|
|
|
|
|
- const auto to_legacy_case_label = [&](uint32_t condition, const SmallVector<uint32_t> &labels,
|
|
|
+ const auto to_legacy_case_label = [&](uint32_t condition, const SmallVector<uint64_t> &labels,
|
|
|
const char *suffix) -> string {
|
|
|
string ret;
|
|
|
size_t count = labels.size();
|
|
|
@@ -14911,7 +14927,7 @@ void CompilerGLSL::emit_block_chain(SPIRBlock &block)
|
|
|
auto &negative_literals = case_constructs[block_declaration_order[j]];
|
|
|
for (auto &case_label : negative_literals)
|
|
|
conditions.push_back(join(to_enclosed_expression(block.condition),
|
|
|
- " != ", to_case_label(case_label, unsigned_case)));
|
|
|
+ " != ", to_case_label(case_label, type.width, unsigned_case)));
|
|
|
}
|
|
|
|
|
|
statement("if (", merge(conditions, " && "), ")");
|
|
|
@@ -14925,7 +14941,7 @@ void CompilerGLSL::emit_block_chain(SPIRBlock &block)
|
|
|
conditions.reserve(literals.size());
|
|
|
for (auto &case_label : literals)
|
|
|
conditions.push_back(join(to_enclosed_expression(block.condition),
|
|
|
- " == ", to_case_label(case_label, unsigned_case)));
|
|
|
+ " == ", to_case_label(case_label, type.width, unsigned_case)));
|
|
|
statement("if (", merge(conditions, " || "), ")");
|
|
|
begin_scope();
|
|
|
flush_phi(block.self, target_block);
|
|
|
@@ -14940,7 +14956,7 @@ void CompilerGLSL::emit_block_chain(SPIRBlock &block)
|
|
|
// If there is only one default block, and no cases, this is a case where SPIRV-opt decided to emulate
|
|
|
// non-structured exits with the help of a switch block.
|
|
|
// 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_32bit.empty();
|
|
|
+ bool degenerate_switch = block.default_block != block.merge_block && cases.empty();
|
|
|
|
|
|
if (degenerate_switch || is_legacy_es())
|
|
|
{
|
|
|
@@ -14989,7 +15005,7 @@ void CompilerGLSL::emit_block_chain(SPIRBlock &block)
|
|
|
for (auto &case_literal : literals)
|
|
|
{
|
|
|
// The case label value must be sign-extended properly in SPIR-V, so we can assume 32-bit values here.
|
|
|
- statement("case ", to_case_label(case_literal, unsigned_case), label_suffix, ":");
|
|
|
+ statement("case ", to_case_label(case_literal, type.width, unsigned_case), label_suffix, ":");
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
@@ -15027,7 +15043,7 @@ void CompilerGLSL::emit_block_chain(SPIRBlock &block)
|
|
|
if ((header_merge_requires_phi && need_fallthrough_block) || !literals_to_merge.empty())
|
|
|
{
|
|
|
for (auto &case_literal : literals_to_merge)
|
|
|
- statement("case ", to_case_label(case_literal, unsigned_case), label_suffix, ":");
|
|
|
+ statement("case ", to_case_label(case_literal, type.width, unsigned_case), label_suffix, ":");
|
|
|
|
|
|
if (block.default_block == block.next_block)
|
|
|
{
|