summaryrefslogtreecommitdiffstats
path: root/src/glsl/linker.cpp
diff options
context:
space:
mode:
authorPaul Berry <[email protected]>2013-07-30 21:13:48 -0700
committerPaul Berry <[email protected]>2013-08-01 20:24:39 -0700
commit7cfefe6965d50d8b1b494396d7b3b16d87bb2060 (patch)
tree789a59eac0c0568b5c53d8c79cad3dca5b2ea1d8 /src/glsl/linker.cpp
parent20ae8e0c9168d900246d5940e07cf668dba8f0ce (diff)
glsl: Implement rules for geometry shader input sizes.
Section 4.3.8.1 (Input Layout Qualifiers) of the GLSL 1.50 spec contains some tricky rules for how the sizes of geometry shader input arrays are related to the input layout specification. In essence, those rules boil down to the following: - If an input array declaration does not specify a size, and it follows an input layout declaration, it is sized according to the input layout. - If an input layout declaration follows an input array declaration that didn't specify a size, the input array declaration is given a size at the time the input layout declaration appears. - All input layout declarations and input array sizes must ultimately match. Inconsistencies are reported as soon as they are detected, at compile time if the inconsistency is within one compilation unit, otherwise at link time. - At least one compilation unit must contain an input layout declaration. (Note: the geom_array_resize_visitor class was contributed by Bryan Cain <[email protected]>.) Reviewed-by: Ian Romanick <[email protected]> Reviewed-by: Kenneth Graunke <[email protected]>
Diffstat (limited to 'src/glsl/linker.cpp')
-rw-r--r--src/glsl/linker.cpp81
1 files changed, 81 insertions, 0 deletions
diff --git a/src/glsl/linker.cpp b/src/glsl/linker.cpp
index 2a17d065260..94ea54ceb69 100644
--- a/src/glsl/linker.cpp
+++ b/src/glsl/linker.cpp
@@ -178,6 +178,77 @@ private:
};
+class geom_array_resize_visitor : public ir_hierarchical_visitor {
+public:
+ unsigned num_vertices;
+ gl_shader_program *prog;
+
+ geom_array_resize_visitor(unsigned num_vertices, gl_shader_program *prog)
+ {
+ this->num_vertices = num_vertices;
+ this->prog = prog;
+ }
+
+ virtual ~geom_array_resize_visitor()
+ {
+ /* empty */
+ }
+
+ virtual ir_visitor_status visit(ir_variable *var)
+ {
+ if (!var->type->is_array() || var->mode != ir_var_shader_in)
+ return visit_continue;
+
+ unsigned size = var->type->length;
+
+ /* Generate a link error if the shader has declared this array with an
+ * incorrect size.
+ */
+ if (size && size != this->num_vertices) {
+ linker_error(this->prog, "size of array %s declared as %u, "
+ "but number of input vertices is %u\n",
+ var->name, size, this->num_vertices);
+ return visit_continue;
+ }
+
+ /* Generate a link error if the shader attempts to access an input
+ * array using an index too large for its actual size assigned at link
+ * time.
+ */
+ if (var->max_array_access >= this->num_vertices) {
+ linker_error(this->prog, "geometry shader accesses element %i of "
+ "%s, but only %i input vertices\n",
+ var->max_array_access, var->name, this->num_vertices);
+ return visit_continue;
+ }
+
+ var->type = glsl_type::get_array_instance(var->type->element_type(),
+ this->num_vertices);
+ var->max_array_access = this->num_vertices - 1;
+
+ return visit_continue;
+ }
+
+ /* Dereferences of input variables need to be updated so that their type
+ * matches the newly assigned type of the variable they are accessing. */
+ virtual ir_visitor_status visit(ir_dereference_variable *ir)
+ {
+ ir->type = ir->var->type;
+ return visit_continue;
+ }
+
+ /* Dereferences of 2D input arrays need to be updated so that their type
+ * matches the newly assigned type of the array they are accessing. */
+ virtual ir_visitor_status visit_leave(ir_dereference_array *ir)
+ {
+ const glsl_type *const vt = ir->array->type;
+ if (vt->is_array())
+ ir->type = vt->element_type();
+ return visit_continue;
+ }
+};
+
+
void
linker_error(gl_shader_program *prog, const char *fmt, ...)
{
@@ -1173,6 +1244,16 @@ link_intrastage_shaders(void *mem_ctx,
if (linked)
validate_ir_tree(linked->ir);
+ /* Set the size of geometry shader input arrays */
+ if (linked->Type == GL_GEOMETRY_SHADER) {
+ unsigned num_vertices = vertices_per_prim(prog->Geom.InputType);
+ geom_array_resize_visitor input_resize_visitor(num_vertices, prog);
+ foreach_iter(exec_list_iterator, iter, *linked->ir) {
+ ir_instruction *ir = (ir_instruction *)iter.get();
+ ir->accept(&input_resize_visitor);
+ }
+ }
+
/* Make a pass over all variable declarations to ensure that arrays with
* unspecified sizes have a size specified. The size is inferred from the
* max_array_access field.