aboutsummaryrefslogtreecommitdiff
path: root/mesalib/src/glsl/linker.cpp
diff options
context:
space:
mode:
authormarha <marha@users.sourceforge.net>2013-08-19 09:03:18 +0200
committermarha <marha@users.sourceforge.net>2013-08-19 09:03:18 +0200
commit854ec4da20ddff9b830be0a7d5b81d8cb4774132 (patch)
tree223425d84b5ea3727f74546c92dee8b03c074158 /mesalib/src/glsl/linker.cpp
parent0659c77949b38440a2a9ba67e1ee9cacef1f3a7f (diff)
downloadvcxsrv-854ec4da20ddff9b830be0a7d5b81d8cb4774132.tar.gz
vcxsrv-854ec4da20ddff9b830be0a7d5b81d8cb4774132.tar.bz2
vcxsrv-854ec4da20ddff9b830be0a7d5b81d8cb4774132.zip
fontconfig libX11 libXdmcp libxcb xkeyboard-config mesa pixman xserver git update 19 aug 2013
xserver commit fe7463b8ce0de301c2f82b108c93963424f77219 libxcb commit 5648ddd2b97068f549268284129a438a6845e14c libxcb/xcb-proto commit 56a82005ac388fcb7a4d1c82e07c7e72eaf69a32 xkeyboard-config commit 87c865aee1844b2cc6b1a5a208116dd095f4d76a libX11 commit 9b291044a240e5b9b031ed814e0c84e53a1c3084 libXdmcp commit 66514a4af7eaa47e8718434356d7efce95e570cf libXext commit 7378d4bdbd33ed49ed6cfa5c4f73d7527982aab4 libfontenc commit 3acba630d8b57084f7e92c15732408711ed5137a libXinerama commit 6e1d1dc328ba8162bba2f4694e7f3c706a1491ff libXau commit 899790011304c4029e15abf410e49ce7cec17e0a xkbcomp commit 0ebdf47fd4bc434ac3d2339544c022a869510738 pixman commit 3518a0dafa63098d41e466f73d105b7e3e4b12de xextproto commit f27fcc99d1cf935cc289933326f7d3baacd5107a randrproto commit ca7cc541c2e43e6c784df19b4583ac35829d2f72 glproto commit 8e3407e02980d088e20041e79bdcdd3737e7827e mkfontscale commit f48de13423c7300f4da9f61993b624426b38ddc0 xwininfo commit ba0d1b0da21d2dbdd81098ed5778f3792b472e13 libXft commit c5e760a239afc62a1c75e0509868e35957c8df52 libXmu commit d5dac08d65c4865f311cb62c161dbb1300eecd11 libxtrans commit f6a161f2a003f4da0a2e414b4faa0ee0de0c01f0 fontconfig commit 084cf7c44e985dd48c088d921ad0d9a43b0b00b4 mesa commit d13003f544417db6de44c65a0c118bd2b189458a
Diffstat (limited to 'mesalib/src/glsl/linker.cpp')
-rw-r--r--mesalib/src/glsl/linker.cpp312
1 files changed, 254 insertions, 58 deletions
diff --git a/mesalib/src/glsl/linker.cpp b/mesalib/src/glsl/linker.cpp
index 942f90615..f87ae0eec 100644
--- a/mesalib/src/glsl/linker.cpp
+++ b/mesalib/src/glsl/linker.cpp
@@ -73,11 +73,15 @@
#include "linker.h"
#include "link_varyings.h"
#include "ir_optimization.h"
+#include "ir_rvalue_visitor.h"
extern "C" {
#include "main/shaderobj.h"
+#include "main/enums.h"
}
+void linker_error(gl_shader_program *, const char *, ...);
+
/**
* Visitor that determines whether or not a variable is ever written.
*/
@@ -174,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, ...)
{
@@ -298,41 +373,6 @@ link_invalidate_variable_locations(gl_shader *sh, int input_base,
/**
- * Determine the number of attribute slots required for a particular type
- *
- * This code is here because it implements the language rules of a specific
- * GLSL version. Since it's a property of the language and not a property of
- * types in general, it doesn't really belong in glsl_type.
- */
-unsigned
-count_attribute_slots(const glsl_type *t)
-{
- /* From page 31 (page 37 of the PDF) of the GLSL 1.50 spec:
- *
- * "A scalar input counts the same amount against this limit as a vec4,
- * so applications may want to consider packing groups of four
- * unrelated float inputs together into a vector to better utilize the
- * capabilities of the underlying hardware. A matrix input will use up
- * multiple locations. The number of locations used will equal the
- * number of columns in the matrix."
- *
- * The spec does not explicitly say how arrays are counted. However, it
- * should be safe to assume the total number of slots consumed by an array
- * is the number of entries in the array multiplied by the number of slots
- * consumed by a single element of the array.
- */
-
- if (t->is_array())
- return t->array_size() * count_attribute_slots(t->element_type());
-
- if (t->is_matrix())
- return t->matrix_columns;
-
- return 1;
-}
-
-
-/**
* Verify that a vertex shader executable meets all semantic requirements.
*
* Also sets prog->Vert.UsesClipDistance and prog->Vert.ClipDistanceArraySize
@@ -437,6 +477,24 @@ validate_fragment_shader_executable(struct gl_shader_program *prog,
}
}
+/**
+ * Verify that a geometry shader executable meets all semantic requirements
+ *
+ * Also sets prog->Geom.VerticesIn as a side effect.
+ *
+ * \param shader Geometry shader executable to be verified
+ */
+void
+validate_geometry_shader_executable(struct gl_shader_program *prog,
+ struct gl_shader *shader)
+{
+ if (shader == NULL)
+ return;
+
+ unsigned num_vertices = vertices_per_prim(prog->Geom.InputType);
+ prog->Geom.VerticesIn = num_vertices;
+}
+
/**
* Generate a string describing the mode of a variable
@@ -931,6 +989,99 @@ public:
};
/**
+ * Performs the cross-validation of geometry shader max_vertices and
+ * primitive type layout qualifiers for the attached geometry shaders,
+ * and propagates them to the linked GS and linked shader program.
+ */
+static void
+link_gs_inout_layout_qualifiers(struct gl_shader_program *prog,
+ struct gl_shader *linked_shader,
+ struct gl_shader **shader_list,
+ unsigned num_shaders)
+{
+ linked_shader->Geom.VerticesOut = 0;
+ linked_shader->Geom.InputType = PRIM_UNKNOWN;
+ linked_shader->Geom.OutputType = PRIM_UNKNOWN;
+
+ /* No in/out qualifiers defined for anything but GLSL 1.50+
+ * geometry shaders so far.
+ */
+ if (linked_shader->Type != GL_GEOMETRY_SHADER || prog->Version < 150)
+ return;
+
+ /* From the GLSL 1.50 spec, page 46:
+ *
+ * "All geometry shader output layout declarations in a program
+ * must declare the same layout and same value for
+ * max_vertices. There must be at least one geometry output
+ * layout declaration somewhere in a program, but not all
+ * geometry shaders (compilation units) are required to
+ * declare it."
+ */
+
+ for (unsigned i = 0; i < num_shaders; i++) {
+ struct gl_shader *shader = shader_list[i];
+
+ if (shader->Geom.InputType != PRIM_UNKNOWN) {
+ if (linked_shader->Geom.InputType != PRIM_UNKNOWN &&
+ linked_shader->Geom.InputType != shader->Geom.InputType) {
+ linker_error(prog, "geometry shader defined with conflicting "
+ "input types\n");
+ return;
+ }
+ linked_shader->Geom.InputType = shader->Geom.InputType;
+ }
+
+ if (shader->Geom.OutputType != PRIM_UNKNOWN) {
+ if (linked_shader->Geom.OutputType != PRIM_UNKNOWN &&
+ linked_shader->Geom.OutputType != shader->Geom.OutputType) {
+ linker_error(prog, "geometry shader defined with conflicting "
+ "output types\n");
+ return;
+ }
+ linked_shader->Geom.OutputType = shader->Geom.OutputType;
+ }
+
+ if (shader->Geom.VerticesOut != 0) {
+ if (linked_shader->Geom.VerticesOut != 0 &&
+ linked_shader->Geom.VerticesOut != shader->Geom.VerticesOut) {
+ linker_error(prog, "geometry shader defined with conflicting "
+ "output vertex count (%d and %d)\n",
+ linked_shader->Geom.VerticesOut,
+ shader->Geom.VerticesOut);
+ return;
+ }
+ linked_shader->Geom.VerticesOut = shader->Geom.VerticesOut;
+ }
+ }
+
+ /* Just do the intrastage -> interstage propagation right now,
+ * since we already know we're in the right type of shader program
+ * for doing it.
+ */
+ if (linked_shader->Geom.InputType == PRIM_UNKNOWN) {
+ linker_error(prog,
+ "geometry shader didn't declare primitive input type\n");
+ return;
+ }
+ prog->Geom.InputType = linked_shader->Geom.InputType;
+
+ if (linked_shader->Geom.OutputType == PRIM_UNKNOWN) {
+ linker_error(prog,
+ "geometry shader didn't declare primitive output type\n");
+ return;
+ }
+ prog->Geom.OutputType = linked_shader->Geom.OutputType;
+
+ if (linked_shader->Geom.VerticesOut == 0) {
+ linker_error(prog,
+ "geometry shader didn't declare max_vertices\n");
+ return;
+ }
+ prog->Geom.VerticesOut = linked_shader->Geom.VerticesOut;
+}
+
+/**
* Combine a group of shaders for a single stage to generate a linked shader
*
* \note
@@ -1034,6 +1185,8 @@ link_intrastage_shaders(void *mem_ctx,
linked->NumUniformBlocks = num_uniform_blocks;
ralloc_steal(linked, linked->UniformBlocks);
+ link_gs_inout_layout_qualifiers(prog, linked, shader_list, num_shaders);
+
populate_symbol_table(linked);
/* The a pointer to the main function in the final linked shader (i.e., the
@@ -1080,7 +1233,8 @@ link_intrastage_shaders(void *mem_ctx,
if (!link_function_calls(prog, linked, linking_shaders,
num_linking_shaders)) {
ctx->Driver.DeleteShader(ctx, linked);
- linked = NULL;
+ free(linking_shaders);
+ return NULL;
}
free(linking_shaders);
@@ -1088,18 +1242,24 @@ link_intrastage_shaders(void *mem_ctx,
/* At this point linked should contain all of the linked IR, so
* validate it to make sure nothing went wrong.
*/
- if (linked)
- validate_ir_tree(linked->ir);
+ 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.
*/
- if (linked != NULL) {
- array_sizing_visitor v;
-
- v.run(linked->ir);
- }
+ array_sizing_visitor v;
+ v.run(linked->ir);
return linked;
}
@@ -1129,9 +1289,7 @@ update_array_sizes(struct gl_shader_program *prog)
foreach_list(node, prog->_LinkedShaders[i]->ir) {
ir_variable *const var = ((ir_instruction *) node)->as_variable();
- if ((var == NULL) || (var->mode != ir_var_uniform &&
- var->mode != ir_var_shader_in &&
- var->mode != ir_var_shader_out) ||
+ if ((var == NULL) || (var->mode != ir_var_uniform) ||
!var->type->is_array())
continue;
@@ -1334,7 +1492,7 @@ assign_attribute_or_color_locations(gl_shader_program *prog,
* that it doesn't collide with other assigned locations. Otherwise,
* add it to the list of variables that need linker-assigned locations.
*/
- const unsigned slots = count_attribute_slots(var->type);
+ const unsigned slots = var->type->count_attribute_slots();
if (var->location != -1) {
if (var->location >= generic_base && var->index < 1) {
/* From page 61 of the OpenGL 4.0 spec:
@@ -1650,10 +1808,15 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
unsigned num_vert_shaders = 0;
struct gl_shader **frag_shader_list;
unsigned num_frag_shaders = 0;
+ struct gl_shader **geom_shader_list;
+ unsigned num_geom_shaders = 0;
vert_shader_list = (struct gl_shader **)
- calloc(2 * prog->NumShaders, sizeof(struct gl_shader *));
- frag_shader_list = &vert_shader_list[prog->NumShaders];
+ calloc(prog->NumShaders, sizeof(struct gl_shader *));
+ frag_shader_list = (struct gl_shader **)
+ calloc(prog->NumShaders, sizeof(struct gl_shader *));
+ geom_shader_list = (struct gl_shader **)
+ calloc(prog->NumShaders, sizeof(struct gl_shader *));
unsigned min_version = UINT_MAX;
unsigned max_version = 0;
@@ -1679,8 +1842,8 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
num_frag_shaders++;
break;
case GL_GEOMETRY_SHADER:
- /* FINISHME: Support geometry shaders. */
- assert(prog->Shaders[i]->Type != GL_GEOMETRY_SHADER);
+ geom_shader_list[num_geom_shaders] = prog->Shaders[i];
+ num_geom_shaders++;
break;
}
}
@@ -1701,6 +1864,14 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
prog->Version = max_version;
prog->IsES = is_es_prog;
+ /* Geometry shaders have to be linked with vertex shaders.
+ */
+ if (num_geom_shaders > 0 && num_vert_shaders == 0) {
+ linker_error(prog, "Geometry shader must be linked with "
+ "vertex shader\n");
+ goto done;
+ }
+
for (unsigned int i = 0; i < MESA_SHADER_TYPES; i++) {
if (prog->_LinkedShaders[i] != NULL)
ctx->Driver.DeleteShader(ctx, prog->_LinkedShaders[i]);
@@ -1742,6 +1913,22 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
sh);
}
+ if (num_geom_shaders > 0) {
+ gl_shader *const sh =
+ link_intrastage_shaders(mem_ctx, ctx, prog, geom_shader_list,
+ num_geom_shaders);
+
+ if (!prog->LinkStatus)
+ goto done;
+
+ validate_geometry_shader_executable(prog, sh);
+ if (!prog->LinkStatus)
+ goto done;
+
+ _mesa_reference_shader(ctx, &prog->_LinkedShaders[MESA_SHADER_GEOMETRY],
+ sh);
+ }
+
/* Here begins the inter-stage linking phase. Some initial validation is
* performed, then locations are assigned for uniforms, attributes, and
* varyings.
@@ -1828,7 +2015,11 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
prog->_LinkedShaders[MESA_SHADER_VERTEX],
VERT_ATTRIB_GENERIC0, VARYING_SLOT_VAR0);
}
- /* FINISHME: Geometry shaders not implemented yet */
+ if (prog->_LinkedShaders[MESA_SHADER_GEOMETRY] != NULL) {
+ link_invalidate_variable_locations(
+ prog->_LinkedShaders[MESA_SHADER_GEOMETRY],
+ VARYING_SLOT_VAR0, VARYING_SLOT_VAR0);
+ }
if (prog->_LinkedShaders[MESA_SHADER_FRAGMENT] != NULL) {
link_invalidate_variable_locations(
prog->_LinkedShaders[MESA_SHADER_FRAGMENT],
@@ -1862,7 +2053,7 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
* non-zero, but the program object has no vertex or geometry
* shader;
*/
- if (first >= MESA_SHADER_FRAGMENT) {
+ if (first == MESA_SHADER_FRAGMENT) {
linker_error(prog, "Transform feedback varyings specified, but "
"no vertex or geometry shader is present.");
goto done;
@@ -1895,11 +2086,12 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
*/
if (!assign_varying_locations(ctx, mem_ctx, prog,
sh, NULL,
- num_tfeedback_decls, tfeedback_decls))
+ num_tfeedback_decls, tfeedback_decls,
+ 0))
goto done;
}
- do_dead_builtin_varyings(ctx, sh->ir, NULL,
+ do_dead_builtin_varyings(ctx, sh, NULL,
num_tfeedback_decls, tfeedback_decls);
demote_shader_inputs_and_outputs(sh, ir_var_shader_out);
@@ -1914,7 +2106,7 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
*/
gl_shader *const sh = prog->_LinkedShaders[first];
- do_dead_builtin_varyings(ctx, NULL, sh->ir,
+ do_dead_builtin_varyings(ctx, NULL, sh,
num_tfeedback_decls, tfeedback_decls);
demote_shader_inputs_and_outputs(sh, ir_var_shader_in);
@@ -1930,13 +2122,15 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
gl_shader *const sh_i = prog->_LinkedShaders[i];
gl_shader *const sh_next = prog->_LinkedShaders[next];
+ unsigned gs_input_vertices =
+ next == MESA_SHADER_GEOMETRY ? prog->Geom.VerticesIn : 0;
if (!assign_varying_locations(ctx, mem_ctx, prog, sh_i, sh_next,
next == MESA_SHADER_FRAGMENT ? num_tfeedback_decls : 0,
- tfeedback_decls))
+ tfeedback_decls, gs_input_vertices))
goto done;
- do_dead_builtin_varyings(ctx, sh_i->ir, sh_next->ir,
+ do_dead_builtin_varyings(ctx, sh_i, sh_next,
next == MESA_SHADER_FRAGMENT ? num_tfeedback_decls : 0,
tfeedback_decls);
@@ -1985,6 +2179,8 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
done:
free(vert_shader_list);
+ free(frag_shader_list);
+ free(geom_shader_list);
for (unsigned i = 0; i < MESA_SHADER_TYPES; i++) {
if (prog->_LinkedShaders[i] == NULL)