From 5827dd54ea6a9fa7c77c3edfeed7a1be7a4a653b Mon Sep 17 00:00:00 2001 From: Hans-Kristian Arntzen Date: Tue, 3 Apr 2018 14:00:34 +0200 Subject: [PATCH] Support array of images and samplers in MSL. --- spirv_msl.cpp | 80 ++++++++++++++++++++++++++++++++++++++++++--------- spirv_msl.hpp | 1 + 2 files changed, 68 insertions(+), 13 deletions(-) diff --git a/spirv_msl.cpp b/spirv_msl.cpp index d6daf4be..59ff02a0 100644 --- a/spirv_msl.cpp +++ b/spirv_msl.cpp @@ -2292,7 +2292,11 @@ void CompilerMSL::emit_function_prototype(SPIRFunction &func, const Bitset &) // Manufacture automatic sampler arg for SampledImage texture auto &arg_type = get(arg.type); if (arg_type.basetype == SPIRType::SampledImage && arg_type.image.dim != DimBuffer) - decl += ", thread const sampler& " + to_sampler_expression(arg.id); + { + //const char *reference = arg_type.array.empty() ? "& " : " "; + const char *reference = " "; + decl += join(", thread const ", sampler_type(arg_type), reference, to_sampler_expression(arg.id)); + } if (&arg != &func.arguments.back()) decl += ", "; @@ -2594,14 +2598,9 @@ string CompilerMSL::to_func_call_arg(uint32_t id) string arg_str = CompilerGLSL::to_func_call_arg(id); // Manufacture automatic sampler arg if the arg is a SampledImage texture. - Variant &id_v = ids[id]; - if (id_v.get_type() == TypeVariable) - { - auto &var = id_v.get(); - auto &type = get(var.basetype); - if (type.basetype == SPIRType::SampledImage && type.image.dim != DimBuffer) - arg_str += ", " + to_sampler_expression(id); - } + auto &type = expression_type(id); + if (type.basetype == SPIRType::SampledImage && type.image.dim != DimBuffer) + arg_str += ", " + to_sampler_expression(id); return arg_str; } @@ -2611,8 +2610,18 @@ string CompilerMSL::to_func_call_arg(uint32_t id) // by appending a suffix to the expression constructed from the ID. string CompilerMSL::to_sampler_expression(uint32_t id) { + auto expr = to_expression(id); + auto index = expr.find_first_of('['); uint32_t samp_id = meta[id].sampler; - return samp_id ? to_expression(samp_id) : to_expression(id) + sampler_name_suffix; + + if (index == string::npos) + return samp_id ? to_expression(samp_id) : expr + sampler_name_suffix; + else + { + auto image_expr = expr.substr(0, index); + auto array_expr = expr.substr(index); + return samp_id ? to_expression(samp_id) : (image_expr + sampler_name_suffix + array_expr); + } } // Checks whether the ID is a row_major matrix that requires conversion before use @@ -3110,7 +3119,7 @@ string CompilerMSL::entry_point_args(bool append_comma) case SPIRType::Sampler: if (!ep_args.empty()) ep_args += ", "; - ep_args += "sampler " + r.name; + ep_args += type_to_glsl(type) + " " + r.name; ep_args += " [[sampler(" + convert_to_string(r.index) + ")]]"; break; case SPIRType::Image: @@ -3215,6 +3224,15 @@ string CompilerMSL::argument_decl(const SPIRFunction::Parameter &arg) auto &type = expression_type(arg.id); bool constref = !arg.alias_global_variable && (!type.pointer || arg.write_count == 0); + bool type_is_image = + type.basetype == SPIRType::Image || + type.basetype == SPIRType::SampledImage || + type.basetype == SPIRType::Sampler; + + // Arrays of images/samplers in MSL are always const. + if (!type.array.empty() && type_is_image) + constref = true; + // TODO: Check if this arg is an uniform pointer bool pointer = type.storage == StorageClassUniformConstant; @@ -3227,7 +3245,8 @@ string CompilerMSL::argument_decl(const SPIRFunction::Parameter &arg) else decl += type_to_glsl(type, arg.id); - if (is_array(type)) + // Arrays of images and samplers are special cased. + if (is_array(type) && !type_is_image) { decl += " (&"; decl += to_expression(var.self); @@ -3383,7 +3402,7 @@ string CompilerMSL::type_to_glsl(const SPIRType &type, uint32_t id) return image_type_glsl(type, id); case SPIRType::Sampler: - return "sampler"; + return sampler_type(type); case SPIRType::Void: return "void"; @@ -3435,9 +3454,44 @@ string CompilerMSL::type_to_glsl(const SPIRType &type, uint32_t id) return type_name; } +std::string CompilerMSL::sampler_type(const SPIRType &type) +{ + if (!type.array.empty()) + { + // Arrays of samplers in MSL must be declared with a special array syntax ala C++11 std::array. + auto *parent = &type; + while (parent->pointer) + parent = &get(parent->parent_type); + parent = &get(parent->parent_type); + + uint32_t array_size = type.array_size_literal.back() ? + type.array.back() : get(type.array.back()).scalar(); + + if (array_size == 0) + SPIRV_CROSS_THROW("Unsized array of samplers is not supported in MSL."); + return join("array<", sampler_type(*parent), ", ", array_size, ">"); + } + else + return "sampler"; +} + // Returns an MSL string describing the SPIR-V image type string CompilerMSL::image_type_glsl(const SPIRType &type, uint32_t id) { + if (!type.array.empty()) + { + // Arrays of images in MSL must be declared with a special array syntax ala C++11 std::array. + auto *parent = &type; + while (parent->pointer) + parent = &get(parent->parent_type); + parent = &get(parent->parent_type); + + uint32_t array_size = type.array_size_literal.back() ? type.array.back() : get(type.array.back()).scalar(); + if (array_size == 0) + SPIRV_CROSS_THROW("Unsized array of images is not supported in MSL."); + return join("array<", image_type_glsl(*parent, id), ", ", array_size, ">"); + } + string img_type_name; // Bypass pointers because we need the real image struct diff --git a/spirv_msl.hpp b/spirv_msl.hpp index 7f142c3f..ae343e05 100644 --- a/spirv_msl.hpp +++ b/spirv_msl.hpp @@ -202,6 +202,7 @@ protected: const std::string &qualifier = "", uint32_t base_offset = 0) override; std::string type_to_glsl(const SPIRType &type, uint32_t id = 0) override; std::string image_type_glsl(const SPIRType &type, uint32_t id = 0) override; + std::string sampler_type(const SPIRType &type); std::string builtin_to_glsl(spv::BuiltIn builtin, spv::StorageClass storage) override; std::string constant_expression(const SPIRConstant &c) override; size_t get_declared_struct_member_size(const SPIRType &struct_type, uint32_t index) const override;