From 168e46fdf9cf9e3cd17d137b1c27d0c38c65c7a1 Mon Sep 17 00:00:00 2001 From: Hans-Kristian Arntzen Date: Sat, 28 May 2016 13:09:26 +0200 Subject: [PATCH] Use std::array in C++ backend. Deals better with composite construction in C++ and also fixes a few bugs in GLSL backend with array-of-arrays. --- include/spirv_cross/image.hpp | 12 ++++ .../shaders/comp/composite-construct.comp | 38 ++++++++++ reference/shaders/comp/struct-packing.comp | 2 +- shaders/comp/composite-construct.comp | 40 +++++++++++ spirv_cpp.cpp | 66 ++++++++---------- spirv_cpp.hpp | 2 +- spirv_glsl.cpp | 69 ++++++++++++++----- spirv_glsl.hpp | 2 + 8 files changed, 175 insertions(+), 56 deletions(-) create mode 100644 reference/shaders/comp/composite-construct.comp create mode 100644 shaders/comp/composite-construct.comp diff --git a/include/spirv_cross/image.hpp b/include/spirv_cross/image.hpp index 1216f117..927c426e 100644 --- a/include/spirv_cross/image.hpp +++ b/include/spirv_cross/image.hpp @@ -45,6 +45,18 @@ struct image2DBase typedef image2DBase image2D; typedef image2DBase iimage2D; typedef image2DBase uimage2D; + +template +inline T imageLoad(const image2DBase &image, glm::ivec2 coord) +{ + return image.load(coord); +} + +template +void imageStore(image2DBase &image, glm::ivec2 coord, const T &value) +{ + image.store(coord, value); +} } #endif diff --git a/reference/shaders/comp/composite-construct.comp b/reference/shaders/comp/composite-construct.comp new file mode 100644 index 00000000..828be805 --- /dev/null +++ b/reference/shaders/comp/composite-construct.comp @@ -0,0 +1,38 @@ +#version 310 es +layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in; + +struct Composite +{ + vec4 a[2]; + vec4 b[2]; +}; + +layout(binding = 0, std430) buffer SSBO0 +{ + vec4 as[]; +} _41; + +layout(binding = 1, std430) buffer SSBO1 +{ + vec4 bs[]; +} _55; + +vec4 summe(vec4 values[3][2]) +{ + return (((values[0][0] + values[2][1]) + values[0][1]) + values[1][0]); +} + +void main() +{ + vec4 values[2] = vec4[](_41.as[gl_GlobalInvocationID.x], _55.bs[gl_GlobalInvocationID.x]); + vec4 const_values[2] = vec4[](vec4(10.0), vec4(30.0)); + vec4 copy_values[2] = const_values; + vec4 copy_values2[2] = values; + vec4 param[3][2] = vec4[][](values, copy_values, copy_values2); + _41.as[gl_GlobalInvocationID.x] = summe(param); + Composite c = Composite(values, copy_values); + float arrayofarray[2][3] = float[][](float[](1.0, 1.0, 1.0), float[](2.0, 2.0, 2.0)); + float b = 10.0; + float values_scalar[4] = float[](b, b, b, b); +} + diff --git a/reference/shaders/comp/struct-packing.comp b/reference/shaders/comp/struct-packing.comp index 5c73f9fd..eeeaa036 100644 --- a/reference/shaders/comp/struct-packing.comp +++ b/reference/shaders/comp/struct-packing.comp @@ -48,7 +48,7 @@ layout(binding = 1, std430) buffer SSBO1 mat3x2 m3; layout(row_major) mat2 m4; layout(row_major) mat2 m5[9]; - layout(row_major) mat2x3 m6[2][4]; + layout(row_major) mat2x3 m6[4][2]; layout(row_major) mat3x2 m7; float array[]; } ssbo_430; diff --git a/shaders/comp/composite-construct.comp b/shaders/comp/composite-construct.comp new file mode 100644 index 00000000..859c56f5 --- /dev/null +++ b/shaders/comp/composite-construct.comp @@ -0,0 +1,40 @@ +#version 310 es +layout(local_size_x = 1) in; + +layout(std430, binding = 0) buffer SSBO0 +{ + vec4 as[]; +}; + +layout(std430, binding = 1) buffer SSBO1 +{ + vec4 bs[]; +}; + +vec4 summe(vec4 values[3][2]) +{ + return values[0][0] + values[2][1] + values[0][1] + values[1][0]; +} + +struct Composite +{ + vec4 a[2]; + vec4 b[2]; +}; + +void main() +{ + vec4 values[2] = vec4[](as[gl_GlobalInvocationID.x], bs[gl_GlobalInvocationID.x]); + vec4 const_values[2] = vec4[](vec4(10.0), vec4(30.0)); + vec4 copy_values[2]; + copy_values = const_values; + vec4 copy_values2[2] = values; + as[gl_GlobalInvocationID.x] = summe(vec4[][](values, copy_values, copy_values2)); + + Composite c = Composite(values, copy_values); + + float arrayofarray[2][3] = float[][](float[](1.0, 1.0, 1.0), float[](2.0, 2.0, 2.0)); + + float b = 10.0; + float values_scalar[4] = float[](b, b, b, b); +} diff --git a/spirv_cpp.cpp b/spirv_cpp.cpp index 8a01f81c..cccb5613 100644 --- a/spirv_cpp.cpp +++ b/spirv_cpp.cpp @@ -67,7 +67,7 @@ void CompilerCPP::emit_shared(const SPIRVariable &var) add_resource_name(var.self); auto instance_name = to_name(var.self); - statement(variable_decl(var), ";"); + statement(CompilerGLSL::variable_decl(var), ";"); statement_no_indent("#define ", instance_name, " __res->", instance_name); } @@ -257,7 +257,7 @@ void CompilerCPP::emit_resources() if (var.storage == StorageClassWorkgroup) emit_shared(var); else - statement(variable_decl(var), ";"); + statement(CompilerGLSL::variable_decl(var), ";"); emitted = true; } } @@ -279,6 +279,7 @@ string CompilerCPP::compile() backend.shared_is_implied = true; backend.flexible_member_array_supported = false; backend.explicit_struct_type = true; + backend.use_initializer_list = true; uint32_t pass_count = 0; do @@ -347,39 +348,6 @@ void CompilerCPP::emit_c_linkage() end_scope(); } -string CompilerCPP::constant_expression(const SPIRConstant &c) -{ - if (!c.subconstants.empty()) - { - // Handles Arrays and structures. - string res = "{"; - for (auto &elem : c.subconstants) - { - res += constant_expression(get(elem)); - if (&elem != &c.subconstants.back()) - res += ", "; - } - res += "}"; - return res; - } - else if (c.columns() == 1) - { - return constant_expression_vector(c, 0); - } - else - { - string res = "{"; - for (uint32_t col = 0; col < c.columns(); col++) - { - res += constant_expression_vector(c, col); - if (col + 1 < c.columns()) - res += ", "; - } - res += "}"; - return res; - } -} - void CompilerCPP::emit_function_prototype(SPIRFunction &func, uint64_t) { local_variable_names = resource_names; @@ -423,7 +391,31 @@ string CompilerCPP::argument_decl(const SPIRFunction::Parameter &arg) bool constref = !type.pointer || arg.write_count == 0; auto &var = get(arg.id); - return join(constref ? "const " : "", type_to_glsl(type), "& ", to_name(var.self), type_to_array_glsl(type)); + + string base = type_to_glsl(type); + for (auto &array : type.array) + base = join("std::array<", base, ", ", array, ">"); + + return join(constref ? "const " : "", base, " &", to_name(var.self)); +} + +string CompilerCPP::variable_decl(const SPIRType &type, const string &name) +{ + string base = type_to_glsl(type); + bool runtime = false; + for (auto &array : type.array) + { + if (array) + base = join("std::array<", base, ", ", array, ">"); + else + { + // Avoid using runtime arrays with std::array since this is undefined. + // Runtime arrays cannot be passed around as values, so this is fine. + runtime = true; + } + } + base += ' '; + return base + name + (runtime ? "[1]" : ""); } void CompilerCPP::emit_header() @@ -431,6 +423,8 @@ void CompilerCPP::emit_header() statement("// This C++ shader is autogenerated by spirv-cross."); statement("#include \"spirv_cross/internal_interface.hpp\""); statement("#include \"spirv_cross/external_interface.h\""); + // Needed to properly implement GLSL-style arrays. + statement("#include "); statement("#include "); statement(""); statement("using namespace spirv_cross;"); diff --git a/spirv_cpp.hpp b/spirv_cpp.hpp index 342f3a92..c0194517 100644 --- a/spirv_cpp.hpp +++ b/spirv_cpp.hpp @@ -44,8 +44,8 @@ private: void emit_uniform(const SPIRVariable &var); void emit_shared(const SPIRVariable &var); void emit_block_struct(SPIRType &type); + std::string variable_decl(const SPIRType &type, const std::string &name) override; - std::string constant_expression(const SPIRConstant &c) override; std::string argument_decl(const SPIRFunction::Parameter &arg); std::vector resource_registrations; diff --git a/spirv_glsl.cpp b/spirv_glsl.cpp index 0112f94e..1cee3753 100644 --- a/spirv_glsl.cpp +++ b/spirv_glsl.cpp @@ -1175,14 +1175,20 @@ string CompilerGLSL::constant_expression(const SPIRConstant &c) if (!c.subconstants.empty()) { // Handles Arrays and structures. - string res = type_to_glsl_constructor(get(c.constant_type)) + "("; + string res; + if (backend.use_initializer_list) + res = "{ "; + else + res = type_to_glsl_constructor(get(c.constant_type)) + "("; + for (auto &elem : c.subconstants) { res += constant_expression(get(elem)); if (&elem != &c.subconstants.back()) res += ", "; } - res += ")"; + + res += backend.use_initializer_list ? " }" : ")"; return res; } else if (c.columns() == 1) @@ -1325,8 +1331,7 @@ string CompilerGLSL::declare_temporary(uint32_t result_type, uint32_t result_id) else { // The result_id has not been made into an expression yet, so use flags interface. - return join(flags_to_precision_qualifiers_glsl(type, flags), type_to_glsl(type), " ", to_name(result_id), - type_to_array_glsl(type), " = "); + return join(flags_to_precision_qualifiers_glsl(type, flags), variable_decl(type, to_name(result_id)), " = "); } } @@ -2723,7 +2728,12 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) forward = forward && should_forward(elems[i]); auto &in_type = expression_type(elems[0]); - bool splat = in_type.vecsize == 1 && in_type.columns == 1; + auto &out_type = get(result_type); + + // Only splat if we have vector constructors. + // Arrays and structs must be initialized properly in full. + bool composite = !out_type.array.empty() || out_type.basetype == SPIRType::Struct; + bool splat = in_type.vecsize == 1 && in_type.columns == 1 && !composite; if (splat) { @@ -2733,12 +2743,28 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) splat = false; } - auto constructor_op = type_to_glsl_constructor(get(result_type)) + "("; - if (splat) - constructor_op += to_expression(elems[0]); + string constructor_op; + if (backend.use_initializer_list && composite) + { + // Only use this path if we are building composites. + // This path cannot be used for arithmetic. + constructor_op += "{ "; + if (splat) + constructor_op += to_expression(elems[0]); + else + constructor_op += build_composite_combiner(elems, length); + constructor_op += " }"; + } else - constructor_op += build_composite_combiner(elems, length); - constructor_op += ")"; + { + constructor_op = type_to_glsl_constructor(get(result_type)) + "("; + if (splat) + constructor_op += to_expression(elems[0]); + else + constructor_op += build_composite_combiner(elems, length); + constructor_op += ")"; + } + emit_op(result_type, id, constructor_op, forward, false); break; } @@ -3632,6 +3658,11 @@ void CompilerGLSL::add_member_name(SPIRType &type, uint32_t index) } } +string CompilerGLSL::variable_decl(const SPIRType &type, const std::string &name) +{ + return join(type_to_glsl(type), " ", name, type_to_array_glsl(type)); +} + string CompilerGLSL::member_decl(const SPIRType &type, const SPIRType &membertype, uint32_t index) { uint64_t memberflags = 0; @@ -3640,7 +3671,7 @@ string CompilerGLSL::member_decl(const SPIRType &type, const SPIRType &membertyp memberflags = memb[index].decoration_flags; return join(layout_for_member(type, index), flags_to_precision_qualifiers_glsl(membertype, memberflags), - type_to_glsl(membertype), " ", to_member_name(type, index), type_to_array_glsl(membertype)); + variable_decl(membertype, to_member_name(type, index))); } const char *CompilerGLSL::flags_to_precision_qualifiers_glsl(const SPIRType &type, uint64_t flags) @@ -3741,16 +3772,14 @@ string CompilerGLSL::argument_decl(const SPIRFunction::Parameter &arg) direction = "out "; } - return join(direction, to_qualifiers_glsl(arg.id), type_to_glsl(type), " ", to_name(arg.id), - type_to_array_glsl(type)); + return join(direction, to_qualifiers_glsl(arg.id), variable_decl(type, to_name(arg.id))); } string CompilerGLSL::variable_decl(const SPIRVariable &variable) { // Ignore the pointer type since GLSL doesn't have pointers. auto &type = get(variable.basetype); - auto res = join(to_qualifiers_glsl(variable.self), type_to_glsl(type), " ", to_name(variable.self), - type_to_array_glsl(type)); + auto res = join(to_qualifiers_glsl(variable.self), variable_decl(type, to_name(variable.self))); if (variable.initializer) res += join(" = ", to_expression(variable.initializer)); return res; @@ -3779,9 +3808,14 @@ string CompilerGLSL::pls_decl(const PlsRemap &var) string CompilerGLSL::type_to_array_glsl(const SPIRType &type) { + if (type.array.empty()) + return ""; + string res; - for (auto &size : type.array) + for (size_t i = type.array.size(); i; i--) { + auto &size = type.array[i - 1]; + res += "["; if (size) { @@ -4481,8 +4515,7 @@ void CompilerGLSL::emit_block_chain(SPIRBlock &block) { auto flags = meta[tmp.second].decoration.decoration_flags; auto &type = get(tmp.first); - statement(flags_to_precision_qualifiers_glsl(type, flags), type_to_glsl(type), " ", to_name(tmp.second), - type_to_array_glsl(type), ";"); + statement(flags_to_precision_qualifiers_glsl(type, flags), variable_decl(type, to_name(tmp.second)), ";"); } SPIRBlock::ContinueBlockType continue_type = SPIRBlock::ContinueNone; diff --git a/spirv_glsl.hpp b/spirv_glsl.hpp index 5332b3ee..3831740c 100644 --- a/spirv_glsl.hpp +++ b/spirv_glsl.hpp @@ -130,6 +130,7 @@ protected: virtual std::string constant_expression(const SPIRConstant &c); virtual std::string constant_expression_vector(const SPIRConstant &c, uint32_t vector); virtual void emit_fixup(); + virtual std::string variable_decl(const SPIRType &type, const std::string &name); std::unique_ptr buffer; @@ -208,6 +209,7 @@ protected: bool shared_is_implied = false; bool flexible_member_array_supported = true; bool explicit_struct_type = false; + bool use_initializer_list = false; } backend; void emit_struct(SPIRType &type);