From 18a594a76bdf47b6d35cc3aa9aa4f187924e374a Mon Sep 17 00:00:00 2001 From: Hans-Kristian Arntzen Date: Fri, 9 Feb 2018 10:26:20 +0100 Subject: [PATCH 1/5] Implement subpass input support in HLSL. --- .../frag/input-attachment-ms.frag | 32 ++++++++++ .../shaders-hlsl/frag/input-attachment.frag | 29 +++++++++ .../frag/input-attachment-ms.frag | 37 +++++++++++ .../shaders-hlsl/frag/input-attachment.frag | 34 ++++++++++ shaders-hlsl/frag/input-attachment-ms.frag | 15 +++++ shaders-hlsl/frag/input-attachment.frag | 16 +++++ spirv_cross.cpp | 22 ++++++- spirv_cross.hpp | 9 ++- spirv_glsl.cpp | 2 +- spirv_hlsl.cpp | 62 +++++++++++++++---- 10 files changed, 242 insertions(+), 16 deletions(-) create mode 100644 reference/opt/shaders-hlsl/frag/input-attachment-ms.frag create mode 100644 reference/opt/shaders-hlsl/frag/input-attachment.frag create mode 100644 reference/shaders-hlsl/frag/input-attachment-ms.frag create mode 100644 reference/shaders-hlsl/frag/input-attachment.frag create mode 100644 shaders-hlsl/frag/input-attachment-ms.frag create mode 100644 shaders-hlsl/frag/input-attachment.frag diff --git a/reference/opt/shaders-hlsl/frag/input-attachment-ms.frag b/reference/opt/shaders-hlsl/frag/input-attachment-ms.frag new file mode 100644 index 00000000..e206b837 --- /dev/null +++ b/reference/opt/shaders-hlsl/frag/input-attachment-ms.frag @@ -0,0 +1,32 @@ +Texture2DMS uSubpass0 : register(t0); +Texture2DMS uSubpass1 : register(t1); + +static float4 gl_FragCoord; +static int gl_SampleID; +static float4 FragColor; + +struct SPIRV_Cross_Input +{ + float4 gl_FragCoord : SV_Position; + uint gl_SampleID : SV_SampleIndex; +}; + +struct SPIRV_Cross_Output +{ + float4 FragColor : SV_Target0; +}; + +void frag_main() +{ + FragColor = (uSubpass0.Load(int2(gl_FragCoord.xy), 1) + uSubpass1.Load(int2(gl_FragCoord.xy), 2)) + uSubpass0.Load(int2(gl_FragCoord.xy), gl_SampleID); +} + +SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input) +{ + gl_FragCoord = stage_input.gl_FragCoord; + gl_SampleID = stage_input.gl_SampleID; + frag_main(); + SPIRV_Cross_Output stage_output; + stage_output.FragColor = FragColor; + return stage_output; +} diff --git a/reference/opt/shaders-hlsl/frag/input-attachment.frag b/reference/opt/shaders-hlsl/frag/input-attachment.frag new file mode 100644 index 00000000..d87661e5 --- /dev/null +++ b/reference/opt/shaders-hlsl/frag/input-attachment.frag @@ -0,0 +1,29 @@ +Texture2D uSubpass0 : register(t0); +Texture2D uSubpass1 : register(t1); + +static float4 gl_FragCoord; +static float4 FragColor; + +struct SPIRV_Cross_Input +{ + float4 gl_FragCoord : SV_Position; +}; + +struct SPIRV_Cross_Output +{ + float4 FragColor : SV_Target0; +}; + +void frag_main() +{ + FragColor = uSubpass0.Load(int3(int2(gl_FragCoord.xy), 0)) + uSubpass1.Load(int3(int2(gl_FragCoord.xy), 0)); +} + +SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input) +{ + gl_FragCoord = stage_input.gl_FragCoord; + frag_main(); + SPIRV_Cross_Output stage_output; + stage_output.FragColor = FragColor; + return stage_output; +} diff --git a/reference/shaders-hlsl/frag/input-attachment-ms.frag b/reference/shaders-hlsl/frag/input-attachment-ms.frag new file mode 100644 index 00000000..130b7996 --- /dev/null +++ b/reference/shaders-hlsl/frag/input-attachment-ms.frag @@ -0,0 +1,37 @@ +Texture2DMS uSubpass0 : register(t0); +Texture2DMS uSubpass1 : register(t1); + +static float4 gl_FragCoord; +static int gl_SampleID; +static float4 FragColor; + +struct SPIRV_Cross_Input +{ + float4 gl_FragCoord : SV_Position; + uint gl_SampleID : SV_SampleIndex; +}; + +struct SPIRV_Cross_Output +{ + float4 FragColor : SV_Target0; +}; + +float4 load_subpasses(Texture2DMS uInput) +{ + return uInput.Load(int2(gl_FragCoord.xy), gl_SampleID); +} + +void frag_main() +{ + FragColor = (uSubpass0.Load(int2(gl_FragCoord.xy), 1) + uSubpass1.Load(int2(gl_FragCoord.xy), 2)) + load_subpasses(uSubpass0); +} + +SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input) +{ + gl_FragCoord = stage_input.gl_FragCoord; + gl_SampleID = stage_input.gl_SampleID; + frag_main(); + SPIRV_Cross_Output stage_output; + stage_output.FragColor = FragColor; + return stage_output; +} diff --git a/reference/shaders-hlsl/frag/input-attachment.frag b/reference/shaders-hlsl/frag/input-attachment.frag new file mode 100644 index 00000000..0b815ae0 --- /dev/null +++ b/reference/shaders-hlsl/frag/input-attachment.frag @@ -0,0 +1,34 @@ +Texture2D uSubpass0 : register(t0); +Texture2D uSubpass1 : register(t1); + +static float4 gl_FragCoord; +static float4 FragColor; + +struct SPIRV_Cross_Input +{ + float4 gl_FragCoord : SV_Position; +}; + +struct SPIRV_Cross_Output +{ + float4 FragColor : SV_Target0; +}; + +float4 load_subpasses(Texture2D uInput) +{ + return uInput.Load(int3(int2(gl_FragCoord.xy), 0)); +} + +void frag_main() +{ + FragColor = uSubpass0.Load(int3(int2(gl_FragCoord.xy), 0)) + load_subpasses(uSubpass1); +} + +SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input) +{ + gl_FragCoord = stage_input.gl_FragCoord; + frag_main(); + SPIRV_Cross_Output stage_output; + stage_output.FragColor = FragColor; + return stage_output; +} diff --git a/shaders-hlsl/frag/input-attachment-ms.frag b/shaders-hlsl/frag/input-attachment-ms.frag new file mode 100644 index 00000000..b3d44c94 --- /dev/null +++ b/shaders-hlsl/frag/input-attachment-ms.frag @@ -0,0 +1,15 @@ +#version 450 + +layout(input_attachment_index = 0, set = 0, binding = 0) uniform subpassInputMS uSubpass0; +layout(input_attachment_index = 1, set = 0, binding = 1) uniform subpassInputMS uSubpass1; +layout(location = 0) out vec4 FragColor; + +vec4 load_subpasses(mediump subpassInputMS uInput) +{ + return subpassLoad(uInput, gl_SampleID); +} + +void main() +{ + FragColor = subpassLoad(uSubpass0, 1) + subpassLoad(uSubpass1, 2) + load_subpasses(uSubpass0); +} diff --git a/shaders-hlsl/frag/input-attachment.frag b/shaders-hlsl/frag/input-attachment.frag new file mode 100644 index 00000000..877d0525 --- /dev/null +++ b/shaders-hlsl/frag/input-attachment.frag @@ -0,0 +1,16 @@ +#version 310 es +precision mediump float; + +layout(input_attachment_index = 0, set = 0, binding = 0) uniform mediump subpassInput uSubpass0; +layout(input_attachment_index = 1, set = 0, binding = 1) uniform mediump subpassInput uSubpass1; +layout(location = 0) out vec4 FragColor; + +vec4 load_subpasses(mediump subpassInput uInput) +{ + return subpassLoad(uInput); +} + +void main() +{ + FragColor = subpassLoad(uSubpass0) + load_subpasses(uSubpass1); +} diff --git a/spirv_cross.cpp b/spirv_cross.cpp index d0462104..d1b9a65c 100644 --- a/spirv_cross.cpp +++ b/spirv_cross.cpp @@ -3752,11 +3752,13 @@ bool Compiler::has_active_builtin(BuiltIn builtin, StorageClass storage) return flags & (1ull << builtin); } -void Compiler::analyze_sampler_comparison_states() +void Compiler::analyze_image_and_sampler_usage() { CombinedImageSamplerUsageHandler handler(*this); traverse_all_reachable_opcodes(get(entry_point), handler); comparison_samplers = move(handler.comparison_samplers); + comparison_images = move(handler.comparison_images); + need_subpass_input = handler.need_subpass_input; } bool Compiler::CombinedImageSamplerUsageHandler::begin_function_scope(const uint32_t *args, uint32_t length) @@ -3777,6 +3779,14 @@ bool Compiler::CombinedImageSamplerUsageHandler::begin_function_scope(const uint return true; } +void Compiler::CombinedImageSamplerUsageHandler::add_hierarchy_to_comparison_images(uint32_t image) +{ + // Traverse the variable dependency hierarchy and tag everything in its path with comparison samplers. + comparison_images.insert(image); + for (auto &img : dependency_hierarchy[image]) + add_hierarchy_to_comparison_samplers(img); +} + void Compiler::CombinedImageSamplerUsageHandler::add_hierarchy_to_comparison_samplers(uint32_t sampler) { // Traverse the variable dependency hierarchy and tag everything in its path with comparison samplers. @@ -3796,6 +3806,12 @@ bool Compiler::CombinedImageSamplerUsageHandler::handle(Op opcode, const uint32_ if (length < 3) return false; dependency_hierarchy[args[1]].insert(args[2]); + + // Ideally defer this to OpImageRead, but then we'd need to track loaded IDs. + // If we load an image, we're going to use it and there is little harm in declaring an unused gl_FragCoord. + auto &type = compiler.get(args[0]); + if (type.image.dim == DimSubpassData) + need_subpass_input = true; break; } @@ -3808,6 +3824,10 @@ bool Compiler::CombinedImageSamplerUsageHandler::handle(Op opcode, const uint32_ auto &type = compiler.get(result_type); if (type.image.depth) { + // This image must be a depth image. + uint32_t image = args[2]; + add_hierarchy_to_comparison_images(image); + // This sampler must be a SamplerComparisionState, and not a regular SamplerState. uint32_t sampler = args[3]; add_hierarchy_to_comparison_samplers(sampler); diff --git a/spirv_cross.hpp b/spirv_cross.hpp index c477ea95..7e613f91 100644 --- a/spirv_cross.hpp +++ b/spirv_cross.hpp @@ -720,8 +720,12 @@ protected: // SPIR-V does not support this distinction, so we must keep track of this information outside the type system. // There might be unrelated IDs found in this set which do not correspond to actual variables. // This set should only be queried for the existence of samplers which are already known to be variables or parameter IDs. + // Similar is implemented for images, as well as if subpass inputs are needed. std::unordered_set comparison_samplers; - void analyze_sampler_comparison_states(); + std::unordered_set comparison_images; + bool need_subpass_input = false; + + void analyze_image_and_sampler_usage(); struct CombinedImageSamplerUsageHandler : OpcodeHandler { CombinedImageSamplerUsageHandler(Compiler &compiler_) @@ -734,9 +738,12 @@ protected: Compiler &compiler; std::unordered_map> dependency_hierarchy; + std::unordered_set comparison_images; std::unordered_set comparison_samplers; void add_hierarchy_to_comparison_samplers(uint32_t sampler); + void add_hierarchy_to_comparison_images(uint32_t sampler); + bool need_subpass_input = false; }; void make_constant_null(uint32_t id, uint32_t type); diff --git a/spirv_glsl.cpp b/spirv_glsl.cpp index a2f218b9..bbc14b81 100644 --- a/spirv_glsl.cpp +++ b/spirv_glsl.cpp @@ -376,7 +376,7 @@ string CompilerGLSL::compile() find_static_extensions(); fixup_image_load_store_access(); update_active_builtins(); - analyze_sampler_comparison_states(); + analyze_image_and_sampler_usage(); uint32_t pass_count = 0; do diff --git a/spirv_hlsl.cpp b/spirv_hlsl.cpp index edae89c0..774d30e1 100644 --- a/spirv_hlsl.cpp +++ b/spirv_hlsl.cpp @@ -260,8 +260,9 @@ string CompilerHLSL::image_type_hlsl_modern(const SPIRType &type) else SPIRV_CROSS_THROW("Sampler buffers must be either sampled or unsampled. Cannot deduce in runtime."); case DimSubpassData: - // This should be implemented same way as desktop GL. Fetch on a 2D texture based on int2(SV_Position). - SPIRV_CROSS_THROW("Subpass data support is not yet implemented for HLSL"); // TODO + dim = "2D"; + typed_load = false; + break; default: SPIRV_CROSS_THROW("Invalid dimension."); } @@ -2402,7 +2403,7 @@ string CompilerHLSL::to_resource_binding(const SPIRVariable &var) break; case SPIRType::Image: - if (type.image.sampled == 2) + if (type.image.sampled == 2 && type.image.dim != DimSubpassData) space = 'u'; // UAV else space = 't'; // SRV @@ -3483,21 +3484,52 @@ void CompilerHLSL::emit_instruction(const Instruction &instruction) uint32_t result_type = ops[0]; uint32_t id = ops[1]; auto *var = maybe_get_backing_variable(ops[2]); - auto imgexpr = join(to_expression(ops[2]), "[", to_expression(ops[3]), "]"); + auto &type = expression_type(ops[2]); + bool subpass_data = type.image.dim == DimSubpassData; + bool pure = false; - // The underlying image type in HLSL depends on the image format, unlike GLSL, where all images are "vec4", - // except that the underlying type changes how the data is interpreted. - if (var) - imgexpr = remap_swizzle(get(result_type), - image_format_to_components(get(var->basetype).image.format), imgexpr); + string imgexpr; + + if (subpass_data) + { + if (options.shader_model < 40) + SPIRV_CROSS_THROW("Subpass loads are not supported in HLSL shader model 2/3."); + + // Similar to GLSL, implement subpass loads using texelFetch. + if (type.image.ms) + { + uint32_t operands = ops[4]; + if (operands != ImageOperandsSampleMask || instruction.length != 6) + SPIRV_CROSS_THROW("Multisampled image used in OpImageRead, but unexpected operand mask was used."); + uint32_t sample = ops[5]; + imgexpr = join(to_expression(ops[2]), ".Load(int2(gl_FragCoord.xy), ", to_expression(sample), ")"); + } + else + imgexpr = join(to_expression(ops[2]), ".Load(int3(int2(gl_FragCoord.xy), 0))"); + + pure = true; + } + else + { + imgexpr = join(to_expression(ops[2]), "[", to_expression(ops[3]), "]"); + // The underlying image type in HLSL depends on the image format, unlike GLSL, where all images are "vec4", + // except that the underlying type changes how the data is interpreted. + if (var && !subpass_data) + imgexpr = remap_swizzle(get(result_type), + image_format_to_components(get(var->basetype).image.format), imgexpr); + } if (var && var->forwardable) { bool forward = forced_temporaries.find(id) == end(forced_temporaries); auto &e = emit_op(result_type, id, imgexpr, forward); - e.loaded_from = var->self; - if (forward) - var->dependees.push_back(id); + + if (!pure) + { + e.loaded_from = var->self; + if (forward) + var->dependees.push_back(id); + } } else emit_op(result_type, id, imgexpr, false); @@ -3826,7 +3858,11 @@ string CompilerHLSL::compile() backend.can_return_array = false; update_active_builtins(); - analyze_sampler_comparison_states(); + analyze_image_and_sampler_usage(); + + // Subpass input needs SV_Position. + if (need_subpass_input) + active_input_builtins |= 1ull << BuiltInFragCoord; uint32_t pass_count = 0; do From 0912427046f03e7ea77c1ff7d1179fe25729843a Mon Sep 17 00:00:00 2001 From: Hans-Kristian Arntzen Date: Fri, 9 Feb 2018 11:27:23 +0100 Subject: [PATCH 2/5] Begin implementing subpassLoad in MSL. --- spirv_msl.cpp | 77 +++++++++++++++++++++++++++++++++++++++++++++++---- spirv_msl.hpp | 1 + 2 files changed, 72 insertions(+), 6 deletions(-) diff --git a/spirv_msl.cpp b/spirv_msl.cpp index 71a32b5e..b1b3ff4d 100644 --- a/spirv_msl.cpp +++ b/spirv_msl.cpp @@ -52,6 +52,55 @@ CompilerMSL::CompilerMSL(const uint32_t *ir, size_t word_count, MSLVertexAttr *p resource_bindings.push_back(&p_res_bindings[i]); } +void CompilerMSL::build_implicit_builtins() +{ + if (need_subpass_input) + { + bool has_frag_coord = false; + + for (auto &id : ids) + { + if (id.get_type() != TypeVariable) + continue; + + auto &var = id.get(); + + if (var.storage == StorageClassInput && + meta[var.self].decoration.builtin && + meta[var.self].decoration.builtin_type == BuiltInFragCoord) + { + has_frag_coord = true; + break; + } + } + + if (!has_frag_coord) + { + uint32_t offset = 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.vecsize = 4; + set(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(type_ptr_id, vec4_type_ptr); + ptr_type.self = offset; + + set(var_id, type_ptr_id, StorageClassInput); + set_decoration(var_id, DecorationBuiltIn, BuiltInFragCoord); + } + } +} + string CompilerMSL::compile() { // Force a classic "C" locale, reverts when function returns @@ -60,7 +109,7 @@ string CompilerMSL::compile() // Do not deal with GLES-isms like precision, older extensions and such. CompilerGLSL::options.vulkan_semantics = true; CompilerGLSL::options.es = false; - CompilerGLSL::options.version = 120; + CompilerGLSL::options.version = 450; backend.float_literal_suffix = false; backend.uint32_t_literal_suffix = true; backend.basic_int_type = "int"; @@ -81,6 +130,9 @@ string CompilerMSL::compile() struct_member_padding.clear(); update_active_builtins(); + analyze_image_and_sampler_usage(); + build_implicit_builtins(); + fixup_image_load_store_access(); set_enabled_interface_variables(get_active_interface_variables()); @@ -273,6 +325,7 @@ void CompilerMSL::extract_global_variables_from_function(uint32_t func_id, std:: switch (op) { case OpLoad: + case OpInBoundsAccessChain: case OpAccessChain: { uint32_t base_id = ops[2]; @@ -1462,11 +1515,15 @@ void CompilerMSL::emit_instruction(const Instruction &instruction) { // Mark that this shader reads from this image uint32_t img_id = ops[2]; - auto *p_var = maybe_get_backing_variable(img_id); - if (p_var && has_decoration(p_var->self, DecorationNonReadable)) + auto &type = expression_type(img_id); + if (type.image.dim != DimSubpassData) { - unset_decoration(p_var->self, DecorationNonReadable); - force_recompile = true; + auto *p_var = maybe_get_backing_variable(img_id); + if (p_var && has_decoration(p_var->self, DecorationNonReadable)) + { + unset_decoration(p_var->self, DecorationNonReadable); + force_recompile = true; + } } emit_texture_op(instruction); @@ -2141,6 +2198,13 @@ string CompilerMSL::to_function_args(uint32_t img, const SPIRType &imgtype, bool break; + case DimSubpassData: + if (imgtype.image.ms) + tex_coords = "uint2(gl_FragCoord.xy)"; + else + tex_coords = join("uint2(gl_FragCoord.xy), 0"); + break; + case Dim2D: if (coord_type.vecsize > 2) tex_coords += ".xy"; @@ -3192,6 +3256,7 @@ string CompilerMSL::image_type_glsl(const SPIRType &type, uint32_t id) break; case DimBuffer: case Dim2D: + case DimSubpassData: img_type_name += (img_type.ms ? "texture2d_ms" : (img_type.arrayed ? "texture2d_array" : "texture2d")); break; case Dim3D: @@ -3213,7 +3278,7 @@ string CompilerMSL::image_type_glsl(const SPIRType &type, uint32_t id) // For unsampled images, append the sample/read/write access qualifier. // For kernel images, the access qualifier my be supplied directly by SPIR-V. // Otherwise it may be set based on whether the image is read from or written to within the shader. - if (type.basetype == SPIRType::Image && type.image.sampled == 2) + if (type.basetype == SPIRType::Image && type.image.sampled == 2 && type.image.dim != DimSubpassData) { switch (img_type.access) { diff --git a/spirv_msl.hpp b/spirv_msl.hpp index f54839fb..d3ee4652 100644 --- a/spirv_msl.hpp +++ b/spirv_msl.hpp @@ -267,6 +267,7 @@ protected: void add_pragma_line(const std::string &line); void emit_barrier(uint32_t id_exe_scope, uint32_t id_mem_scope, uint32_t id_mem_sem); void emit_array_copy(const std::string &lhs, uint32_t rhs_id) override; + void build_implicit_builtins(); Options options; std::set spv_function_implementations; From 702e08671b142c7943af3bf80fcd685427c70eda Mon Sep 17 00:00:00 2001 From: Hans-Kristian Arntzen Date: Fri, 9 Feb 2018 12:13:33 +0100 Subject: [PATCH 3/5] Support passing implicit frag_coord arguments down to functions. --- .../shaders-msl/frag/input-attachment-ms.frag | 17 +++++++++++++ .../shaders-msl/frag/input-attachment.frag | 17 +++++++++++++ .../shaders-msl/frag/input-attachment-ms.frag | 24 +++++++++++++++++++ .../shaders-msl/frag/input-attachment.frag | 24 +++++++++++++++++++ shaders-msl/frag/input-attachment-ms.frag | 15 ++++++++++++ shaders-msl/frag/input-attachment.frag | 16 +++++++++++++ spirv_msl.cpp | 20 ++++++++++++---- spirv_msl.hpp | 1 + 8 files changed, 130 insertions(+), 4 deletions(-) create mode 100644 reference/opt/shaders-msl/frag/input-attachment-ms.frag create mode 100644 reference/opt/shaders-msl/frag/input-attachment.frag create mode 100644 reference/shaders-msl/frag/input-attachment-ms.frag create mode 100644 reference/shaders-msl/frag/input-attachment.frag create mode 100644 shaders-msl/frag/input-attachment-ms.frag create mode 100644 shaders-msl/frag/input-attachment.frag diff --git a/reference/opt/shaders-msl/frag/input-attachment-ms.frag b/reference/opt/shaders-msl/frag/input-attachment-ms.frag new file mode 100644 index 00000000..906cabbf --- /dev/null +++ b/reference/opt/shaders-msl/frag/input-attachment-ms.frag @@ -0,0 +1,17 @@ +#include +#include + +using namespace metal; + +struct main0_out +{ + float4 FragColor [[color(0)]]; +}; + +fragment main0_out main0(texture2d_ms uSubpass0 [[texture(0)]], texture2d_ms uSubpass1 [[texture(1)]], uint gl_SampleID [[sample_id]], float4 gl_FragCoord [[position]]) +{ + main0_out out = {}; + out.FragColor = (uSubpass0.read(uint2(gl_FragCoord.xy), 1) + uSubpass1.read(uint2(gl_FragCoord.xy), 2)) + uSubpass0.read(uint2(gl_FragCoord.xy), gl_SampleID); + return out; +} + diff --git a/reference/opt/shaders-msl/frag/input-attachment.frag b/reference/opt/shaders-msl/frag/input-attachment.frag new file mode 100644 index 00000000..12219064 --- /dev/null +++ b/reference/opt/shaders-msl/frag/input-attachment.frag @@ -0,0 +1,17 @@ +#include +#include + +using namespace metal; + +struct main0_out +{ + float4 FragColor [[color(0)]]; +}; + +fragment main0_out main0(texture2d uSubpass0 [[texture(0)]], texture2d uSubpass1 [[texture(1)]], float4 gl_FragCoord [[position]]) +{ + main0_out out = {}; + out.FragColor = uSubpass0.read(uint2(gl_FragCoord.xy), 0) + uSubpass1.read(uint2(gl_FragCoord.xy), 0); + return out; +} + diff --git a/reference/shaders-msl/frag/input-attachment-ms.frag b/reference/shaders-msl/frag/input-attachment-ms.frag new file mode 100644 index 00000000..d38712e9 --- /dev/null +++ b/reference/shaders-msl/frag/input-attachment-ms.frag @@ -0,0 +1,24 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" + +#include +#include + +using namespace metal; + +struct main0_out +{ + float4 FragColor [[color(0)]]; +}; + +float4 load_subpasses(thread const texture2d_ms uInput, thread uint& gl_SampleID, thread float4& gl_FragCoord) +{ + return uInput.read(uint2(gl_FragCoord.xy), gl_SampleID); +} + +fragment main0_out main0(texture2d_ms uSubpass0 [[texture(0)]], texture2d_ms uSubpass1 [[texture(1)]], uint gl_SampleID [[sample_id]], float4 gl_FragCoord [[position]]) +{ + main0_out out = {}; + out.FragColor = (uSubpass0.read(uint2(gl_FragCoord.xy), 1) + uSubpass1.read(uint2(gl_FragCoord.xy), 2)) + load_subpasses(uSubpass0, gl_SampleID, gl_FragCoord); + return out; +} + diff --git a/reference/shaders-msl/frag/input-attachment.frag b/reference/shaders-msl/frag/input-attachment.frag new file mode 100644 index 00000000..3cc92918 --- /dev/null +++ b/reference/shaders-msl/frag/input-attachment.frag @@ -0,0 +1,24 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" + +#include +#include + +using namespace metal; + +struct main0_out +{ + float4 FragColor [[color(0)]]; +}; + +float4 load_subpasses(thread const texture2d uInput, thread float4& gl_FragCoord) +{ + return uInput.read(uint2(gl_FragCoord.xy), 0); +} + +fragment main0_out main0(texture2d uSubpass0 [[texture(0)]], texture2d uSubpass1 [[texture(1)]], float4 gl_FragCoord [[position]]) +{ + main0_out out = {}; + out.FragColor = uSubpass0.read(uint2(gl_FragCoord.xy), 0) + load_subpasses(uSubpass1, gl_FragCoord); + return out; +} + diff --git a/shaders-msl/frag/input-attachment-ms.frag b/shaders-msl/frag/input-attachment-ms.frag new file mode 100644 index 00000000..b3d44c94 --- /dev/null +++ b/shaders-msl/frag/input-attachment-ms.frag @@ -0,0 +1,15 @@ +#version 450 + +layout(input_attachment_index = 0, set = 0, binding = 0) uniform subpassInputMS uSubpass0; +layout(input_attachment_index = 1, set = 0, binding = 1) uniform subpassInputMS uSubpass1; +layout(location = 0) out vec4 FragColor; + +vec4 load_subpasses(mediump subpassInputMS uInput) +{ + return subpassLoad(uInput, gl_SampleID); +} + +void main() +{ + FragColor = subpassLoad(uSubpass0, 1) + subpassLoad(uSubpass1, 2) + load_subpasses(uSubpass0); +} diff --git a/shaders-msl/frag/input-attachment.frag b/shaders-msl/frag/input-attachment.frag new file mode 100644 index 00000000..877d0525 --- /dev/null +++ b/shaders-msl/frag/input-attachment.frag @@ -0,0 +1,16 @@ +#version 310 es +precision mediump float; + +layout(input_attachment_index = 0, set = 0, binding = 0) uniform mediump subpassInput uSubpass0; +layout(input_attachment_index = 1, set = 0, binding = 1) uniform mediump subpassInput uSubpass1; +layout(location = 0) out vec4 FragColor; + +vec4 load_subpasses(mediump subpassInput uInput) +{ + return subpassLoad(uInput); +} + +void main() +{ + FragColor = subpassLoad(uSubpass0) + load_subpasses(uSubpass1); +} diff --git a/spirv_msl.cpp b/spirv_msl.cpp index b1b3ff4d..39ab79fa 100644 --- a/spirv_msl.cpp +++ b/spirv_msl.cpp @@ -19,6 +19,7 @@ #include #include +#include using namespace spv; using namespace spirv_cross; @@ -69,6 +70,7 @@ void CompilerMSL::build_implicit_builtins() meta[var.self].decoration.builtin && meta[var.self].decoration.builtin_type == BuiltInFragCoord) { + builtin_frag_coord_id = var.self; has_frag_coord = true; break; } @@ -93,10 +95,11 @@ void CompilerMSL::build_implicit_builtins() vec4_type_ptr.parent_type = type_id; vec4_type_ptr.storage = StorageClassInput; auto &ptr_type = set(type_ptr_id, vec4_type_ptr); - ptr_type.self = offset; + ptr_type.self = type_id; set(var_id, type_ptr_id, StorageClassInput); set_decoration(var_id, DecorationBuiltIn, BuiltInFragCoord); + builtin_frag_coord_id = var_id; } } } @@ -123,6 +126,7 @@ string CompilerMSL::compile() backend.flexible_member_array_supported = false; backend.can_declare_arrays_inline = false; backend.can_return_array = false; + backend.boolean_mix_support = false; replace_illegal_names(); @@ -332,6 +336,14 @@ void CompilerMSL::extract_global_variables_from_function(uint32_t func_id, std:: if (global_var_ids.find(base_id) != global_var_ids.end()) added_arg_ids.insert(base_id); + auto &type = get(ops[0]); + if (type.image.dim == DimSubpassData) + { + // Implicitly reads gl_FragCoord. + assert(builtin_frag_coord_id != 0); + added_arg_ids.insert(builtin_frag_coord_id); + } + break; } case OpFunctionCall: @@ -3023,7 +3035,7 @@ string CompilerMSL::argument_decl(const SPIRFunction::Parameter &arg) if (is_array(type)) { decl += " (&"; - decl += to_name(var.self); + decl += to_expression(var.self); decl += ")"; decl += type_to_array_glsl(type); } @@ -3031,12 +3043,12 @@ string CompilerMSL::argument_decl(const SPIRFunction::Parameter &arg) { decl += "&"; decl += " "; - decl += to_name(var.self); + decl += to_expression(var.self); } else { decl += " "; - decl += to_name(var.self); + decl += to_expression(var.self); } return decl; diff --git a/spirv_msl.hpp b/spirv_msl.hpp index d3ee4652..2c378632 100644 --- a/spirv_msl.hpp +++ b/spirv_msl.hpp @@ -268,6 +268,7 @@ protected: void emit_barrier(uint32_t id_exe_scope, uint32_t id_mem_scope, uint32_t id_mem_sem); void emit_array_copy(const std::string &lhs, uint32_t rhs_id) override; void build_implicit_builtins(); + uint32_t builtin_frag_coord_id = 0; Options options; std::set spv_function_implementations; From a3ae861844f0232e68f1912abf12daa77059a0f3 Mon Sep 17 00:00:00 2001 From: Hans-Kristian Arntzen Date: Fri, 9 Feb 2018 12:37:17 +0100 Subject: [PATCH 4/5] Fix depth image usage in MSL for separate image/samplers. --- .../sample-depth-separate-image-sampler.frag | 17 +++++++++++ .../sample-depth-separate-image-sampler.frag | 29 +++++++++++++++++++ .../sample-depth-separate-image-sampler.frag | 22 ++++++++++++++ spirv_cross.cpp | 4 +-- spirv_glsl.cpp | 4 ++- spirv_msl.cpp | 3 +- 6 files changed, 75 insertions(+), 4 deletions(-) create mode 100644 reference/opt/shaders-msl/frag/sample-depth-separate-image-sampler.frag create mode 100644 reference/shaders-msl/frag/sample-depth-separate-image-sampler.frag create mode 100644 shaders-msl/frag/sample-depth-separate-image-sampler.frag diff --git a/reference/opt/shaders-msl/frag/sample-depth-separate-image-sampler.frag b/reference/opt/shaders-msl/frag/sample-depth-separate-image-sampler.frag new file mode 100644 index 00000000..6626946c --- /dev/null +++ b/reference/opt/shaders-msl/frag/sample-depth-separate-image-sampler.frag @@ -0,0 +1,17 @@ +#include +#include + +using namespace metal; + +struct main0_out +{ + float FragColor [[color(0)]]; +}; + +fragment main0_out main0(depth2d uDepth [[texture(0)]], texture2d uColor [[texture(1)]], sampler uSamplerShadow [[sampler(0)]], sampler uSampler [[sampler(1)]]) +{ + main0_out out = {}; + out.FragColor = uDepth.sample_compare(uSamplerShadow, float3(0.5).xy, 0.5) + uColor.sample(uSampler, float2(0.5)).x; + return out; +} + diff --git a/reference/shaders-msl/frag/sample-depth-separate-image-sampler.frag b/reference/shaders-msl/frag/sample-depth-separate-image-sampler.frag new file mode 100644 index 00000000..a9c0f8b4 --- /dev/null +++ b/reference/shaders-msl/frag/sample-depth-separate-image-sampler.frag @@ -0,0 +1,29 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" + +#include +#include + +using namespace metal; + +struct main0_out +{ + float FragColor [[color(0)]]; +}; + +float sample_depth_from_function(thread const depth2d uT, thread const sampler uS) +{ + return uT.sample_compare(uS, float3(0.5).xy, float3(0.5).z); +} + +float sample_color_from_function(thread const texture2d uT, thread const sampler uS) +{ + return uT.sample(uS, float2(0.5)).x; +} + +fragment main0_out main0(depth2d uDepth [[texture(0)]], texture2d uColor [[texture(1)]], sampler uSamplerShadow [[sampler(0)]], sampler uSampler [[sampler(1)]]) +{ + main0_out out = {}; + out.FragColor = sample_depth_from_function(uDepth, uSamplerShadow) + sample_color_from_function(uColor, uSampler); + return out; +} + diff --git a/shaders-msl/frag/sample-depth-separate-image-sampler.frag b/shaders-msl/frag/sample-depth-separate-image-sampler.frag new file mode 100644 index 00000000..db1f5e98 --- /dev/null +++ b/shaders-msl/frag/sample-depth-separate-image-sampler.frag @@ -0,0 +1,22 @@ +#version 450 + +layout(set = 0, binding = 0) uniform texture2D uDepth; +layout(set = 0, binding = 1) uniform texture2D uColor; +layout(set = 0, binding = 2) uniform sampler uSampler; +layout(set = 0, binding = 3) uniform samplerShadow uSamplerShadow; +layout(location = 0) out float FragColor; + +float sample_depth_from_function(texture2D uT, samplerShadow uS) +{ + return texture(sampler2DShadow(uT, uS), vec3(0.5)); +} + +float sample_color_from_function(texture2D uT, sampler uS) +{ + return texture(sampler2D(uT, uS), vec2(0.5)).x; +} + +void main() +{ + FragColor = sample_depth_from_function(uDepth, uSamplerShadow) + sample_color_from_function(uColor, uSampler); +} diff --git a/spirv_cross.cpp b/spirv_cross.cpp index d1b9a65c..41964564 100644 --- a/spirv_cross.cpp +++ b/spirv_cross.cpp @@ -3781,10 +3781,10 @@ bool Compiler::CombinedImageSamplerUsageHandler::begin_function_scope(const uint void Compiler::CombinedImageSamplerUsageHandler::add_hierarchy_to_comparison_images(uint32_t image) { - // Traverse the variable dependency hierarchy and tag everything in its path with comparison samplers. + // Traverse the variable dependency hierarchy and tag everything in its path with comparison images. comparison_images.insert(image); for (auto &img : dependency_hierarchy[image]) - add_hierarchy_to_comparison_samplers(img); + add_hierarchy_to_comparison_images(img); } void Compiler::CombinedImageSamplerUsageHandler::add_hierarchy_to_comparison_samplers(uint32_t sampler) diff --git a/spirv_glsl.cpp b/spirv_glsl.cpp index bbc14b81..f0be61a1 100644 --- a/spirv_glsl.cpp +++ b/spirv_glsl.cpp @@ -7419,7 +7419,9 @@ string CompilerGLSL::image_type_glsl(const SPIRType &type, uint32_t /* id */) require_extension("GL_EXT_texture_array"); res += "Array"; } - if (type.image.depth) + + // "Shadow" state in GLSL only exists for samplers and combined image samplers. + if (((type.basetype == SPIRType::SampledImage) || (type.basetype == SPIRType::Sampler)) && type.image.depth) res += "Shadow"; return res; diff --git a/spirv_msl.cpp b/spirv_msl.cpp index 39ab79fa..25d7a541 100644 --- a/spirv_msl.cpp +++ b/spirv_msl.cpp @@ -3237,8 +3237,9 @@ string CompilerMSL::image_type_glsl(const SPIRType &type, uint32_t id) // Bypass pointers because we need the real image struct auto &img_type = get(type.self).image; + bool shadow_image = comparison_images.count(id) != 0; - if (img_type.depth) + if (img_type.depth || shadow_image) { switch (img_type.dim) { From a3104e98f951142d5c0838d2428c6c990d1478b2 Mon Sep 17 00:00:00 2001 From: Hans-Kristian Arntzen Date: Sat, 10 Feb 2018 11:12:05 +0100 Subject: [PATCH 5/5] Also check that type we load is an image. --- spirv_msl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spirv_msl.cpp b/spirv_msl.cpp index 25d7a541..c9efc9ac 100644 --- a/spirv_msl.cpp +++ b/spirv_msl.cpp @@ -337,7 +337,7 @@ void CompilerMSL::extract_global_variables_from_function(uint32_t func_id, std:: added_arg_ids.insert(base_id); auto &type = get(ops[0]); - if (type.image.dim == DimSubpassData) + if (type.basetype == SPIRType::Image && type.image.dim == DimSubpassData) { // Implicitly reads gl_FragCoord. assert(builtin_frag_coord_id != 0);