From 608eef3720cba1aeef9fa851f625ec8b380d71a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=91=D1=80=D0=B0=D0=BD=D0=B8=D0=BC=D0=B8=D1=80=20=D0=9A?= =?UTF-8?q?=D0=B0=D1=80=D0=B0=D1=9F=D0=B8=D1=9B?= Date: Fri, 20 Mar 2020 20:30:44 -0700 Subject: [PATCH] Updated spirv-cross. --- 3rdparty/spirv-cross/main.cpp | 22 ++- .../spirv-cross/spirv_cross_containers.hpp | 9 +- 3rdparty/spirv-cross/spirv_glsl.cpp | 141 +++++++++++++++++- 3rdparty/spirv-cross/spirv_glsl.hpp | 12 ++ 3rdparty/spirv-cross/spirv_hlsl.cpp | 12 +- 5 files changed, 173 insertions(+), 23 deletions(-) diff --git a/3rdparty/spirv-cross/main.cpp b/3rdparty/spirv-cross/main.cpp index 5b1b96e20..37575f9e5 100644 --- a/3rdparty/spirv-cross/main.cpp +++ b/3rdparty/spirv-cross/main.cpp @@ -525,6 +525,7 @@ struct CLIArguments bool msl_force_native_arrays = false; bool glsl_emit_push_constant_as_ubo = false; bool glsl_emit_ubo_as_plain_uniforms = false; + SmallVector> glsl_ext_framebuffer_fetch; bool vulkan_glsl_disable_ext_samplerless_texture_functions = false; bool emit_line_directives = false; bool enable_storage_image_qualifier_deduction = true; @@ -599,6 +600,7 @@ static void print_help() "\t[--disable-storage-image-qualifier-deduction]\n" "\t[--glsl-emit-push-constant-as-ubo]\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[--msl]\n" "\t[--msl-version ]\n" @@ -949,6 +951,9 @@ static string compile_iteration(const CLIArguments &args, std::vector opts.enable_storage_image_qualifier_deduction = args.enable_storage_image_qualifier_deduction; 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. 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("--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-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", [&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("--hlsl", [&args](CLIParser &) { args.hlsl = 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) { 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("-V", [&args](CLIParser &) { args.vulkan_semantics = 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(); 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("--rename-entry-point", [&args](CLIParser &parser) { auto old_name = parser.next_string(); diff --git a/3rdparty/spirv-cross/spirv_cross_containers.hpp b/3rdparty/spirv-cross/spirv_cross_containers.hpp index 327d6b6ca..f5760a0e0 100644 --- a/3rdparty/spirv-cross/spirv_cross_containers.hpp +++ b/3rdparty/spirv-cross/spirv_cross_containers.hpp @@ -202,8 +202,7 @@ public: 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); reserve(count); @@ -247,8 +246,7 @@ public: return *this; } - SmallVector(const SmallVector &other) SPIRV_CROSS_NOEXCEPT - : SmallVector() + SmallVector(const SmallVector &other) SPIRV_CROSS_NOEXCEPT : SmallVector() { *this = other; } @@ -266,8 +264,7 @@ public: return *this; } - explicit SmallVector(size_t count) SPIRV_CROSS_NOEXCEPT - : SmallVector() + explicit SmallVector(size_t count) SPIRV_CROSS_NOEXCEPT : SmallVector() { resize(count); } diff --git a/3rdparty/spirv-cross/spirv_glsl.cpp b/3rdparty/spirv-cross/spirv_glsl.cpp index 0afd9cef9..0009fc23e 100644 --- a/3rdparty/spirv-cross/spirv_glsl.cpp +++ b/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() { ir.for_each_typed_id([&](uint32_t, const SPIRType &type) { @@ -455,7 +461,20 @@ void CompilerGLSL::find_static_extensions() } 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"); + } + + 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) require_extension_internal("GL_ARB_separate_shader_objects"); @@ -519,6 +538,8 @@ string CompilerGLSL::compile() update_active_builtins(); analyze_image_and_sampler_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. // 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()) return ""; + if (subpass_input_is_framebuffer_fetch(var.self)) + return ""; + SmallVector attr; auto &type = get(var.basetype); @@ -2031,12 +2055,22 @@ const char *CompilerGLSL::to_storage_qualifiers_glsl(const SPIRVariable &var) { auto &execution = get_entry_point(); + if (subpass_input_is_framebuffer_fetch(var.self)) + return ""; + if (var.storage == StorageClassInput || var.storage == StorageClassOutput) { if (is_legacy() && execution.model == ExecutionModelVertex) return var.storage == StorageClassInput ? "attribute " : "varying "; else if (is_legacy() && execution.model == ExecutionModelFragment) 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 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) { auto &type = get(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) require_extension_internal("GL_ARB_shader_image_load_store"); @@ -3025,9 +3059,18 @@ void CompilerGLSL::emit_resources() ir.for_each_typed_id([&](uint32_t, SPIRVariable &var) { auto &type = this->get(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 && (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); emitted = true; @@ -3700,7 +3743,8 @@ string CompilerGLSL::constant_expression(const SPIRConstant &c) { 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) + "({ "; needs_trailing_tracket = true; @@ -8474,6 +8518,9 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) if (expr.expression_dependencies.empty()) forwarded_temporaries.erase(ops[1]); + if (has_decoration(ops[1], DecorationNonUniformEXT) || has_decoration(ops[2], DecorationNonUniformEXT)) + propagate_nonuniform_qualifier(ops[1]); + break; } @@ -8481,9 +8528,6 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) { auto *var = maybe_get(ops[0]); - if (has_decoration(ops[0], DecorationNonUniformEXT)) - propagate_nonuniform_qualifier(ops[0]); - if (var && var->statically_assigned) var->static_expression = ops[1]; 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) { - 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. if (type.image.ms) @@ -10088,7 +10136,11 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) target_coord_type.basetype = SPIRType::Int; coord_expr = bitcast_expression(target_coord_type, expression_type(ops[3]).basetype, coord_expr); - auto &e = set(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(id, expr, result_type, true); // When using the pointer, we need to know which variable it is actually loaded from. 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) 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(type.image.type); + sampled_type.vecsize = 4; + return type_to_glsl(sampled_type); + } // If we're emulating subpassInput with samplers, force sampler2D // 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); } } + +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([&](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([&](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(output_var->basetype))) + SPIRV_CROSS_THROW("Cannot use GL_EXT_shader_framebuffer_fetch with arrays of color outputs."); + + auto &func = get(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(output_var->basetype).vecsize; + statement(to_expression(subpass_var->self), vector_swizzle(num_rt_components, 0), " = ", + to_expression(output_var->self), ";"); + } + }); + } +} diff --git a/3rdparty/spirv-cross/spirv_glsl.hpp b/3rdparty/spirv-cross/spirv_glsl.hpp index da00c05df..5fca9a1a3 100644 --- a/3rdparty/spirv-cross/spirv_glsl.hpp +++ b/3rdparty/spirv-cross/spirv_glsl.hpp @@ -156,6 +156,10 @@ public: 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 spirv_) : Compiler(std::move(spirv_)) { @@ -663,6 +667,14 @@ protected: void emit_pls(); void remap_pls_variables(); + // GL_EXT_shader_framebuffer_fetch support. + std::vector> subpass_to_framebuffer_fetch_attachment; + std::unordered_set 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, // but the set is not updated when we have found a new name. // Used primarily when adding block interface names. diff --git a/3rdparty/spirv-cross/spirv_hlsl.cpp b/3rdparty/spirv-cross/spirv_hlsl.cpp index f3e63b068..5f7cc3929 100644 --- a/3rdparty/spirv-cross/spirv_hlsl.cpp +++ b/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]); add_implied_read_expression(e, ops[i]); } + + if (has_decoration(ops[1], DecorationNonUniformEXT) || has_decoration(ops[2], DecorationNonUniformEXT)) + propagate_nonuniform_qualifier(ops[1]); } else { @@ -4848,8 +4851,13 @@ void CompilerHLSL::emit_instruction(const Instruction &instruction) { uint32_t result_type = ops[0]; uint32_t id = ops[1]; - auto &e = - set(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(id, expr, result_type, true); // When using the pointer, we need to know which variable it is actually loaded from. auto *var = maybe_get_backing_variable(ops[2]);