From ae9cca39a49c438338cfe7884c7ba5df1ae97fe9 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: Sat, 28 Mar 2020 16:26:16 -0700 Subject: [PATCH] Updated spirv-cross. --- 3rdparty/spirv-cross/main.cpp | 5 ++ 3rdparty/spirv-cross/spirv_cross_c.cpp | 3 + 3rdparty/spirv-cross/spirv_cross_c.h | 4 +- .../spirv-cross/spirv_cross_parsed_ir.cpp | 53 +++++++++++++ .../spirv-cross/spirv_cross_parsed_ir.hpp | 2 + 3rdparty/spirv-cross/spirv_glsl.cpp | 79 +++++++++++++++++-- 3rdparty/spirv-cross/spirv_glsl.hpp | 7 ++ 3rdparty/spirv-cross/spirv_hlsl.cpp | 17 +++- 3rdparty/spirv-cross/spirv_msl.cpp | 7 +- 3rdparty/spirv-cross/spirv_msl.hpp | 1 + 3rdparty/spirv-cross/spirv_parser.cpp | 44 +---------- 3rdparty/spirv-cross/spirv_parser.hpp | 1 - 12 files changed, 170 insertions(+), 53 deletions(-) diff --git a/3rdparty/spirv-cross/main.cpp b/3rdparty/spirv-cross/main.cpp index 37575f9e5..31b77baf9 100644 --- a/3rdparty/spirv-cross/main.cpp +++ b/3rdparty/spirv-cross/main.cpp @@ -529,6 +529,7 @@ struct CLIArguments bool vulkan_glsl_disable_ext_samplerless_texture_functions = false; bool emit_line_directives = false; bool enable_storage_image_qualifier_deduction = true; + bool force_zero_initialized_variables = false; SmallVector msl_discrete_descriptor_sets; SmallVector msl_device_argument_buffers; SmallVector> msl_dynamic_buffers; @@ -598,6 +599,7 @@ static void print_help() "\t[--cpp]\n" "\t[--cpp-interface-name ]\n" "\t[--disable-storage-image-qualifier-deduction]\n" + "\t[--force-zero-initialized-variables]\n" "\t[--glsl-emit-push-constant-as-ubo]\n" "\t[--glsl-emit-ubo-as-plain-uniforms]\n" "\t[--glsl-remap-ext-framebuffer-fetch input-attachment color-location]\n" @@ -949,6 +951,7 @@ static string compile_iteration(const CLIArguments &args, std::vector opts.emit_uniform_buffer_as_plain_uniforms = args.glsl_emit_ubo_as_plain_uniforms; opts.emit_line_directives = args.emit_line_directives; opts.enable_storage_image_qualifier_deduction = args.enable_storage_image_qualifier_deduction; + opts.force_zero_initialized_variables = args.force_zero_initialized_variables; compiler->set_common_options(opts); for (auto &fetch : args.glsl_ext_framebuffer_fetch) @@ -1139,6 +1142,8 @@ static int main_inner(int argc, char *argv[]) [&args](CLIParser &) { args.vulkan_glsl_disable_ext_samplerless_texture_functions = true; }); cbs.add("--disable-storage-image-qualifier-deduction", [&args](CLIParser &) { args.enable_storage_image_qualifier_deduction = false; }); + cbs.add("--force-zero-initialized-variables", + [&args](CLIParser &) { args.force_zero_initialized_variables = true; }); cbs.add("--msl", [&args](CLIParser &) { args.msl = true; }); cbs.add("--hlsl", [&args](CLIParser &) { args.hlsl = true; }); cbs.add("--hlsl-enable-compat", [&args](CLIParser &) { args.hlsl_compat = true; }); diff --git a/3rdparty/spirv-cross/spirv_cross_c.cpp b/3rdparty/spirv-cross/spirv_cross_c.cpp index 3b1139f3e..ead446912 100644 --- a/3rdparty/spirv-cross/spirv_cross_c.cpp +++ b/3rdparty/spirv-cross/spirv_cross_c.cpp @@ -423,6 +423,9 @@ spvc_result spvc_compiler_options_set_uint(spvc_compiler_options options, spvc_c case SPVC_COMPILER_OPTION_ENABLE_STORAGE_IMAGE_QUALIFIER_DEDUCTION: options->glsl.enable_storage_image_qualifier_deduction = value != 0; break; + case SPVC_COMPILER_OPTION_FORCE_ZERO_INITIALIZED_VARIABLES: + options->glsl.force_zero_initialized_variables = value != 0; + break; case SPVC_COMPILER_OPTION_GLSL_SUPPORT_NONZERO_BASE_INSTANCE: options->glsl.vertex.support_nonzero_base_instance = value != 0; diff --git a/3rdparty/spirv-cross/spirv_cross_c.h b/3rdparty/spirv-cross/spirv_cross_c.h index 405ff616b..3ff245a6d 100644 --- a/3rdparty/spirv-cross/spirv_cross_c.h +++ b/3rdparty/spirv-cross/spirv_cross_c.h @@ -33,7 +33,7 @@ extern "C" { /* Bumped if ABI or API breaks backwards compatibility. */ #define SPVC_C_API_VERSION_MAJOR 0 /* Bumped if APIs or enumerations are added in a backwards compatible way. */ -#define SPVC_C_API_VERSION_MINOR 27 +#define SPVC_C_API_VERSION_MINOR 28 /* Bumped if internal implementation details change. */ #define SPVC_C_API_VERSION_PATCH 0 @@ -578,6 +578,8 @@ typedef enum spvc_compiler_option SPVC_COMPILER_OPTION_HLSL_FORCE_STORAGE_BUFFER_AS_UAV = 53 | SPVC_COMPILER_OPTION_HLSL_BIT, + SPVC_COMPILER_OPTION_FORCE_ZERO_INITIALIZED_VARIABLES = 54 | SPVC_COMPILER_OPTION_COMMON_BIT, + SPVC_COMPILER_OPTION_INT_MAX = 0x7fffffff } spvc_compiler_option; diff --git a/3rdparty/spirv-cross/spirv_cross_parsed_ir.cpp b/3rdparty/spirv-cross/spirv_cross_parsed_ir.cpp index b49a0574c..655713f8c 100644 --- a/3rdparty/spirv-cross/spirv_cross_parsed_ir.cpp +++ b/3rdparty/spirv-cross/spirv_cross_parsed_ir.cpp @@ -854,4 +854,57 @@ ParsedIR::LoopLock &ParsedIR::LoopLock::operator=(LoopLock &&other) SPIRV_CROSS_ return *this; } +void ParsedIR::make_constant_null(uint32_t id, uint32_t type, bool add_to_typed_id_set) +{ + auto &constant_type = get(type); + + if (constant_type.pointer) + { + if (add_to_typed_id_set) + add_typed_id(TypeConstant, id); + auto &constant = variant_set(ids[id], type); + constant.self = id; + constant.make_null(constant_type); + } + else if (!constant_type.array.empty()) + { + assert(constant_type.parent_type); + uint32_t parent_id = increase_bound_by(1); + make_constant_null(parent_id, constant_type.parent_type, add_to_typed_id_set); + + if (!constant_type.array_size_literal.back()) + SPIRV_CROSS_THROW("Array size of OpConstantNull must be a literal."); + + SmallVector elements(constant_type.array.back()); + for (uint32_t i = 0; i < constant_type.array.back(); i++) + elements[i] = parent_id; + + if (add_to_typed_id_set) + add_typed_id(TypeConstant, id); + variant_set(ids[id], type, elements.data(), uint32_t(elements.size()), false).self = id; + } + else if (!constant_type.member_types.empty()) + { + uint32_t member_ids = increase_bound_by(uint32_t(constant_type.member_types.size())); + SmallVector elements(constant_type.member_types.size()); + for (uint32_t i = 0; i < constant_type.member_types.size(); i++) + { + make_constant_null(member_ids + i, constant_type.member_types[i], add_to_typed_id_set); + elements[i] = member_ids + i; + } + + if (add_to_typed_id_set) + add_typed_id(TypeConstant, id); + variant_set(ids[id], type, elements.data(), uint32_t(elements.size()), false).self = id; + } + else + { + if (add_to_typed_id_set) + add_typed_id(TypeConstant, id); + auto &constant = variant_set(ids[id], type); + constant.self = id; + constant.make_null(constant_type); + } +} + } // namespace SPIRV_CROSS_NAMESPACE diff --git a/3rdparty/spirv-cross/spirv_cross_parsed_ir.hpp b/3rdparty/spirv-cross/spirv_cross_parsed_ir.hpp index 7cff915f5..4880c8419 100644 --- a/3rdparty/spirv-cross/spirv_cross_parsed_ir.hpp +++ b/3rdparty/spirv-cross/spirv_cross_parsed_ir.hpp @@ -206,6 +206,8 @@ public: return empty_string; } + void make_constant_null(uint32_t id, uint32_t type, bool add_to_typed_id_set); + private: template T &get(uint32_t id) diff --git a/3rdparty/spirv-cross/spirv_glsl.cpp b/3rdparty/spirv-cross/spirv_glsl.cpp index 0009fc23e..d5c428331 100644 --- a/3rdparty/spirv-cross/spirv_glsl.cpp +++ b/3rdparty/spirv-cross/spirv_glsl.cpp @@ -2806,7 +2806,12 @@ void CompilerGLSL::declare_undefined_values() { bool emitted = false; ir.for_each_typed_id([&](uint32_t, const SPIRUndef &undef) { - statement(variable_decl(this->get(undef.basetype), to_name(undef.self), undef.self), ";"); + string initializer; + if (options.force_zero_initialized_variables && type_can_zero_initialize(this->get(undef.basetype))) + initializer = join(" = ", to_zero_initialized_expression(undef.basetype)); + + statement(variable_decl(this->get(undef.basetype), to_name(undef.self), undef.self), initializer, + ";"); emitted = true; }); @@ -3097,7 +3102,15 @@ void CompilerGLSL::emit_resources() if (!variable_is_lut(var)) { add_resource_name(var.self); - statement(variable_decl(var), ";"); + + string initializer; + if (options.force_zero_initialized_variables && var.storage == StorageClassPrivate && + !var.initializer && !var.static_expression && type_can_zero_initialize(get_variable_data_type(var))) + { + initializer = join(" = ", to_zero_initialized_expression(get_variable_data_type_id(var))); + } + + statement(variable_decl(var), initializer, ";"); emitted = true; } } @@ -4415,7 +4428,12 @@ void CompilerGLSL::emit_uninitialized_temporary(uint32_t result_type, uint32_t r // The result_id has not been made into an expression yet, so use flags interface. add_local_variable_name(result_id); - statement(flags_to_qualifiers_glsl(type, flags), variable_decl(type, to_name(result_id)), ";"); + + string initializer; + if (options.force_zero_initialized_variables && type_can_zero_initialize(type)) + initializer = join(" = ", to_zero_initialized_expression(result_type)); + + statement(flags_to_qualifiers_glsl(type, flags), variable_decl(type, to_name(result_id)), initializer, ";"); } } @@ -7947,7 +7965,16 @@ void CompilerGLSL::flush_variable_declaration(uint32_t id) auto *var = maybe_get(id); if (var && var->deferred_declaration) { - statement(variable_decl_function_local(*var), ";"); + string initializer; + if (options.force_zero_initialized_variables && + (var->storage == StorageClassFunction || var->storage == StorageClassGeneric || + var->storage == StorageClassPrivate) && + !var->initializer && type_can_zero_initialize(get_variable_data_type(*var))) + { + initializer = join(" = ", to_zero_initialized_expression(get_variable_data_type_id(*var))); + } + + statement(variable_decl_function_local(*var), initializer, ";"); var->deferred_declaration = false; } if (var) @@ -11113,6 +11140,37 @@ string CompilerGLSL::to_initializer_expression(const SPIRVariable &var) return to_expression(var.initializer); } +string CompilerGLSL::to_zero_initialized_expression(uint32_t type_id) +{ +#ifndef NDEBUG + auto &type = get(type_id); + assert(type.storage == StorageClassPrivate || type.storage == StorageClassFunction || + type.storage == StorageClassGeneric); +#endif + uint32_t id = ir.increase_bound_by(1); + ir.make_constant_null(id, type_id, false); + return constant_expression(get(id)); +} + +bool CompilerGLSL::type_can_zero_initialize(const SPIRType &type) const +{ + if (type.pointer) + return false; + + if (!type.array.empty() && options.flatten_multidimensional_arrays) + return false; + + for (auto &literal : type.array_size_literal) + if (!literal) + return false; + + for (auto &memb : type.member_types) + if (!type_can_zero_initialize(get(memb))) + return false; + + return true; +} + string CompilerGLSL::variable_decl(const SPIRVariable &variable) { // Ignore the pointer type since GLSL doesn't have pointers. @@ -11128,13 +11186,18 @@ string CompilerGLSL::variable_decl(const SPIRVariable &variable) uint32_t expr = variable.static_expression; if (ir.ids[expr].get_type() != TypeUndef) res += join(" = ", to_expression(variable.static_expression)); + else if (options.force_zero_initialized_variables && type_can_zero_initialize(type)) + res += join(" = ", to_zero_initialized_expression(get_variable_data_type_id(variable))); } else if (variable.initializer) { uint32_t expr = variable.initializer; if (ir.ids[expr].get_type() != TypeUndef) res += join(" = ", to_initializer_expression(variable)); + else if (options.force_zero_initialized_variables && type_can_zero_initialize(type)) + res += join(" = ", to_zero_initialized_expression(get_variable_data_type_id(variable))); } + return res; } @@ -12523,7 +12586,13 @@ void CompilerGLSL::emit_hoisted_temporaries(SmallVector> &tempo add_local_variable_name(tmp.second); auto &flags = ir.meta[tmp.second].decoration.decoration_flags; auto &type = get(tmp.first); - statement(flags_to_qualifiers_glsl(type, flags), variable_decl(type, to_name(tmp.second)), ";"); + + // Not all targets support pointer literals, so don't bother with that case. + string initializer; + if (options.force_zero_initialized_variables && type_can_zero_initialize(type)) + initializer = join(" = ", to_zero_initialized_expression(tmp.first)); + + statement(flags_to_qualifiers_glsl(type, flags), variable_decl(type, to_name(tmp.second)), initializer, ";"); hoisted_temporaries.insert(tmp.second); forced_temporaries.insert(tmp.second); diff --git a/3rdparty/spirv-cross/spirv_glsl.hpp b/3rdparty/spirv-cross/spirv_glsl.hpp index 5fca9a1a3..065bdf041 100644 --- a/3rdparty/spirv-cross/spirv_glsl.hpp +++ b/3rdparty/spirv-cross/spirv_glsl.hpp @@ -115,6 +115,11 @@ public: // by the SPIR-V, it's recommended to set this to false. bool enable_storage_image_qualifier_deduction = true; + // On some targets (WebGPU), uninitialized variables are banned. + // If this is enabled, all variables (temporaries, Private, Function) + // which would otherwise be uninitialized will now be initialized to 0 instead. + bool force_zero_initialized_variables = false; + enum Precision { DontCare, @@ -576,6 +581,8 @@ protected: spv::StorageClass rhs_storage); virtual void emit_block_hints(const SPIRBlock &block); virtual std::string to_initializer_expression(const SPIRVariable &var); + virtual std::string to_zero_initialized_expression(uint32_t type_id); + bool type_can_zero_initialize(const SPIRType &type) const; bool buffer_is_packing_standard(const SPIRType &type, BufferPackingStandard packing, uint32_t *failed_index = nullptr, uint32_t start_offset = 0, diff --git a/3rdparty/spirv-cross/spirv_hlsl.cpp b/3rdparty/spirv-cross/spirv_hlsl.cpp index 5f7cc3929..8639f201a 100644 --- a/3rdparty/spirv-cross/spirv_hlsl.cpp +++ b/3rdparty/spirv-cross/spirv_hlsl.cpp @@ -1121,7 +1121,12 @@ void CompilerHLSL::declare_undefined_values() { bool emitted = false; ir.for_each_typed_id([&](uint32_t, const SPIRUndef &undef) { - statement("static ", variable_decl(this->get(undef.basetype), to_name(undef.self), undef.self), ";"); + string initializer; + if (options.force_zero_initialized_variables && type_can_zero_initialize(this->get(undef.basetype))) + initializer = join(" = ", to_zero_initialized_expression(undef.basetype)); + + statement("static ", variable_decl(this->get(undef.basetype), to_name(undef.self), undef.self), + initializer, ";"); emitted = true; }); @@ -1362,7 +1367,15 @@ void CompilerHLSL::emit_resources() storage = "static"; break; } - statement(storage, " ", variable_decl(var), ";"); + + string initializer; + if (options.force_zero_initialized_variables && var.storage == StorageClassPrivate && + !var.initializer && !var.static_expression && type_can_zero_initialize(get_variable_data_type(var))) + { + initializer = join(" = ", to_zero_initialized_expression(get_variable_data_type_id(var))); + } + statement(storage, " ", variable_decl(var), initializer, ";"); + emitted = true; } } diff --git a/3rdparty/spirv-cross/spirv_msl.cpp b/3rdparty/spirv-cross/spirv_msl.cpp index 515cb06e4..361c338a5 100644 --- a/3rdparty/spirv-cross/spirv_msl.cpp +++ b/3rdparty/spirv-cross/spirv_msl.cpp @@ -12450,7 +12450,7 @@ void CompilerMSL::bitcast_to_builtin_store(uint32_t target_id, std::string &expr } } -std::string CompilerMSL::to_initializer_expression(const SPIRVariable &var) +string CompilerMSL::to_initializer_expression(const SPIRVariable &var) { // We risk getting an array initializer here with MSL. If we have an array. // FIXME: We cannot handle non-constant arrays being initialized. @@ -12463,6 +12463,11 @@ std::string CompilerMSL::to_initializer_expression(const SPIRVariable &var) return CompilerGLSL::to_initializer_expression(var); } +string CompilerMSL::to_zero_initialized_expression(uint32_t) +{ + return "{}"; +} + bool CompilerMSL::descriptor_set_is_argument_buffer(uint32_t desc_set) const { if (!msl_options.argument_buffers) diff --git a/3rdparty/spirv-cross/spirv_msl.hpp b/3rdparty/spirv-cross/spirv_msl.hpp index 6b021c66b..677978941 100644 --- a/3rdparty/spirv-cross/spirv_msl.hpp +++ b/3rdparty/spirv-cross/spirv_msl.hpp @@ -619,6 +619,7 @@ protected: uint32_t grad_y, uint32_t lod, uint32_t coffset, uint32_t offset, uint32_t bias, uint32_t comp, uint32_t sample, uint32_t minlod, bool *p_forward) override; std::string to_initializer_expression(const SPIRVariable &var) override; + std::string to_zero_initialized_expression(uint32_t type_id) override; std::string unpack_expression_type(std::string expr_str, const SPIRType &type, uint32_t physical_type_id, bool is_packed, bool row_major) override; diff --git a/3rdparty/spirv-cross/spirv_parser.cpp b/3rdparty/spirv-cross/spirv_parser.cpp index 447900264..c20edccd9 100644 --- a/3rdparty/spirv-cross/spirv_parser.cpp +++ b/3rdparty/spirv-cross/spirv_parser.cpp @@ -771,7 +771,7 @@ void Parser::parse(const Instruction &instruction) { uint32_t id = ops[1]; uint32_t type = ops[0]; - make_constant_null(id, type); + ir.make_constant_null(id, type, true); break; } @@ -1136,46 +1136,4 @@ bool Parser::variable_storage_is_aliased(const SPIRVariable &v) const return !is_restrict && (ssbo || image || counter); } - -void Parser::make_constant_null(uint32_t id, uint32_t type) -{ - auto &constant_type = get(type); - - if (constant_type.pointer) - { - auto &constant = set(id, type); - constant.make_null(constant_type); - } - else if (!constant_type.array.empty()) - { - assert(constant_type.parent_type); - uint32_t parent_id = ir.increase_bound_by(1); - make_constant_null(parent_id, constant_type.parent_type); - - if (!constant_type.array_size_literal.back()) - SPIRV_CROSS_THROW("Array size of OpConstantNull must be a literal."); - - SmallVector elements(constant_type.array.back()); - for (uint32_t i = 0; i < constant_type.array.back(); i++) - elements[i] = parent_id; - set(id, type, elements.data(), uint32_t(elements.size()), false); - } - else if (!constant_type.member_types.empty()) - { - uint32_t member_ids = ir.increase_bound_by(uint32_t(constant_type.member_types.size())); - SmallVector elements(constant_type.member_types.size()); - for (uint32_t i = 0; i < constant_type.member_types.size(); i++) - { - make_constant_null(member_ids + i, constant_type.member_types[i]); - elements[i] = member_ids + i; - } - set(id, type, elements.data(), uint32_t(elements.size()), false); - } - else - { - auto &constant = set(id, type); - constant.make_null(constant_type); - } -} - } // namespace SPIRV_CROSS_NAMESPACE diff --git a/3rdparty/spirv-cross/spirv_parser.hpp b/3rdparty/spirv-cross/spirv_parser.hpp index 7d5b79973..dafa3e868 100644 --- a/3rdparty/spirv-cross/spirv_parser.hpp +++ b/3rdparty/spirv-cross/spirv_parser.hpp @@ -87,7 +87,6 @@ private: bool types_are_logically_equivalent(const SPIRType &a, const SPIRType &b) const; bool variable_storage_is_aliased(const SPIRVariable &v) const; - void make_constant_null(uint32_t id, uint32_t type); }; } // namespace SPIRV_CROSS_NAMESPACE