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.
This commit is contained in:
Hans-Kristian Arntzen 2016-05-28 13:09:26 +02:00
parent 4739d16e98
commit 168e46fdf9
8 changed files with 175 additions and 56 deletions

View File

@ -45,6 +45,18 @@ struct image2DBase
typedef image2DBase<glm::vec4> image2D; typedef image2DBase<glm::vec4> image2D;
typedef image2DBase<glm::ivec4> iimage2D; typedef image2DBase<glm::ivec4> iimage2D;
typedef image2DBase<glm::uvec4> uimage2D; typedef image2DBase<glm::uvec4> uimage2D;
template <typename T>
inline T imageLoad(const image2DBase<T> &image, glm::ivec2 coord)
{
return image.load(coord);
}
template <typename T>
void imageStore(image2DBase<T> &image, glm::ivec2 coord, const T &value)
{
image.store(coord, value);
}
} }
#endif #endif

View File

@ -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);
}

View File

@ -48,7 +48,7 @@ layout(binding = 1, std430) buffer SSBO1
mat3x2 m3; mat3x2 m3;
layout(row_major) mat2 m4; layout(row_major) mat2 m4;
layout(row_major) mat2 m5[9]; 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; layout(row_major) mat3x2 m7;
float array[]; float array[];
} ssbo_430; } ssbo_430;

View File

@ -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);
}

View File

@ -67,7 +67,7 @@ void CompilerCPP::emit_shared(const SPIRVariable &var)
add_resource_name(var.self); add_resource_name(var.self);
auto instance_name = to_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); statement_no_indent("#define ", instance_name, " __res->", instance_name);
} }
@ -257,7 +257,7 @@ void CompilerCPP::emit_resources()
if (var.storage == StorageClassWorkgroup) if (var.storage == StorageClassWorkgroup)
emit_shared(var); emit_shared(var);
else else
statement(variable_decl(var), ";"); statement(CompilerGLSL::variable_decl(var), ";");
emitted = true; emitted = true;
} }
} }
@ -279,6 +279,7 @@ string CompilerCPP::compile()
backend.shared_is_implied = true; backend.shared_is_implied = true;
backend.flexible_member_array_supported = false; backend.flexible_member_array_supported = false;
backend.explicit_struct_type = true; backend.explicit_struct_type = true;
backend.use_initializer_list = true;
uint32_t pass_count = 0; uint32_t pass_count = 0;
do do
@ -347,39 +348,6 @@ void CompilerCPP::emit_c_linkage()
end_scope(); 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<SPIRConstant>(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) void CompilerCPP::emit_function_prototype(SPIRFunction &func, uint64_t)
{ {
local_variable_names = resource_names; 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; bool constref = !type.pointer || arg.write_count == 0;
auto &var = get<SPIRVariable>(arg.id); auto &var = get<SPIRVariable>(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() void CompilerCPP::emit_header()
@ -431,6 +423,8 @@ void CompilerCPP::emit_header()
statement("// This C++ shader is autogenerated by spirv-cross."); statement("// This C++ shader is autogenerated by spirv-cross.");
statement("#include \"spirv_cross/internal_interface.hpp\""); statement("#include \"spirv_cross/internal_interface.hpp\"");
statement("#include \"spirv_cross/external_interface.h\""); statement("#include \"spirv_cross/external_interface.h\"");
// Needed to properly implement GLSL-style arrays.
statement("#include <array>");
statement("#include <stdint.h>"); statement("#include <stdint.h>");
statement(""); statement("");
statement("using namespace spirv_cross;"); statement("using namespace spirv_cross;");

View File

@ -44,8 +44,8 @@ private:
void emit_uniform(const SPIRVariable &var); void emit_uniform(const SPIRVariable &var);
void emit_shared(const SPIRVariable &var); void emit_shared(const SPIRVariable &var);
void emit_block_struct(SPIRType &type); 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::string argument_decl(const SPIRFunction::Parameter &arg);
std::vector<std::string> resource_registrations; std::vector<std::string> resource_registrations;

View File

@ -1175,14 +1175,20 @@ string CompilerGLSL::constant_expression(const SPIRConstant &c)
if (!c.subconstants.empty()) if (!c.subconstants.empty())
{ {
// Handles Arrays and structures. // Handles Arrays and structures.
string res = type_to_glsl_constructor(get<SPIRType>(c.constant_type)) + "("; string res;
if (backend.use_initializer_list)
res = "{ ";
else
res = type_to_glsl_constructor(get<SPIRType>(c.constant_type)) + "(";
for (auto &elem : c.subconstants) for (auto &elem : c.subconstants)
{ {
res += constant_expression(get<SPIRConstant>(elem)); res += constant_expression(get<SPIRConstant>(elem));
if (&elem != &c.subconstants.back()) if (&elem != &c.subconstants.back())
res += ", "; res += ", ";
} }
res += ")";
res += backend.use_initializer_list ? " }" : ")";
return res; return res;
} }
else if (c.columns() == 1) else if (c.columns() == 1)
@ -1325,8 +1331,7 @@ string CompilerGLSL::declare_temporary(uint32_t result_type, uint32_t result_id)
else else
{ {
// The result_id has not been made into an expression yet, so use flags interface. // 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), return join(flags_to_precision_qualifiers_glsl(type, flags), variable_decl(type, to_name(result_id)), " = ");
type_to_array_glsl(type), " = ");
} }
} }
@ -2723,7 +2728,12 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
forward = forward && should_forward(elems[i]); forward = forward && should_forward(elems[i]);
auto &in_type = expression_type(elems[0]); auto &in_type = expression_type(elems[0]);
bool splat = in_type.vecsize == 1 && in_type.columns == 1; auto &out_type = get<SPIRType>(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) if (splat)
{ {
@ -2733,12 +2743,28 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
splat = false; splat = false;
} }
auto constructor_op = type_to_glsl_constructor(get<SPIRType>(result_type)) + "("; string constructor_op;
if (splat) if (backend.use_initializer_list && composite)
constructor_op += to_expression(elems[0]); {
// 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 else
constructor_op += build_composite_combiner(elems, length); {
constructor_op += ")"; constructor_op = type_to_glsl_constructor(get<SPIRType>(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); emit_op(result_type, id, constructor_op, forward, false);
break; 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) string CompilerGLSL::member_decl(const SPIRType &type, const SPIRType &membertype, uint32_t index)
{ {
uint64_t memberflags = 0; uint64_t memberflags = 0;
@ -3640,7 +3671,7 @@ string CompilerGLSL::member_decl(const SPIRType &type, const SPIRType &membertyp
memberflags = memb[index].decoration_flags; memberflags = memb[index].decoration_flags;
return join(layout_for_member(type, index), flags_to_precision_qualifiers_glsl(membertype, memberflags), 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) 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 "; direction = "out ";
} }
return join(direction, to_qualifiers_glsl(arg.id), type_to_glsl(type), " ", to_name(arg.id), return join(direction, to_qualifiers_glsl(arg.id), variable_decl(type, to_name(arg.id)));
type_to_array_glsl(type));
} }
string CompilerGLSL::variable_decl(const SPIRVariable &variable) string CompilerGLSL::variable_decl(const SPIRVariable &variable)
{ {
// Ignore the pointer type since GLSL doesn't have pointers. // Ignore the pointer type since GLSL doesn't have pointers.
auto &type = get<SPIRType>(variable.basetype); auto &type = get<SPIRType>(variable.basetype);
auto res = join(to_qualifiers_glsl(variable.self), type_to_glsl(type), " ", to_name(variable.self), auto res = join(to_qualifiers_glsl(variable.self), variable_decl(type, to_name(variable.self)));
type_to_array_glsl(type));
if (variable.initializer) if (variable.initializer)
res += join(" = ", to_expression(variable.initializer)); res += join(" = ", to_expression(variable.initializer));
return res; return res;
@ -3779,9 +3808,14 @@ string CompilerGLSL::pls_decl(const PlsRemap &var)
string CompilerGLSL::type_to_array_glsl(const SPIRType &type) string CompilerGLSL::type_to_array_glsl(const SPIRType &type)
{ {
if (type.array.empty())
return "";
string res; string res;
for (auto &size : type.array) for (size_t i = type.array.size(); i; i--)
{ {
auto &size = type.array[i - 1];
res += "["; res += "[";
if (size) if (size)
{ {
@ -4481,8 +4515,7 @@ void CompilerGLSL::emit_block_chain(SPIRBlock &block)
{ {
auto flags = meta[tmp.second].decoration.decoration_flags; auto flags = meta[tmp.second].decoration.decoration_flags;
auto &type = get<SPIRType>(tmp.first); auto &type = get<SPIRType>(tmp.first);
statement(flags_to_precision_qualifiers_glsl(type, flags), type_to_glsl(type), " ", to_name(tmp.second), statement(flags_to_precision_qualifiers_glsl(type, flags), variable_decl(type, to_name(tmp.second)), ";");
type_to_array_glsl(type), ";");
} }
SPIRBlock::ContinueBlockType continue_type = SPIRBlock::ContinueNone; SPIRBlock::ContinueBlockType continue_type = SPIRBlock::ContinueNone;

View File

@ -130,6 +130,7 @@ protected:
virtual std::string constant_expression(const SPIRConstant &c); virtual std::string constant_expression(const SPIRConstant &c);
virtual std::string constant_expression_vector(const SPIRConstant &c, uint32_t vector); virtual std::string constant_expression_vector(const SPIRConstant &c, uint32_t vector);
virtual void emit_fixup(); virtual void emit_fixup();
virtual std::string variable_decl(const SPIRType &type, const std::string &name);
std::unique_ptr<std::ostringstream> buffer; std::unique_ptr<std::ostringstream> buffer;
@ -208,6 +209,7 @@ protected:
bool shared_is_implied = false; bool shared_is_implied = false;
bool flexible_member_array_supported = true; bool flexible_member_array_supported = true;
bool explicit_struct_type = false; bool explicit_struct_type = false;
bool use_initializer_list = false;
} backend; } backend;
void emit_struct(SPIRType &type); void emit_struct(SPIRType &type);