From bdd174b74cbe94a741aae35b09ddd0b12e6f61ed 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, 2 Oct 2021 10:49:50 -0700 Subject: [PATCH] Updated spirv-cross. --- 3rdparty/spirv-cross/main.cpp | 7 +- 3rdparty/spirv-cross/spirv_common.hpp | 34 +++++- .../spirv-cross/spirv_cross_containers.hpp | 8 +- 3rdparty/spirv-cross/spirv_glsl.cpp | 21 ++-- 3rdparty/spirv-cross/spirv_hlsl.cpp | 1 + 3rdparty/spirv-cross/spirv_msl.cpp | 107 ++++++++---------- 3rdparty/spirv-cross/spirv_msl.hpp | 6 +- 7 files changed, 94 insertions(+), 90 deletions(-) diff --git a/3rdparty/spirv-cross/main.cpp b/3rdparty/spirv-cross/main.cpp index e5b4e3a19..6cb539cf8 100644 --- a/3rdparty/spirv-cross/main.cpp +++ b/3rdparty/spirv-cross/main.cpp @@ -1407,12 +1407,7 @@ static string compile_iteration(const CLIArguments &args, std::vector if (args.hlsl) { auto *hlsl_compiler = static_cast(compiler.get()); - uint32_t new_builtin = hlsl_compiler->remap_num_workgroups_builtin(); - if (new_builtin) - { - hlsl_compiler->set_decoration(new_builtin, DecorationDescriptorSet, 0); - hlsl_compiler->set_decoration(new_builtin, DecorationBinding, 0); - } + hlsl_compiler->remap_num_workgroups_builtin(); } if (args.hlsl) diff --git a/3rdparty/spirv-cross/spirv_common.hpp b/3rdparty/spirv-cross/spirv_common.hpp index 4bafbf93d..e602fbd44 100644 --- a/3rdparty/spirv-cross/spirv_common.hpp +++ b/3rdparty/spirv-cross/spirv_common.hpp @@ -211,6 +211,28 @@ inline std::string convert_to_string(const T &t) return std::to_string(t); } +static inline std::string convert_to_string(int32_t value) +{ + // INT_MIN is ... special on some backends. If we use a decimal literal, and negate it, we + // could accidentally promote the literal to long first, then negate. + // To workaround it, emit int(0x80000000) instead. + if (value == std::numeric_limits::min()) + return "int(0x80000000)"; + else + return std::to_string(value); +} + +static inline std::string convert_to_string(int64_t value, const std::string &int64_type, bool long_long_literal_suffix) +{ + // INT64_MIN is ... special on some backends. + // If we use a decimal literal, and negate it, we might overflow the representable numbers. + // To workaround it, emit int(0x80000000) instead. + if (value == std::numeric_limits::min()) + return join(int64_type, "(0x8000000000000000u", (long_long_literal_suffix ? "ll" : "l"), ")"); + else + return std::to_string(value) + (long_long_literal_suffix ? "ll" : "l"); +} + // Allow implementations to set a convenient standard precision #ifndef SPIRV_CROSS_FLT_FMT #define SPIRV_CROSS_FLT_FMT "%.32g" @@ -1377,7 +1399,7 @@ public: ~Variant() { if (holder) - group->pools[type]->free_opaque(holder); + group->pools[type]->deallocate_opaque(holder); } // Marking custom move constructor as noexcept is important. @@ -1396,7 +1418,7 @@ public: if (this != &other) { if (holder) - group->pools[type]->free_opaque(holder); + group->pools[type]->deallocate_opaque(holder); holder = other.holder; group = other.group; type = other.type; @@ -1420,7 +1442,7 @@ public: if (this != &other) { if (holder) - group->pools[type]->free_opaque(holder); + group->pools[type]->deallocate_opaque(holder); if (other.holder) holder = other.holder->clone(group->pools[other.type].get()); @@ -1436,13 +1458,13 @@ public: void set(IVariant *val, Types new_type) { if (holder) - group->pools[type]->free_opaque(holder); + group->pools[type]->deallocate_opaque(holder); holder = nullptr; if (!allow_type_rewrite && type != TypeNone && type != new_type) { if (val) - group->pools[new_type]->free_opaque(val); + group->pools[new_type]->deallocate_opaque(val); SPIRV_CROSS_THROW("Overwriting a variant with new type."); } @@ -1497,7 +1519,7 @@ public: void reset() { if (holder) - group->pools[type]->free_opaque(holder); + group->pools[type]->deallocate_opaque(holder); holder = nullptr; type = TypeNone; } diff --git a/3rdparty/spirv-cross/spirv_cross_containers.hpp b/3rdparty/spirv-cross/spirv_cross_containers.hpp index f2179b4ed..a027250bd 100644 --- a/3rdparty/spirv-cross/spirv_cross_containers.hpp +++ b/3rdparty/spirv-cross/spirv_cross_containers.hpp @@ -546,7 +546,7 @@ class ObjectPoolBase { public: virtual ~ObjectPoolBase() = default; - virtual void free_opaque(void *ptr) = 0; + virtual void deallocate_opaque(void *ptr) = 0; }; template @@ -580,15 +580,15 @@ public: return ptr; } - void free(T *ptr) + void deallocate(T *ptr) { ptr->~T(); vacants.push_back(ptr); } - void free_opaque(void *ptr) override + void deallocate_opaque(void *ptr) override { - free(static_cast(ptr)); + deallocate(static_cast(ptr)); } void clear() diff --git a/3rdparty/spirv-cross/spirv_glsl.cpp b/3rdparty/spirv-cross/spirv_glsl.cpp index 2b19346d9..af486e4ee 100644 --- a/3rdparty/spirv-cross/spirv_glsl.cpp +++ b/3rdparty/spirv-cross/spirv_glsl.cpp @@ -5290,13 +5290,15 @@ string CompilerGLSL::constant_expression_vector(const SPIRConstant &c, uint32_t break; case SPIRType::Int64: + { + auto tmp = type; + tmp.vecsize = 1; + tmp.columns = 1; + auto int64_type = type_to_glsl(tmp); + if (splat) { - res += convert_to_string(c.scalar_i64(vector, 0)); - if (backend.long_long_literal_suffix) - res += "ll"; - else - res += "l"; + res += convert_to_string(c.scalar_i64(vector, 0), int64_type, backend.long_long_literal_suffix); } else { @@ -5305,19 +5307,14 @@ string CompilerGLSL::constant_expression_vector(const SPIRConstant &c, uint32_t if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0) res += to_name(c.specialization_constant_id(vector, i)); else - { - res += convert_to_string(c.scalar_i64(vector, i)); - if (backend.long_long_literal_suffix) - res += "ll"; - else - res += "l"; - } + res += convert_to_string(c.scalar_i64(vector, i), int64_type, backend.long_long_literal_suffix); if (i + 1 < c.vector_size()) res += ", "; } } break; + } case SPIRType::UInt64: if (splat) diff --git a/3rdparty/spirv-cross/spirv_hlsl.cpp b/3rdparty/spirv-cross/spirv_hlsl.cpp index 3ca4c2f90..1f04c400a 100644 --- a/3rdparty/spirv-cross/spirv_hlsl.cpp +++ b/3rdparty/spirv-cross/spirv_hlsl.cpp @@ -5696,6 +5696,7 @@ VariableID CompilerHLSL::remap_num_workgroups_builtin() ir.meta[variable_id].decoration.alias = "SPIRV_Cross_NumWorkgroups"; num_workgroups_builtin = variable_id; + get_entry_point().interface_variables.push_back(num_workgroups_builtin); return variable_id; } diff --git a/3rdparty/spirv-cross/spirv_msl.cpp b/3rdparty/spirv-cross/spirv_msl.cpp index 2b1e06263..f12b1ebed 100644 --- a/3rdparty/spirv-cross/spirv_msl.cpp +++ b/3rdparty/spirv-cross/spirv_msl.cpp @@ -58,7 +58,7 @@ CompilerMSL::CompilerMSL(ParsedIR &&ir_) void CompilerMSL::add_msl_shader_input(const MSLShaderInput &si) { - inputs_by_location[si.location] = si; + inputs_by_location[{si.location, si.component}] = si; if (si.builtin != BuiltInMax && !inputs_by_builtin.count(si.builtin)) inputs_by_builtin[si.builtin] = si; } @@ -1462,9 +1462,9 @@ string CompilerMSL::compile() emit_header(); emit_custom_templates(); + emit_custom_functions(); emit_specialization_constants_and_structs(); emit_resources(); - emit_custom_functions(); emit_function(get(ir.default_entry_point), Bitset()); pass_count++; @@ -2224,9 +2224,10 @@ void CompilerMSL::add_plain_variable_to_interface_block(StorageClass storage, co if (get_decoration_bitset(var.self).get(DecorationLocation)) { uint32_t locn = get_decoration(var.self, DecorationLocation); + uint32_t comp = get_decoration(var.self, DecorationComponent); if (storage == StorageClassInput) { - type_id = ensure_correct_input_type(var.basetype, locn, 0, meta.strip_array); + type_id = ensure_correct_input_type(var.basetype, locn, comp, 0, meta.strip_array); var.basetype = type_id; type_id = get_pointee_type_id(type_id); @@ -2238,6 +2239,8 @@ void CompilerMSL::add_plain_variable_to_interface_block(StorageClass storage, co ib_type.member_types[ib_mbr_idx] = type_id; } set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, locn); + if (comp) + set_member_decoration(ib_type.self, ib_mbr_idx, DecorationComponent, comp); mark_location_as_used_by_shader(locn, get(type_id), storage); } else if (is_builtin && is_tessellation_shader() && inputs_by_builtin.count(builtin)) @@ -2393,8 +2396,8 @@ void CompilerMSL::add_composite_variable_to_interface_block(StorageClass storage uint32_t comp = get_decoration(var.self, DecorationComponent); if (storage == StorageClassInput) { - var.basetype = ensure_correct_input_type(var.basetype, locn, 0, meta.strip_array); - uint32_t mbr_type_id = ensure_correct_input_type(usable_type->self, locn, 0, meta.strip_array); + var.basetype = ensure_correct_input_type(var.basetype, locn, comp, 0, meta.strip_array); + uint32_t mbr_type_id = ensure_correct_input_type(usable_type->self, locn, comp, 0, meta.strip_array); if (storage == StorageClassInput && pull_model_inputs.count(var.self)) ib_type.member_types[ib_mbr_idx] = build_msl_interpolant_type(mbr_type_id, is_noperspective); else @@ -2739,9 +2742,10 @@ void CompilerMSL::add_plain_member_variable_to_interface_block(StorageClass stor if (has_member_decoration(var_type.self, mbr_idx, DecorationLocation)) { uint32_t locn = get_member_decoration(var_type.self, mbr_idx, DecorationLocation); + uint32_t comp = get_member_decoration(var_type.self, mbr_idx, DecorationComponent); if (storage == StorageClassInput) { - mbr_type_id = ensure_correct_input_type(mbr_type_id, locn, 0, meta.strip_array); + mbr_type_id = ensure_correct_input_type(mbr_type_id, locn, comp, 0, meta.strip_array); var_type.member_types[mbr_idx] = mbr_type_id; if (storage == StorageClassInput && pull_model_inputs.count(var.self)) ib_type.member_types[ib_mbr_idx] = build_msl_interpolant_type(mbr_type_id, is_noperspective); @@ -2758,7 +2762,7 @@ void CompilerMSL::add_plain_member_variable_to_interface_block(StorageClass stor uint32_t locn = get_accumulated_member_location(var, mbr_idx, meta.strip_array); if (storage == StorageClassInput) { - mbr_type_id = ensure_correct_input_type(mbr_type_id, locn, 0, meta.strip_array); + mbr_type_id = ensure_correct_input_type(mbr_type_id, locn, 0, 0, meta.strip_array); var_type.member_types[mbr_idx] = mbr_type_id; if (storage == StorageClassInput && pull_model_inputs.count(var.self)) ib_type.member_types[ib_mbr_idx] = build_msl_interpolant_type(mbr_type_id, is_noperspective); @@ -3602,7 +3606,7 @@ uint32_t CompilerMSL::add_interface_block(StorageClass storage, bool patch) // the struct containing them is the correct size and layout. for (auto &input : inputs_by_location) { - if (location_inputs_in_use.count(input.first) != 0) + if (location_inputs_in_use.count(input.first.location) != 0) continue; // Create a fake variable to put at the location. @@ -3642,7 +3646,10 @@ uint32_t CompilerMSL::add_interface_block(StorageClass storage, bool patch) ptr_type.self = array_type_id; auto &fake_var = set(var_id, ptr_type_id, storage); - set_decoration(var_id, DecorationLocation, input.first); + set_decoration(var_id, DecorationLocation, input.first.location); + if (input.first.component) + set_decoration(var_id, DecorationComponent, input.first.component); + meta.strip_array = true; meta.allow_local_declaration = false; add_variable_to_interface_block(storage, ib_var_ref, ib_type, fake_var, meta); @@ -3794,7 +3801,7 @@ uint32_t CompilerMSL::ensure_correct_builtin_type(uint32_t type_id, BuiltIn buil // Ensure that the type is compatible with the shader input. // If it is, simply return the given type ID. // Otherwise, create a new type, and return its ID. -uint32_t CompilerMSL::ensure_correct_input_type(uint32_t type_id, uint32_t location, uint32_t num_components, bool strip_array) +uint32_t CompilerMSL::ensure_correct_input_type(uint32_t type_id, uint32_t location, uint32_t component, uint32_t num_components, bool strip_array) { auto &type = get(type_id); @@ -3804,7 +3811,7 @@ uint32_t CompilerMSL::ensure_correct_input_type(uint32_t type_id, uint32_t locat if (type.basetype == SPIRType::Struct || type.array.size() > max_array_dimensions) return type_id; - auto p_va = inputs_by_location.find(location); + auto p_va = inputs_by_location.find({location, component}); if (p_va == end(inputs_by_location)) { if (num_components > type.vecsize) @@ -5001,6 +5008,24 @@ void CompilerMSL::emit_custom_functions() statement(""); break; + case SPVFuncImplQuantizeToF16: + // Ensure fast-math is disabled to match Vulkan results. + // SpvHalfTypeSelector is used to match the half* template type to the float* template type. + // Depending on GPU, MSL does not always flush converted subnormal halfs to zero, + // as required by OpQuantizeToF16, so check for subnormals and flush them to zero. + statement("template struct SpvHalfTypeSelector;"); + statement("template <> struct SpvHalfTypeSelector { public: using H = half; };"); + statement("template struct SpvHalfTypeSelector> { using H = vec; };"); + statement("template::H>"); + statement("[[clang::optnone]] F spvQuantizeToF16(F fval)"); + begin_scope(); + statement("H hval = H(fval);"); + statement("hval = select(copysign(H(0), hval), hval, isnormal(hval) || isinf(hval) || isnan(hval));"); + statement("return F(hval);"); + end_scope(); + statement(""); + break; + // Emulate texturecube_array with texture2d_array for iOS where this type is not available case SPVFuncImplCubemapTo2DArrayFace: statement(force_inline); @@ -8064,28 +8089,7 @@ void CompilerMSL::emit_instruction(const Instruction &instruction) uint32_t result_type = ops[0]; uint32_t id = ops[1]; uint32_t arg = ops[2]; - - string exp; - auto &type = get(result_type); - - switch (type.vecsize) - { - case 1: - exp = join("float(half(", to_expression(arg), "))"); - break; - case 2: - exp = join("float2(half2(", to_expression(arg), "))"); - break; - case 3: - exp = join("float3(half3(", to_expression(arg), "))"); - break; - case 4: - exp = join("float4(half4(", to_expression(arg), "))"); - break; - default: - SPIRV_CROSS_THROW("Illegal argument to OpQuantizeToF16."); - } - + string exp = join("spvQuantizeToF16(", to_expression(arg), ")"); emit_op(result_type, id, exp, should_forward(arg)); break; } @@ -13338,31 +13342,11 @@ string CompilerMSL::type_to_array_glsl(const SPIRType &type) string CompilerMSL::constant_op_expression(const SPIRConstantOp &cop) { - auto &type = get(cop.basetype); - string op; - switch (cop.opcode) { case OpQuantizeToF16: - switch (type.vecsize) - { - case 1: - op = "float(half("; - break; - case 2: - op = "float2(half2("; - break; - case 3: - op = "float3(half3("; - break; - case 4: - op = "float4(half4("; - break; - default: - SPIRV_CROSS_THROW("Illegal argument to OpSpecConstantOp QuantizeToF16."); - } - return join(op, to_expression(cop.arguments[0]), "))"); - + add_spv_func_and_recompile(SPVFuncImplQuantizeToF16); + return join("spvQuantizeToF16(", to_expression(cop.arguments[0]), ")"); default: return CompilerGLSL::constant_op_expression(cop); } @@ -14536,11 +14520,11 @@ SPIRType CompilerMSL::get_presumed_input_type(const SPIRType &ib_type, uint32_t { SPIRType type = get_physical_member_type(ib_type, index); uint32_t loc = get_member_decoration(ib_type.self, index, DecorationLocation); - if (inputs_by_location.count(loc)) - { - if (inputs_by_location.at(loc).vecsize > type.vecsize) - type.vecsize = inputs_by_location.at(loc).vecsize; - } + uint32_t cmp = get_member_decoration(ib_type.self, index, DecorationComponent); + auto p_va = inputs_by_location.find({loc, cmp}); + if (p_va != end(inputs_by_location) && p_va->second.vecsize > type.vecsize) + type.vecsize = p_va->second.vecsize; + return type; } @@ -15054,6 +15038,9 @@ CompilerMSL::SPVFuncImpl CompilerMSL::OpCodePreprocessor::get_spv_func_impl(Op o } break; + case OpQuantizeToF16: + return SPVFuncImplQuantizeToF16; + case OpTypeArray: { // Allow Metal to use the array template to make arrays a value type diff --git a/3rdparty/spirv-cross/spirv_msl.hpp b/3rdparty/spirv-cross/spirv_msl.hpp index 9dc1a1a03..50d06860f 100644 --- a/3rdparty/spirv-cross/spirv_msl.hpp +++ b/3rdparty/spirv-cross/spirv_msl.hpp @@ -60,6 +60,7 @@ enum MSLShaderInputFormat struct MSLShaderInput { uint32_t location = 0; + uint32_t component = 0; MSLShaderInputFormat format = MSL_SHADER_INPUT_FORMAT_OTHER; spv::BuiltIn builtin = spv::BuiltInMax; uint32_t vecsize = 0; @@ -656,6 +657,7 @@ protected: SPVFuncImplFMul, SPVFuncImplFAdd, SPVFuncImplFSub, + SPVFuncImplQuantizeToF16, SPVFuncImplCubemapTo2DArrayFace, SPVFuncImplUnsafeArray, // Allow Metal to use the array template to make arrays a value type SPVFuncImplInverse4x4, @@ -837,7 +839,7 @@ protected: void mark_location_as_used_by_shader(uint32_t location, const SPIRType &type, spv::StorageClass storage, bool fallback = false); uint32_t ensure_correct_builtin_type(uint32_t type_id, spv::BuiltIn builtin); - uint32_t ensure_correct_input_type(uint32_t type_id, uint32_t location, + uint32_t ensure_correct_input_type(uint32_t type_id, uint32_t location, uint32_t component, uint32_t num_components, bool strip_array); void emit_custom_templates(); @@ -980,7 +982,7 @@ protected: Options msl_options; std::set spv_function_implementations; // Must be ordered to ensure declarations are in a specific order. - std::map inputs_by_location; + std::map inputs_by_location; std::unordered_map inputs_by_builtin; std::unordered_set location_inputs_in_use; std::unordered_set location_inputs_in_use_fallback;