--- /dev/null
+#include "reflect.h"
+
+namespace Msp {
+namespace GL {
+namespace SL {
+
+LocationCounter::LocationCounter():
+ r_count(0)
+{ }
+
+void LocationCounter::visit(BasicTypeDeclaration &basic)
+{
+ r_count = basic.kind==BasicTypeDeclaration::MATRIX ? basic.size>>16 : 1;
+}
+
+void LocationCounter::visit(ImageTypeDeclaration &)
+{
+ r_count = 1;
+}
+
+void LocationCounter::visit(StructDeclaration &strct)
+{
+ unsigned total = 0;
+ for(NodeList<Statement>::const_iterator i=strct.members.body.begin(); i!=strct.members.body.end(); ++i)
+ {
+ r_count = 1;
+ (*i)->visit(*this);
+ total += r_count;
+ }
+ r_count = total;
+}
+
+void LocationCounter::visit(VariableDeclaration &var)
+{
+ r_count = 1;
+ if(var.type_declaration)
+ var.type_declaration->visit(*this);
+ if(var.array)
+ if(const Literal *literal = dynamic_cast<const Literal *>(var.array_size.get()))
+ if(literal->value.check_type<int>())
+ r_count *= literal->value.value<int>();
+}
+
+} // namespace SL
+} // namespace GL
+} // namespace Msp
--- /dev/null
+#ifndef MSP_GL_SL_REFLECT_H_
+#define MSP_GL_SL_REFLECT_H_
+
+#include "visitor.h"
+
+namespace Msp {
+namespace GL {
+namespace SL {
+
+class LocationCounter: private NodeVisitor
+{
+private:
+ unsigned r_count;
+
+public:
+ LocationCounter();
+
+ unsigned apply(VariableDeclaration &v) { v.visit(*this); return r_count; }
+
+private:
+ virtual void visit(BasicTypeDeclaration &);
+ virtual void visit(ImageTypeDeclaration &);
+ virtual void visit(StructDeclaration &);
+ virtual void visit(VariableDeclaration &);
+};
+
+} // namespace SL
+} // namespace GL
+} // namespace Msp
+
+#endif
return false;
}
+int get_layout_value(const Layout &layout, const string &name, int def_value)
+{
+ for(vector<Layout::Qualifier>::const_iterator i=layout.qualifiers.begin(); i!=layout.qualifiers.end(); ++i)
+ if(i->name==name)
+ return i->value;
+ return def_value;
+}
+
} // namespace SL
} // namespace GL
} // namespace Msp
std::string get_unused_variable_name(const Block &, const std::string &);
bool is_same_type(const TypeDeclaration &, const TypeDeclaration &);
+int get_layout_value(const Layout &, const std::string &, int = -1);
} // namespace SL
} // namespace GL
#include <msp/core/raii.h>
#include <msp/strings/format.h>
#include <msp/strings/utils.h>
+#include "reflect.h"
#include "validate.h"
using namespace std;
{
map<unsigned, VariableDeclaration *> &used = used_locations[var.interface];
- unsigned loc_count = 1;
- if(var.array)
- if(const Literal *literal = dynamic_cast<const Literal *>(var.array_size.get()))
- if(literal->value.check_type<int>())
- loc_count = literal->value.value<int>();
-
+ unsigned loc_count = LocationCounter().apply(var);
for(unsigned i=0; i<loc_count; ++i)
{
map<unsigned, VariableDeclaration *>::const_iterator j = used.find(location+i);
}
}
-void GlobalInterfaceValidator::get_binding(const Layout &layout, unsigned &desc_set, int &binding)
+void GlobalInterfaceValidator::check_uniform(const Uniform &uni)
{
- for(vector<Layout::Qualifier>::const_iterator i=layout.qualifiers.begin(); i!=layout.qualifiers.end(); ++i)
+ map<std::string, const Uniform *>::const_iterator i = used_names.find(uni.name);
+ if(i!=used_names.end())
{
- if(i->name=="set")
- desc_set = i->value;
- else if(i->name=="binding")
- binding = i->value;
+ if(uni.location>=0 && i->second->location>=0 && i->second->location!=uni.location)
+ {
+ error(*uni.node, format("Mismatched location %d for uniform '%s'", uni.location, uni.name));
+ add_info(*i->second->node, format("Previously declared here with location %d", i->second->location));
+ }
+ if(uni.bind_point>=0 && i->second->bind_point>=0 && i->second->bind_point!=uni.bind_point)
+ {
+ error(*uni.node, format("Mismatched binding %d for uniform '%s'", uni.bind_point, uni.name));
+ add_info(*i->second->node, format("Previously declared here with binding %d", i->second->bind_point));
+ }
+ if(uni.type && i->second->type && !is_same_type(*uni.type, *i->second->type))
+ {
+ string type_name = (dynamic_cast<const StructDeclaration *>(uni.type) ?
+ "structure" : format("type '%s'", uni.type->name));
+ error(*uni.node, format("Mismatched %s for uniform '%s'", type_name, uni.name));
+
+ string message = "Previously declared here";
+ if(!dynamic_cast<const StructDeclaration *>(i->second->type))
+ message += format(" with type '%s'", i->second->type->name);
+ add_info(*i->second->node, message);
+ }
}
-}
-
-void GlobalInterfaceValidator::check_binding(const Layout &layout, const Binding &binding)
-{
- unsigned desc_set = 0;
- int bind_point = -1;
- get_binding(layout, desc_set, bind_point);
- if(bind_point<0)
- return;
+ else
+ used_names.insert(make_pair(uni.name, &uni));
- map<unsigned, Binding> &used = used_bindings[desc_set];
- map<unsigned, Binding>::const_iterator i = used.find(bind_point);
- if(i!=used.end())
+ if(uni.location>=0)
{
- if(i->second.name!=binding.name)
+ map<unsigned, const Uniform *>::const_iterator j = used_locations.find(uni.location);
+ if(j!=used_locations.end())
+ {
+ if(j->second->name!=uni.name)
+ {
+ error(*uni.node, format("Overlapping location %d for '%s'", uni.location, uni.name));
+ add_info(*j->second->node, format("Previously used here for '%s'", j->second->name));
+ }
+ }
+ else
{
- error(*binding.node, format("Overlapping binding %d for '%s'", bind_point, binding.name));
- add_info(*i->second.node, format("Previously used here for '%s'", i->second.name));
+ for(unsigned k=0; k<uni.loc_count; ++k)
+ used_locations.insert(make_pair(uni.location+k, &uni));
}
- if(i->second.type && binding.type)
+ }
+
+ if(uni.bind_point>=0)
+ {
+ map<unsigned, const Uniform *> &used = used_bindings[uni.desc_set];
+ map<unsigned, const Uniform *>::const_iterator j = used.find(uni.bind_point);
+ if(j!=used.end())
{
- if(!is_same_type(*i->second.type, *binding.type))
+ if(j->second->name!=uni.name)
{
- string type_name = (dynamic_cast<const StructDeclaration *>(binding.type) ? "struct type" :
- format("type '%s'", binding.type->name));
- error(*binding.node, format("Mismatched %s for binding %d '%s'", type_name, bind_point, binding.name));
-
- string message = "Previously used here";
- if(!dynamic_cast<const StructDeclaration *>(i->second.type))
- message += format(" with type '%s'", i->second.type->name);
- add_info(*i->second.node, message);
+ error(*uni.node, format("Overlapping binding %d for '%s'", uni.bind_point, uni.name));
+ add_info(*j->second->node, format("Previously used here for '%s'", j->second->name));
}
}
+ else
+ used.insert(make_pair(uni.bind_point, &uni));
}
- else
- used.insert(make_pair(bind_point, binding));
}
void GlobalInterfaceValidator::visit(VariableDeclaration &var)
{
- if(var.interface=="uniform" && var.layout)
- check_binding(*var.layout, var);
+ if(var.interface=="uniform")
+ {
+ Uniform uni;
+ uni.node = &var;
+ uni.type = var.type_declaration;
+ uni.name = var.name;
+ if(var.layout)
+ {
+ uni.location = get_layout_value(*var.layout, "location");
+ uni.loc_count = LocationCounter().apply(var);
+ uni.desc_set = get_layout_value(*var.layout, "set", 0);
+ uni.bind_point = get_layout_value(*var.layout, "binding");
+ }
+
+ uniforms.push_back(uni);
+ check_uniform(uniforms.back());
+ }
}
void GlobalInterfaceValidator::visit(InterfaceBlock &iface)
{
- if(iface.interface=="uniform" && iface.layout)
- check_binding(*iface.layout, iface);
+ if(iface.interface=="uniform")
+ {
+ Uniform uni;
+ uni.node = &iface;
+ uni.type = iface.struct_declaration;
+ uni.name = iface.block_name;
+ if(iface.layout)
+ {
+ uni.desc_set = get_layout_value(*iface.layout, "set", 0);
+ uni.bind_point = get_layout_value(*iface.layout, "binding");
+ }
+
+ uniforms.push_back(uni);
+ check_uniform(uniforms.back());
+ }
}
} // namespace SL
class GlobalInterfaceValidator: private Validator
{
private:
- struct Binding
+ struct Uniform
{
Node *node;
TypeDeclaration *type;
std::string name;
+ int location;
+ unsigned loc_count;
+ int desc_set;
+ int bind_point;
- Binding(VariableDeclaration &v): node(&v), type(v.type_declaration), name(v.name) { }
- Binding(InterfaceBlock &i): node(&i), type(i.struct_declaration), name(i.block_name) { }
+ Uniform(): node(0), type(0), location(-1), loc_count(1), desc_set(0), bind_point(-1) { }
};
- std::map<unsigned, std::map<unsigned, Binding> > used_bindings;
+ std::list<Uniform> uniforms;
+ std::map<std::string, const Uniform *> used_names;
+ std::map<unsigned, const Uniform *> used_locations;
+ std::map<unsigned, std::map<unsigned, const Uniform *> > used_bindings;
public:
void apply(Module &);
private:
- void get_binding(const Layout &, unsigned &, int &);
- void check_binding(const Layout &, const Binding &);
+ void check_uniform(const Uniform &);
virtual void visit(VariableDeclaration &);
virtual void visit(InterfaceBlock &);
+++ /dev/null
-#pragma MSP stage(vertex)
-layout(binding=0) uniform Transform
-{
- mat4 model;
- mat4 vp;
-};
-layout(binding=1) uniform Lighting
-{
- vec3 position;
-} light;
-layout(location=0) in vec4 position;
-layout(location=1) in vec3 normal;
-void main()
-{
- vec4 world_pos = model*position;
- gl_Position = vp*world_pos;
- out vec3 light_dir = world_pos.xyz-light.position;
- passthrough;
-}
-
-#pragma MSP stage(fragment)
-layout(binding=1) uniform Lighting
-{
- vec4 color;
-} light;
-layout(binding=0) uniform Material
-{
- vec4 color;
-};
-layout(location=0) out vec4 frag_color;
-void main()
-{
- frag_color = color*vec4(vec3(max(dot(normalize(normal), normalize(light_dir)), 0.0)), 1.0);
-}
-
-/* Expected error:
-<test>:23: Mismatched struct type for binding 1 'Lighting'
-<test>:8: Previously used here
-<test>:27: Overlapping binding 0 for 'Material'
-<test>:3: Previously used here for 'Transform'
-<test>:27: Mismatched struct type for binding 0 'Material'
-<test>:3: Previously used here
-*/
#pragma MSP stage(vertex)
layout(location=0) in vec4 position;
layout(location=0) in vec2 texcoords[3];
-layout(location=2) in vec4 color;
+layout(location=2) in mat4 instance_transform;
+layout(location=4) in vec4 color;
void main()
{
gl_Position = position;
/* Expected error:
<test>:3: Overlapping location 0 for 'in texcoords'
<test>:2: Previously used here for 'in position'
-<test>:4: Overlapping location 2 for 'in color'
+<test>:4: Overlapping location 2 for 'in instance_transform'
<test>:3: Previously used here for 'in texcoords'
+<test>:5: Overlapping location 4 for 'in color'
+<test>:4: Previously used here for 'in instance_transform'
*/
--- /dev/null
+#pragma MSP stage(vertex)
+layout(binding=0) uniform Transform
+{
+ mat4 model;
+ mat4 vp;
+};
+layout(binding=1) uniform Lighting
+{
+ vec3 position;
+} light;
+layout(location=0) in vec4 position;
+layout(location=1) in vec3 normal;
+void main()
+{
+ vec4 world_pos = model*position;
+ gl_Position = vp*world_pos;
+ out vec3 light_dir = world_pos.xyz-light.position;
+ passthrough;
+}
+
+#pragma MSP stage(fragment)
+layout(binding=1) uniform Lighting
+{
+ vec4 color;
+} light;
+layout(binding=0) uniform Material
+{
+ vec4 color;
+};
+layout(location=0) out vec4 frag_color;
+void main()
+{
+ frag_color = color*vec4(vec3(max(dot(normalize(normal), normalize(light_dir)), 0.0)), 1.0);
+}
+
+/* Expected error:
+<test>:23: Mismatched structure for uniform 'Lighting'
+<test>:8: Previously declared here
+<test>:27: Overlapping binding 0 for 'Material'
+<test>:3: Previously used here for 'Transform'
+*/
--- /dev/null
+#pragma MSP stage(vertex)
+layout(binding=0) uniform sampler2D heightmap;
+layout(location=0) uniform mat4 mvp;
+layout(location=0) in vec2 position;
+layout(location=1) in vec3 texcoord;
+void main()
+{
+ gl_Position = mvp*vec4(position, texture(heightmap, texcoord.xy).r, 1.0);
+ passthrough;
+}
+
+#pragma MSP stage(fragment)
+layout(binding=1) uniform sampler2DArray heightmap;
+layout(location=3) uniform vec4 color;
+layout(location=0) out vec4 frag_color;
+void main()
+{
+ frag_color = color*texture(heightmap, texcoord).r;
+}
+
+/* Expected error:
+<test>:13: Mismatched binding 1 for uniform 'heightmap'
+<test>:2: Previously declared here with binding 0
+<test>:13: Mismatched type 'sampler2DArray' for uniform 'heightmap'
+<test>:2: Previously declared here with type 'sampler2D'
+<test>:14: Overlapping location 3 for 'color'
+<test>:3: Previously used here for 'mvp'
+*/