Bläddra i källkod

Updated spirv-cross.

Бранимир Караџић 5 år sedan
förälder
incheckning
78675e238d

+ 1 - 1
3rdparty/spirv-cross/include/spirv_cross/sampler.hpp

@@ -85,7 +85,7 @@ struct sampler2DBase : spirv_cross_sampler_2d
 	std::vector<spirv_cross_miplevel> mips;
 	std::vector<spirv_cross_miplevel> mips;
 	spirv_cross_format format;
 	spirv_cross_format format;
 	spirv_cross_wrap wrap_s;
 	spirv_cross_wrap wrap_s;
-	spirv_cross_format wrap_t;
+	spirv_cross_wrap wrap_t;
 	spirv_cross_filter min_filter;
 	spirv_cross_filter min_filter;
 	spirv_cross_filter mag_filter;
 	spirv_cross_filter mag_filter;
 	spirv_cross_mipfilter mip_filter;
 	spirv_cross_mipfilter mip_filter;

+ 18 - 1
3rdparty/spirv-cross/main.cpp

@@ -522,10 +522,12 @@ struct CLIArguments
 	bool msl_dispatch_base = false;
 	bool msl_dispatch_base = false;
 	bool msl_decoration_binding = false;
 	bool msl_decoration_binding = false;
 	bool msl_force_active_argument_buffer_resources = false;
 	bool msl_force_active_argument_buffer_resources = false;
+	bool msl_force_native_arrays = false;
 	bool glsl_emit_push_constant_as_ubo = false;
 	bool glsl_emit_push_constant_as_ubo = false;
 	bool glsl_emit_ubo_as_plain_uniforms = false;
 	bool glsl_emit_ubo_as_plain_uniforms = false;
 	bool vulkan_glsl_disable_ext_samplerless_texture_functions = false;
 	bool vulkan_glsl_disable_ext_samplerless_texture_functions = false;
 	bool emit_line_directives = false;
 	bool emit_line_directives = false;
+	bool enable_storage_image_qualifier_deduction = true;
 	SmallVector<uint32_t> msl_discrete_descriptor_sets;
 	SmallVector<uint32_t> msl_discrete_descriptor_sets;
 	SmallVector<uint32_t> msl_device_argument_buffers;
 	SmallVector<uint32_t> msl_device_argument_buffers;
 	SmallVector<pair<uint32_t, uint32_t>> msl_dynamic_buffers;
 	SmallVector<pair<uint32_t, uint32_t>> msl_dynamic_buffers;
@@ -555,6 +557,7 @@ struct CLIArguments
 	bool hlsl = false;
 	bool hlsl = false;
 	bool hlsl_compat = false;
 	bool hlsl_compat = false;
 	bool hlsl_support_nonzero_base = false;
 	bool hlsl_support_nonzero_base = false;
+	bool hlsl_force_storage_buffer_as_uav = false;
 	HLSLBindingFlags hlsl_binding_flags = 0;
 	HLSLBindingFlags hlsl_binding_flags = 0;
 	bool vulkan_semantics = false;
 	bool vulkan_semantics = false;
 	bool flatten_multidimensional_arrays = false;
 	bool flatten_multidimensional_arrays = false;
@@ -586,13 +589,14 @@ static void print_help()
 	                "\t[--help]\n"
 	                "\t[--help]\n"
 	                "\t[--revision]\n"
 	                "\t[--revision]\n"
 	                "\t[--force-temporary]\n"
 	                "\t[--force-temporary]\n"
-	                "\t[--vulkan-semantics]\n"
+	                "\t[--vulkan-semantics] or [-V]\n"
 	                "\t[--flatten-ubo]\n"
 	                "\t[--flatten-ubo]\n"
 	                "\t[--fixup-clipspace]\n"
 	                "\t[--fixup-clipspace]\n"
 	                "\t[--flip-vert-y]\n"
 	                "\t[--flip-vert-y]\n"
 	                "\t[--iterations iter]\n"
 	                "\t[--iterations iter]\n"
 	                "\t[--cpp]\n"
 	                "\t[--cpp]\n"
 	                "\t[--cpp-interface-name <name>]\n"
 	                "\t[--cpp-interface-name <name>]\n"
+	                "\t[--disable-storage-image-qualifier-deduction]\n"
 	                "\t[--glsl-emit-push-constant-as-ubo]\n"
 	                "\t[--glsl-emit-push-constant-as-ubo]\n"
 	                "\t[--glsl-emit-ubo-as-plain-uniforms]\n"
 	                "\t[--glsl-emit-ubo-as-plain-uniforms]\n"
 	                "\t[--vulkan-glsl-disable-ext-samplerless-texture-functions]\n"
 	                "\t[--vulkan-glsl-disable-ext-samplerless-texture-functions]\n"
@@ -616,12 +620,14 @@ static void print_help()
 	                "\t[--msl-inline-uniform-block <set index> <binding>]\n"
 	                "\t[--msl-inline-uniform-block <set index> <binding>]\n"
 	                "\t[--msl-decoration-binding]\n"
 	                "\t[--msl-decoration-binding]\n"
 	                "\t[--msl-force-active-argument-buffer-resources]\n"
 	                "\t[--msl-force-active-argument-buffer-resources]\n"
+	                "\t[--msl-force-native-arrays]\n"
 	                "\t[--hlsl]\n"
 	                "\t[--hlsl]\n"
 	                "\t[--reflect]\n"
 	                "\t[--reflect]\n"
 	                "\t[--shader-model]\n"
 	                "\t[--shader-model]\n"
 	                "\t[--hlsl-enable-compat]\n"
 	                "\t[--hlsl-enable-compat]\n"
 	                "\t[--hlsl-support-nonzero-basevertex-baseinstance]\n"
 	                "\t[--hlsl-support-nonzero-basevertex-baseinstance]\n"
 	                "\t[--hlsl-auto-binding (push, cbv, srv, uav, sampler, all)]\n"
 	                "\t[--hlsl-auto-binding (push, cbv, srv, uav, sampler, all)]\n"
+	                "\t[--hlsl-force-storage-buffer-as-uav]\n"
 	                "\t[--separate-shader-objects]\n"
 	                "\t[--separate-shader-objects]\n"
 	                "\t[--pls-in format input-name]\n"
 	                "\t[--pls-in format input-name]\n"
 	                "\t[--pls-out format output-name]\n"
 	                "\t[--pls-out format output-name]\n"
@@ -806,6 +812,7 @@ static string compile_iteration(const CLIArguments &args, std::vector<uint32_t>
 		msl_opts.dispatch_base = args.msl_dispatch_base;
 		msl_opts.dispatch_base = args.msl_dispatch_base;
 		msl_opts.enable_decoration_binding = args.msl_decoration_binding;
 		msl_opts.enable_decoration_binding = args.msl_decoration_binding;
 		msl_opts.force_active_argument_buffer_resources = args.msl_force_active_argument_buffer_resources;
 		msl_opts.force_active_argument_buffer_resources = args.msl_force_active_argument_buffer_resources;
+		msl_opts.force_native_arrays = args.msl_force_native_arrays;
 		msl_comp->set_msl_options(msl_opts);
 		msl_comp->set_msl_options(msl_opts);
 		for (auto &v : args.msl_discrete_descriptor_sets)
 		for (auto &v : args.msl_discrete_descriptor_sets)
 			msl_comp->add_discrete_descriptor_set(v);
 			msl_comp->add_discrete_descriptor_set(v);
@@ -939,6 +946,7 @@ static string compile_iteration(const CLIArguments &args, std::vector<uint32_t>
 	opts.emit_push_constant_as_uniform_buffer = args.glsl_emit_push_constant_as_ubo;
 	opts.emit_push_constant_as_uniform_buffer = args.glsl_emit_push_constant_as_ubo;
 	opts.emit_uniform_buffer_as_plain_uniforms = args.glsl_emit_ubo_as_plain_uniforms;
 	opts.emit_uniform_buffer_as_plain_uniforms = args.glsl_emit_ubo_as_plain_uniforms;
 	opts.emit_line_directives = args.emit_line_directives;
 	opts.emit_line_directives = args.emit_line_directives;
+	opts.enable_storage_image_qualifier_deduction = args.enable_storage_image_qualifier_deduction;
 	compiler->set_common_options(opts);
 	compiler->set_common_options(opts);
 
 
 	// Set HLSL specific options.
 	// Set HLSL specific options.
@@ -971,6 +979,7 @@ static string compile_iteration(const CLIArguments &args, std::vector<uint32_t>
 		}
 		}
 
 
 		hlsl_opts.support_nonzero_base_vertex_base_instance = args.hlsl_support_nonzero_base;
 		hlsl_opts.support_nonzero_base_vertex_base_instance = args.hlsl_support_nonzero_base;
+		hlsl_opts.force_storage_buffer_as_uav = args.hlsl_force_storage_buffer_as_uav;
 		hlsl->set_hlsl_options(hlsl_opts);
 		hlsl->set_hlsl_options(hlsl_opts);
 		hlsl->set_resource_binding_flags(args.hlsl_binding_flags);
 		hlsl->set_resource_binding_flags(args.hlsl_binding_flags);
 	}
 	}
@@ -1118,6 +1127,7 @@ static int main_inner(int argc, char *argv[])
 	cbs.add("--glsl-emit-ubo-as-plain-uniforms", [&args](CLIParser &) { args.glsl_emit_ubo_as_plain_uniforms = true; });
 	cbs.add("--glsl-emit-ubo-as-plain-uniforms", [&args](CLIParser &) { args.glsl_emit_ubo_as_plain_uniforms = true; });
 	cbs.add("--vulkan-glsl-disable-ext-samplerless-texture-functions",
 	cbs.add("--vulkan-glsl-disable-ext-samplerless-texture-functions",
 	        [&args](CLIParser &) { args.vulkan_glsl_disable_ext_samplerless_texture_functions = true; });
 	        [&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("--msl", [&args](CLIParser &) { args.msl = true; });
 	cbs.add("--msl", [&args](CLIParser &) { args.msl = true; });
 	cbs.add("--hlsl", [&args](CLIParser &) { args.hlsl = true; });
 	cbs.add("--hlsl", [&args](CLIParser &) { args.hlsl = true; });
 	cbs.add("--hlsl-enable-compat", [&args](CLIParser &) { args.hlsl_compat = true; });
 	cbs.add("--hlsl-enable-compat", [&args](CLIParser &) { args.hlsl_compat = true; });
@@ -1126,7 +1136,11 @@ static int main_inner(int argc, char *argv[])
 	cbs.add("--hlsl-auto-binding", [&args](CLIParser &parser) {
 	cbs.add("--hlsl-auto-binding", [&args](CLIParser &parser) {
 		args.hlsl_binding_flags |= hlsl_resource_type_to_flag(parser.next_string());
 		args.hlsl_binding_flags |= hlsl_resource_type_to_flag(parser.next_string());
 	});
 	});
+	cbs.add("--hlsl-force-storage-buffer-as-uav", [&args](CLIParser &) {
+		args.hlsl_force_storage_buffer_as_uav = true;
+	});
 	cbs.add("--vulkan-semantics", [&args](CLIParser &) { args.vulkan_semantics = true; });
 	cbs.add("--vulkan-semantics", [&args](CLIParser &) { args.vulkan_semantics = true; });
+	cbs.add("-V", [&args](CLIParser &) { args.vulkan_semantics = true; });
 	cbs.add("--flatten-multidimensional-arrays", [&args](CLIParser &) { args.flatten_multidimensional_arrays = true; });
 	cbs.add("--flatten-multidimensional-arrays", [&args](CLIParser &) { args.flatten_multidimensional_arrays = true; });
 	cbs.add("--no-420pack-extension", [&args](CLIParser &) { args.use_420pack_extension = false; });
 	cbs.add("--no-420pack-extension", [&args](CLIParser &) { args.use_420pack_extension = false; });
 	cbs.add("--msl-capture-output", [&args](CLIParser &) { args.msl_capture_output_to_buffer = true; });
 	cbs.add("--msl-capture-output", [&args](CLIParser &) { args.msl_capture_output_to_buffer = true; });
@@ -1164,6 +1178,9 @@ static int main_inner(int argc, char *argv[])
 		uint32_t binding = parser.next_uint();
 		uint32_t binding = parser.next_uint();
 		args.msl_inline_uniform_blocks.push_back(make_pair(desc_set, binding));
 		args.msl_inline_uniform_blocks.push_back(make_pair(desc_set, binding));
 	});
 	});
+	cbs.add("--msl-force-native-arrays", [&args](CLIParser &) {
+		args.msl_force_native_arrays = true;
+	});
 	cbs.add("--extension", [&args](CLIParser &parser) { args.extensions.push_back(parser.next_string()); });
 	cbs.add("--extension", [&args](CLIParser &parser) { args.extensions.push_back(parser.next_string()); });
 	cbs.add("--rename-entry-point", [&args](CLIParser &parser) {
 	cbs.add("--rename-entry-point", [&args](CLIParser &parser) {
 		auto old_name = parser.next_string();
 		auto old_name = parser.next_string();

+ 5 - 0
3rdparty/spirv-cross/spirv_common.hpp

@@ -939,6 +939,11 @@ struct SPIRFunction : IVariant
 	// Intentionally not a small vector, this one is rare, and std::function can be large.
 	// Intentionally not a small vector, this one is rare, and std::function can be large.
 	Vector<std::function<void()>> fixup_hooks_in;
 	Vector<std::function<void()>> fixup_hooks_in;
 
 
+	// On function entry, make sure to copy a constant array into thread addr space to work around
+	// the case where we are passing a constant array by value to a function on backends which do not
+	// consider arrays value types.
+	SmallVector<ID> constant_arrays_needed_on_stack;
+
 	bool active = false;
 	bool active = false;
 	bool flush_undeclared = true;
 	bool flush_undeclared = true;
 	bool do_combined_parameters = true;
 	bool do_combined_parameters = true;

+ 11 - 0
3rdparty/spirv-cross/spirv_cross_c.cpp

@@ -420,6 +420,9 @@ spvc_result spvc_compiler_options_set_uint(spvc_compiler_options options, spvc_c
 	case SPVC_COMPILER_OPTION_EMIT_LINE_DIRECTIVES:
 	case SPVC_COMPILER_OPTION_EMIT_LINE_DIRECTIVES:
 		options->glsl.emit_line_directives = value != 0;
 		options->glsl.emit_line_directives = value != 0;
 		break;
 		break;
+	case SPVC_COMPILER_OPTION_ENABLE_STORAGE_IMAGE_QUALIFIER_DEDUCTION:
+		options->glsl.enable_storage_image_qualifier_deduction = value != 0;
+		break;
 
 
 	case SPVC_COMPILER_OPTION_GLSL_SUPPORT_NONZERO_BASE_INSTANCE:
 	case SPVC_COMPILER_OPTION_GLSL_SUPPORT_NONZERO_BASE_INSTANCE:
 		options->glsl.vertex.support_nonzero_base_instance = value != 0;
 		options->glsl.vertex.support_nonzero_base_instance = value != 0;
@@ -471,6 +474,10 @@ spvc_result spvc_compiler_options_set_uint(spvc_compiler_options options, spvc_c
 	case SPVC_COMPILER_OPTION_HLSL_SUPPORT_NONZERO_BASE_VERTEX_BASE_INSTANCE:
 	case SPVC_COMPILER_OPTION_HLSL_SUPPORT_NONZERO_BASE_VERTEX_BASE_INSTANCE:
 		options->hlsl.support_nonzero_base_vertex_base_instance = value != 0;
 		options->hlsl.support_nonzero_base_vertex_base_instance = value != 0;
 		break;
 		break;
+
+	case SPVC_COMPILER_OPTION_HLSL_FORCE_STORAGE_BUFFER_AS_UAV:
+		options->hlsl.force_storage_buffer_as_uav = value != 0;
+		break;
 #endif
 #endif
 
 
 #if SPIRV_CROSS_C_API_MSL
 #if SPIRV_CROSS_C_API_MSL
@@ -597,6 +604,10 @@ spvc_result spvc_compiler_options_set_uint(spvc_compiler_options options, spvc_c
 	case SPVC_COMPILER_OPTION_MSL_FORCE_ACTIVE_ARGUMENT_BUFFER_RESOURCES:
 	case SPVC_COMPILER_OPTION_MSL_FORCE_ACTIVE_ARGUMENT_BUFFER_RESOURCES:
 		options->msl.force_active_argument_buffer_resources = value != 0;
 		options->msl.force_active_argument_buffer_resources = value != 0;
 		break;
 		break;
+
+	case SPVC_COMPILER_OPTION_MSL_FORCE_NATIVE_ARRAYS:
+		options->msl.force_native_arrays = value != 0;
+		break;
 #endif
 #endif
 
 
 	default:
 	default:

+ 6 - 1
3rdparty/spirv-cross/spirv_cross_c.h

@@ -33,7 +33,7 @@ extern "C" {
 /* Bumped if ABI or API breaks backwards compatibility. */
 /* Bumped if ABI or API breaks backwards compatibility. */
 #define SPVC_C_API_VERSION_MAJOR 0
 #define SPVC_C_API_VERSION_MAJOR 0
 /* Bumped if APIs or enumerations are added in a backwards compatible way. */
 /* Bumped if APIs or enumerations are added in a backwards compatible way. */
-#define SPVC_C_API_VERSION_MINOR 24
+#define SPVC_C_API_VERSION_MINOR 27
 /* Bumped if internal implementation details change. */
 /* Bumped if internal implementation details change. */
 #define SPVC_C_API_VERSION_PATCH 0
 #define SPVC_C_API_VERSION_PATCH 0
 
 
@@ -572,6 +572,11 @@ typedef enum spvc_compiler_option
 	SPVC_COMPILER_OPTION_MSL_EMULATE_CUBEMAP_ARRAY = 48 | SPVC_COMPILER_OPTION_MSL_BIT,
 	SPVC_COMPILER_OPTION_MSL_EMULATE_CUBEMAP_ARRAY = 48 | SPVC_COMPILER_OPTION_MSL_BIT,
 	SPVC_COMPILER_OPTION_MSL_ENABLE_DECORATION_BINDING = 49 | SPVC_COMPILER_OPTION_MSL_BIT,
 	SPVC_COMPILER_OPTION_MSL_ENABLE_DECORATION_BINDING = 49 | SPVC_COMPILER_OPTION_MSL_BIT,
 	SPVC_COMPILER_OPTION_MSL_FORCE_ACTIVE_ARGUMENT_BUFFER_RESOURCES = 50 | SPVC_COMPILER_OPTION_MSL_BIT,
 	SPVC_COMPILER_OPTION_MSL_FORCE_ACTIVE_ARGUMENT_BUFFER_RESOURCES = 50 | SPVC_COMPILER_OPTION_MSL_BIT,
+	SPVC_COMPILER_OPTION_MSL_FORCE_NATIVE_ARRAYS = 51 | SPVC_COMPILER_OPTION_MSL_BIT,
+
+	SPVC_COMPILER_OPTION_ENABLE_STORAGE_IMAGE_QUALIFIER_DEDUCTION = 52 | SPVC_COMPILER_OPTION_COMMON_BIT,
+
+	SPVC_COMPILER_OPTION_HLSL_FORCE_STORAGE_BUFFER_AS_UAV = 53 | SPVC_COMPILER_OPTION_HLSL_BIT,
 
 
 	SPVC_COMPILER_OPTION_INT_MAX = 0x7fffffff
 	SPVC_COMPILER_OPTION_INT_MAX = 0x7fffffff
 } spvc_compiler_option;
 } spvc_compiler_option;

+ 11 - 0
3rdparty/spirv-cross/spirv_cross_containers.hpp

@@ -21,8 +21,10 @@
 #include <algorithm>
 #include <algorithm>
 #include <functional>
 #include <functional>
 #include <iterator>
 #include <iterator>
+#include <limits>
 #include <memory>
 #include <memory>
 #include <stack>
 #include <stack>
+#include <stddef.h>
 #include <stdint.h>
 #include <stdint.h>
 #include <stdlib.h>
 #include <stdlib.h>
 #include <string.h>
 #include <string.h>
@@ -316,6 +318,13 @@ public:
 
 
 	void reserve(size_t count) SPIRV_CROSS_NOEXCEPT
 	void reserve(size_t count) SPIRV_CROSS_NOEXCEPT
 	{
 	{
+		if ((count > std::numeric_limits<size_t>::max() / sizeof(T)) ||
+		    (count > std::numeric_limits<size_t>::max() / 2))
+		{
+			// Only way this should ever happen is with garbage input, terminate.
+			std::terminate();
+		}
+
 		if (count > buffer_capacity)
 		if (count > buffer_capacity)
 		{
 		{
 			size_t target_capacity = buffer_capacity;
 			size_t target_capacity = buffer_capacity;
@@ -324,6 +333,8 @@ public:
 			if (target_capacity < N)
 			if (target_capacity < N)
 				target_capacity = N;
 				target_capacity = N;
 
 
+			// Need to ensure there is a POT value of target capacity which is larger than count,
+			// otherwise this will overflow.
 			while (target_capacity < count)
 			while (target_capacity < count)
 				target_capacity <<= 1u;
 				target_capacity <<= 1u;
 
 

+ 14 - 3
3rdparty/spirv-cross/spirv_glsl.cpp

@@ -2504,11 +2504,14 @@ void CompilerGLSL::emit_pls()
 
 
 void CompilerGLSL::fixup_image_load_store_access()
 void CompilerGLSL::fixup_image_load_store_access()
 {
 {
+	if (!options.enable_storage_image_qualifier_deduction)
+		return;
+
 	ir.for_each_typed_id<SPIRVariable>([&](uint32_t var, const SPIRVariable &) {
 	ir.for_each_typed_id<SPIRVariable>([&](uint32_t var, const SPIRVariable &) {
 		auto &vartype = expression_type(var);
 		auto &vartype = expression_type(var);
 		if (vartype.basetype == SPIRType::Image)
 		if (vartype.basetype == SPIRType::Image)
 		{
 		{
-			// Older glslangValidator does not emit required qualifiers here.
+			// Very old glslangValidator and HLSL compilers do not emit required qualifiers here.
 			// Solve this by making the image access as restricted as possible and loosen up if we need to.
 			// Solve this by making the image access as restricted as possible and loosen up if we need to.
 			// If any no-read/no-write flags are actually set, assume that the compiler knows what it's doing.
 			// If any no-read/no-write flags are actually set, assume that the compiler knows what it's doing.
 
 
@@ -3697,7 +3700,7 @@ string CompilerGLSL::constant_expression(const SPIRConstant &c)
 		{
 		{
 			res = type_to_glsl_constructor(type) + "{ ";
 			res = type_to_glsl_constructor(type) + "{ ";
 		}
 		}
-		else if (backend.use_initializer_list && backend.use_typed_initializer_list && !type.array.empty())
+		else if (backend.use_initializer_list && backend.use_typed_initializer_list && backend.array_is_value_type && !type.array.empty())
 		{
 		{
 			res = type_to_glsl_constructor(type) + "({ ";
 			res = type_to_glsl_constructor(type) + "({ ";
 			needs_trailing_tracket = true;
 			needs_trailing_tracket = true;
@@ -8686,7 +8689,7 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
 			// This path cannot be used for arithmetic.
 			// This path cannot be used for arithmetic.
 			if (backend.use_typed_initializer_list && out_type.basetype == SPIRType::Struct && out_type.array.empty())
 			if (backend.use_typed_initializer_list && out_type.basetype == SPIRType::Struct && out_type.array.empty())
 				constructor_op += type_to_glsl_constructor(get<SPIRType>(result_type));
 				constructor_op += type_to_glsl_constructor(get<SPIRType>(result_type));
-			else if (backend.use_typed_initializer_list && !out_type.array.empty())
+			else if (backend.use_typed_initializer_list && backend.array_is_value_type && !out_type.array.empty())
 			{
 			{
 				// MSL path. Array constructor is baked into type here, do not use _constructor variant.
 				// MSL path. Array constructor is baked into type here, do not use _constructor variant.
 				constructor_op += type_to_glsl_constructor(get<SPIRType>(result_type)) + "(";
 				constructor_op += type_to_glsl_constructor(get<SPIRType>(result_type)) + "(";
@@ -11751,6 +11754,14 @@ void CompilerGLSL::emit_function(SPIRFunction &func, const Bitset &return_flags)
 	current_function = &func;
 	current_function = &func;
 	auto &entry_block = get<SPIRBlock>(func.entry_block);
 	auto &entry_block = get<SPIRBlock>(func.entry_block);
 
 
+	sort(begin(func.constant_arrays_needed_on_stack), end(func.constant_arrays_needed_on_stack));
+	for (auto &array : func.constant_arrays_needed_on_stack)
+	{
+		auto &c = get<SPIRConstant>(array);
+		auto &type = get<SPIRType>(c.constant_type);
+		statement(variable_decl(type, join("_", array, "_array_copy")), " = ", constant_expression(c), ";");
+	}
+
 	for (auto &v : func.local_variables)
 	for (auto &v : func.local_variables)
 	{
 	{
 		auto &var = get<SPIRVariable>(v);
 		auto &var = get<SPIRVariable>(v);

+ 7 - 0
3rdparty/spirv-cross/spirv_glsl.hpp

@@ -108,6 +108,13 @@ public:
 		// May not correspond exactly to original source, but should be a good approximation.
 		// May not correspond exactly to original source, but should be a good approximation.
 		bool emit_line_directives = false;
 		bool emit_line_directives = false;
 
 
+		// In cases where readonly/writeonly decoration are not used at all,
+		// we try to deduce which qualifier(s) we should actually used, since actually emitting
+		// read-write decoration is very rare, and older glslang/HLSL compilers tend to just emit readwrite as a matter of fact.
+		// The default (true) is to enable automatic deduction for these cases, but if you trust the decorations set
+		// by the SPIR-V, it's recommended to set this to false.
+		bool enable_storage_image_qualifier_deduction = true;
+
 		enum Precision
 		enum Precision
 		{
 		{
 			DontCare,
 			DontCare,

+ 16 - 4
3rdparty/spirv-cross/spirv_hlsl.cpp

@@ -1117,6 +1117,18 @@ void CompilerHLSL::replace_illegal_names()
 	CompilerGLSL::replace_illegal_names();
 	CompilerGLSL::replace_illegal_names();
 }
 }
 
 
+void CompilerHLSL::declare_undefined_values()
+{
+	bool emitted = false;
+	ir.for_each_typed_id<SPIRUndef>([&](uint32_t, const SPIRUndef &undef) {
+		statement("static ", variable_decl(this->get<SPIRType>(undef.basetype), to_name(undef.self), undef.self), ";");
+		emitted = true;
+	});
+
+	if (emitted)
+		statement("");
+}
+
 void CompilerHLSL::emit_resources()
 void CompilerHLSL::emit_resources()
 {
 {
 	auto &execution = get_entry_point();
 	auto &execution = get_entry_point();
@@ -1845,8 +1857,8 @@ void CompilerHLSL::emit_buffer_block(const SPIRVariable &var)
 	if (is_uav)
 	if (is_uav)
 	{
 	{
 		Bitset flags = ir.get_buffer_block_flags(var);
 		Bitset flags = ir.get_buffer_block_flags(var);
-		bool is_readonly = flags.get(DecorationNonWritable);
-		bool is_coherent = flags.get(DecorationCoherent);
+		bool is_readonly = flags.get(DecorationNonWritable) && !hlsl_options.force_storage_buffer_as_uav;
+		bool is_coherent = flags.get(DecorationCoherent) && !is_readonly;
 		bool is_interlocked = interlocked_resources.count(var.self) > 0;
 		bool is_interlocked = interlocked_resources.count(var.self) > 0;
 		const char *type_name = "ByteAddressBuffer ";
 		const char *type_name = "ByteAddressBuffer ";
 		if (!is_readonly)
 		if (!is_readonly)
@@ -2969,7 +2981,7 @@ string CompilerHLSL::to_resource_binding(const SPIRVariable &var)
 			if (has_decoration(type.self, DecorationBufferBlock))
 			if (has_decoration(type.self, DecorationBufferBlock))
 			{
 			{
 				Bitset flags = ir.get_buffer_block_flags(var);
 				Bitset flags = ir.get_buffer_block_flags(var);
-				bool is_readonly = flags.get(DecorationNonWritable);
+				bool is_readonly = flags.get(DecorationNonWritable) && !hlsl_options.force_storage_buffer_as_uav;
 				space = is_readonly ? 't' : 'u'; // UAV
 				space = is_readonly ? 't' : 'u'; // UAV
 				resource_flags = is_readonly ? HLSL_BINDING_AUTO_SRV_BIT : HLSL_BINDING_AUTO_UAV_BIT;
 				resource_flags = is_readonly ? HLSL_BINDING_AUTO_SRV_BIT : HLSL_BINDING_AUTO_UAV_BIT;
 			}
 			}
@@ -2988,7 +3000,7 @@ string CompilerHLSL::to_resource_binding(const SPIRVariable &var)
 		{
 		{
 			// UAV or SRV depending on readonly flag.
 			// UAV or SRV depending on readonly flag.
 			Bitset flags = ir.get_buffer_block_flags(var);
 			Bitset flags = ir.get_buffer_block_flags(var);
-			bool is_readonly = flags.get(DecorationNonWritable);
+			bool is_readonly = flags.get(DecorationNonWritable) && !hlsl_options.force_storage_buffer_as_uav;
 			space = is_readonly ? 't' : 'u';
 			space = is_readonly ? 't' : 'u';
 			resource_flags = is_readonly ? HLSL_BINDING_AUTO_SRV_BIT : HLSL_BINDING_AUTO_UAV_BIT;
 			resource_flags = is_readonly ? HLSL_BINDING_AUTO_SRV_BIT : HLSL_BINDING_AUTO_UAV_BIT;
 		}
 		}

+ 5 - 0
3rdparty/spirv-cross/spirv_hlsl.hpp

@@ -109,6 +109,10 @@ public:
 		// Set to false if you know you will never use base instance or base vertex
 		// Set to false if you know you will never use base instance or base vertex
 		// functionality as it might remove an internal cbuffer.
 		// functionality as it might remove an internal cbuffer.
 		bool support_nonzero_base_vertex_base_instance = false;
 		bool support_nonzero_base_vertex_base_instance = false;
+
+		// Forces a storage buffer to always be declared as UAV, even if the readonly decoration is used.
+		// By default, a readonly storage buffer will be declared as ByteAddressBuffer (SRV) instead.
+		bool force_storage_buffer_as_uav = false;
 	};
 	};
 
 
 	explicit CompilerHLSL(std::vector<uint32_t> spirv_)
 	explicit CompilerHLSL(std::vector<uint32_t> spirv_)
@@ -186,6 +190,7 @@ private:
 	void emit_hlsl_entry_point();
 	void emit_hlsl_entry_point();
 	void emit_header() override;
 	void emit_header() override;
 	void emit_resources();
 	void emit_resources();
+	void declare_undefined_values() override;
 	void emit_interface_block_globally(const SPIRVariable &type);
 	void emit_interface_block_globally(const SPIRVariable &type);
 	void emit_interface_block_in_struct(const SPIRVariable &type, std::unordered_set<uint32_t> &active_locations);
 	void emit_interface_block_in_struct(const SPIRVariable &type, std::unordered_set<uint32_t> &active_locations);
 	void emit_builtin_inputs_in_struct();
 	void emit_builtin_inputs_in_struct();

+ 100 - 50
3rdparty/spirv-cross/spirv_msl.cpp

@@ -890,7 +890,7 @@ void CompilerMSL::emit_entry_point_declarations()
 				SPIRV_CROSS_THROW("Runtime arrays with dynamic offsets are not supported yet.");
 				SPIRV_CROSS_THROW("Runtime arrays with dynamic offsets are not supported yet.");
 			else
 			else
 			{
 			{
-				use_builtin_array = true;
+				is_using_builtin_array = true;
 				statement(get_argument_address_space(var), " ", type_to_glsl(type), "* ", to_restrict(var_id), name,
 				statement(get_argument_address_space(var), " ", type_to_glsl(type), "* ", to_restrict(var_id), name,
 				          type_to_array_glsl(type), " =");
 				          type_to_array_glsl(type), " =");
 
 
@@ -921,7 +921,7 @@ void CompilerMSL::emit_entry_point_declarations()
 				}
 				}
 				end_scope_decl();
 				end_scope_decl();
 				statement_no_indent("");
 				statement_no_indent("");
-				use_builtin_array = false;
+				is_using_builtin_array = false;
 			}
 			}
 		}
 		}
 		else
 		else
@@ -979,15 +979,17 @@ string CompilerMSL::compile()
 	backend.native_row_major_matrix = false;
 	backend.native_row_major_matrix = false;
 	backend.unsized_array_supported = false;
 	backend.unsized_array_supported = false;
 	backend.can_declare_arrays_inline = false;
 	backend.can_declare_arrays_inline = false;
-	backend.can_return_array = true; // <-- Allow Metal to use the array<T> template
 	backend.allow_truncated_access_chain = true;
 	backend.allow_truncated_access_chain = true;
-	backend.array_is_value_type = true; // <-- Allow Metal to use the array<T> template to make arrays a value type
 	backend.comparison_image_samples_scalar = true;
 	backend.comparison_image_samples_scalar = true;
 	backend.native_pointers = true;
 	backend.native_pointers = true;
 	backend.nonuniform_qualifier = "";
 	backend.nonuniform_qualifier = "";
 	backend.support_small_type_sampling_result = true;
 	backend.support_small_type_sampling_result = true;
 	backend.supports_empty_struct = true;
 	backend.supports_empty_struct = true;
 
 
+	// Allow Metal to use the array<T> template unless we force it off.
+	backend.can_return_array = !msl_options.force_native_arrays;
+	backend.array_is_value_type = !msl_options.force_native_arrays;
+
 	capture_output_to_buffer = msl_options.capture_output_to_buffer;
 	capture_output_to_buffer = msl_options.capture_output_to_buffer;
 	is_rasterization_disabled = msl_options.disable_rasterization || capture_output_to_buffer;
 	is_rasterization_disabled = msl_options.disable_rasterization || capture_output_to_buffer;
 
 
@@ -6707,29 +6709,6 @@ void CompilerMSL::emit_barrier(uint32_t id_exe_scope, uint32_t id_mem_scope, uin
 			bar_stmt += "mem_flags::mem_none";
 			bar_stmt += "mem_flags::mem_none";
 	}
 	}
 
 
-	if (msl_options.is_ios() && (msl_options.supports_msl_version(2) && !msl_options.supports_msl_version(2, 1)))
-	{
-		bar_stmt += ", ";
-
-		switch (mem_scope)
-		{
-		case ScopeCrossDevice:
-		case ScopeDevice:
-			bar_stmt += "memory_scope_device";
-			break;
-
-		case ScopeSubgroup:
-		case ScopeInvocation:
-			bar_stmt += "memory_scope_simdgroup";
-			break;
-
-		case ScopeWorkgroup:
-		default:
-			bar_stmt += "memory_scope_threadgroup";
-			break;
-		}
-	}
-
 	bar_stmt += ");";
 	bar_stmt += ");";
 
 
 	statement(bar_stmt);
 	statement(bar_stmt);
@@ -6751,7 +6730,7 @@ void CompilerMSL::emit_array_copy(const string &lhs, uint32_t rhs_id, StorageCla
 
 
 	// If threadgroup storage qualifiers are *not* used:
 	// If threadgroup storage qualifiers are *not* used:
 	// Avoid spvCopy* wrapper functions; Otherwise, spvUnsafeArray<> template cannot be used with that storage qualifier.
 	// Avoid spvCopy* wrapper functions; Otherwise, spvUnsafeArray<> template cannot be used with that storage qualifier.
-	if (lhs_thread && rhs_thread && !use_builtin_array)
+	if (lhs_thread && rhs_thread && !using_builtin_array())
 	{
 	{
 		statement(lhs, " = ", to_expression(rhs_id), ";");
 		statement(lhs, " = ", to_expression(rhs_id), ";");
 	}
 	}
@@ -6805,9 +6784,9 @@ void CompilerMSL::emit_array_copy(const string &lhs, uint32_t rhs_id, StorageCla
 			SPIRV_CROSS_THROW("Unknown storage class used for copying arrays.");
 			SPIRV_CROSS_THROW("Unknown storage class used for copying arrays.");
 
 
 		// Pass internal array of spvUnsafeArray<> into wrapper functions
 		// Pass internal array of spvUnsafeArray<> into wrapper functions
-		if (lhs_thread)
+		if (lhs_thread && !msl_options.force_native_arrays)
 			statement("spvArrayCopy", tag, type.array.size(), "(", lhs, ".elements, ", to_expression(rhs_id), ");");
 			statement("spvArrayCopy", tag, type.array.size(), "(", lhs, ".elements, ", to_expression(rhs_id), ");");
-		else if (rhs_thread)
+		else if (rhs_thread && !msl_options.force_native_arrays)
 			statement("spvArrayCopy", tag, type.array.size(), "(", lhs, ", ", to_expression(rhs_id), ".elements);");
 			statement("spvArrayCopy", tag, type.array.size(), "(", lhs, ", ", to_expression(rhs_id), ".elements);");
 		else
 		else
 			statement("spvArrayCopy", tag, type.array.size(), "(", lhs, ", ", to_expression(rhs_id), ");");
 			statement("spvArrayCopy", tag, type.array.size(), "(", lhs, ", ", to_expression(rhs_id), ");");
@@ -7257,11 +7236,31 @@ void CompilerMSL::emit_function_prototype(SPIRFunction &func, const Bitset &)
 
 
 	auto &type = get<SPIRType>(func.return_type);
 	auto &type = get<SPIRType>(func.return_type);
 
 
-	decl += func_type_decl(type);
+	if (!type.array.empty() && msl_options.force_native_arrays)
+	{
+		// We cannot return native arrays in MSL, so "return" through an out variable.
+		decl += "void";
+	}
+	else
+	{
+		decl += func_type_decl(type);
+	}
+
 	decl += " ";
 	decl += " ";
 	decl += to_name(func.self);
 	decl += to_name(func.self);
 	decl += "(";
 	decl += "(";
 
 
+	if (!type.array.empty() && msl_options.force_native_arrays)
+	{
+		// Fake arrays returns by writing to an out array instead.
+		decl += "thread ";
+		decl += type_to_glsl(type);
+		decl += " (&SPIRV_Cross_return_value)";
+		decl += type_to_array_glsl(type);
+		if (!func.arguments.empty())
+			decl += ", ";
+	}
+
 	if (processing_entry_point)
 	if (processing_entry_point)
 	{
 	{
 		if (msl_options.argument_buffers)
 		if (msl_options.argument_buffers)
@@ -8206,7 +8205,29 @@ string CompilerMSL::to_func_call_arg(const SPIRFunction::Parameter &arg, uint32_
 	if (is_dynamic_img_sampler && !arg_is_dynamic_img_sampler)
 	if (is_dynamic_img_sampler && !arg_is_dynamic_img_sampler)
 		arg_str = join("spvDynamicImageSampler<", type_to_glsl(get<SPIRType>(type.image.type)), ">(");
 		arg_str = join("spvDynamicImageSampler<", type_to_glsl(get<SPIRType>(type.image.type)), ">(");
 
 
-	arg_str += CompilerGLSL::to_func_call_arg(arg, id);
+	auto *c = maybe_get<SPIRConstant>(id);
+	if (msl_options.force_native_arrays && c && !get<SPIRType>(c->constant_type).array.empty())
+	{
+		// If we are passing a constant array directly to a function for some reason,
+		// the callee will expect an argument in thread const address space
+		// (since we can only bind to arrays with references in MSL).
+		// To resolve this, we must emit a copy in this address space.
+		// This kind of code gen should be rare enough that performance is not a real concern.
+		// Inline the SPIR-V to avoid this kind of suboptimal codegen.
+		//
+		// We risk calling this inside a continue block (invalid code),
+		// so just create a thread local copy in the current function.
+		arg_str = join("_", id, "_array_copy");
+		auto &constants = current_function->constant_arrays_needed_on_stack;
+		auto itr = find(begin(constants), end(constants), ID(id));
+		if (itr == end(constants))
+		{
+			force_recompile();
+			constants.push_back(id);
+		}
+	}
+	else
+		arg_str += CompilerGLSL::to_func_call_arg(arg, id);
 
 
 	// Need to check the base variable in case we need to apply a qualified alias.
 	// Need to check the base variable in case we need to apply a qualified alias.
 	uint32_t var_id = 0;
 	uint32_t var_id = 0;
@@ -8481,9 +8502,9 @@ string CompilerMSL::to_struct_member(const SPIRType &type, uint32_t member_type_
 	// address space.
 	// address space.
 	// Array of resources should also be declared as builtin arrays.
 	// Array of resources should also be declared as builtin arrays.
 	if (has_member_decoration(type.self, index, DecorationOffset))
 	if (has_member_decoration(type.self, index, DecorationOffset))
-		use_builtin_array = true;
+		is_using_builtin_array = true;
 	else if (has_extended_member_decoration(type.self, index, SPIRVCrossDecorationResourceIndexPrimary))
 	else if (has_extended_member_decoration(type.self, index, SPIRVCrossDecorationResourceIndexPrimary))
-		use_builtin_array = true;
+		is_using_builtin_array = true;
 
 
 	if (member_is_packed_physical_type(type, index))
 	if (member_is_packed_physical_type(type, index))
 	{
 	{
@@ -8539,14 +8560,14 @@ string CompilerMSL::to_struct_member(const SPIRType &type, uint32_t member_type_
 	{
 	{
 		BuiltIn builtin = BuiltInMax;
 		BuiltIn builtin = BuiltInMax;
 		if (is_member_builtin(type, index, &builtin))
 		if (is_member_builtin(type, index, &builtin))
-			use_builtin_array = true;
+			is_using_builtin_array = true;
 		array_type = type_to_array_glsl(physical_type);
 		array_type = type_to_array_glsl(physical_type);
 	}
 	}
 
 
 	auto result = join(pack_pfx, type_to_glsl(*declared_type, orig_id), " ", qualifier, to_member_name(type, index),
 	auto result = join(pack_pfx, type_to_glsl(*declared_type, orig_id), " ", qualifier, to_member_name(type, index),
 	                   member_attribute_qualifier(type, index), array_type, ";");
 	                   member_attribute_qualifier(type, index), array_type, ";");
 
 
-	use_builtin_array = false;
+	is_using_builtin_array = false;
 	return result;
 	return result;
 }
 }
 
 
@@ -9423,7 +9444,7 @@ void CompilerMSL::entry_point_args_discrete_descriptors(string &ep_args)
 					SPIRV_CROSS_THROW("Unsized arrays of buffers are not supported in MSL.");
 					SPIRV_CROSS_THROW("Unsized arrays of buffers are not supported in MSL.");
 
 
 				// Allow Metal to use the array<T> template to make arrays a value type
 				// Allow Metal to use the array<T> template to make arrays a value type
-				use_builtin_array = true;
+				is_using_builtin_array = true;
 				buffer_arrays.push_back(var_id);
 				buffer_arrays.push_back(var_id);
 				for (uint32_t i = 0; i < array_size; ++i)
 				for (uint32_t i = 0; i < array_size; ++i)
 				{
 				{
@@ -9436,7 +9457,7 @@ void CompilerMSL::entry_point_args_discrete_descriptors(string &ep_args)
 						ep_args += ", raster_order_group(0)";
 						ep_args += ", raster_order_group(0)";
 					ep_args += "]]";
 					ep_args += "]]";
 				}
 				}
-				use_builtin_array = false;
+				is_using_builtin_array = false;
 			}
 			}
 			else
 			else
 			{
 			{
@@ -10002,9 +10023,9 @@ string CompilerMSL::argument_decl(const SPIRFunction::Parameter &arg)
 	// Allow Metal to use the array<T> template to make arrays a value type
 	// Allow Metal to use the array<T> template to make arrays a value type
 	string address_space = get_argument_address_space(var);
 	string address_space = get_argument_address_space(var);
 	bool builtin = is_builtin_variable(var);
 	bool builtin = is_builtin_variable(var);
-	use_builtin_array = builtin;
+	is_using_builtin_array = builtin;
 	if (address_space == "threadgroup")
 	if (address_space == "threadgroup")
-		use_builtin_array = true;
+		is_using_builtin_array = true;
 
 
 	if (var.basevariable && (var.basevariable == stage_in_ptr_var_id || var.basevariable == stage_out_ptr_var_id))
 	if (var.basevariable && (var.basevariable == stage_in_ptr_var_id || var.basevariable == stage_out_ptr_var_id))
 		decl += type_to_glsl(type, arg.id);
 		decl += type_to_glsl(type, arg.id);
@@ -10012,7 +10033,7 @@ string CompilerMSL::argument_decl(const SPIRFunction::Parameter &arg)
 		decl += builtin_type_decl(static_cast<BuiltIn>(get_decoration(arg.id, DecorationBuiltIn)), arg.id);
 		decl += builtin_type_decl(static_cast<BuiltIn>(get_decoration(arg.id, DecorationBuiltIn)), arg.id);
 	else if ((storage == StorageClassUniform || storage == StorageClassStorageBuffer) && is_array(type))
 	else if ((storage == StorageClassUniform || storage == StorageClassStorageBuffer) && is_array(type))
 	{
 	{
-		use_builtin_array = true;
+		is_using_builtin_array = true;
 		decl += join(type_to_glsl(type, arg.id), "*");
 		decl += join(type_to_glsl(type, arg.id), "*");
 	}
 	}
 	else if (is_dynamic_img_sampler)
 	else if (is_dynamic_img_sampler)
@@ -10030,10 +10051,34 @@ string CompilerMSL::argument_decl(const SPIRFunction::Parameter &arg)
 	    (storage == StorageClassFunction || storage == StorageClassGeneric))
 	    (storage == StorageClassFunction || storage == StorageClassGeneric))
 	{
 	{
 		// If the argument is a pure value and not an opaque type, we will pass by value.
 		// If the argument is a pure value and not an opaque type, we will pass by value.
-		if (!address_space.empty())
-			decl = join(address_space, " ", decl);
-		decl += " ";
-		decl += to_expression(name_id);
+		if (msl_options.force_native_arrays && is_array(type))
+		{
+			// We are receiving an array by value. This is problematic.
+			// We cannot be sure of the target address space since we are supposed to receive a copy,
+			// but this is not possible with MSL without some extra work.
+			// We will have to assume we're getting a reference in thread address space.
+			// If we happen to get a reference in constant address space, the caller must emit a copy and pass that.
+			// Thread const therefore becomes the only logical choice, since we cannot "create" a constant array from
+			// non-constant arrays, but we can create thread const from constant.
+			decl = string("thread const ") + decl;
+			decl += " (&";
+			const char *restrict_kw = to_restrict(name_id);
+			if (*restrict_kw)
+			{
+				decl += " ";
+				decl += restrict_kw;
+			}
+			decl += to_expression(name_id);
+			decl += ")";
+			decl += type_to_array_glsl(type);
+		}
+		else
+		{
+			if (!address_space.empty())
+				decl = join(address_space, " ", decl);
+			decl += " ";
+			decl += to_expression(name_id);
+		}
 	}
 	}
 	else if (is_array(type) && !type_is_image)
 	else if (is_array(type) && !type_is_image)
 	{
 	{
@@ -10109,7 +10154,7 @@ string CompilerMSL::argument_decl(const SPIRFunction::Parameter &arg)
 		decl += "* " + to_expression(name_id) + "_atomic";
 		decl += "* " + to_expression(name_id) + "_atomic";
 	}
 	}
 
 
-	use_builtin_array = false;
+	is_using_builtin_array = false;
 
 
 	return decl;
 	return decl;
 }
 }
@@ -10594,7 +10639,7 @@ string CompilerMSL::type_to_glsl(const SPIRType &type, uint32_t id)
 	if (type.vecsize > 1)
 	if (type.vecsize > 1)
 		type_name += to_string(type.vecsize);
 		type_name += to_string(type.vecsize);
 
 
-	if (type.array.empty() || use_builtin_array)
+	if (type.array.empty() || using_builtin_array())
 	{
 	{
 		return type_name;
 		return type_name;
 	}
 	}
@@ -10630,7 +10675,7 @@ string CompilerMSL::type_to_array_glsl(const SPIRType &type)
 	}
 	}
 	default:
 	default:
 	{
 	{
-		if (use_builtin_array)
+		if (using_builtin_array())
 			return CompilerGLSL::type_to_array_glsl(type);
 			return CompilerGLSL::type_to_array_glsl(type);
 		else
 		else
 			return "";
 			return "";
@@ -10643,12 +10688,12 @@ std::string CompilerMSL::variable_decl(const SPIRVariable &variable)
 {
 {
 	if (variable.storage == StorageClassWorkgroup)
 	if (variable.storage == StorageClassWorkgroup)
 	{
 	{
-		use_builtin_array = true;
+		is_using_builtin_array = true;
 	}
 	}
 	std::string expr = CompilerGLSL::variable_decl(variable);
 	std::string expr = CompilerGLSL::variable_decl(variable);
 	if (variable.storage == StorageClassWorkgroup)
 	if (variable.storage == StorageClassWorkgroup)
 	{
 	{
-		use_builtin_array = false;
+		is_using_builtin_array = false;
 	}
 	}
 	return expr;
 	return expr;
 }
 }
@@ -12733,3 +12778,8 @@ void CompilerMSL::activate_argument_buffer_resources()
 			active_interface_variables.insert(self);
 			active_interface_variables.insert(self);
 	});
 	});
 }
 }
+
+bool CompilerMSL::using_builtin_array() const
+{
+	return msl_options.force_native_arrays || is_using_builtin_array;
+}

+ 9 - 1
3rdparty/spirv-cross/spirv_msl.hpp

@@ -312,6 +312,11 @@ public:
 		// and would otherwise declare a different IAB.
 		// and would otherwise declare a different IAB.
 		bool force_active_argument_buffer_resources = false;
 		bool force_active_argument_buffer_resources = false;
 
 
+		// Forces the use of plain arrays, which works around certain driver bugs on certain versions
+		// of Intel Macbooks. See https://github.com/KhronosGroup/SPIRV-Cross/issues/1210.
+		// May reduce performance in scenarios where arrays are copied around as value-types.
+		bool force_native_arrays = false;
+
 		bool is_ios()
 		bool is_ios()
 		{
 		{
 			return platform == iOS;
 			return platform == iOS;
@@ -827,7 +832,10 @@ protected:
 
 
 	bool has_sampled_images = false;
 	bool has_sampled_images = false;
 	bool builtin_declaration = false; // Handle HLSL-style 0-based vertex/instance index.
 	bool builtin_declaration = false; // Handle HLSL-style 0-based vertex/instance index.
-	bool use_builtin_array = false; // Force the use of C style array declaration.
+
+	bool is_using_builtin_array = false; // Force the use of C style array declaration.
+	bool using_builtin_array() const;
+
 	bool is_rasterization_disabled = false;
 	bool is_rasterization_disabled = false;
 	bool capture_output_to_buffer = false;
 	bool capture_output_to_buffer = false;
 	bool needs_swizzle_buffer_def = false;
 	bool needs_swizzle_buffer_def = false;

+ 5 - 9
3rdparty/spirv-cross/spirv_parser.cpp

@@ -86,6 +86,11 @@ void Parser::parse()
 		SPIRV_CROSS_THROW("Invalid SPIRV format.");
 		SPIRV_CROSS_THROW("Invalid SPIRV format.");
 
 
 	uint32_t bound = s[3];
 	uint32_t bound = s[3];
+
+	const uint32_t MaximumNumberOfIDs = 0x3fffff;
+	if (bound > MaximumNumberOfIDs)
+		SPIRV_CROSS_THROW("ID bound exceeds limit of 0x3fffff.\n");
+
 	ir.set_id_bounds(bound);
 	ir.set_id_bounds(bound);
 
 
 	uint32_t offset = 5;
 	uint32_t offset = 5;
@@ -703,15 +708,6 @@ void Parser::parse(const Instruction &instruction)
 		}
 		}
 
 
 		set<SPIRVariable>(id, type, storage, initializer);
 		set<SPIRVariable>(id, type, storage, initializer);
-
-		// hlsl based shaders don't have those decorations. force them and then reset when reading/writing images
-		auto &ttype = get<SPIRType>(type);
-		if (ttype.basetype == SPIRType::BaseType::Image)
-		{
-			ir.set_decoration(id, DecorationNonWritable);
-			ir.set_decoration(id, DecorationNonReadable);
-		}
-
 		break;
 		break;
 	}
 	}