Sfoglia il codice sorgente

Updated spirv-cross.

Бранимир Караџић 5 anni fa
parent
commit
608eef3720

+ 15 - 7
3rdparty/spirv-cross/main.cpp

@@ -525,6 +525,7 @@ struct CLIArguments
 	bool msl_force_native_arrays = 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;
+	SmallVector<pair<uint32_t, uint32_t>> glsl_ext_framebuffer_fetch;
 	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;
 	bool enable_storage_image_qualifier_deduction = true;
@@ -599,6 +600,7 @@ static void print_help()
 	                "\t[--disable-storage-image-qualifier-deduction]\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[--glsl-remap-ext-framebuffer-fetch input-attachment color-location]\n"
 	                "\t[--vulkan-glsl-disable-ext-samplerless-texture-functions]\n"
 	                "\t[--vulkan-glsl-disable-ext-samplerless-texture-functions]\n"
 	                "\t[--msl]\n"
 	                "\t[--msl]\n"
 	                "\t[--msl-version <MMmmpp>]\n"
 	                "\t[--msl-version <MMmmpp>]\n"
@@ -949,6 +951,9 @@ static string compile_iteration(const CLIArguments &args, std::vector<uint32_t>
 	opts.enable_storage_image_qualifier_deduction = args.enable_storage_image_qualifier_deduction;
 	opts.enable_storage_image_qualifier_deduction = args.enable_storage_image_qualifier_deduction;
 	compiler->set_common_options(opts);
 	compiler->set_common_options(opts);
 
 
+	for (auto &fetch : args.glsl_ext_framebuffer_fetch)
+		compiler->remap_ext_framebuffer_fetch(fetch.first, fetch.second);
+
 	// Set HLSL specific options.
 	// Set HLSL specific options.
 	if (args.hlsl)
 	if (args.hlsl)
 	{
 	{
@@ -1125,9 +1130,15 @@ static int main_inner(int argc, char *argv[])
 	cbs.add("--metal", [&args](CLIParser &) { args.msl = true; }); // Legacy compatibility
 	cbs.add("--metal", [&args](CLIParser &) { args.msl = true; }); // Legacy compatibility
 	cbs.add("--glsl-emit-push-constant-as-ubo", [&args](CLIParser &) { args.glsl_emit_push_constant_as_ubo = true; });
 	cbs.add("--glsl-emit-push-constant-as-ubo", [&args](CLIParser &) { args.glsl_emit_push_constant_as_ubo = true; });
 	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("--glsl-remap-ext-framebuffer-fetch", [&args](CLIParser &parser) {
+		uint32_t input_index = parser.next_uint();
+		uint32_t color_attachment = parser.next_uint();
+		args.glsl_ext_framebuffer_fetch.push_back({ input_index, color_attachment });
+	});
 	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("--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; });
@@ -1136,9 +1147,8 @@ 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("--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("-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; });
@@ -1178,9 +1188,7 @@ 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("--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();

+ 3 - 6
3rdparty/spirv-cross/spirv_cross_containers.hpp

@@ -202,8 +202,7 @@ public:
 		buffer_capacity = N;
 		buffer_capacity = N;
 	}
 	}
 
 
-	SmallVector(const T *arg_list_begin, const T *arg_list_end) SPIRV_CROSS_NOEXCEPT
-	    : SmallVector()
+	SmallVector(const T *arg_list_begin, const T *arg_list_end) SPIRV_CROSS_NOEXCEPT : SmallVector()
 	{
 	{
 		auto count = size_t(arg_list_end - arg_list_begin);
 		auto count = size_t(arg_list_end - arg_list_begin);
 		reserve(count);
 		reserve(count);
@@ -247,8 +246,7 @@ public:
 		return *this;
 		return *this;
 	}
 	}
 
 
-	SmallVector(const SmallVector &other) SPIRV_CROSS_NOEXCEPT
-	    : SmallVector()
+	SmallVector(const SmallVector &other) SPIRV_CROSS_NOEXCEPT : SmallVector()
 	{
 	{
 		*this = other;
 		*this = other;
 	}
 	}
@@ -266,8 +264,7 @@ public:
 		return *this;
 		return *this;
 	}
 	}
 
 
-	explicit SmallVector(size_t count) SPIRV_CROSS_NOEXCEPT
-	    : SmallVector()
+	explicit SmallVector(size_t count) SPIRV_CROSS_NOEXCEPT : SmallVector()
 	{
 	{
 		resize(count);
 		resize(count);
 	}
 	}

+ 133 - 8
3rdparty/spirv-cross/spirv_glsl.cpp

@@ -370,6 +370,12 @@ void CompilerGLSL::remap_pls_variables()
 	}
 	}
 }
 }
 
 
+void CompilerGLSL::remap_ext_framebuffer_fetch(uint32_t input_attachment_index, uint32_t color_location)
+{
+	subpass_to_framebuffer_fetch_attachment.push_back({ input_attachment_index, color_location });
+	inout_color_attachments.insert(color_location);
+}
+
 void CompilerGLSL::find_static_extensions()
 void CompilerGLSL::find_static_extensions()
 {
 {
 	ir.for_each_typed_id<SPIRType>([&](uint32_t, const SPIRType &type) {
 	ir.for_each_typed_id<SPIRType>([&](uint32_t, const SPIRType &type) {
@@ -455,7 +461,20 @@ void CompilerGLSL::find_static_extensions()
 	}
 	}
 
 
 	if (!pls_inputs.empty() || !pls_outputs.empty())
 	if (!pls_inputs.empty() || !pls_outputs.empty())
+	{
+		if (execution.model != ExecutionModelFragment)
+			SPIRV_CROSS_THROW("Can only use GL_EXT_shader_pixel_local_storage in fragment shaders.");
 		require_extension_internal("GL_EXT_shader_pixel_local_storage");
 		require_extension_internal("GL_EXT_shader_pixel_local_storage");
+	}
+
+	if (!inout_color_attachments.empty())
+	{
+		if (execution.model != ExecutionModelFragment)
+			SPIRV_CROSS_THROW("Can only use GL_EXT_shader_framebuffer_fetch in fragment shaders.");
+		if (options.vulkan_semantics)
+			SPIRV_CROSS_THROW("Cannot use EXT_shader_framebuffer_fetch in Vulkan GLSL.");
+		require_extension_internal("GL_EXT_shader_framebuffer_fetch");
+	}
 
 
 	if (options.separate_shader_objects && !options.es && options.version < 410)
 	if (options.separate_shader_objects && !options.es && options.version < 410)
 		require_extension_internal("GL_ARB_separate_shader_objects");
 		require_extension_internal("GL_ARB_separate_shader_objects");
@@ -519,6 +538,8 @@ string CompilerGLSL::compile()
 	update_active_builtins();
 	update_active_builtins();
 	analyze_image_and_sampler_usage();
 	analyze_image_and_sampler_usage();
 	analyze_interlocked_resource_usage();
 	analyze_interlocked_resource_usage();
+	if (!inout_color_attachments.empty())
+		emit_inout_fragment_outputs_copy_to_subpass_inputs();
 
 
 	// Shaders might cast unrelated data to pointers of non-block types.
 	// Shaders might cast unrelated data to pointers of non-block types.
 	// Find all such instances and make sure we can cast the pointers to a synthesized block type.
 	// Find all such instances and make sure we can cast the pointers to a synthesized block type.
@@ -1519,6 +1540,9 @@ string CompilerGLSL::layout_for_variable(const SPIRVariable &var)
 	if (is_legacy())
 	if (is_legacy())
 		return "";
 		return "";
 
 
+	if (subpass_input_is_framebuffer_fetch(var.self))
+		return "";
+
 	SmallVector<string> attr;
 	SmallVector<string> attr;
 
 
 	auto &type = get<SPIRType>(var.basetype);
 	auto &type = get<SPIRType>(var.basetype);
@@ -2031,12 +2055,22 @@ const char *CompilerGLSL::to_storage_qualifiers_glsl(const SPIRVariable &var)
 {
 {
 	auto &execution = get_entry_point();
 	auto &execution = get_entry_point();
 
 
+	if (subpass_input_is_framebuffer_fetch(var.self))
+		return "";
+
 	if (var.storage == StorageClassInput || var.storage == StorageClassOutput)
 	if (var.storage == StorageClassInput || var.storage == StorageClassOutput)
 	{
 	{
 		if (is_legacy() && execution.model == ExecutionModelVertex)
 		if (is_legacy() && execution.model == ExecutionModelVertex)
 			return var.storage == StorageClassInput ? "attribute " : "varying ";
 			return var.storage == StorageClassInput ? "attribute " : "varying ";
 		else if (is_legacy() && execution.model == ExecutionModelFragment)
 		else if (is_legacy() && execution.model == ExecutionModelFragment)
 			return "varying "; // Fragment outputs are renamed so they never hit this case.
 			return "varying "; // Fragment outputs are renamed so they never hit this case.
+		else if (execution.model == ExecutionModelFragment && var.storage == StorageClassOutput)
+		{
+			if (inout_color_attachments.count(get_decoration(var.self, DecorationLocation)) != 0)
+				return "inout ";
+			else
+				return "out ";
+		}
 		else
 		else
 			return var.storage == StorageClassInput ? "in " : "out ";
 			return var.storage == StorageClassInput ? "in " : "out ";
 	}
 	}
@@ -2229,7 +2263,7 @@ void CompilerGLSL::emit_interface_block(const SPIRVariable &var)
 void CompilerGLSL::emit_uniform(const SPIRVariable &var)
 void CompilerGLSL::emit_uniform(const SPIRVariable &var)
 {
 {
 	auto &type = get<SPIRType>(var.basetype);
 	auto &type = get<SPIRType>(var.basetype);
-	if (type.basetype == SPIRType::Image && type.image.sampled == 2)
+	if (type.basetype == SPIRType::Image && type.image.sampled == 2 && type.image.dim != DimSubpassData)
 	{
 	{
 		if (!options.es && options.version < 420)
 		if (!options.es && options.version < 420)
 			require_extension_internal("GL_ARB_shader_image_load_store");
 			require_extension_internal("GL_ARB_shader_image_load_store");
@@ -3025,9 +3059,18 @@ void CompilerGLSL::emit_resources()
 	ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
 	ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
 		auto &type = this->get<SPIRType>(var.basetype);
 		auto &type = this->get<SPIRType>(var.basetype);
 
 
+		bool is_hidden = is_hidden_variable(var);
+
+		// Unused output I/O variables might still be required to implement framebuffer fetch.
+		if (var.storage == StorageClassOutput && !is_legacy() &&
+		    inout_color_attachments.count(get_decoration(var.self, DecorationLocation)) != 0)
+		{
+			is_hidden = false;
+		}
+
 		if (var.storage != StorageClassFunction && type.pointer &&
 		if (var.storage != StorageClassFunction && type.pointer &&
 		    (var.storage == StorageClassInput || var.storage == StorageClassOutput) &&
 		    (var.storage == StorageClassInput || var.storage == StorageClassOutput) &&
-		    interface_variable_exists_in_entry_point(var.self) && !is_hidden_variable(var))
+		    interface_variable_exists_in_entry_point(var.self) && !is_hidden)
 		{
 		{
 			emit_interface_block(var);
 			emit_interface_block(var);
 			emitted = true;
 			emitted = true;
@@ -3700,7 +3743,8 @@ 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 && backend.array_is_value_type && !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;
@@ -8474,6 +8518,9 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
 		if (expr.expression_dependencies.empty())
 		if (expr.expression_dependencies.empty())
 			forwarded_temporaries.erase(ops[1]);
 			forwarded_temporaries.erase(ops[1]);
 
 
+		if (has_decoration(ops[1], DecorationNonUniformEXT) || has_decoration(ops[2], DecorationNonUniformEXT))
+			propagate_nonuniform_qualifier(ops[1]);
+
 		break;
 		break;
 	}
 	}
 
 
@@ -8481,9 +8528,6 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
 	{
 	{
 		auto *var = maybe_get<SPIRVariable>(ops[0]);
 		auto *var = maybe_get<SPIRVariable>(ops[0]);
 
 
-		if (has_decoration(ops[0], DecorationNonUniformEXT))
-			propagate_nonuniform_qualifier(ops[0]);
-
 		if (var && var->statically_assigned)
 		if (var && var->statically_assigned)
 			var->static_expression = ops[1];
 			var->static_expression = ops[1];
 		else if (var && var->loop_variable && !var->loop_variable_enable)
 		else if (var && var->loop_variable && !var->loop_variable_enable)
@@ -9992,7 +10036,11 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
 		}
 		}
 		else if (type.image.dim == DimSubpassData)
 		else if (type.image.dim == DimSubpassData)
 		{
 		{
-			if (options.vulkan_semantics)
+			if (var && subpass_input_is_framebuffer_fetch(var->self))
+			{
+				imgexpr = to_expression(var->self);
+			}
+			else if (options.vulkan_semantics)
 			{
 			{
 				// With Vulkan semantics, use the proper Vulkan GLSL construct.
 				// With Vulkan semantics, use the proper Vulkan GLSL construct.
 				if (type.image.ms)
 				if (type.image.ms)
@@ -10088,7 +10136,11 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
 		target_coord_type.basetype = SPIRType::Int;
 		target_coord_type.basetype = SPIRType::Int;
 		coord_expr = bitcast_expression(target_coord_type, expression_type(ops[3]).basetype, coord_expr);
 		coord_expr = bitcast_expression(target_coord_type, expression_type(ops[3]).basetype, coord_expr);
 
 
-		auto &e = set<SPIRExpression>(id, join(to_expression(ops[2]), ", ", coord_expr), result_type, true);
+		auto expr = join(to_expression(ops[2]), ", ", coord_expr);
+		if (has_decoration(id, DecorationNonUniformEXT) || has_decoration(ops[2], DecorationNonUniformEXT))
+			convert_non_uniform_expression(expression_type(ops[2]), expr);
+
+		auto &e = set<SPIRExpression>(id, expr, result_type, true);
 
 
 		// When using the pointer, we need to know which variable it is actually loaded from.
 		// When using the pointer, we need to know which variable it is actually loaded from.
 		auto *var = maybe_get_backing_variable(ops[2]);
 		auto *var = maybe_get_backing_variable(ops[2]);
@@ -11232,6 +11284,13 @@ string CompilerGLSL::image_type_glsl(const SPIRType &type, uint32_t id)
 
 
 	if (type.basetype == SPIRType::Image && type.image.dim == DimSubpassData && options.vulkan_semantics)
 	if (type.basetype == SPIRType::Image && type.image.dim == DimSubpassData && options.vulkan_semantics)
 		return res + "subpassInput" + (type.image.ms ? "MS" : "");
 		return res + "subpassInput" + (type.image.ms ? "MS" : "");
+	else if (type.basetype == SPIRType::Image && type.image.dim == DimSubpassData &&
+	         subpass_input_is_framebuffer_fetch(id))
+	{
+		SPIRType sampled_type = get<SPIRType>(type.image.type);
+		sampled_type.vecsize = 4;
+		return type_to_glsl(sampled_type);
+	}
 
 
 	// If we're emulating subpassInput with samplers, force sampler2D
 	// If we're emulating subpassInput with samplers, force sampler2D
 	// so we don't have to specify format.
 	// so we don't have to specify format.
@@ -13508,3 +13567,69 @@ void CompilerGLSL::emit_copy_logical_type(uint32_t lhs_id, uint32_t lhs_type_id,
 		emit_store_statement(lhs_id, rhs_id);
 		emit_store_statement(lhs_id, rhs_id);
 	}
 	}
 }
 }
+
+bool CompilerGLSL::subpass_input_is_framebuffer_fetch(uint32_t id) const
+{
+	if (!has_decoration(id, DecorationInputAttachmentIndex))
+		return false;
+
+	uint32_t input_attachment_index = get_decoration(id, DecorationInputAttachmentIndex);
+	for (auto &remap : subpass_to_framebuffer_fetch_attachment)
+		if (remap.first == input_attachment_index)
+			return true;
+
+	return false;
+}
+
+const SPIRVariable *CompilerGLSL::find_subpass_input_by_attachment_index(uint32_t index) const
+{
+	const SPIRVariable *ret = nullptr;
+	ir.for_each_typed_id<SPIRVariable>([&](uint32_t, const SPIRVariable &var) {
+		if (has_decoration(var.self, DecorationInputAttachmentIndex) &&
+		    get_decoration(var.self, DecorationInputAttachmentIndex) == index)
+		{
+			ret = &var;
+		}
+	});
+	return ret;
+}
+
+const SPIRVariable *CompilerGLSL::find_color_output_by_location(uint32_t location) const
+{
+	const SPIRVariable *ret = nullptr;
+	ir.for_each_typed_id<SPIRVariable>([&](uint32_t, const SPIRVariable &var) {
+		if (var.storage == StorageClassOutput && get_decoration(var.self, DecorationLocation) == location)
+			ret = &var;
+	});
+	return ret;
+}
+
+void CompilerGLSL::emit_inout_fragment_outputs_copy_to_subpass_inputs()
+{
+	for (auto &remap : subpass_to_framebuffer_fetch_attachment)
+	{
+		auto *subpass_var = find_subpass_input_by_attachment_index(remap.first);
+		auto *output_var = find_color_output_by_location(remap.second);
+		if (!subpass_var)
+			continue;
+		if (!output_var)
+			SPIRV_CROSS_THROW("Need to declare the corresponding fragment output variable to be able to read from it.");
+		if (is_array(get<SPIRType>(output_var->basetype)))
+			SPIRV_CROSS_THROW("Cannot use GL_EXT_shader_framebuffer_fetch with arrays of color outputs.");
+
+		auto &func = get<SPIRFunction>(get_entry_point().self);
+		func.fixup_hooks_in.push_back([=]() {
+			if (is_legacy())
+			{
+				statement(to_expression(subpass_var->self), " = ", "gl_LastFragData[",
+				          get_decoration(output_var->self, DecorationLocation), "];");
+			}
+			else
+			{
+				uint32_t num_rt_components = this->get<SPIRType>(output_var->basetype).vecsize;
+				statement(to_expression(subpass_var->self), vector_swizzle(num_rt_components, 0), " = ",
+				          to_expression(output_var->self), ";");
+			}
+		});
+	}
+}

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

@@ -156,6 +156,10 @@ public:
 		remap_pls_variables();
 		remap_pls_variables();
 	}
 	}
 
 
+	// Redirect a subpassInput reading from input_attachment_index to instead load its value from
+	// the color attachment at location = color_location. Requires ESSL.
+	void remap_ext_framebuffer_fetch(uint32_t input_attachment_index, uint32_t color_location);
+
 	explicit CompilerGLSL(std::vector<uint32_t> spirv_)
 	explicit CompilerGLSL(std::vector<uint32_t> spirv_)
 	    : Compiler(std::move(spirv_))
 	    : Compiler(std::move(spirv_))
 	{
 	{
@@ -663,6 +667,14 @@ protected:
 	void emit_pls();
 	void emit_pls();
 	void remap_pls_variables();
 	void remap_pls_variables();
 
 
+	// GL_EXT_shader_framebuffer_fetch support.
+	std::vector<std::pair<uint32_t, uint32_t>> subpass_to_framebuffer_fetch_attachment;
+	std::unordered_set<uint32_t> inout_color_attachments;
+	bool subpass_input_is_framebuffer_fetch(uint32_t id) const;
+	void emit_inout_fragment_outputs_copy_to_subpass_inputs();
+	const SPIRVariable *find_subpass_input_by_attachment_index(uint32_t index) const;
+	const SPIRVariable *find_color_output_by_location(uint32_t location) const;
+
 	// A variant which takes two sets of name. The secondary is only used to verify there are no collisions,
 	// A variant which takes two sets of name. The secondary is only used to verify there are no collisions,
 	// but the set is not updated when we have found a new name.
 	// but the set is not updated when we have found a new name.
 	// Used primarily when adding block interface names.
 	// Used primarily when adding block interface names.

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

@@ -4010,6 +4010,9 @@ void CompilerHLSL::emit_access_chain(const Instruction &instruction)
 			inherit_expression_dependencies(ops[1], ops[i]);
 			inherit_expression_dependencies(ops[1], ops[i]);
 			add_implied_read_expression(e, ops[i]);
 			add_implied_read_expression(e, ops[i]);
 		}
 		}
+
+		if (has_decoration(ops[1], DecorationNonUniformEXT) || has_decoration(ops[2], DecorationNonUniformEXT))
+			propagate_nonuniform_qualifier(ops[1]);
 	}
 	}
 	else
 	else
 	{
 	{
@@ -4848,8 +4851,13 @@ void CompilerHLSL::emit_instruction(const Instruction &instruction)
 	{
 	{
 		uint32_t result_type = ops[0];
 		uint32_t result_type = ops[0];
 		uint32_t id = ops[1];
 		uint32_t id = ops[1];
-		auto &e =
-		    set<SPIRExpression>(id, join(to_expression(ops[2]), "[", to_expression(ops[3]), "]"), result_type, true);
+
+		auto expr = to_expression(ops[2]);
+		if (has_decoration(id, DecorationNonUniformEXT) || has_decoration(ops[2], DecorationNonUniformEXT))
+			convert_non_uniform_expression(expression_type(ops[2]), expr);
+		expr += join("[", to_expression(ops[3]), "]");
+
+		auto &e = set<SPIRExpression>(id, expr, result_type, true);
 
 
 		// When using the pointer, we need to know which variable it is actually loaded from.
 		// When using the pointer, we need to know which variable it is actually loaded from.
 		auto *var = maybe_get_backing_variable(ops[2]);
 		auto *var = maybe_get_backing_variable(ops[2]);