2
0
Бранимир Караџић 5 жил өмнө
parent
commit
248d56709e

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

@@ -549,6 +549,7 @@ struct CLIArguments
 	bool msl_invariant_float_math = false;
 	bool msl_invariant_float_math = false;
 	bool msl_emulate_cube_array = false;
 	bool msl_emulate_cube_array = false;
 	bool msl_multiview = false;
 	bool msl_multiview = false;
+	bool msl_multiview_layered_rendering = true;
 	bool msl_view_index_from_device_index = false;
 	bool msl_view_index_from_device_index = false;
 	bool msl_dispatch_base = false;
 	bool msl_dispatch_base = false;
 	bool msl_decoration_binding = false;
 	bool msl_decoration_binding = false;
@@ -561,6 +562,7 @@ struct CLIArguments
 	bool msl_multi_patch_workgroup = false;
 	bool msl_multi_patch_workgroup = false;
 	bool msl_vertex_for_tessellation = false;
 	bool msl_vertex_for_tessellation = false;
 	uint32_t msl_additional_fixed_sample_mask = 0xffffffff;
 	uint32_t msl_additional_fixed_sample_mask = 0xffffffff;
+	bool msl_arrayed_subpass_input = 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 glsl_force_flattened_io_blocks = false;
 	bool glsl_force_flattened_io_blocks = false;
@@ -732,6 +734,8 @@ static void print_help_msl()
 	                "\t[--msl-device-argument-buffer <descriptor set index>]:\n\t\tUse device address space to hold indirect argument buffers instead of constant.\n"
 	                "\t[--msl-device-argument-buffer <descriptor set index>]:\n\t\tUse device address space to hold indirect argument buffers instead of constant.\n"
 	                "\t\tComes up when trying to support argument buffers which are larger than 64 KiB.\n"
 	                "\t\tComes up when trying to support argument buffers which are larger than 64 KiB.\n"
 	                "\t[--msl-multiview]:\n\t\tEnable SPV_KHR_multiview emulation.\n"
 	                "\t[--msl-multiview]:\n\t\tEnable SPV_KHR_multiview emulation.\n"
+	                "\t[--msl-multiview-no-layered-rendering]:\n\t\tDon't set [[render_target_array_index]] in multiview shaders.\n"
+	                "\t\tUseful for devices which don't support layered rendering. Only effective when --msl-multiview is enabled.\n"
 	                "\t[--msl-view-index-from-device-index]:\n\t\tTreat the view index as the device index instead.\n"
 	                "\t[--msl-view-index-from-device-index]:\n\t\tTreat the view index as the device index instead.\n"
 	                "\t\tFor multi-GPU rendering.\n"
 	                "\t\tFor multi-GPU rendering.\n"
 	                "\t[--msl-dispatch-base]:\n\t\tAdd support for vkCmdDispatchBase() or similar APIs.\n"
 	                "\t[--msl-dispatch-base]:\n\t\tAdd support for vkCmdDispatchBase() or similar APIs.\n"
@@ -762,7 +766,9 @@ static void print_help_msl()
 	                "\t[--msl-vertex-for-tessellation]:\n\t\tWhen handling a vertex shader, marks it as one that will be used with a new-style tessellation control shader.\n"
 	                "\t[--msl-vertex-for-tessellation]:\n\t\tWhen handling a vertex shader, marks it as one that will be used with a new-style tessellation control shader.\n"
 					"\t\tThe vertex shader is output to MSL as a compute kernel which outputs vertices to the buffer in the order they are received, rather than in index order as with --msl-capture-output normally.\n"
 					"\t\tThe vertex shader is output to MSL as a compute kernel which outputs vertices to the buffer in the order they are received, rather than in index order as with --msl-capture-output normally.\n"
 	                "\t[--msl-additional-fixed-sample-mask <mask>]:\n"
 	                "\t[--msl-additional-fixed-sample-mask <mask>]:\n"
-	                "\t\tSet an additional fixed sample mask. If the shader outputs a sample mask, then the final sample mask will be a bitwise AND of the two.\n");
+	                "\t\tSet an additional fixed sample mask. If the shader outputs a sample mask, then the final sample mask will be a bitwise AND of the two.\n"
+	                "\t[--msl-arrayed-subpass-input]:\n\t\tAssume that images of dimension SubpassData have multiple layers. Layered input attachments are accessed relative to BuiltInLayer.\n"
+	                "\t\tThis option has no effect if multiview is also enabled.\n");
 	// clang-format on
 	// clang-format on
 }
 }
 
 
@@ -987,6 +993,7 @@ static string compile_iteration(const CLIArguments &args, std::vector<uint32_t>
 		msl_opts.argument_buffers = args.msl_argument_buffers;
 		msl_opts.argument_buffers = args.msl_argument_buffers;
 		msl_opts.texture_buffer_native = args.msl_texture_buffer_native;
 		msl_opts.texture_buffer_native = args.msl_texture_buffer_native;
 		msl_opts.multiview = args.msl_multiview;
 		msl_opts.multiview = args.msl_multiview;
+		msl_opts.multiview_layered_rendering = args.msl_multiview_layered_rendering;
 		msl_opts.view_index_from_device_index = args.msl_view_index_from_device_index;
 		msl_opts.view_index_from_device_index = args.msl_view_index_from_device_index;
 		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;
@@ -999,6 +1006,7 @@ static string compile_iteration(const CLIArguments &args, std::vector<uint32_t>
 		msl_opts.multi_patch_workgroup = args.msl_multi_patch_workgroup;
 		msl_opts.multi_patch_workgroup = args.msl_multi_patch_workgroup;
 		msl_opts.vertex_for_tessellation = args.msl_vertex_for_tessellation;
 		msl_opts.vertex_for_tessellation = args.msl_vertex_for_tessellation;
 		msl_opts.additional_fixed_sample_mask = args.msl_additional_fixed_sample_mask;
 		msl_opts.additional_fixed_sample_mask = args.msl_additional_fixed_sample_mask;
+		msl_opts.arrayed_subpass_input = args.msl_arrayed_subpass_input;
 		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);
@@ -1366,6 +1374,8 @@ static int main_inner(int argc, char *argv[])
 	cbs.add("--msl-invariant-float-math", [&args](CLIParser &) { args.msl_invariant_float_math = true; });
 	cbs.add("--msl-invariant-float-math", [&args](CLIParser &) { args.msl_invariant_float_math = true; });
 	cbs.add("--msl-emulate-cube-array", [&args](CLIParser &) { args.msl_emulate_cube_array = true; });
 	cbs.add("--msl-emulate-cube-array", [&args](CLIParser &) { args.msl_emulate_cube_array = true; });
 	cbs.add("--msl-multiview", [&args](CLIParser &) { args.msl_multiview = true; });
 	cbs.add("--msl-multiview", [&args](CLIParser &) { args.msl_multiview = true; });
+	cbs.add("--msl-multiview-no-layered-rendering",
+	        [&args](CLIParser &) { args.msl_multiview_layered_rendering = false; });
 	cbs.add("--msl-view-index-from-device-index",
 	cbs.add("--msl-view-index-from-device-index",
 	        [&args](CLIParser &) { args.msl_view_index_from_device_index = true; });
 	        [&args](CLIParser &) { args.msl_view_index_from_device_index = true; });
 	cbs.add("--msl-dispatch-base", [&args](CLIParser &) { args.msl_dispatch_base = true; });
 	cbs.add("--msl-dispatch-base", [&args](CLIParser &) { args.msl_dispatch_base = true; });
@@ -1416,6 +1426,7 @@ static int main_inner(int argc, char *argv[])
 	cbs.add("--msl-vertex-for-tessellation", [&args](CLIParser &) { args.msl_vertex_for_tessellation = true; });
 	cbs.add("--msl-vertex-for-tessellation", [&args](CLIParser &) { args.msl_vertex_for_tessellation = true; });
 	cbs.add("--msl-additional-fixed-sample-mask",
 	cbs.add("--msl-additional-fixed-sample-mask",
 	        [&args](CLIParser &parser) { args.msl_additional_fixed_sample_mask = parser.next_hex_uint(); });
 	        [&args](CLIParser &parser) { args.msl_additional_fixed_sample_mask = parser.next_hex_uint(); });
+	cbs.add("--msl-arrayed-subpass-input", [&args](CLIParser &) { args.msl_arrayed_subpass_input = 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();

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

@@ -658,6 +658,14 @@ spvc_result spvc_compiler_options_set_uint(spvc_compiler_options options, spvc_c
 	case SPVC_COMPILER_OPTION_MSL_VERTEX_INDEX_TYPE:
 	case SPVC_COMPILER_OPTION_MSL_VERTEX_INDEX_TYPE:
 		options->msl.vertex_index_type = static_cast<CompilerMSL::Options::IndexType>(value);
 		options->msl.vertex_index_type = static_cast<CompilerMSL::Options::IndexType>(value);
 		break;
 		break;
+
+	case SPVC_COMPILER_OPTION_MSL_MULTIVIEW_LAYERED_RENDERING:
+		options->msl.multiview_layered_rendering = value != 0;
+		break;
+
+	case SPVC_COMPILER_OPTION_MSL_ARRAYED_SUBPASS_INPUT:
+		options->msl.arrayed_subpass_input = value != 0;
+		break;
 #endif
 #endif
 
 
 	default:
 	default:

+ 4 - 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 37
+#define SPVC_C_API_VERSION_MINOR 39
 /* 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
 
 
@@ -636,6 +636,9 @@ typedef enum spvc_compiler_option
 
 
 	SPVC_COMPILER_OPTION_GLSL_FORCE_FLATTENED_IO_BLOCKS = 66 | SPVC_COMPILER_OPTION_GLSL_BIT,
 	SPVC_COMPILER_OPTION_GLSL_FORCE_FLATTENED_IO_BLOCKS = 66 | SPVC_COMPILER_OPTION_GLSL_BIT,
 
 
+	SPVC_COMPILER_OPTION_MSL_MULTIVIEW_LAYERED_RENDERING = 67 | SPVC_COMPILER_OPTION_MSL_BIT,
+	SPVC_COMPILER_OPTION_MSL_ARRAYED_SUBPASS_INPUT = 68 | SPVC_COMPILER_OPTION_MSL_BIT,
+
 	SPVC_COMPILER_OPTION_INT_MAX = 0x7fffffff
 	SPVC_COMPILER_OPTION_INT_MAX = 0x7fffffff
 } spvc_compiler_option;
 } spvc_compiler_option;
 
 

+ 10 - 5
3rdparty/spirv-cross/spirv_glsl.cpp

@@ -2881,11 +2881,16 @@ void CompilerGLSL::declare_undefined_values()
 {
 {
 	bool emitted = false;
 	bool emitted = false;
 	ir.for_each_typed_id<SPIRUndef>([&](uint32_t, const SPIRUndef &undef) {
 	ir.for_each_typed_id<SPIRUndef>([&](uint32_t, const SPIRUndef &undef) {
+		auto &type = this->get<SPIRType>(undef.basetype);
+		// OpUndef can be void for some reason ...
+		if (type.basetype == SPIRType::Void)
+			return;
+
 		string initializer;
 		string initializer;
-		if (options.force_zero_initialized_variables && type_can_zero_initialize(this->get<SPIRType>(undef.basetype)))
+		if (options.force_zero_initialized_variables && type_can_zero_initialize(type))
 			initializer = join(" = ", to_zero_initialized_expression(undef.basetype));
 			initializer = join(" = ", to_zero_initialized_expression(undef.basetype));
 
 
-		statement(variable_decl(this->get<SPIRType>(undef.basetype), to_name(undef.self), undef.self), initializer,
+		statement(variable_decl(type, to_name(undef.self), undef.self), initializer,
 		          ";");
 		          ";");
 		emitted = true;
 		emitted = true;
 	});
 	});
@@ -9280,7 +9285,7 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
 		statement(declare_temporary(result_type, id), to_expression(vec), ";");
 		statement(declare_temporary(result_type, id), to_expression(vec), ";");
 		set<SPIRExpression>(id, to_name(id), result_type, true);
 		set<SPIRExpression>(id, to_name(id), result_type, true);
 		auto chain = access_chain_internal(id, &index, 1, 0, nullptr);
 		auto chain = access_chain_internal(id, &index, 1, 0, nullptr);
-		statement(chain, " = ", to_expression(comp), ";");
+		statement(chain, " = ", to_unpacked_expression(comp), ";");
 		break;
 		break;
 	}
 	}
 
 
@@ -9382,7 +9387,7 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
 		statement(declare_temporary(result_type, id), to_expression(composite), ";");
 		statement(declare_temporary(result_type, id), to_expression(composite), ";");
 		set<SPIRExpression>(id, to_name(id), result_type, true);
 		set<SPIRExpression>(id, to_name(id), result_type, true);
 		auto chain = access_chain_internal(id, elems, length, ACCESS_CHAIN_INDEX_IS_LITERAL_BIT, nullptr);
 		auto chain = access_chain_internal(id, elems, length, ACCESS_CHAIN_INDEX_IS_LITERAL_BIT, nullptr);
-		statement(chain, " = ", to_expression(obj), ";");
+		statement(chain, " = ", to_unpacked_expression(obj), ";");
 
 
 		break;
 		break;
 	}
 	}
@@ -9395,7 +9400,7 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
 		{
 		{
 			flush_variable_declaration(lhs);
 			flush_variable_declaration(lhs);
 			flush_variable_declaration(rhs);
 			flush_variable_declaration(rhs);
-			statement(to_expression(lhs), " = ", to_expression(rhs), ";");
+			statement(to_expression(lhs), " = ", to_unpacked_expression(rhs), ";");
 			register_write(lhs);
 			register_write(lhs);
 		}
 		}
 		break;
 		break;

+ 7 - 2
3rdparty/spirv-cross/spirv_hlsl.cpp

@@ -1220,11 +1220,16 @@ void CompilerHLSL::declare_undefined_values()
 {
 {
 	bool emitted = false;
 	bool emitted = false;
 	ir.for_each_typed_id<SPIRUndef>([&](uint32_t, const SPIRUndef &undef) {
 	ir.for_each_typed_id<SPIRUndef>([&](uint32_t, const SPIRUndef &undef) {
+		auto &type = this->get<SPIRType>(undef.basetype);
+		// OpUndef can be void for some reason ...
+		if (type.basetype == SPIRType::Void)
+			return;
+
 		string initializer;
 		string initializer;
-		if (options.force_zero_initialized_variables && type_can_zero_initialize(this->get<SPIRType>(undef.basetype)))
+		if (options.force_zero_initialized_variables && type_can_zero_initialize(type))
 			initializer = join(" = ", to_zero_initialized_expression(undef.basetype));
 			initializer = join(" = ", to_zero_initialized_expression(undef.basetype));
 
 
-		statement("static ", variable_decl(this->get<SPIRType>(undef.basetype), to_name(undef.self), undef.self),
+		statement("static ", variable_decl(type, to_name(undef.self), undef.self),
 		          initializer, ";");
 		          initializer, ";");
 		emitted = true;
 		emitted = true;
 	});
 	});

+ 170 - 47
3rdparty/spirv-cross/spirv_msl.cpp

@@ -146,6 +146,7 @@ void CompilerMSL::build_implicit_builtins()
 	bool need_subgroup_ge_mask = !msl_options.is_ios() && (active_input_builtins.get(BuiltInSubgroupGeMask) ||
 	bool need_subgroup_ge_mask = !msl_options.is_ios() && (active_input_builtins.get(BuiltInSubgroupGeMask) ||
 	                                                       active_input_builtins.get(BuiltInSubgroupGtMask));
 	                                                       active_input_builtins.get(BuiltInSubgroupGtMask));
 	bool need_multiview = get_execution_model() == ExecutionModelVertex && !msl_options.view_index_from_device_index &&
 	bool need_multiview = get_execution_model() == ExecutionModelVertex && !msl_options.view_index_from_device_index &&
+	                      msl_options.multiview_layered_rendering &&
 	                      (msl_options.multiview || active_input_builtins.get(BuiltInViewIndex));
 	                      (msl_options.multiview || active_input_builtins.get(BuiltInViewIndex));
 	bool need_dispatch_base =
 	bool need_dispatch_base =
 	    msl_options.dispatch_base && get_execution_model() == ExecutionModelGLCompute &&
 	    msl_options.dispatch_base && get_execution_model() == ExecutionModelGLCompute &&
@@ -172,6 +173,7 @@ void CompilerMSL::build_implicit_builtins()
 		bool has_subgroup_invocation_id = false;
 		bool has_subgroup_invocation_id = false;
 		bool has_subgroup_size = false;
 		bool has_subgroup_size = false;
 		bool has_view_idx = false;
 		bool has_view_idx = false;
+		bool has_layer = false;
 		uint32_t workgroup_id_type = 0;
 		uint32_t workgroup_id_type = 0;
 
 
 		// FIXME: Investigate the fact that there are no checks for the entry point interface variables.
 		// FIXME: Investigate the fact that there are no checks for the entry point interface variables.
@@ -195,12 +197,32 @@ void CompilerMSL::build_implicit_builtins()
 			if (var.storage != StorageClassInput)
 			if (var.storage != StorageClassInput)
 				return;
 				return;
 
 
-			if (need_subpass_input && (!msl_options.is_ios() || !msl_options.ios_use_framebuffer_fetch_subpasses) &&
-			    builtin == BuiltInFragCoord)
+			if (need_subpass_input && (!msl_options.is_ios() || !msl_options.ios_use_framebuffer_fetch_subpasses))
 			{
 			{
-				mark_implicit_builtin(StorageClassInput, BuiltInFragCoord, var.self);
-				builtin_frag_coord_id = var.self;
-				has_frag_coord = true;
+				switch (builtin)
+				{
+				case BuiltInFragCoord:
+					mark_implicit_builtin(StorageClassInput, BuiltInFragCoord, var.self);
+					builtin_frag_coord_id = var.self;
+					has_frag_coord = true;
+					break;
+				case BuiltInLayer:
+					if (!msl_options.arrayed_subpass_input || msl_options.multiview)
+						break;
+					mark_implicit_builtin(StorageClassInput, BuiltInLayer, var.self);
+					builtin_layer_id = var.self;
+					has_layer = true;
+					break;
+				case BuiltInViewIndex:
+					if (!msl_options.multiview)
+						break;
+					mark_implicit_builtin(StorageClassInput, BuiltInViewIndex, var.self);
+					builtin_view_idx_id = var.self;
+					has_view_idx = true;
+					break;
+				default:
+					break;
+				}
 			}
 			}
 
 
 			if (need_sample_pos && builtin == BuiltInSampleId)
 			if (need_sample_pos && builtin == BuiltInSampleId)
@@ -282,6 +304,12 @@ void CompilerMSL::build_implicit_builtins()
 					mark_implicit_builtin(StorageClassInput, BuiltInInstanceIndex, var.self);
 					mark_implicit_builtin(StorageClassInput, BuiltInInstanceIndex, var.self);
 					has_instance_idx = true;
 					has_instance_idx = true;
 					break;
 					break;
+				case BuiltInBaseInstance:
+					// If a non-zero base instance is used, we need to adjust for it when calculating the view index.
+					builtin_base_instance_id = var.self;
+					mark_implicit_builtin(StorageClassInput, BuiltInBaseInstance, var.self);
+					has_base_instance = true;
+					break;
 				case BuiltInViewIndex:
 				case BuiltInViewIndex:
 					builtin_view_idx_id = var.self;
 					builtin_view_idx_id = var.self;
 					mark_implicit_builtin(StorageClassInput, BuiltInViewIndex, var.self);
 					mark_implicit_builtin(StorageClassInput, BuiltInViewIndex, var.self);
@@ -301,33 +329,79 @@ void CompilerMSL::build_implicit_builtins()
 		});
 		});
 
 
 		// Use Metal's native frame-buffer fetch API for subpass inputs.
 		// Use Metal's native frame-buffer fetch API for subpass inputs.
-		if (!has_frag_coord && (!msl_options.is_ios() || !msl_options.ios_use_framebuffer_fetch_subpasses) &&
-		    need_subpass_input)
-		{
-			uint32_t offset = ir.increase_bound_by(3);
-			uint32_t type_id = offset;
-			uint32_t type_ptr_id = offset + 1;
-			uint32_t var_id = offset + 2;
-
-			// Create gl_FragCoord.
-			SPIRType vec4_type;
-			vec4_type.basetype = SPIRType::Float;
-			vec4_type.width = 32;
-			vec4_type.vecsize = 4;
-			set<SPIRType>(type_id, vec4_type);
-
-			SPIRType vec4_type_ptr;
-			vec4_type_ptr = vec4_type;
-			vec4_type_ptr.pointer = true;
-			vec4_type_ptr.parent_type = type_id;
-			vec4_type_ptr.storage = StorageClassInput;
-			auto &ptr_type = set<SPIRType>(type_ptr_id, vec4_type_ptr);
-			ptr_type.self = type_id;
+		if ((!has_frag_coord || (msl_options.multiview && !has_view_idx) ||
+		     (msl_options.arrayed_subpass_input && !msl_options.multiview && !has_layer)) &&
+		    (!msl_options.is_ios() || !msl_options.ios_use_framebuffer_fetch_subpasses) && need_subpass_input)
+		{
+			if (!has_frag_coord)
+			{
+				uint32_t offset = ir.increase_bound_by(3);
+				uint32_t type_id = offset;
+				uint32_t type_ptr_id = offset + 1;
+				uint32_t var_id = offset + 2;
+
+				// Create gl_FragCoord.
+				SPIRType vec4_type;
+				vec4_type.basetype = SPIRType::Float;
+				vec4_type.width = 32;
+				vec4_type.vecsize = 4;
+				set<SPIRType>(type_id, vec4_type);
+
+				SPIRType vec4_type_ptr;
+				vec4_type_ptr = vec4_type;
+				vec4_type_ptr.pointer = true;
+				vec4_type_ptr.parent_type = type_id;
+				vec4_type_ptr.storage = StorageClassInput;
+				auto &ptr_type = set<SPIRType>(type_ptr_id, vec4_type_ptr);
+				ptr_type.self = type_id;
 
 
-			set<SPIRVariable>(var_id, type_ptr_id, StorageClassInput);
-			set_decoration(var_id, DecorationBuiltIn, BuiltInFragCoord);
-			builtin_frag_coord_id = var_id;
-			mark_implicit_builtin(StorageClassInput, BuiltInFragCoord, var_id);
+				set<SPIRVariable>(var_id, type_ptr_id, StorageClassInput);
+				set_decoration(var_id, DecorationBuiltIn, BuiltInFragCoord);
+				builtin_frag_coord_id = var_id;
+				mark_implicit_builtin(StorageClassInput, BuiltInFragCoord, var_id);
+			}
+
+			if (!has_layer && msl_options.arrayed_subpass_input && !msl_options.multiview)
+			{
+				uint32_t offset = ir.increase_bound_by(2);
+				uint32_t type_ptr_id = offset;
+				uint32_t var_id = offset + 1;
+
+				// Create gl_Layer.
+				SPIRType uint_type_ptr;
+				uint_type_ptr = get_uint_type();
+				uint_type_ptr.pointer = true;
+				uint_type_ptr.parent_type = get_uint_type_id();
+				uint_type_ptr.storage = StorageClassInput;
+				auto &ptr_type = set<SPIRType>(type_ptr_id, uint_type_ptr);
+				ptr_type.self = get_uint_type_id();
+
+				set<SPIRVariable>(var_id, type_ptr_id, StorageClassInput);
+				set_decoration(var_id, DecorationBuiltIn, BuiltInLayer);
+				builtin_layer_id = var_id;
+				mark_implicit_builtin(StorageClassInput, BuiltInLayer, var_id);
+			}
+
+			if (!has_view_idx && msl_options.multiview)
+			{
+				uint32_t offset = ir.increase_bound_by(2);
+				uint32_t type_ptr_id = offset;
+				uint32_t var_id = offset + 1;
+
+				// Create gl_ViewIndex.
+				SPIRType uint_type_ptr;
+				uint_type_ptr = get_uint_type();
+				uint_type_ptr.pointer = true;
+				uint_type_ptr.parent_type = get_uint_type_id();
+				uint_type_ptr.storage = StorageClassInput;
+				auto &ptr_type = set<SPIRType>(type_ptr_id, uint_type_ptr);
+				ptr_type.self = get_uint_type_id();
+
+				set<SPIRVariable>(var_id, type_ptr_id, StorageClassInput);
+				set_decoration(var_id, DecorationBuiltIn, BuiltInViewIndex);
+				builtin_view_idx_id = var_id;
+				mark_implicit_builtin(StorageClassInput, BuiltInViewIndex, var_id);
+			}
 		}
 		}
 
 
 		if (!has_sample_id && need_sample_pos)
 		if (!has_sample_id && need_sample_pos)
@@ -352,7 +426,7 @@ void CompilerMSL::build_implicit_builtins()
 		}
 		}
 
 
 		if ((need_vertex_params && (!has_vertex_idx || !has_base_vertex || !has_instance_idx || !has_base_instance)) ||
 		if ((need_vertex_params && (!has_vertex_idx || !has_base_vertex || !has_instance_idx || !has_base_instance)) ||
-		    (need_multiview && (!has_instance_idx || !has_view_idx)))
+		    (need_multiview && (!has_instance_idx || !has_base_instance || !has_view_idx)))
 		{
 		{
 			uint32_t type_ptr_id = ir.increase_bound_by(1);
 			uint32_t type_ptr_id = ir.increase_bound_by(1);
 
 
@@ -397,7 +471,7 @@ void CompilerMSL::build_implicit_builtins()
 				mark_implicit_builtin(StorageClassInput, BuiltInInstanceIndex, var_id);
 				mark_implicit_builtin(StorageClassInput, BuiltInInstanceIndex, var_id);
 			}
 			}
 
 
-			if (need_vertex_params && !has_base_instance)
+			if (!has_base_instance) // Needed by both multiview and tessellation
 			{
 			{
 				uint32_t var_id = ir.increase_bound_by(1);
 				uint32_t var_id = ir.increase_bound_by(1);
 
 
@@ -1303,6 +1377,18 @@ void CompilerMSL::extract_global_variables_from_function(uint32_t func_id, std::
 					// Implicitly reads gl_FragCoord.
 					// Implicitly reads gl_FragCoord.
 					assert(builtin_frag_coord_id != 0);
 					assert(builtin_frag_coord_id != 0);
 					added_arg_ids.insert(builtin_frag_coord_id);
 					added_arg_ids.insert(builtin_frag_coord_id);
+					if (msl_options.multiview)
+					{
+						// Implicitly reads gl_ViewIndex.
+						assert(builtin_view_idx_id != 0);
+						added_arg_ids.insert(builtin_view_idx_id);
+					}
+					else if (msl_options.arrayed_subpass_input)
+					{
+						// Implicitly reads gl_Layer.
+						assert(builtin_layer_id != 0);
+						added_arg_ids.insert(builtin_layer_id);
+					}
 				}
 				}
 
 
 				break;
 				break;
@@ -3904,7 +3990,7 @@ void CompilerMSL::emit_custom_templates()
 // otherwise they will cause problems when linked together in a single Metallib.
 // otherwise they will cause problems when linked together in a single Metallib.
 void CompilerMSL::emit_custom_functions()
 void CompilerMSL::emit_custom_functions()
 {
 {
-	for (uint32_t i = SPVFuncImplArrayCopyMultidimMax; i >= 2; i--)
+	for (uint32_t i = kArrayCopyMultidimMax; i >= 2; i--)
 		if (spv_function_implementations.count(static_cast<SPVFuncImpl>(SPVFuncImplArrayCopyMultidimBase + i)))
 		if (spv_function_implementations.count(static_cast<SPVFuncImpl>(SPVFuncImplArrayCopyMultidimBase + i)))
 			spv_function_implementations.insert(static_cast<SPVFuncImpl>(SPVFuncImplArrayCopyMultidimBase + i - 1));
 			spv_function_implementations.insert(static_cast<SPVFuncImpl>(SPVFuncImplArrayCopyMultidimBase + i - 1));
 
 
@@ -5339,6 +5425,10 @@ void CompilerMSL::declare_undefined_values()
 	bool emitted = false;
 	bool emitted = false;
 	ir.for_each_typed_id<SPIRUndef>([&](uint32_t, SPIRUndef &undef) {
 	ir.for_each_typed_id<SPIRUndef>([&](uint32_t, SPIRUndef &undef) {
 		auto &type = this->get<SPIRType>(undef.basetype);
 		auto &type = this->get<SPIRType>(undef.basetype);
+		// OpUndef can be void for some reason ...
+		if (type.basetype == SPIRType::Void)
+			return;
+
 		statement("constant ", variable_decl(type, to_name(undef.self), undef.self), " = {};");
 		statement("constant ", variable_decl(type, to_name(undef.self), undef.self), " = {};");
 		emitted = true;
 		emitted = true;
 	});
 	});
@@ -7198,7 +7288,7 @@ void CompilerMSL::emit_array_copy(const string &lhs, uint32_t rhs_id, StorageCla
 		// if this is the only use of array copies in our shader.
 		// if this is the only use of array copies in our shader.
 		if (type.array.size() > 1)
 		if (type.array.size() > 1)
 		{
 		{
-			if (type.array.size() > SPVFuncImplArrayCopyMultidimMax)
+			if (type.array.size() > kArrayCopyMultidimMax)
 				SPIRV_CROSS_THROW("Cannot support this many dimensions for arrays of arrays.");
 				SPIRV_CROSS_THROW("Cannot support this many dimensions for arrays of arrays.");
 			auto func = static_cast<SPVFuncImpl>(SPVFuncImplArrayCopyMultidimBase + type.array.size());
 			auto func = static_cast<SPVFuncImpl>(SPVFuncImplArrayCopyMultidimBase + type.array.size());
 			add_spv_func_and_recompile(func);
 			add_spv_func_and_recompile(func);
@@ -8100,10 +8190,8 @@ string CompilerMSL::to_function_args(const TextureFunctionArguments &args, bool
 	case DimSubpassData:
 	case DimSubpassData:
 		// If we're using Metal's native frame-buffer fetch API for subpass inputs,
 		// If we're using Metal's native frame-buffer fetch API for subpass inputs,
 		// this path will not be hit.
 		// this path will not be hit.
-		if (imgtype.image.ms)
-			tex_coords = "uint2(gl_FragCoord.xy)";
-		else
-			tex_coords = join("uint2(gl_FragCoord.xy), 0");
+		tex_coords = "uint2(gl_FragCoord.xy)";
+		alt_coord_component = 2;
 		break;
 		break;
 
 
 	case Dim2D:
 	case Dim2D:
@@ -8220,12 +8308,30 @@ string CompilerMSL::to_function_args(const TextureFunctionArguments &args, bool
 		{
 		{
 			// Special case for cube arrays, face and layer are packed in one dimension.
 			// Special case for cube arrays, face and layer are packed in one dimension.
 			if (imgtype.image.dim == DimCube && args.base.is_fetch)
 			if (imgtype.image.dim == DimCube && args.base.is_fetch)
+			{
 				farg_str += ", uint(" + to_extract_component_expression(args.coord, 2) + ") / 6u";
 				farg_str += ", uint(" + to_extract_component_expression(args.coord, 2) + ") / 6u";
+			}
 			else
 			else
+			{
 				farg_str +=
 				farg_str +=
 				    ", uint(" +
 				    ", uint(" +
 				    round_fp_tex_coords(to_extract_component_expression(args.coord, alt_coord_component), coord_is_fp) +
 				    round_fp_tex_coords(to_extract_component_expression(args.coord, alt_coord_component), coord_is_fp) +
 				    ")";
 				    ")";
+				if (imgtype.image.dim == DimSubpassData)
+				{
+					if (msl_options.multiview)
+						farg_str += " + gl_ViewIndex";
+					else if (msl_options.arrayed_subpass_input)
+						farg_str += " + gl_Layer";
+				}
+			}
+		}
+		else if (imgtype.image.dim == DimSubpassData)
+		{
+			if (msl_options.multiview)
+				farg_str += ", gl_ViewIndex";
+			else if (msl_options.arrayed_subpass_input)
+				farg_str += ", gl_Layer";
 		}
 		}
 	}
 	}
 
 
@@ -9236,7 +9342,7 @@ string CompilerMSL::member_attribute_qualifier(const SPIRType &type, uint32_t in
 			switch (builtin)
 			switch (builtin)
 			{
 			{
 			case BuiltInViewIndex:
 			case BuiltInViewIndex:
-				if (!msl_options.multiview)
+				if (!msl_options.multiview || !msl_options.multiview_layered_rendering)
 					break;
 					break;
 				/* fallthrough */
 				/* fallthrough */
 			case BuiltInFrontFacing:
 			case BuiltInFrontFacing:
@@ -9654,7 +9760,8 @@ bool CompilerMSL::is_direct_input_builtin(BuiltIn bi_type)
 	case BuiltInBaryCoordNoPerspNV:
 	case BuiltInBaryCoordNoPerspNV:
 		return false;
 		return false;
 	case BuiltInViewIndex:
 	case BuiltInViewIndex:
-		return get_execution_model() == ExecutionModelFragment && msl_options.multiview;
+		return get_execution_model() == ExecutionModelFragment && msl_options.multiview &&
+		       msl_options.multiview_layered_rendering;
 	// Any stage function in
 	// Any stage function in
 	case BuiltInDeviceIndex:
 	case BuiltInDeviceIndex:
 	case BuiltInSubgroupEqMask:
 	case BuiltInSubgroupEqMask:
@@ -10424,6 +10531,15 @@ void CompilerMSL::fix_up_shader_inputs_outputs()
 					// Since every physical device is rendering a different view,
 					// Since every physical device is rendering a different view,
 					// there's no need for layered rendering here.
 					// there's no need for layered rendering here.
 				}
 				}
+				else if (!msl_options.multiview_layered_rendering)
+				{
+					// In this case, the views are rendered one at a time. The view index, then,
+					// is just the first part of the "view mask".
+					entry_func.fixup_hooks_in.push_back([=]() {
+						statement("const ", builtin_type_decl(bi_type), " ", to_expression(var_id), " = ",
+						          to_expression(view_mask_buffer_id), "[0];");
+					});
+				}
 				else if (get_execution_model() == ExecutionModelFragment)
 				else if (get_execution_model() == ExecutionModelFragment)
 				{
 				{
 					// Because we adjusted the view index in the vertex shader, we have to
 					// Because we adjusted the view index in the vertex shader, we have to
@@ -10438,10 +10554,13 @@ void CompilerMSL::fix_up_shader_inputs_outputs()
 					// the view index in the instance index.
 					// the view index in the instance index.
 					entry_func.fixup_hooks_in.push_back([=]() {
 					entry_func.fixup_hooks_in.push_back([=]() {
 						statement(builtin_type_decl(bi_type), " ", to_expression(var_id), " = ",
 						statement(builtin_type_decl(bi_type), " ", to_expression(var_id), " = ",
-						          to_expression(view_mask_buffer_id), "[0] + ", to_expression(builtin_instance_idx_id),
-						          " % ", to_expression(view_mask_buffer_id), "[1];");
-						statement(to_expression(builtin_instance_idx_id), " /= ", to_expression(view_mask_buffer_id),
-						          "[1];");
+						          to_expression(view_mask_buffer_id), "[0] + (", to_expression(builtin_instance_idx_id),
+						          " - ", to_expression(builtin_base_instance_id), ") % ",
+						          to_expression(view_mask_buffer_id), "[1];");
+						statement(to_expression(builtin_instance_idx_id), " = (",
+						          to_expression(builtin_instance_idx_id), " - ",
+						          to_expression(builtin_base_instance_id), ") / ", to_expression(view_mask_buffer_id),
+						          "[1] + ", to_expression(builtin_base_instance_id), ";");
 					});
 					});
 					// In addition to setting the variable itself, we also need to
 					// In addition to setting the variable itself, we also need to
 					// set the render_target_array_index with it on output. We have to
 					// set the render_target_array_index with it on output. We have to
@@ -11556,6 +11675,9 @@ string CompilerMSL::image_type_glsl(const SPIRType &type, uint32_t id)
 		case Dim1D:
 		case Dim1D:
 		case Dim2D:
 		case Dim2D:
 		case DimSubpassData:
 		case DimSubpassData:
+		{
+			bool subpass_array =
+			    img_type.dim == DimSubpassData && (msl_options.multiview || msl_options.arrayed_subpass_input);
 			if (img_type.dim == Dim1D && !msl_options.texture_1D_as_2D)
 			if (img_type.dim == Dim1D && !msl_options.texture_1D_as_2D)
 			{
 			{
 				// Use a native Metal 1D texture
 				// Use a native Metal 1D texture
@@ -11570,7 +11692,7 @@ string CompilerMSL::image_type_glsl(const SPIRType &type, uint32_t id)
 				img_type_4.vecsize = 4;
 				img_type_4.vecsize = 4;
 				return type_to_glsl(img_type_4);
 				return type_to_glsl(img_type_4);
 			}
 			}
-			if (img_type.ms && img_type.arrayed)
+			if (img_type.ms && (img_type.arrayed || subpass_array))
 			{
 			{
 				if (!msl_options.supports_msl_version(2, 1))
 				if (!msl_options.supports_msl_version(2, 1))
 					SPIRV_CROSS_THROW("Multisampled array textures are supported from 2.1.");
 					SPIRV_CROSS_THROW("Multisampled array textures are supported from 2.1.");
@@ -11578,11 +11700,12 @@ string CompilerMSL::image_type_glsl(const SPIRType &type, uint32_t id)
 			}
 			}
 			else if (img_type.ms)
 			else if (img_type.ms)
 				img_type_name += "texture2d_ms";
 				img_type_name += "texture2d_ms";
-			else if (img_type.arrayed)
+			else if (img_type.arrayed || subpass_array)
 				img_type_name += "texture2d_array";
 				img_type_name += "texture2d_array";
 			else
 			else
 				img_type_name += "texture2d";
 				img_type_name += "texture2d";
 			break;
 			break;
+		}
 		case Dim3D:
 		case Dim3D:
 			img_type_name += "texture3d";
 			img_type_name += "texture3d";
 			break;
 			break;

+ 10 - 2
3rdparty/spirv-cross/spirv_msl.hpp

@@ -249,6 +249,9 @@ static const uint32_t kArgumentBufferBinding = ~(3u);
 
 
 static const uint32_t kMaxArgumentBuffers = 8;
 static const uint32_t kMaxArgumentBuffers = 8;
 
 
+// The arbitrary maximum for the nesting of array of array copies.
+static const uint32_t kArrayCopyMultidimMax = 6;
+
 // Decompiles SPIR-V to Metal Shading Language
 // Decompiles SPIR-V to Metal Shading Language
 class CompilerMSL : public CompilerGLSL
 class CompilerMSL : public CompilerGLSL
 {
 {
@@ -290,6 +293,7 @@ public:
 		bool swizzle_texture_samples = false;
 		bool swizzle_texture_samples = false;
 		bool tess_domain_origin_lower_left = false;
 		bool tess_domain_origin_lower_left = false;
 		bool multiview = false;
 		bool multiview = false;
+		bool multiview_layered_rendering = true;
 		bool view_index_from_device_index = false;
 		bool view_index_from_device_index = false;
 		bool dispatch_base = false;
 		bool dispatch_base = false;
 		bool texture_1D_as_2D = false;
 		bool texture_1D_as_2D = false;
@@ -347,6 +351,12 @@ public:
 		// to index the output buffer.
 		// to index the output buffer.
 		bool vertex_for_tessellation = false;
 		bool vertex_for_tessellation = false;
 
 
+		// Assume that SubpassData images have multiple layers. Layered input attachments
+		// are addressed relative to the Layer output from the vertex pipeline. This option
+		// has no effect with multiview, since all input attachments are assumed to be layered
+		// and will be addressed using the current ViewIndex.
+		bool arrayed_subpass_input = false;
+
 		enum class IndexType
 		enum class IndexType
 		{
 		{
 			None = 0,
 			None = 0,
@@ -614,8 +624,6 @@ protected:
 		SPVFuncImplConvertYCbCrBT601,
 		SPVFuncImplConvertYCbCrBT601,
 		SPVFuncImplConvertYCbCrBT2020,
 		SPVFuncImplConvertYCbCrBT2020,
 		SPVFuncImplDynamicImageSampler,
 		SPVFuncImplDynamicImageSampler,
-
-		SPVFuncImplArrayCopyMultidimMax = 6
 	};
 	};
 
 
 	// If the underlying resource has been used for comparison then duplicate loads of that resource must be too
 	// If the underlying resource has been used for comparison then duplicate loads of that resource must be too

+ 1 - 1
3rdparty/spirv-cross/spirv_reflect.cpp

@@ -647,7 +647,7 @@ void CompilerReflection::emit_specialization_constants()
 		return;
 		return;
 
 
 	json_stream->emit_json_key_array("specialization_constants");
 	json_stream->emit_json_key_array("specialization_constants");
-	for (const auto spec_const : specialization_constants)
+	for (const auto &spec_const : specialization_constants)
 	{
 	{
 		auto &c = get<SPIRConstant>(spec_const.id);
 		auto &c = get<SPIRConstant>(spec_const.id);
 		auto type = get<SPIRType>(c.constant_type);
 		auto type = get<SPIRType>(c.constant_type);