From 97350d32fdffe4b3b1114b8d86cced32039cfe44 Mon Sep 17 00:00:00 2001 From: Hans-Kristian Arntzen Date: Thu, 23 Feb 2017 19:03:07 +0100 Subject: [PATCH] Fix cases for flattened struct write. Handle writing the entire struct as well as writing the elements individually. --- .../legacy/vert/struct-varying..legacy.vert | 28 +++++++++++++++ .../legacy/vert/struct-varying..legacy.vert | 23 ++++++++++++ spirv_glsl.cpp | 35 ++++++++++++------- spirv_glsl.hpp | 4 +-- 4 files changed, 75 insertions(+), 15 deletions(-) create mode 100644 reference/shaders/legacy/vert/struct-varying..legacy.vert create mode 100644 shaders/legacy/vert/struct-varying..legacy.vert diff --git a/reference/shaders/legacy/vert/struct-varying..legacy.vert b/reference/shaders/legacy/vert/struct-varying..legacy.vert new file mode 100644 index 0000000..55f9d7b --- /dev/null +++ b/reference/shaders/legacy/vert/struct-varying..legacy.vert @@ -0,0 +1,28 @@ +#version 100 + +struct Output +{ + vec4 a; + vec2 b; +}; + +varying vec4 Output_a; +varying vec2 Output_b; + +void main() +{ + Output s = Output(vec4(0.5), vec2(0.25)); + { + Output vout = s; + Output_a = vout.a; + Output_b = vout.b; + } + { + Output vout = s; + Output_a = vout.a; + Output_b = vout.b; + } + Output_a = s.a; + Output_b = s.b; +} + diff --git a/shaders/legacy/vert/struct-varying..legacy.vert b/shaders/legacy/vert/struct-varying..legacy.vert new file mode 100644 index 0000000..4a55bc7 --- /dev/null +++ b/shaders/legacy/vert/struct-varying..legacy.vert @@ -0,0 +1,23 @@ +#version 310 es + +struct Output +{ + vec4 a; + vec2 b; +}; + +layout(location = 0) out Output vout; + +void main() +{ + Output s = Output(vec4(0.5), vec2(0.25)); + + // Write whole struct. + vout = s; + // Write whole struct again, checks for scoping. + vout = s; + + // Write elements individually. + vout.a = s.a; + vout.b = s.b; +} diff --git a/spirv_glsl.cpp b/spirv_glsl.cpp index f3a7f5f..a79073b 100644 --- a/spirv_glsl.cpp +++ b/spirv_glsl.cpp @@ -3259,8 +3259,8 @@ const char *CompilerGLSL::index_to_swizzle(uint32_t index) } } -string CompilerGLSL::access_chain(uint32_t base, const uint32_t *indices, uint32_t count, bool index_is_literal, - bool chain_only, bool *need_transpose) +string CompilerGLSL::access_chain_internal(uint32_t base, const uint32_t *indices, uint32_t count, bool index_is_literal, + bool chain_only, bool *need_transpose) { string expr; if (!chain_only) @@ -3400,9 +3400,15 @@ string CompilerGLSL::access_chain(uint32_t base, const uint32_t *indices, uint32 return flattened_access_chain(base, indices, count, target_type, 0, matrix_stride, need_transpose); } + else if (flattened_structs.count(base) && count > 0) + { + auto chain = access_chain_internal(base, indices, count, false, true).substr(1); + auto &type = get(get(base).basetype); + return sanitize_underscores(join(to_name(type.self), "_", chain)); + } else { - return access_chain(base, indices, count, false, false, out_need_transpose); + return access_chain_internal(base, indices, count, false, false, out_need_transpose); } } @@ -3423,9 +3429,9 @@ void CompilerGLSL::store_flattened_struct(SPIRVariable &var, uint32_t value) { // Flatten the varyings. // Apply name transformation for flattened I/O blocks. - auto chain = access_chain(var.self, &i, 1, true, true).substr(1); - auto lhs = sanitize_underscores(join(to_name(type.self), "_", chain)); - rhs = access_chain(var.self, &i, 1, true); + + auto lhs = sanitize_underscores(join(to_name(type.self), "_", to_member_name(type, i))); + rhs = access_chain_internal(var.self, &i, 1, true); statement(lhs, " = ", rhs, ";"); } end_scope(); @@ -4087,7 +4093,10 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) else if (var && var->loop_variable && !var->loop_variable_enable) var->static_expression = ops[1]; else if (var && flattened_structs.count(ops[0])) + { store_flattened_struct(*var, ops[1]); + register_write(ops[0]); + } else { auto lhs = to_expression(ops[0]); @@ -4113,7 +4122,7 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) { uint32_t result_type = ops[0]; uint32_t id = ops[1]; - auto e = access_chain(ops[2], &ops[3], length - 3, true); + auto e = access_chain_internal(ops[2], &ops[3], length - 3, true); set(id, e + ".length()", result_type, true); break; } @@ -4284,7 +4293,7 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) // Make a copy, then use access chain to store the variable. statement(declare_temporary(result_type, id), to_expression(vec), ";"); set(id, to_name(id), result_type, true); - auto chain = access_chain(id, &index, 1, false); + auto chain = access_chain_internal(id, &index, 1, false); statement(chain, " = ", to_expression(comp), ";"); break; } @@ -4294,7 +4303,7 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) uint32_t result_type = ops[0]; uint32_t id = ops[1]; - auto expr = access_chain(ops[2], &ops[3], 1, false); + auto expr = access_chain_internal(ops[2], &ops[3], 1, false); emit_op(result_type, id, expr, should_forward(ops[2])); break; } @@ -4325,13 +4334,13 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) // // Including the base will prevent this and would trigger multiple reads // from expression causing it to be forced to an actual temporary in GLSL. - auto expr = access_chain(ops[2], &ops[3], length, true, true); + auto expr = access_chain_internal(ops[2], &ops[3], length, true, true); auto &e = emit_op(result_type, id, expr, true, !expression_is_forwarded(ops[2])); e.base_expression = ops[2]; } else { - auto expr = access_chain(ops[2], &ops[3], length, true); + auto expr = access_chain_internal(ops[2], &ops[3], length, true); emit_op(result_type, id, expr, should_forward(ops[2]), !expression_is_forwarded(ops[2])); } break; @@ -4354,12 +4363,12 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) // Make a copy, then use access chain to store the variable. statement(declare_temporary(result_type, id), to_expression(composite), ";"); set(id, to_name(id), result_type, true); - auto chain = access_chain(id, elems, length, true); + auto chain = access_chain_internal(id, elems, length, true); statement(chain, " = ", to_expression(obj), ";"); } else { - auto chain = access_chain(composite, elems, length, true); + auto chain = access_chain_internal(composite, elems, length, true); statement(chain, " = ", to_expression(obj), ";"); set(id, to_expression(composite), result_type, true); diff --git a/spirv_glsl.hpp b/spirv_glsl.hpp index 75cb40f..287690f 100644 --- a/spirv_glsl.hpp +++ b/spirv_glsl.hpp @@ -316,8 +316,8 @@ protected: bool expression_is_forwarded(uint32_t id); SPIRExpression &emit_op(uint32_t result_type, uint32_t result_id, const std::string &rhs, bool forward_rhs, bool suppress_usage_tracking = false); - std::string access_chain(uint32_t base, const uint32_t *indices, uint32_t count, bool index_is_literal, - bool chain_only = false, bool *need_transpose = nullptr); + std::string access_chain_internal(uint32_t base, const uint32_t *indices, uint32_t count, bool index_is_literal, + bool chain_only = false, bool *need_transpose = nullptr); std::string access_chain(uint32_t base, const uint32_t *indices, uint32_t count, const SPIRType &target_type, bool *need_transpose = nullptr);