From c6b37def250e68d755aa989988dcb3daf9f774de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=91=D1=80=D0=B0=D0=BD=D0=B8=D0=BC=D0=B8=D1=80=20=D0=9A?= =?UTF-8?q?=D0=B0=D1=80=D0=B0=D1=9F=D0=B8=D1=9B?= Date: Fri, 28 Aug 2020 23:15:26 -0700 Subject: [PATCH] Updated spirv-cross. --- 3rdparty/spirv-cross/spirv_cpp.cpp | 2 + .../spirv-cross/spirv_cross_containers.hpp | 5 +- .../spirv-cross/spirv_cross_parsed_ir.cpp | 214 ++++++++++++++---- .../spirv-cross/spirv_cross_parsed_ir.hpp | 8 + 3rdparty/spirv-cross/spirv_glsl.cpp | 91 ++++---- 3rdparty/spirv-cross/spirv_glsl.hpp | 3 +- 3rdparty/spirv-cross/spirv_hlsl.cpp | 15 +- 3rdparty/spirv-cross/spirv_msl.cpp | 14 +- 8 files changed, 240 insertions(+), 112 deletions(-) diff --git a/3rdparty/spirv-cross/spirv_cpp.cpp b/3rdparty/spirv-cross/spirv_cpp.cpp index 53094d4e1..d13d6006a 100644 --- a/3rdparty/spirv-cross/spirv_cpp.cpp +++ b/3rdparty/spirv-cross/spirv_cpp.cpp @@ -306,6 +306,8 @@ void CompilerCPP::emit_resources() string CompilerCPP::compile() { + ir.fixup_reserved_names(); + // Do not deal with ES-isms like precision, older extensions and such. options.es = false; options.version = 450; diff --git a/3rdparty/spirv-cross/spirv_cross_containers.hpp b/3rdparty/spirv-cross/spirv_cross_containers.hpp index 37238ec1b..05498f672 100644 --- a/3rdparty/spirv-cross/spirv_cross_containers.hpp +++ b/3rdparty/spirv-cross/spirv_cross_containers.hpp @@ -328,8 +328,9 @@ public: size_t target_capacity = buffer_capacity; if (target_capacity == 0) target_capacity = 1; - if (target_capacity < N) - target_capacity = N; + + // Weird parens works around macro issues on Windows if NOMINMAX is not used. + target_capacity = (std::max)(target_capacity, N); // Need to ensure there is a POT value of target capacity which is larger than count, // otherwise this will overflow. diff --git a/3rdparty/spirv-cross/spirv_cross_parsed_ir.cpp b/3rdparty/spirv-cross/spirv_cross_parsed_ir.cpp index 655713f8c..d7b82fbf6 100644 --- a/3rdparty/spirv-cross/spirv_cross_parsed_ir.cpp +++ b/3rdparty/spirv-cross/spirv_cross_parsed_ir.cpp @@ -74,6 +74,8 @@ ParsedIR &ParsedIR::operator=(ParsedIR &&other) SPIRV_CROSS_NOEXCEPT source = other.source; loop_iteration_depth_hard = other.loop_iteration_depth_hard; loop_iteration_depth_soft = other.loop_iteration_depth_soft; + + meta_needing_name_fixup = std::move(other.meta_needing_name_fixup); } return *this; } @@ -106,6 +108,8 @@ ParsedIR &ParsedIR::operator=(const ParsedIR &other) addressing_model = other.addressing_model; memory_model = other.memory_model; + meta_needing_name_fixup = other.meta_needing_name_fixup; + // Very deliberate copying of IDs. There is no default copy constructor, nor a simple default constructor. // Construct object first so we have the correct allocator set-up, then we can copy object into our new pool group. ids.clear(); @@ -134,42 +138,146 @@ static bool is_alpha(char c) return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); } -static bool is_alphanumeric(char c) +static bool is_numeric(char c) { - return is_alpha(c) || (c >= '0' && c <= '9'); + return c >= '0' && c <= '9'; } -static string ensure_valid_identifier(const string &name, bool member) +static bool is_alphanumeric(char c) +{ + return is_alpha(c) || is_numeric(c); +} + +static bool is_valid_identifier(const string &name) +{ + if (name.empty()) + return true; + + if (is_numeric(name[0])) + return false; + + for (auto c : name) + if (!is_alphanumeric(c) && c != '_') + return false; + + bool saw_underscore = false; + // Two underscores in a row is not a valid identifier either. + // Technically reserved, but it's easier to treat it as invalid. + for (auto c : name) + { + bool is_underscore = c == '_'; + if (is_underscore && saw_underscore) + return false; + saw_underscore = is_underscore; + } + + return true; +} + +static bool is_reserved_prefix(const string &name) +{ + // Generic reserved identifiers used by the implementation. + return name.compare(0, 3, "gl_", 3) == 0 || + // Ignore this case for now, might rewrite internal code to always use spv prefix. + //name.compare(0, 11, "SPIRV_Cross", 11) == 0 || + name.compare(0, 3, "spv", 3) == 0; +} + +static bool is_reserved_identifier(const string &name, bool member, bool allow_reserved_prefixes) +{ + if (!allow_reserved_prefixes && is_reserved_prefix(name)) + return true; + + if (member) + { + // Reserved member identifiers come in one form: + // _m[0-9]+$. + if (name.size() < 3) + return false; + + if (name.compare(0, 2, "_m", 2) != 0) + return false; + + size_t index = 2; + while (index < name.size() && is_numeric(name[index])) + index++; + + return index == name.size(); + } + else + { + // Reserved non-member identifiers come in two forms: + // _[0-9]+$, used for temporaries which map directly to a SPIR-V ID. + // _[0-9]+_, used for auxillary temporaries which derived from a SPIR-V ID. + if (name.size() < 2) + return false; + + if (name[0] != '_' || !is_numeric(name[1])) + return false; + + size_t index = 2; + while (index < name.size() && is_numeric(name[index])) + index++; + + return index == name.size() || (index < name.size() && name[index] == '_'); + } +} + +bool ParsedIR::is_globally_reserved_identifier(std::string &str, bool allow_reserved_prefixes) +{ + return is_reserved_identifier(str, false, allow_reserved_prefixes); +} + +static string make_unreserved_identifier(const string &name) +{ + if (is_reserved_prefix(name)) + return "_RESERVED_IDENTIFIER_FIXUP_" + name; + else + return "_RESERVED_IDENTIFIER_FIXUP" + name; +} + +void ParsedIR::sanitize_underscores(std::string &str) +{ + // Compact adjacent underscores to make it valid. + auto dst = str.begin(); + auto src = dst; + bool saw_underscore = false; + while (src != str.end()) + { + bool is_underscore = *src == '_'; + if (saw_underscore && is_underscore) + { + src++; + } + else + { + if (dst != src) + *dst = *src; + dst++; + src++; + saw_underscore = is_underscore; + } + } + str.erase(dst, str.end()); +} + +static string ensure_valid_identifier(const string &name) { // Functions in glslangValidator are mangled with name( stuff. // Normally, we would never see '(' in any legal identifiers, so just strip them out. auto str = name.substr(0, name.find('(')); - for (uint32_t i = 0; i < str.size(); i++) - { - auto &c = str[i]; + if (str.empty()) + return str; - if (member) - { - // _m variables are reserved by the internal implementation, - // otherwise, make sure the name is a valid identifier. - if (i == 0) - c = is_alpha(c) ? c : '_'; - else if (i == 2 && str[0] == '_' && str[1] == 'm') - c = is_alpha(c) ? c : '_'; - else - c = is_alphanumeric(c) ? c : '_'; - } - else - { - // _ variables are reserved by the internal implementation, - // otherwise, make sure the name is a valid identifier. - if (i == 0 || (str[0] == '_' && i == 1)) - c = is_alpha(c) ? c : '_'; - else - c = is_alphanumeric(c) ? c : '_'; - } - } + if (is_numeric(str[0])) + str[0] = '_'; + + for (auto &c : str) + if (!is_alphanumeric(c) && c != '_') + c = '_'; + + ParsedIR::sanitize_underscores(str); return str; } @@ -195,35 +303,41 @@ const string &ParsedIR::get_member_name(TypeID id, uint32_t index) const return empty_string; } +void ParsedIR::sanitize_identifier(std::string &name, bool member, bool allow_reserved_prefixes) +{ + if (!is_valid_identifier(name)) + name = ensure_valid_identifier(name); + if (is_reserved_identifier(name, member, allow_reserved_prefixes)) + name = make_unreserved_identifier(name); +} + +void ParsedIR::fixup_reserved_names() +{ + for (uint32_t id : meta_needing_name_fixup) + { + auto &m = meta[id]; + sanitize_identifier(m.decoration.alias, false, false); + for (auto &memb : m.members) + sanitize_identifier(memb.alias, true, false); + } + meta_needing_name_fixup.clear(); +} + void ParsedIR::set_name(ID id, const string &name) { - auto &str = meta[id].decoration.alias; - str.clear(); - - if (name.empty()) - return; - - // Reserved for temporaries. - if (name[0] == '_' && name.size() >= 2 && isdigit(name[1])) - return; - - str = ensure_valid_identifier(name, false); + auto &m = meta[id]; + m.decoration.alias = name; + if (!is_valid_identifier(name) || is_reserved_identifier(name, false, false)) + meta_needing_name_fixup.insert(id); } void ParsedIR::set_member_name(TypeID id, uint32_t index, const string &name) { - meta[id].members.resize(max(meta[id].members.size(), size_t(index) + 1)); - - auto &str = meta[id].members[index].alias; - str.clear(); - if (name.empty()) - return; - - // Reserved for unnamed members. - if (name[0] == '_' && name.size() >= 3 && name[1] == 'm' && isdigit(name[2])) - return; - - str = ensure_valid_identifier(name, true); + auto &m = meta[id]; + m.members.resize(max(meta[id].members.size(), size_t(index) + 1)); + m.members[index].alias = name; + if (!is_valid_identifier(name) || is_reserved_identifier(name, true, false)) + meta_needing_name_fixup.insert(id); } void ParsedIR::set_decoration_string(ID id, Decoration decoration, const string &argument) diff --git a/3rdparty/spirv-cross/spirv_cross_parsed_ir.hpp b/3rdparty/spirv-cross/spirv_cross_parsed_ir.hpp index 4880c8419..36d6ac7b2 100644 --- a/3rdparty/spirv-cross/spirv_cross_parsed_ir.hpp +++ b/3rdparty/spirv-cross/spirv_cross_parsed_ir.hpp @@ -208,6 +208,12 @@ public: void make_constant_null(uint32_t id, uint32_t type, bool add_to_typed_id_set); + void fixup_reserved_names(); + + static void sanitize_underscores(std::string &str); + static void sanitize_identifier(std::string &str, bool member, bool allow_reserved_prefixes); + static bool is_globally_reserved_identifier(std::string &str, bool allow_reserved_prefixes); + private: template T &get(uint32_t id) @@ -225,6 +231,8 @@ private: mutable uint32_t loop_iteration_depth_soft = 0; std::string empty_string; Bitset cleared_bitset; + + std::unordered_set meta_needing_name_fixup; }; } // namespace SPIRV_CROSS_NAMESPACE diff --git a/3rdparty/spirv-cross/spirv_glsl.cpp b/3rdparty/spirv-cross/spirv_glsl.cpp index 2002b9e1f..ef4a705ff 100644 --- a/3rdparty/spirv-cross/spirv_glsl.cpp +++ b/3rdparty/spirv-cross/spirv_glsl.cpp @@ -145,32 +145,6 @@ static BufferPackingStandard packing_to_substruct_packing(BufferPackingStandard } } -// Sanitizes underscores for GLSL where multiple underscores in a row are not allowed. -string CompilerGLSL::sanitize_underscores(const string &str) -{ - string res; - res.reserve(str.size()); - - bool last_underscore = false; - for (auto c : str) - { - if (c == '_') - { - if (last_underscore) - continue; - - res += c; - last_underscore = true; - } - else - { - res += c; - last_underscore = false; - } - } - return res; -} - void CompilerGLSL::init() { if (ir.source.known) @@ -529,6 +503,8 @@ void CompilerGLSL::find_static_extensions() string CompilerGLSL::compile() { + ir.fixup_reserved_names(); + if (options.vulkan_semantics) backend.allow_precision_qualifiers = true; else @@ -2150,7 +2126,7 @@ void CompilerGLSL::emit_flattened_io_block_member(const std::string &basename, c // Sanitize underscores because joining the two identifiers might create more than 1 underscore in a row, // which is not allowed. - flattened_name = sanitize_underscores(flattened_name); + ParsedIR::sanitize_underscores(flattened_name); uint32_t last_index = indices.back(); @@ -2693,6 +2669,23 @@ bool CompilerGLSL::should_force_emit_builtin_block(StorageClass storage) return should_force; } +void CompilerGLSL::fixup_implicit_builtin_block_names() +{ + ir.for_each_typed_id([&](uint32_t, SPIRVariable &var) { + auto &type = this->get(var.basetype); + bool block = has_decoration(type.self, DecorationBlock); + if ((var.storage == StorageClassOutput || var.storage == StorageClassInput) && block && + is_builtin_variable(var)) + { + // Make sure the array has a supported name in the code. + if (var.storage == StorageClassOutput) + set_name(var.self, "gl_out"); + else if (var.storage == StorageClassInput) + set_name(var.self, "gl_in"); + } + }); +} + void CompilerGLSL::emit_declared_builtin_block(StorageClass storage, ExecutionModel model) { Bitset emitted_builtins; @@ -2874,12 +2867,6 @@ void CompilerGLSL::emit_declared_builtin_block(StorageClass storage, ExecutionMo if (builtin_array) { - // Make sure the array has a supported name in the code. - if (storage == StorageClassOutput) - set_name(block_var->self, "gl_out"); - else if (storage == StorageClassInput) - set_name(block_var->self, "gl_in"); - if (model == ExecutionModelTessellationControl && storage == StorageClassOutput) end_scope_decl(join(to_name(block_var->self), "[", get_entry_point().output_vertices, "]")); else @@ -2936,6 +2923,18 @@ void CompilerGLSL::emit_resources() if (!pls_inputs.empty() || !pls_outputs.empty()) emit_pls(); + switch (execution.model) + { + case ExecutionModelGeometry: + case ExecutionModelTessellationControl: + case ExecutionModelTessellationEvaluation: + fixup_implicit_builtin_block_names(); + break; + + default: + break; + } + // Emit custom gl_PerVertex for SSO compatibility. if (options.separate_shader_objects && !options.es && execution.model != ExecutionModelFragment) { @@ -7793,7 +7792,9 @@ void CompilerGLSL::prepare_access_chain_for_scalar_access(std::string &, const S string CompilerGLSL::to_flattened_struct_member(const string &basename, const SPIRType &type, uint32_t index) { - return sanitize_underscores(join(basename, "_", to_member_name(type, index))); + auto ret = join(basename, "_", to_member_name(type, index)); + ParsedIR::sanitize_underscores(ret); + return ret; } string CompilerGLSL::access_chain(uint32_t base, const uint32_t *indices, uint32_t count, const SPIRType &target_type, @@ -7837,7 +7838,9 @@ string CompilerGLSL::access_chain(uint32_t base, const uint32_t *indices, uint32 } auto basename = to_flattened_access_chain_expression(base); - return sanitize_underscores(join(basename, "_", chain)); + auto ret = join(basename, "_", chain); + ParsedIR::sanitize_underscores(ret); + return ret; } else { @@ -7895,7 +7898,8 @@ void CompilerGLSL::store_flattened_struct(const string &basename, uint32_t rhs_i for (uint32_t i = 0; i < uint32_t(member_type->member_types.size()); i++) { sub_indices.back() = i; - auto lhs = sanitize_underscores(join(basename, "_", to_member_name(*member_type, i))); + auto lhs = join(basename, "_", to_member_name(*member_type, i)); + ParsedIR::sanitize_underscores(lhs); if (get(member_type->member_types[i]).basetype == SPIRType::Struct) { @@ -11435,13 +11439,7 @@ void CompilerGLSL::add_member_name(SPIRType &type, uint32_t index) if (name.empty()) return; - // Reserved for temporaries. - if (name[0] == '_' && name.size() >= 2 && isdigit(name[1])) - { - name.clear(); - return; - } - + ParsedIR::sanitize_identifier(name, true, true); update_name_cache(type.member_name_cache, name); } } @@ -12167,16 +12165,13 @@ void CompilerGLSL::add_variable(unordered_set &variables_primary, if (name.empty()) return; - // Reserved for temporaries. - if (name[0] == '_' && name.size() >= 2 && isdigit(name[1])) + ParsedIR::sanitize_underscores(name); + if (ParsedIR::is_globally_reserved_identifier(name, true)) { name.clear(); return; } - // Avoid double underscores. - name = sanitize_underscores(name); - update_name_cache(variables_primary, variables_secondary, name); } diff --git a/3rdparty/spirv-cross/spirv_glsl.hpp b/3rdparty/spirv-cross/spirv_glsl.hpp index c3837434f..79f6582c3 100644 --- a/3rdparty/spirv-cross/spirv_glsl.hpp +++ b/3rdparty/spirv-cross/spirv_glsl.hpp @@ -487,6 +487,7 @@ protected: void emit_buffer_reference_block(SPIRType &type, bool forward_declaration); void emit_buffer_block_legacy(const SPIRVariable &var); void emit_buffer_block_flattened(const SPIRVariable &type); + void fixup_implicit_builtin_block_names(); void emit_declared_builtin_block(spv::StorageClass storage, spv::ExecutionModel model); bool should_force_emit_builtin_block(spv::StorageClass storage); void emit_push_constant_block_vulkan(const SPIRVariable &var); @@ -757,8 +758,6 @@ protected: virtual void declare_undefined_values(); - static std::string sanitize_underscores(const std::string &str); - bool can_use_io_location(spv::StorageClass storage, bool block); const Instruction *get_next_instruction_in_block(const Instruction &instr); static uint32_t mask_relevant_memory_semantics(uint32_t semantics); diff --git a/3rdparty/spirv-cross/spirv_hlsl.cpp b/3rdparty/spirv-cross/spirv_hlsl.cpp index 51b3dd48e..9f6a9f1b9 100644 --- a/3rdparty/spirv-cross/spirv_hlsl.cpp +++ b/3rdparty/spirv-cross/spirv_hlsl.cpp @@ -971,7 +971,9 @@ std::string CompilerHLSL::builtin_to_glsl(spv::BuiltIn builtin, spv::StorageClas auto &var = get(num_workgroups_builtin); auto &type = get(var.basetype); - return sanitize_underscores(join(to_name(num_workgroups_builtin), "_", get_member_name(type.self, 0))); + auto ret = join(to_name(num_workgroups_builtin), "_", get_member_name(type.self, 0)); + ParsedIR::sanitize_underscores(ret); + return ret; } case BuiltInPointCoord: // Crude hack, but there is no real alternative. This path is only enabled if point_coord_compat is set. @@ -2076,7 +2078,9 @@ void CompilerHLSL::emit_buffer_block(const SPIRVariable &var) add_member_name(type, i); auto backup_name = get_member_name(type.self, i); auto member_name = to_member_name(type, i); - set_member_name(type.self, i, sanitize_underscores(join(to_name(var.self), "_", member_name))); + member_name = join(to_name(var.self), "_", member_name); + ParsedIR::sanitize_underscores(member_name); + set_member_name(type.self, i, member_name); emit_struct_member(type, member, i, ""); set_member_name(type.self, i, backup_name); i++; @@ -2157,8 +2161,9 @@ void CompilerHLSL::emit_push_constant_block(const SPIRVariable &var) add_member_name(type, constant_index); auto backup_name = get_member_name(type.self, i); auto member_name = to_member_name(type, i); - set_member_name(type.self, constant_index, - sanitize_underscores(join(to_name(var.self), "_", member_name))); + member_name = join(to_name(var.self), "_", member_name); + ParsedIR::sanitize_underscores(member_name); + set_member_name(type.self, constant_index, member_name); emit_struct_member(type, member, i, "", layout.start); set_member_name(type.self, constant_index, backup_name); @@ -5590,6 +5595,8 @@ void CompilerHLSL::validate_shader_model() string CompilerHLSL::compile() { + ir.fixup_reserved_names(); + // Do not deal with ES-isms like precision, older extensions and such. options.es = false; options.version = 450; diff --git a/3rdparty/spirv-cross/spirv_msl.cpp b/3rdparty/spirv-cross/spirv_msl.cpp index 9edad29a6..aaf263123 100644 --- a/3rdparty/spirv-cross/spirv_msl.cpp +++ b/3rdparty/spirv-cross/spirv_msl.cpp @@ -589,7 +589,7 @@ void CompilerMSL::build_implicit_builtins() uint_type_ptr_out.pointer = true; uint_type_ptr_out.parent_type = get_uint_type_id(); uint_type_ptr_out.storage = StorageClassOutput; - + auto &ptr_out_type = set(offset, uint_type_ptr_out); ptr_out_type.self = get_uint_type_id(); set(var_id, offset, StorageClassOutput); @@ -1028,6 +1028,8 @@ void CompilerMSL::emit_entry_point_declarations() string CompilerMSL::compile() { + ir.fixup_reserved_names(); + // Do not deal with GLES-isms like precision, older extensions and such. options.vulkan_semantics = true; options.es = false; @@ -2684,7 +2686,7 @@ uint32_t CompilerMSL::add_interface_block(StorageClass storage, bool patch) statement("device ", to_name(ir.default_entry_point), "_", ib_var_ref, "* gl_in = &", input_buffer_var_name, "[min(", to_expression(builtin_invocation_id_id), ".x / ", get_entry_point().output_vertices, - ", spvIndirectParams[1] - 1) * spvIndirectParams[0]];"); + ", spvIndirectParams[1] - 1) * spvIndirectParams[0]];"); } else { @@ -10555,7 +10557,7 @@ void CompilerMSL::fix_up_shader_inputs_outputs() else if (var.storage == StorageClassOutput && is_builtin_variable(var)) { if (bi_type == BuiltInSampleMask && get_execution_model() == ExecutionModelFragment && - msl_options.additional_fixed_sample_mask != 0xffffffff) + msl_options.additional_fixed_sample_mask != 0xffffffff) { // If the additional fixed sample mask was set, we need to adjust the sample_mask // output to reflect that. If the shader outputs the sample_mask itself too, we need @@ -10563,15 +10565,15 @@ void CompilerMSL::fix_up_shader_inputs_outputs() if (does_shader_write_sample_mask) { entry_func.fixup_hooks_out.push_back([=]() { - statement(to_expression(builtin_sample_mask_id), " &= ", - msl_options.additional_fixed_sample_mask, ";"); + statement(to_expression(builtin_sample_mask_id), + " &= ", msl_options.additional_fixed_sample_mask, ";"); }); } else { entry_func.fixup_hooks_out.push_back([=]() { statement(to_expression(builtin_sample_mask_id), " = ", - msl_options.additional_fixed_sample_mask, ";"); + msl_options.additional_fixed_sample_mask, ";"); }); } }