diff options
author | marha <marha@users.sourceforge.net> | 2013-08-19 09:07:37 +0200 |
---|---|---|
committer | marha <marha@users.sourceforge.net> | 2013-08-19 09:07:37 +0200 |
commit | 2d042f719910c5aa1ba9f4a47b21009c729c345e (patch) | |
tree | 2b20d89d5f1ca342ca6f1d817c18b324adf7086f /mesalib/src/glsl | |
parent | c3d3ea464f7f4e53e8fe3e11ecada36cb209ba4d (diff) | |
parent | 854ec4da20ddff9b830be0a7d5b81d8cb4774132 (diff) | |
download | vcxsrv-2d042f719910c5aa1ba9f4a47b21009c729c345e.tar.gz vcxsrv-2d042f719910c5aa1ba9f4a47b21009c729c345e.tar.bz2 vcxsrv-2d042f719910c5aa1ba9f4a47b21009c729c345e.zip |
Merge remote-tracking branch 'origin/released'
* origin/released:
fontconfig libX11 libXdmcp libxcb xkeyboard-config mesa pixman xserver git update 19 aug 2013
Conflicts:
fontconfig/src/fccache.c
Diffstat (limited to 'mesalib/src/glsl')
31 files changed, 1582 insertions, 201 deletions
diff --git a/mesalib/src/glsl/ast.h b/mesalib/src/glsl/ast.h index 5f2d5b1e4..2cf86e797 100644 --- a/mesalib/src/glsl/ast.h +++ b/mesalib/src/glsl/ast.h @@ -439,6 +439,12 @@ struct ast_type_qualifier { unsigned column_major:1; unsigned row_major:1; /** \} */ + + /** \name Layout qualifiers for GLSL 1.50 geometry shaders */ + /** \{ */ + unsigned prim_type:1; + unsigned max_vertices:1; + /** \} */ } /** \brief Set of flags, accessed by name. */ q; @@ -465,6 +471,12 @@ struct ast_type_qualifier { */ int index; + /** Maximum output vertices in GLSL 1.50 geometry shaders. */ + int max_vertices; + + /** Input or output primitive type in GLSL 1.50 geometry shaders */ + GLenum prim_type; + /** * Binding specified via GL_ARB_shading_language_420pack's "binding" keyword. * @@ -899,12 +911,14 @@ public: class ast_interface_block : public ast_node { public: ast_interface_block(ast_type_qualifier layout, - const char *instance_name, - ast_expression *array_size) + const char *instance_name, + bool is_array, + ast_expression *array_size) : layout(layout), block_name(NULL), instance_name(instance_name), - array_size(array_size) + is_array(is_array), array_size(array_size) { - /* empty */ + if (!is_array) + assert(array_size == NULL); } virtual ir_rvalue *hir(exec_list *instructions, @@ -925,16 +939,44 @@ public: exec_list declarations; /** - * Declared array size of the block instance - * - * If the block is not declared as an array, this field will be \c NULL. + * True if the block is declared as an array * * \note * A block can only be an array if it also has an instance name. If this - * field is not \c NULL, ::instance_name must also not be \c NULL. + * field is true, ::instance_name must also not be \c NULL. + */ + bool is_array; + + /** + * Declared array size of the block instance + * + * If the block is not declared as an array or if the block instance array + * is unsized, this field will be \c NULL. */ ast_expression *array_size; }; + + +/** + * AST node representing a declaration of the input layout for geometry + * shaders. + */ +class ast_gs_input_layout : public ast_node +{ +public: + ast_gs_input_layout(const struct YYLTYPE &locp, GLenum prim_type) + : prim_type(prim_type) + { + set_location(locp); + } + + virtual ir_rvalue *hir(exec_list *instructions, + struct _mesa_glsl_parse_state *state); + +private: + const GLenum prim_type; +}; + /*@}*/ extern void diff --git a/mesalib/src/glsl/ast_array_index.cpp b/mesalib/src/glsl/ast_array_index.cpp index 4baeb6f9d..51f6b10f3 100644 --- a/mesalib/src/glsl/ast_array_index.cpp +++ b/mesalib/src/glsl/ast_array_index.cpp @@ -117,7 +117,8 @@ _mesa_ast_array_index_to_hir(void *mem_ctx, } else if (const_index == NULL && array->type->is_array()) { if (array->type->array_size() == 0) { _mesa_glsl_error(&loc, state, "unsized array index must be constant"); - } else if (array->type->fields.array->is_interface()) { + } else if (array->type->fields.array->is_interface() + && array->variable_referenced()->mode == ir_var_uniform) { /* Page 46 in section 4.3.7 of the OpenGL ES 3.00 spec says: * * "All indexes used to index a uniform block array must be diff --git a/mesalib/src/glsl/ast_to_hir.cpp b/mesalib/src/glsl/ast_to_hir.cpp index 598da92f8..04b16c8aa 100644 --- a/mesalib/src/glsl/ast_to_hir.cpp +++ b/mesalib/src/glsl/ast_to_hir.cpp @@ -72,6 +72,8 @@ _mesa_ast_to_hir(exec_list *instructions, struct _mesa_glsl_parse_state *state) state->toplevel_ir = instructions; + state->gs_input_prim_type_specified = false; + /* Section 4.2 of the GLSL 1.20 specification states: * "The built-in functions are scoped in a scope outside the global scope * users declare global variables in. That is, a shader's global scope, @@ -1771,12 +1773,6 @@ process_array_type(YYLTYPE *loc, const glsl_type *base, ast_node *array_size, } } } - } else if (state->es_shader) { - /* Section 10.17 of the GLSL ES 1.00 specification states that unsized - * array declarations have been removed from the language. - */ - _mesa_glsl_error(loc, state, "unsized array declarations are not " - "allowed in GLSL ES 1.00"); } const glsl_type *array_type = glsl_type::get_array_instance(base, length); @@ -1936,6 +1932,8 @@ apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual, bool ubo_qualifiers_valid, bool is_parameter) { + STATIC_ASSERT(sizeof(qual->flags.q) <= sizeof(qual->flags.i)); + if (qual->flags.q.invariant) { if (var->used) { _mesa_glsl_error(loc, state, @@ -1963,6 +1961,21 @@ apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual, _mesa_glsl_shader_target_name(state->target)); } + /* Section 6.1.1 (Function Calling Conventions) of the GLSL 1.10 spec says: + * + * "However, the const qualifier cannot be used with out or inout." + * + * The same section of the GLSL 4.40 spec further clarifies this saying: + * + * "The const qualifier cannot be used with out or inout, or a + * compile-time error results." + */ + if (is_parameter && qual->flags.q.constant && qual->flags.q.out) { + _mesa_glsl_error(loc, state, + "`const' may not be applied to `out' or `inout' " + "function parameters"); + } + /* If there is no qualifier that changes the mode of the variable, leave * the setting alone. */ @@ -2055,13 +2068,24 @@ apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual, else var->interpolation = INTERP_QUALIFIER_NONE; - if (var->interpolation != INTERP_QUALIFIER_NONE && - !(state->target == vertex_shader && var->mode == ir_var_shader_out) && - !(state->target == fragment_shader && var->mode == ir_var_shader_in)) { - _mesa_glsl_error(loc, state, - "interpolation qualifier `%s' can only be applied to " - "vertex shader outputs and fragment shader inputs", - var->interpolation_string()); + if (var->interpolation != INTERP_QUALIFIER_NONE) { + ir_variable_mode mode = (ir_variable_mode) var->mode; + + if (mode != ir_var_shader_in && mode != ir_var_shader_out) { + _mesa_glsl_error(loc, state, + "interpolation qualifier `%s' can only be applied to " + "shader inputs or outputs.", + var->interpolation_string()); + + } + + if ((state->target == vertex_shader && mode == ir_var_shader_in) || + (state->target == fragment_shader && mode == ir_var_shader_out)) { + _mesa_glsl_error(loc, state, + "interpolation qualifier `%s' cannot be applied to " + "vertex shader inputs or fragment shader outputs", + var->interpolation_string()); + } } var->pixel_center_integer = qual->flags.q.pixel_center_integer; @@ -2317,7 +2341,8 @@ get_variable_being_redeclared(ir_variable *var, ast_declaration *decl, earlier->type = var->type; delete var; var = NULL; - } else if (state->ARB_fragment_coord_conventions_enable + } else if ((state->ARB_fragment_coord_conventions_enable || + state->is_version(150, 0)) && strcmp(var->name, "gl_FragCoord") == 0 && earlier->type == var->type && earlier->mode == var->mode) { @@ -2519,6 +2544,81 @@ process_initializer(ir_variable *var, ast_declaration *decl, return result; } + +/** + * Do additional processing necessary for geometry shader input declarations + * (this covers both interface blocks arrays and bare input variables). + */ +static void +handle_geometry_shader_input_decl(struct _mesa_glsl_parse_state *state, + YYLTYPE loc, ir_variable *var) +{ + unsigned num_vertices = 0; + if (state->gs_input_prim_type_specified) { + num_vertices = vertices_per_prim(state->gs_input_prim_type); + } + + /* Geometry shader input variables must be arrays. Caller should have + * reported an error for this. + */ + if (!var->type->is_array()) { + assert(state->error); + + /* To avoid cascading failures, short circuit the checks below. */ + return; + } + + if (var->type->length == 0) { + /* Section 4.3.8.1 (Input Layout Qualifiers) of the GLSL 1.50 spec says: + * + * All geometry shader input unsized array declarations will be + * sized by an earlier input layout qualifier, when present, as per + * the following table. + * + * Followed by a table mapping each allowed input layout qualifier to + * the corresponding input length. + */ + if (num_vertices != 0) + var->type = glsl_type::get_array_instance(var->type->fields.array, + num_vertices); + } else { + /* Section 4.3.8.1 (Input Layout Qualifiers) of the GLSL 1.50 spec + * includes the following examples of compile-time errors: + * + * // code sequence within one shader... + * in vec4 Color1[]; // size unknown + * ...Color1.length()...// illegal, length() unknown + * in vec4 Color2[2]; // size is 2 + * ...Color1.length()...// illegal, Color1 still has no size + * in vec4 Color3[3]; // illegal, input sizes are inconsistent + * layout(lines) in; // legal, input size is 2, matching + * in vec4 Color4[3]; // illegal, contradicts layout + * ... + * + * To detect the case illustrated by Color3, we verify that the size of + * an explicitly-sized array matches the size of any previously declared + * explicitly-sized array. To detect the case illustrated by Color4, we + * verify that the size of an explicitly-sized array is consistent with + * any previously declared input layout. + */ + if (num_vertices != 0 && var->type->length != num_vertices) { + _mesa_glsl_error(&loc, state, + "geometry shader input size contradicts previously" + " declared layout (size is %u, but layout requires a" + " size of %u)", var->type->length, num_vertices); + } else if (state->gs_input_size != 0 && + var->type->length != state->gs_input_size) { + _mesa_glsl_error(&loc, state, + "geometry shader input sizes are " + "inconsistent (size is %u, but a previous " + "declaration has size %u)", + var->type->length, state->gs_input_size); + } else { + state->gs_input_size = var->type->length; + } + } +} + ir_rvalue * ast_declarator_list::hir(exec_list *instructions, struct _mesa_glsl_parse_state *state) @@ -2605,6 +2705,11 @@ ast_declarator_list::hir(exec_list *instructions, * name of a known structure type. This is both invalid and weird. * Emit an error. * + * - The program text contained something like 'mediump float;' + * when the programmer probably meant 'precision mediump + * float;' Emit a warning with a description of what they + * probably meant to do. + * * Note that if decl_type is NULL and there is a structure involved, * there must have been some sort of error with the structure. In this * case we assume that an error was already generated on this line of @@ -2613,20 +2718,33 @@ ast_declarator_list::hir(exec_list *instructions, */ assert(this->type->specifier->structure == NULL || decl_type != NULL || state->error); - if (this->type->specifier->structure == NULL) { - if (decl_type != NULL) { - _mesa_glsl_warning(&loc, state, "empty declaration"); - } else { - _mesa_glsl_error(&loc, state, - "invalid type `%s' in empty declaration", - type_name); - } - } - if (this->type->qualifier.precision != ast_precision_none && - this->type->specifier->structure != NULL) { - _mesa_glsl_error(&loc, state, "precision qualifiers can't be applied " - "to structures"); + if (decl_type == NULL) { + _mesa_glsl_error(&loc, state, + "invalid type `%s' in empty declaration", + type_name); + } else if (this->type->qualifier.precision != ast_precision_none) { + if (this->type->specifier->structure != NULL) { + _mesa_glsl_error(&loc, state, + "precision qualifiers can't be applied " + "to structures"); + } else { + static const char *const precision_names[] = { + "highp", + "highp", + "mediump", + "lowp" + }; + + _mesa_glsl_warning(&loc, state, + "empty declaration with precision qualifier, " + "to set the default precision, use " + "`precision %s %s;'", + precision_names[this->type->qualifier.precision], + type_name); + } + } else { + _mesa_glsl_warning(&loc, state, "empty declaration"); } } @@ -2662,6 +2780,26 @@ ast_declarator_list::hir(exec_list *instructions, var = new(ctx) ir_variable(var_type, decl->identifier, ir_var_auto); + /* The 'varying in' and 'varying out' qualifiers can only be used with + * ARB_geometry_shader4 and EXT_geometry_shader4, which we don't support + * yet. + */ + if (this->type->qualifier.flags.q.varying) { + if (this->type->qualifier.flags.q.in) { + _mesa_glsl_error(& loc, state, + "`varying in' qualifier in declaration of " + "`%s' only valid for geometry shaders using " + "ARB_geometry_shader4 or EXT_geometry_shader4", + decl->identifier); + } else if (this->type->qualifier.flags.q.out) { + _mesa_glsl_error(& loc, state, + "`varying out' qualifier in declaration of " + "`%s' only valid for geometry shaders using " + "ARB_geometry_shader4 or EXT_geometry_shader4", + decl->identifier); + } + } + /* From page 22 (page 28 of the PDF) of the GLSL 1.10 specification; * * "Global variables can only use the qualifiers const, @@ -2796,7 +2934,22 @@ ast_declarator_list::hir(exec_list *instructions, "cannot have array type")) { error_emitted = true; } - } + } else if (state->target == geometry_shader) { + /* From section 4.3.4 (Inputs) of the GLSL 1.50 spec: + * + * Geometry shader input variables get the per-vertex values + * written out by vertex shader output variables of the same + * names. Since a geometry shader operates on a set of + * vertices, each input varying variable (or input block, see + * interface blocks below) needs to be declared as an array. + */ + if (!var->type->is_array()) { + _mesa_glsl_error(&loc, state, + "geometry shader inputs must be arrays"); + } + + handle_geometry_shader_input_decl(state, loc, var); + } } /* Integer fragment inputs must be qualified with 'flat'. In GLSL ES, @@ -2906,7 +3059,7 @@ ast_declarator_list::hir(exec_list *instructions, } break; default: - assert(0); + break; } } @@ -3015,6 +3168,33 @@ ast_declarator_list::hir(exec_list *instructions, decl->identifier); } + if (state->es_shader) { + const glsl_type *const t = (earlier == NULL) + ? var->type : earlier->type; + + if (t->is_array() && t->length == 0) + /* Section 10.17 of the GLSL ES 1.00 specification states that + * unsized array declarations have been removed from the language. + * Arrays that are sized using an initializer are still explicitly + * sized. However, GLSL ES 1.00 does not allow array + * initializers. That is only allowed in GLSL ES 3.00. + * + * Section 4.1.9 (Arrays) of the GLSL ES 3.00 spec says: + * + * "An array type can also be formed without specifying a size + * if the definition includes an initializer: + * + * float x[] = float[2] (1.0, 2.0); // declares an array of size 2 + * float y[] = float[] (1.0, 2.0, 3.0); // declares an array of size 3 + * + * float a[5]; + * float b[] = a;" + */ + _mesa_glsl_error(& loc, state, + "unsized array declarations are not allowed in " + "GLSL ES"); + } + /* If the declaration is not a redeclaration, there are a few additional * semantic checks that must be applied. In addition, variable that was * created for the declaration should be added to the IR stream. @@ -3323,6 +3503,18 @@ ast_function::hir(exec_list *instructions, "function `%s' return type has qualifiers", name); } + /* Section 6.1 (Function Definitions) of the GLSL 1.20 spec says: + * + * "Arrays are allowed as arguments and as the return type. In both + * cases, the array must be explicitly sized." + */ + if (return_type->is_array() && return_type->length == 0) { + YYLTYPE loc = this->get_location(); + _mesa_glsl_error(& loc, state, + "function `%s' return type array must be explicitly " + "sized", name); + } + /* From page 17 (page 23 of the PDF) of the GLSL 1.20 spec: * * "[Sampler types] can only be declared as function parameters @@ -4362,6 +4554,19 @@ ast_interface_block::hir(exec_list *instructions, */ assert(declared_variables.is_empty()); + /* From section 4.3.4 (Inputs) of the GLSL 1.50 spec: + * + * Geometry shader input variables get the per-vertex values written + * out by vertex shader output variables of the same names. Since a + * geometry shader operates on a set of vertices, each input varying + * variable (or input block, see interface blocks below) needs to be + * declared as an array. + */ + if (state->target == geometry_shader && !this->is_array && + var_mode == ir_var_shader_in) { + _mesa_glsl_error(&loc, state, "geometry shader inputs must be arrays"); + } + /* Page 39 (page 45 of the PDF) of section 4.3.7 in the GLSL ES 3.00 spec * says: * @@ -4372,7 +4577,34 @@ ast_interface_block::hir(exec_list *instructions, if (this->instance_name) { ir_variable *var; - if (this->array_size != NULL) { + if (this->is_array) { + /* Section 4.3.7 (Interface Blocks) of the GLSL 1.50 spec says: + * + * For uniform blocks declared an array, each individual array + * element corresponds to a separate buffer object backing one + * instance of the block. As the array size indicates the number + * of buffer objects needed, uniform block array declarations + * must specify an array size. + * + * And a few paragraphs later: + * + * Geometry shader input blocks must be declared as arrays and + * follow the array declaration and linking rules for all + * geometry shader inputs. All other input and output block + * arrays must specify an array size. + * + * The upshot of this is that the only circumstance where an + * interface array size *doesn't* need to be specified is on a + * geometry shader input. + */ + if (this->array_size == NULL && + (state->target != geometry_shader || !this->layout.flags.q.in)) { + _mesa_glsl_error(&loc, state, + "only geometry shader inputs may be unsized " + "instance block arrays"); + + } + const glsl_type *block_array_type = process_array_type(&loc, block_type, this->array_size, state); @@ -4386,13 +4618,15 @@ ast_interface_block::hir(exec_list *instructions, } var->interface_type = block_type; + if (state->target == geometry_shader && var_mode == ir_var_shader_in) + handle_geometry_shader_input_decl(state, loc, var); state->symbols->add_variable(var); instructions->push_tail(var); } else { /* In order to have an array size, the block must also be declared with * an instane name. */ - assert(this->array_size == NULL); + assert(!this->is_array); for (unsigned i = 0; i < num_variables; i++) { ir_variable *var = @@ -4416,6 +4650,72 @@ ast_interface_block::hir(exec_list *instructions, return NULL; } + +ir_rvalue * +ast_gs_input_layout::hir(exec_list *instructions, + struct _mesa_glsl_parse_state *state) +{ + YYLTYPE loc = this->get_location(); + + /* If any geometry input layout declaration preceded this one, make sure it + * was consistent with this one. + */ + if (state->gs_input_prim_type_specified && + state->gs_input_prim_type != this->prim_type) { + _mesa_glsl_error(&loc, state, + "geometry shader input layout does not match" + " previous declaration"); + return NULL; + } + + /* If any shader inputs occurred before this declaration and specified an + * array size, make sure the size they specified is consistent with the + * primitive type. + */ + unsigned num_vertices = vertices_per_prim(this->prim_type); + if (state->gs_input_size != 0 && state->gs_input_size != num_vertices) { + _mesa_glsl_error(&loc, state, + "this geometry shader input layout implies %u vertices" + " per primitive, but a previous input is declared" + " with size %u", num_vertices, state->gs_input_size); + return NULL; + } + + state->gs_input_prim_type_specified = true; + state->gs_input_prim_type = this->prim_type; + + /* If any shader inputs occurred before this declaration and did not + * specify an array size, their size is determined now. + */ + foreach_list (node, instructions) { + ir_variable *var = ((ir_instruction *) node)->as_variable(); + if (var == NULL || var->mode != ir_var_shader_in) + continue; + + /* Note: gl_PrimitiveIDIn has mode ir_var_shader_in, but it's not an + * array; skip it. + */ + if (!var->type->is_array()) + continue; + + if (var->type->length == 0) { + if (var->max_array_access >= num_vertices) { + _mesa_glsl_error(&loc, state, + "this geometry shader input layout implies %u" + " vertices, but an access to element %u of input" + " `%s' already exists", num_vertices, + var->max_array_access, var->name); + } else { + var->type = glsl_type::get_array_instance(var->type->fields.array, + num_vertices); + } + } + } + + return NULL; +} + + static void detect_conflicting_assignments(struct _mesa_glsl_parse_state *state, exec_list *instructions) diff --git a/mesalib/src/glsl/ast_type.cpp b/mesalib/src/glsl/ast_type.cpp index 38c3f8eb0..ce6b6a771 100644 --- a/mesalib/src/glsl/ast_type.cpp +++ b/mesalib/src/glsl/ast_type.cpp @@ -133,6 +133,25 @@ ast_type_qualifier::merge_qualifier(YYLTYPE *loc, return false; } + if (q.flags.q.prim_type) { + if (this->flags.q.prim_type && this->prim_type != q.prim_type) { + _mesa_glsl_error(loc, state, + "conflicting primitive type qualifiers used"); + return false; + } + this->prim_type = q.prim_type; + } + + if (q.flags.q.max_vertices) { + if (this->flags.q.max_vertices && this->max_vertices != q.max_vertices) { + _mesa_glsl_error(loc, state, + "geometry shader set conflicting max_vertices " + "(%d and %d)", this->max_vertices, q.max_vertices); + return false; + } + this->max_vertices = q.max_vertices; + } + if ((q.flags.i & ubo_mat_mask.flags.i) != 0) this->flags.i &= ~ubo_mat_mask.flags.i; if ((q.flags.i & ubo_layout_mask.flags.i) != 0) diff --git a/mesalib/src/glsl/builtin_variables.cpp b/mesalib/src/glsl/builtin_variables.cpp index 1e88b6a73..6a808c072 100644 --- a/mesalib/src/glsl/builtin_variables.cpp +++ b/mesalib/src/glsl/builtin_variables.cpp @@ -686,8 +686,11 @@ builtin_variable_generator::generate_gs_special_vars() * the specific case of gl_PrimitiveIDIn. So we don't need to treat * gl_PrimitiveIDIn as an {ARB,EXT}_geometry_shader4-only variable. */ - add_input(VARYING_SLOT_PRIMITIVE_ID, int_t, "gl_PrimitiveIDIn"); - add_output(VARYING_SLOT_PRIMITIVE_ID, int_t, "gl_PrimitiveID"); + ir_variable *var; + var = add_input(VARYING_SLOT_PRIMITIVE_ID, int_t, "gl_PrimitiveIDIn"); + var->interpolation = INTERP_QUALIFIER_FLAT; + var = add_output(VARYING_SLOT_PRIMITIVE_ID, int_t, "gl_PrimitiveID"); + var->interpolation = INTERP_QUALIFIER_FLAT; } @@ -702,6 +705,12 @@ builtin_variable_generator::generate_fs_special_vars() if (state->is_version(120, 100)) add_input(VARYING_SLOT_PNTC, vec2_t, "gl_PointCoord"); + if (state->is_version(150, 0)) { + ir_variable *var = + add_input(VARYING_SLOT_PRIMITIVE_ID, int_t, "gl_PrimitiveID"); + var->interpolation = INTERP_QUALIFIER_FLAT; + } + /* gl_FragColor and gl_FragData were deprecated starting in desktop GLSL * 1.30, and were relegated to the compatibility profile in GLSL 4.20. * They were removed from GLSL ES 3.00. diff --git a/mesalib/src/glsl/glsl_parser.yy b/mesalib/src/glsl/glsl_parser.yy index fcc5620cd..e3a57ea02 100644 --- a/mesalib/src/glsl/glsl_parser.yy +++ b/mesalib/src/glsl/glsl_parser.yy @@ -254,6 +254,7 @@ _mesa_glsl_lex(YYSTYPE *val, YYLTYPE *loc, _mesa_glsl_parse_state *state) %type <node> for_init_statement %type <for_rest_statement> for_rest_statement %type <n> integer_constant +%type <node> layout_defaults %right THEN ELSE %% @@ -1157,7 +1158,8 @@ layout_qualifier_id: memset(& $$, 0, sizeof($$)); /* Layout qualifiers for ARB_fragment_coord_conventions. */ - if (!$$.flags.i && state->ARB_fragment_coord_conventions_enable) { + if (!$$.flags.i && (state->ARB_fragment_coord_conventions_enable || + state->is_version(150, 0))) { if (strcmp($1, "origin_upper_left") == 0) { $$.flags.q.origin_upper_left = 1; } else if (strcmp($1, "pixel_center_integer") == 0) { @@ -1222,6 +1224,34 @@ layout_qualifier_id: } } + /* Layout qualifiers for GLSL 1.50 geometry shaders. */ + if (!$$.flags.i) { + struct { + const char *s; + GLenum e; + } map[] = { + { "points", GL_POINTS }, + { "lines", GL_LINES }, + { "lines_adjacency", GL_LINES_ADJACENCY }, + { "line_strip", GL_LINE_STRIP }, + { "triangles", GL_TRIANGLES }, + { "triangles_adjacency", GL_TRIANGLES_ADJACENCY }, + { "triangle_strip", GL_TRIANGLE_STRIP }, + }; + for (unsigned i = 0; i < Elements(map); i++) { + if (strcmp($1, map[i].s) == 0) { + $$.flags.q.prim_type = 1; + $$.prim_type = map[i].e; + break; + } + } + + if ($$.flags.i && !state->is_version(150, 0)) { + _mesa_glsl_error(& @1, state, "#version 150 layout " + "qualifier `%s' used", $1); + } + } + if (!$$.flags.i) { _mesa_glsl_error(& @1, state, "unrecognized layout identifier " "`%s'", $1); @@ -1264,6 +1294,23 @@ layout_qualifier_id: $$.binding = $3; } + if (strcmp("max_vertices", $1) == 0) { + $$.flags.q.max_vertices = 1; + + if ($3 < 0) { + _mesa_glsl_error(& @3, state, + "invalid max_vertices %d specified", $3); + YYERROR; + } else { + $$.max_vertices = $3; + if (!state->is_version(150, 0)) { + _mesa_glsl_error(& @3, state, + "#version 150 max_vertices qualifier " + "specified", $3); + } + } + } + /* If the identifier didn't match any known layout identifiers, * emit an error. */ @@ -2046,7 +2093,7 @@ external_declaration: function_definition { $$ = $1; } | declaration { $$ = $1; } | pragma_statement { $$ = NULL; } - | layout_defaults { $$ = NULL; } + | layout_defaults { $$ = $1; } ; function_definition: @@ -2197,25 +2244,22 @@ instance_name_opt: /* empty */ { $$ = new(state) ast_interface_block(*state->default_uniform_qualifier, - NULL, NULL); + NULL, false, NULL); } | NEW_IDENTIFIER { $$ = new(state) ast_interface_block(*state->default_uniform_qualifier, - $1, NULL); + $1, false, NULL); } | NEW_IDENTIFIER '[' constant_expression ']' { $$ = new(state) ast_interface_block(*state->default_uniform_qualifier, - $1, $3); + $1, true, $3); } | NEW_IDENTIFIER '[' ']' { - _mesa_glsl_error(& @1, state, - "instance block arrays must be explicitly sized"); - $$ = new(state) ast_interface_block(*state->default_uniform_qualifier, - $1, NULL); + $1, true, NULL); } ; @@ -2263,4 +2307,32 @@ layout_defaults: if (!state->default_uniform_qualifier->merge_qualifier(& @1, state, $1)) { YYERROR; } + $$ = NULL; + } + + | layout_qualifier IN_TOK ';' + { + void *ctx = state; + if (state->target != geometry_shader) { + _mesa_glsl_error(& @1, state, + "input layout qualifiers only valid in " + "geometry shaders"); + } else if (!$1.flags.q.prim_type) { + _mesa_glsl_error(& @1, state, + "input layout qualifiers must specify a primitive" + " type"); + } + $$ = new(ctx) ast_gs_input_layout(@1, $1.prim_type); + } + + | layout_qualifier OUT_TOK ';' + { + if (state->target != geometry_shader) { + _mesa_glsl_error(& @1, state, + "out layout qualifiers only valid in " + "geometry shaders"); + } else if (!state->out_qualifier->merge_qualifier(& @1, state, $1)) { + YYERROR; + } + $$ = NULL; } diff --git a/mesalib/src/glsl/glsl_parser_extras.cpp b/mesalib/src/glsl/glsl_parser_extras.cpp index a5bc20c23..88f048365 100644 --- a/mesalib/src/glsl/glsl_parser_extras.cpp +++ b/mesalib/src/glsl/glsl_parser_extras.cpp @@ -159,6 +159,10 @@ _mesa_glsl_parse_state::_mesa_glsl_parse_state(struct gl_context *_ctx, this->default_uniform_qualifier = new(this) ast_type_qualifier(); this->default_uniform_qualifier->flags.q.shared = 1; this->default_uniform_qualifier->flags.q.column_major = 1; + + this->gs_input_prim_type_specified = false; + this->gs_input_prim_type = GL_POINTS; + this->out_qualifier = new(this) ast_type_qualifier(); } /** @@ -1410,6 +1414,34 @@ ast_struct_specifier::ast_struct_specifier(const char *identifier, is_declaration = true; } +static void +set_shader_inout_layout(struct gl_shader *shader, + struct _mesa_glsl_parse_state *state) +{ + if (shader->Type != GL_GEOMETRY_SHADER) { + /* Should have been prevented by the parser. */ + assert(!state->gs_input_prim_type_specified); + assert(!state->out_qualifier->flags.i); + return; + } + + shader->Geom.VerticesOut = 0; + if (state->out_qualifier->flags.q.max_vertices) + shader->Geom.VerticesOut = state->out_qualifier->max_vertices; + + if (state->gs_input_prim_type_specified) { + shader->Geom.InputType = state->gs_input_prim_type; + } else { + shader->Geom.InputType = PRIM_UNKNOWN; + } + + if (state->out_qualifier->flags.q.prim_type) { + shader->Geom.OutputType = state->out_qualifier->prim_type; + } else { + shader->Geom.OutputType = PRIM_UNKNOWN; + } +} + extern "C" { void @@ -1485,6 +1517,9 @@ _mesa_glsl_compile_shader(struct gl_context *ctx, struct gl_shader *shader, shader->UniformBlocks = state->uniform_blocks; ralloc_steal(shader, shader->UniformBlocks); + if (!state->error) + set_shader_inout_layout(shader, state); + /* Retain any live IR, but trash the rest. */ reparent_ir(shader->ir, shader->ir); diff --git a/mesalib/src/glsl/glsl_parser_extras.h b/mesalib/src/glsl/glsl_parser_extras.h index 45f5246f7..7e5a77fa6 100644 --- a/mesalib/src/glsl/glsl_parser_extras.h +++ b/mesalib/src/glsl/glsl_parser_extras.h @@ -170,6 +170,24 @@ struct _mesa_glsl_parse_state { struct ast_type_qualifier *default_uniform_qualifier; /** + * True if a geometry shader input primitive type was specified using a + * layout directive. + * + * Note: this value is computed at ast_to_hir time rather than at parse + * time. + */ + bool gs_input_prim_type_specified; + + /** + * If gs_input_prim_type_specified is true, the primitive type that was + * specified. Otherwise ignored. + */ + GLenum gs_input_prim_type; + + /** Output layout qualifiers from GLSL 1.50. (geometry shader controls)*/ + struct ast_type_qualifier *out_qualifier; + + /** * Printable list of GLSL versions supported by the current context * * \note @@ -302,6 +320,15 @@ struct _mesa_glsl_parse_state { /** Shaders containing built-in functions that are used for linking. */ struct gl_shader *builtins_to_link[16]; unsigned num_builtins_to_link; + + /** + * For geometry shaders, size of the most recently seen input declaration + * that was a sized array, or 0 if no sized input array declarations have + * been seen. + * + * Unused for other shader types. + */ + unsigned gs_input_size; }; # define YYLLOC_DEFAULT(Current, Rhs, N) \ diff --git a/mesalib/src/glsl/glsl_types.cpp b/mesalib/src/glsl/glsl_types.cpp index 8324b8ade..0c7e8eb11 100644 --- a/mesalib/src/glsl/glsl_types.cpp +++ b/mesalib/src/glsl/glsl_types.cpp @@ -828,3 +828,58 @@ glsl_type::std140_size(bool row_major) const assert(!"not reached"); return -1; } + + +unsigned +glsl_type::count_attribute_slots() const +{ + /* 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. + * + * The spec says nothing about how structs are counted, because vertex + * attributes are not allowed to be (or contain) structs. However, Mesa + * allows varying structs, the number of varying slots taken up by a + * varying struct is simply equal to the sum of the number of slots taken + * up by each element. + */ + switch (this->base_type) { + case GLSL_TYPE_UINT: + case GLSL_TYPE_INT: + case GLSL_TYPE_FLOAT: + case GLSL_TYPE_BOOL: + return this->matrix_columns; + + case GLSL_TYPE_STRUCT: + case GLSL_TYPE_INTERFACE: { + unsigned size = 0; + + for (unsigned i = 0; i < this->length; i++) + size += this->fields.structure[i].type->count_attribute_slots(); + + return size; + } + + case GLSL_TYPE_ARRAY: + return this->length * this->fields.array->count_attribute_slots(); + + case GLSL_TYPE_SAMPLER: + case GLSL_TYPE_VOID: + case GLSL_TYPE_ERROR: + break; + } + + assert(!"Unexpected type in count_attribute_slots()"); + + return 0; +} diff --git a/mesalib/src/glsl/glsl_types.h b/mesalib/src/glsl/glsl_types.h index 8172309a7..647867a23 100644 --- a/mesalib/src/glsl/glsl_types.h +++ b/mesalib/src/glsl/glsl_types.h @@ -253,6 +253,18 @@ struct glsl_type { unsigned component_slots() const; /** + * Calculate the number of attribute slots required to hold this type + * + * This implements the language rules of GLSL 1.50 for counting the number + * of slots used by a vertex attribute. It also determines the number of + * varying slots the type will use up in the absence of varying packing + * (and thus, it can be used to measure the number of varying slots used by + * the varyings that are generated by lower_packed_varyings). + */ + unsigned count_attribute_slots() const; + + + /** * Alignment in bytes of the start of this type in a std140 uniform * block. */ diff --git a/mesalib/src/glsl/ir.cpp b/mesalib/src/glsl/ir.cpp index dad58deeb..99dceacf8 100644 --- a/mesalib/src/glsl/ir.cpp +++ b/mesalib/src/glsl/ir.cpp @@ -1778,3 +1778,24 @@ ir_rvalue::as_rvalue_to_saturate() return NULL; } + + +unsigned +vertices_per_prim(GLenum prim) +{ + switch (prim) { + case GL_POINTS: + return 1; + case GL_LINES: + return 2; + case GL_TRIANGLES: + return 3; + case GL_LINES_ADJACENCY: + return 4; + case GL_TRIANGLES_ADJACENCY: + return 6; + default: + assert(!"Bad primitive"); + return 3; + } +} diff --git a/mesalib/src/glsl/ir.h b/mesalib/src/glsl/ir.h index 7ac291cf4..62e3b27ca 100644 --- a/mesalib/src/glsl/ir.h +++ b/mesalib/src/glsl/ir.h @@ -81,6 +81,8 @@ enum ir_node_type { ir_type_return, ir_type_swizzle, ir_type_texture, + ir_type_emit_vertex, + ir_type_end_primitive, ir_type_max /**< maximum ir_type enum number, for validation */ }; @@ -519,6 +521,8 @@ public: * * - Vertex shader input: one of the values from \c gl_vert_attrib. * - Vertex shader output: one of the values from \c gl_varying_slot. + * - Geometry shader input: one of the values from \c gl_varying_slot. + * - Geometry shader output: one of the values from \c gl_varying_slot. * - Fragment shader input: one of the values from \c gl_varying_slot. * - Fragment shader output: one of the values from \c gl_frag_result. * - Uniforms: Per-stage uniform slot number for default uniform block. @@ -1992,6 +1996,53 @@ private: /*@}*/ /** + * IR instruction to emit a vertex in a geometry shader. + */ +class ir_emit_vertex : public ir_instruction { +public: + ir_emit_vertex() + { + ir_type = ir_type_emit_vertex; + } + + virtual void accept(ir_visitor *v) + { + v->visit(this); + } + + virtual ir_emit_vertex *clone(void *mem_ctx, struct hash_table *) const + { + return new(mem_ctx) ir_emit_vertex(); + } + + virtual ir_visitor_status accept(ir_hierarchical_visitor *); +}; + +/** + * IR instruction to complete the current primitive and start a new one in a + * geometry shader. + */ +class ir_end_primitive : public ir_instruction { +public: + ir_end_primitive() + { + ir_type = ir_type_end_primitive; + } + + virtual void accept(ir_visitor *v) + { + v->visit(this); + } + + virtual ir_end_primitive *clone(void *mem_ctx, struct hash_table *) const + { + return new(mem_ctx) ir_end_primitive(); + } + + virtual ir_visitor_status accept(ir_hierarchical_visitor *); +}; + +/** * Apply a visitor to each IR node in a list */ void @@ -2061,7 +2112,7 @@ ir_has_call(ir_instruction *ir); extern void do_set_program_inouts(exec_list *instructions, struct gl_program *prog, - bool is_fragment_shader); + GLenum shader_type); extern char * prototype_string(const glsl_type *return_type, const char *name, @@ -2077,4 +2128,7 @@ extern void _mesa_print_ir(struct exec_list *instructions, } /* extern "C" */ #endif +unsigned +vertices_per_prim(GLenum prim); + #endif /* IR_H */ diff --git a/mesalib/src/glsl/ir_builder.cpp b/mesalib/src/glsl/ir_builder.cpp index 8fb30a02a..7d9cf5e47 100644 --- a/mesalib/src/glsl/ir_builder.cpp +++ b/mesalib/src/glsl/ir_builder.cpp @@ -219,6 +219,12 @@ saturate(operand a) new(mem_ctx) ir_constant(0.0f)); } +ir_expression * +abs(operand a) +{ + return expr(ir_unop_abs, a); +} + ir_expression* equal(operand a, operand b) { @@ -226,6 +232,12 @@ equal(operand a, operand b) } ir_expression* +nequal(operand a, operand b) +{ + return expr(ir_binop_nequal, a, b); +} + +ir_expression* less(operand a, operand b) { return expr(ir_binop_less, a, b); @@ -304,12 +316,24 @@ f2i(operand a) } ir_expression* +bitcast_f2i(operand a) +{ + return expr(ir_unop_bitcast_f2i, a); +} + +ir_expression* i2f(operand a) { return expr(ir_unop_i2f, a); } ir_expression* +bitcast_i2f(operand a) +{ + return expr(ir_unop_bitcast_i2f, a); +} + +ir_expression* i2u(operand a) { return expr(ir_unop_i2u, a); @@ -328,11 +352,35 @@ f2u(operand a) } ir_expression* +bitcast_f2u(operand a) +{ + return expr(ir_unop_bitcast_f2u, a); +} + +ir_expression* u2f(operand a) { return expr(ir_unop_u2f, a); } +ir_expression* +bitcast_u2f(operand a) +{ + return expr(ir_unop_bitcast_u2f, a); +} + +ir_expression* +i2b(operand a) +{ + return expr(ir_unop_i2b, a); +} + +ir_expression* +b2i(operand a) +{ + return expr(ir_unop_b2i, a); +} + ir_if* if_tree(operand condition, ir_instruction *then_branch) diff --git a/mesalib/src/glsl/ir_builder.h b/mesalib/src/glsl/ir_builder.h index 690ac74eb..7049476a1 100644 --- a/mesalib/src/glsl/ir_builder.h +++ b/mesalib/src/glsl/ir_builder.h @@ -133,8 +133,10 @@ ir_expression *round_even(operand a); ir_expression *dot(operand a, operand b); ir_expression *clamp(operand a, operand b, operand c); ir_expression *saturate(operand a); +ir_expression *abs(operand a); ir_expression *equal(operand a, operand b); +ir_expression *nequal(operand a, operand b); ir_expression *less(operand a, operand b); ir_expression *greater(operand a, operand b); ir_expression *lequal(operand a, operand b); @@ -151,11 +153,17 @@ ir_expression *lshift(operand a, operand b); ir_expression *rshift(operand a, operand b); ir_expression *f2i(operand a); +ir_expression *bitcast_f2i(operand a); ir_expression *i2f(operand a); +ir_expression *bitcast_i2f(operand a); ir_expression *f2u(operand a); +ir_expression *bitcast_f2u(operand a); ir_expression *u2f(operand a); +ir_expression *bitcast_u2f(operand a); ir_expression *i2u(operand a); ir_expression *u2i(operand a); +ir_expression *b2i(operand a); +ir_expression *i2b(operand a); /** * Swizzle away later components, but preserve the ordering. diff --git a/mesalib/src/glsl/ir_hierarchical_visitor.cpp b/mesalib/src/glsl/ir_hierarchical_visitor.cpp index f24414046..2e606dda4 100644 --- a/mesalib/src/glsl/ir_hierarchical_visitor.cpp +++ b/mesalib/src/glsl/ir_hierarchical_visitor.cpp @@ -69,6 +69,24 @@ ir_hierarchical_visitor::visit(ir_loop_jump *ir) } ir_visitor_status +ir_hierarchical_visitor::visit(ir_emit_vertex *ir) +{ + if (this->callback != NULL) + this->callback(ir, this->data); + + return visit_continue; +} + +ir_visitor_status +ir_hierarchical_visitor::visit(ir_end_primitive *ir) +{ + if (this->callback != NULL) + this->callback(ir, this->data); + + return visit_continue; +} + +ir_visitor_status ir_hierarchical_visitor::visit(ir_dereference_variable *ir) { if (this->callback != NULL) diff --git a/mesalib/src/glsl/ir_hierarchical_visitor.h b/mesalib/src/glsl/ir_hierarchical_visitor.h index 1988ad091..647d2e002 100644 --- a/mesalib/src/glsl/ir_hierarchical_visitor.h +++ b/mesalib/src/glsl/ir_hierarchical_visitor.h @@ -87,6 +87,8 @@ public: virtual ir_visitor_status visit(class ir_variable *); virtual ir_visitor_status visit(class ir_constant *); virtual ir_visitor_status visit(class ir_loop_jump *); + virtual ir_visitor_status visit(class ir_emit_vertex *); + virtual ir_visitor_status visit(class ir_end_primitive *); /** * ir_dereference_variable isn't technically a leaf, but it is treated as a diff --git a/mesalib/src/glsl/ir_hv_accept.cpp b/mesalib/src/glsl/ir_hv_accept.cpp index 559b71af3..76a607d17 100644 --- a/mesalib/src/glsl/ir_hv_accept.cpp +++ b/mesalib/src/glsl/ir_hv_accept.cpp @@ -415,3 +415,16 @@ ir_if::accept(ir_hierarchical_visitor *v) return v->visit_leave(this); } + +ir_visitor_status +ir_emit_vertex::accept(ir_hierarchical_visitor *v) +{ + return v->visit(this); +} + + +ir_visitor_status +ir_end_primitive::accept(ir_hierarchical_visitor *v) +{ + return v->visit(this); +} diff --git a/mesalib/src/glsl/ir_optimization.h b/mesalib/src/glsl/ir_optimization.h index 2c1479ff4..b79c2b787 100644 --- a/mesalib/src/glsl/ir_optimization.h +++ b/mesalib/src/glsl/ir_optimization.h @@ -77,7 +77,7 @@ bool do_copy_propagation(exec_list *instructions); bool do_copy_propagation_elements(exec_list *instructions); bool do_constant_propagation(exec_list *instructions); void do_dead_builtin_varyings(struct gl_context *ctx, - exec_list *producer, exec_list *consumer, + gl_shader *producer, gl_shader *consumer, unsigned num_tfeedback_decls, class tfeedback_decl *tfeedback_decls); bool do_dead_code(exec_list *instructions, bool uniform_locations_assigned); @@ -112,7 +112,7 @@ bool lower_packing_builtins(exec_list *instructions, int op_mask); void lower_ubo_reference(struct gl_shader *shader, exec_list *instructions); void lower_packed_varyings(void *mem_ctx, unsigned location_base, unsigned locations_used, ir_variable_mode mode, - gl_shader *shader); + unsigned gs_input_vertices, gl_shader *shader); bool lower_vector_insert(exec_list *instructions, bool lower_nonconstant_index); void lower_named_interface_blocks(void *mem_ctx, gl_shader *shader); bool optimize_redundant_jumps(exec_list *instructions); diff --git a/mesalib/src/glsl/ir_print_visitor.cpp b/mesalib/src/glsl/ir_print_visitor.cpp index ca973a5f3..541231a33 100644 --- a/mesalib/src/glsl/ir_print_visitor.cpp +++ b/mesalib/src/glsl/ir_print_visitor.cpp @@ -539,3 +539,15 @@ ir_print_visitor::visit(ir_loop_jump *ir) { printf("%s", ir->is_break() ? "break" : "continue"); } + +void +ir_print_visitor::visit(ir_emit_vertex *ir) +{ + printf("(emit-vertex)"); +} + +void +ir_print_visitor::visit(ir_end_primitive *ir) +{ + printf("(end-primitive)"); +} diff --git a/mesalib/src/glsl/ir_print_visitor.h b/mesalib/src/glsl/ir_print_visitor.h index a84056d16..865376fe0 100644 --- a/mesalib/src/glsl/ir_print_visitor.h +++ b/mesalib/src/glsl/ir_print_visitor.h @@ -69,6 +69,8 @@ public: virtual void visit(ir_if *); virtual void visit(ir_loop *); virtual void visit(ir_loop_jump *); + virtual void visit(ir_emit_vertex *); + virtual void visit(ir_end_primitive *); /*@}*/ private: diff --git a/mesalib/src/glsl/ir_reader.cpp b/mesalib/src/glsl/ir_reader.cpp index 51534ca7c..f263fe810 100644 --- a/mesalib/src/glsl/ir_reader.cpp +++ b/mesalib/src/glsl/ir_reader.cpp @@ -59,6 +59,8 @@ private: ir_swizzle *read_swizzle(s_expression *); ir_constant *read_constant(s_expression *); ir_texture *read_texture(s_expression *); + ir_emit_vertex *read_emit_vertex(s_expression *); + ir_end_primitive *read_end_primitive(s_expression *); ir_dereference *read_dereference(s_expression *); ir_dereference_variable *read_var_ref(s_expression *); @@ -355,6 +357,10 @@ ir_reader::read_instruction(s_expression *expr, ir_loop *loop_ctx) inst = read_return(list); } else if (strcmp(tag->value(), "function") == 0) { inst = read_function(list, false); + } else if (strcmp(tag->value(), "emit-vertex") == 0) { + inst = read_emit_vertex(list); + } else if (strcmp(tag->value(), "end-primitive") == 0) { + inst = read_end_primitive(list); } else { inst = read_rvalue(list); if (inst == NULL) @@ -1065,3 +1071,27 @@ ir_reader::read_texture(s_expression *expr) }; return tex; } + +ir_emit_vertex * +ir_reader::read_emit_vertex(s_expression *expr) +{ + s_pattern pat[] = { "emit-vertex" }; + + if (MATCH(expr, pat)) { + return new(mem_ctx) ir_emit_vertex(); + } + ir_read_error(NULL, "when reading emit-vertex"); + return NULL; +} + +ir_end_primitive * +ir_reader::read_end_primitive(s_expression *expr) +{ + s_pattern pat[] = { "end-primitive" }; + + if (MATCH(expr, pat)) { + return new(mem_ctx) ir_end_primitive(); + } + ir_read_error(NULL, "when reading end-primitive"); + return NULL; +} diff --git a/mesalib/src/glsl/ir_set_program_inouts.cpp b/mesalib/src/glsl/ir_set_program_inouts.cpp index 91a8b4526..6196d6a64 100644 --- a/mesalib/src/glsl/ir_set_program_inouts.cpp +++ b/mesalib/src/glsl/ir_set_program_inouts.cpp @@ -44,11 +44,10 @@ class ir_set_program_inouts_visitor : public ir_hierarchical_visitor { public: - ir_set_program_inouts_visitor(struct gl_program *prog, - bool is_fragment_shader) + ir_set_program_inouts_visitor(struct gl_program *prog, GLenum shader_type) { this->prog = prog; - this->is_fragment_shader = is_fragment_shader; + this->shader_type = shader_type; } ~ir_set_program_inouts_visitor() { @@ -60,8 +59,12 @@ public: virtual ir_visitor_status visit_enter(ir_discard *); virtual ir_visitor_status visit(ir_dereference_variable *); +private: + void mark_whole_variable(ir_variable *var); + bool try_mark_partial_variable(ir_variable *var, ir_rvalue *index); + struct gl_program *prog; - bool is_fragment_shader; + GLenum shader_type; }; static inline bool @@ -104,6 +107,23 @@ mark(struct gl_program *prog, ir_variable *var, int offset, int len, } } +/** + * Mark an entire variable as used. Caller must ensure that the variable + * represents a shader input or output. + */ +void +ir_set_program_inouts_visitor::mark_whole_variable(ir_variable *var) +{ + const glsl_type *type = var->type; + if (this->shader_type == GL_GEOMETRY_SHADER && + var->mode == ir_var_shader_in && type->is_array()) { + type = type->fields.array; + } + + mark(this->prog, var, 0, type->count_attribute_slots(), + this->shader_type == GL_FRAGMENT_SHADER); +} + /* Default handler: Mark all the locations in the variable as used. */ ir_visitor_status ir_set_program_inouts_visitor::visit(ir_dereference_variable *ir) @@ -111,43 +131,154 @@ ir_set_program_inouts_visitor::visit(ir_dereference_variable *ir) if (!is_shader_inout(ir->var)) return visit_continue; - if (ir->type->is_array()) { - mark(this->prog, ir->var, 0, - ir->type->length * ir->type->fields.array->matrix_columns, - this->is_fragment_shader); - } else { - mark(this->prog, ir->var, 0, ir->type->matrix_columns, - this->is_fragment_shader); - } + mark_whole_variable(ir->var); return visit_continue; } -ir_visitor_status -ir_set_program_inouts_visitor::visit_enter(ir_dereference_array *ir) +/** + * Try to mark a portion of the given variable as used. Caller must ensure + * that the variable represents a shader input or output which can be indexed + * into in array fashion (an array or matrix). For the purpose of geometry + * shader inputs (which are always arrays*), this means that the array element + * must be something that can be indexed into in array fashion. + * + * *Except gl_PrimitiveIDIn, as noted below. + * + * If the index can't be interpreted as a constant, or some other problem + * occurs, then nothing will be marked and false will be returned. + */ +bool +ir_set_program_inouts_visitor::try_mark_partial_variable(ir_variable *var, + ir_rvalue *index) { - ir_dereference_variable *deref_var; - ir_constant *index = ir->array_index->as_constant(); - deref_var = ir->array->as_dereference_variable(); - ir_variable *var = deref_var ? deref_var->var : NULL; + const glsl_type *type = var->type; - /* Check that we're dereferencing a shader in or out */ - if (!var || !is_shader_inout(var)) - return visit_continue; + if (this->shader_type == GL_GEOMETRY_SHADER && + var->mode == ir_var_shader_in) { + /* The only geometry shader input that is not an array is + * gl_PrimitiveIDIn, and in that case, this code will never be reached, + * because gl_PrimitiveIDIn can't be indexed into in array fashion. + */ + assert(type->is_array()); + type = type->fields.array; + } - if (index) { - int width = 1; + /* The code below only handles: + * + * - Indexing into matrices + * - Indexing into arrays of (matrices, vectors, or scalars) + * + * All other possibilities are either prohibited by GLSL (vertex inputs and + * fragment outputs can't be structs) or should have been eliminated by + * lowering passes (do_vec_index_to_swizzle() gets rid of indexing into + * vectors, and lower_packed_varyings() gets rid of structs that occur in + * varyings). + */ + if (!(type->is_matrix() || + (type->is_array() && + (type->fields.array->is_numeric() || + type->fields.array->is_boolean())))) { + assert(!"Unexpected indexing in ir_set_program_inouts"); - if (deref_var->type->is_array() && - deref_var->type->fields.array->is_matrix()) { - width = deref_var->type->fields.array->matrix_columns; - } + /* For safety in release builds, in case we ever encounter unexpected + * indexing, give up and let the caller mark the whole variable as used. + */ + return false; + } + + ir_constant *index_as_constant = index->as_constant(); + if (!index_as_constant) + return false; + + unsigned elem_width; + unsigned num_elems; + if (type->is_array()) { + num_elems = type->length; + if (type->fields.array->is_matrix()) + elem_width = type->fields.array->matrix_columns; + else + elem_width = 1; + } else { + num_elems = type->matrix_columns; + elem_width = 1; + } - mark(this->prog, var, index->value.i[0] * width, width, - this->is_fragment_shader); - return visit_continue_with_parent; + if (index_as_constant->value.u[0] >= num_elems) { + /* Constant index outside the bounds of the matrix/array. This could + * arise as a result of constant folding of a legal GLSL program. + * + * Even though the spec says that indexing outside the bounds of a + * matrix/array results in undefined behaviour, we don't want to pass + * out-of-range values to mark() (since this could result in slots that + * don't exist being marked as used), so just let the caller mark the + * whole variable as used. + */ + return false; } + mark(this->prog, var, index_as_constant->value.u[0] * elem_width, + elem_width, this->shader_type == GL_FRAGMENT_SHADER); + return true; +} + +ir_visitor_status +ir_set_program_inouts_visitor::visit_enter(ir_dereference_array *ir) +{ + /* Note: for geometry shader inputs, lower_named_interface_blocks may + * create 2D arrays, so we need to be able to handle those. 2D arrays + * shouldn't be able to crop up for any other reason. + */ + if (ir_dereference_array * const inner_array = + ir->array->as_dereference_array()) { + /* ir => foo[i][j] + * inner_array => foo[i] + */ + if (ir_dereference_variable * const deref_var = + inner_array->array->as_dereference_variable()) { + if (this->shader_type == GL_GEOMETRY_SHADER && + deref_var->var->mode == ir_var_shader_in) { + /* foo is a geometry shader input, so i is the vertex, and j the + * part of the input we're accessing. + */ + if (try_mark_partial_variable(deref_var->var, ir->array_index)) + { + /* We've now taken care of foo and j, but i might contain a + * subexpression that accesses shader inputs. So manually + * visit i and then continue with the parent. + */ + inner_array->array_index->accept(this); + return visit_continue_with_parent; + } + } + } + } else if (ir_dereference_variable * const deref_var = + ir->array->as_dereference_variable()) { + /* ir => foo[i], where foo is a variable. */ + if (this->shader_type == GL_GEOMETRY_SHADER && + deref_var->var->mode == ir_var_shader_in) { + /* foo is a geometry shader input, so i is the vertex, and we're + * accessing the entire input. + */ + mark_whole_variable(deref_var->var); + /* We've now taken care of foo, but i might contain a subexpression + * that accesses shader inputs. So manually visit i and then + * continue with the parent. + */ + ir->array_index->accept(this); + return visit_continue_with_parent; + } else if (is_shader_inout(deref_var->var)) { + /* foo is a shader input/output, but not a geometry shader input, + * so i is the part of the input we're accessing. + */ + if (try_mark_partial_variable(deref_var->var, ir->array_index)) + return visit_continue_with_parent; + } + } + + /* The expression is something we don't recognize. Just visit its + * subexpressions. + */ return visit_continue; } @@ -164,7 +295,8 @@ ir_set_program_inouts_visitor::visit_enter(ir_function_signature *ir) ir_visitor_status ir_set_program_inouts_visitor::visit_enter(ir_expression *ir) { - if (is_fragment_shader && ir->operation == ir_unop_dFdy) { + if (this->shader_type == GL_FRAGMENT_SHADER && + ir->operation == ir_unop_dFdy) { gl_fragment_program *fprog = (gl_fragment_program *) prog; fprog->UsesDFdy = true; } @@ -175,7 +307,7 @@ ir_visitor_status ir_set_program_inouts_visitor::visit_enter(ir_discard *) { /* discards are only allowed in fragment shaders. */ - assert(is_fragment_shader); + assert(this->shader_type == GL_FRAGMENT_SHADER); gl_fragment_program *fprog = (gl_fragment_program *) prog; fprog->UsesKill = true; @@ -185,14 +317,14 @@ ir_set_program_inouts_visitor::visit_enter(ir_discard *) void do_set_program_inouts(exec_list *instructions, struct gl_program *prog, - bool is_fragment_shader) + GLenum shader_type) { - ir_set_program_inouts_visitor v(prog, is_fragment_shader); + ir_set_program_inouts_visitor v(prog, shader_type); prog->InputsRead = 0; prog->OutputsWritten = 0; prog->SystemValuesRead = 0; - if (is_fragment_shader) { + if (shader_type == GL_FRAGMENT_SHADER) { gl_fragment_program *fprog = (gl_fragment_program *) prog; memset(fprog->InterpQualifier, 0, sizeof(fprog->InterpQualifier)); fprog->IsCentroid = 0; diff --git a/mesalib/src/glsl/ir_visitor.h b/mesalib/src/glsl/ir_visitor.h index bd47ef7d5..40f96ffbc 100644 --- a/mesalib/src/glsl/ir_visitor.h +++ b/mesalib/src/glsl/ir_visitor.h @@ -63,6 +63,8 @@ public: virtual void visit(class ir_if *) = 0; virtual void visit(class ir_loop *) = 0; virtual void visit(class ir_loop_jump *) = 0; + virtual void visit(class ir_emit_vertex *) = 0; + virtual void visit(class ir_end_primitive *) = 0; /*@}*/ }; @@ -81,6 +83,8 @@ public: virtual void visit(class ir_assignment *) {} virtual void visit(class ir_constant *) {} virtual void visit(class ir_call *) {} + virtual void visit(class ir_emit_vertex *) {} + virtual void visit(class ir_end_primitive *) {} }; #endif /* __cplusplus */ diff --git a/mesalib/src/glsl/link_varyings.cpp b/mesalib/src/glsl/link_varyings.cpp index 2c7e4514e..4ceb1d33e 100644 --- a/mesalib/src/glsl/link_varyings.cpp +++ b/mesalib/src/glsl/link_varyings.cpp @@ -68,6 +68,10 @@ cross_validate_outputs_to_inputs(struct gl_shader_program *prog, /* Find all shader inputs in the "consumer" stage. Any variables that have * matching outputs already in the symbol table must have the same type and * qualifiers. + * + * Exception: if the consumer is the geometry shader, then the inputs + * should be arrays and the type of the array element should match the type + * of the corresponding producer output. */ foreach_list(node, consumer->ir) { ir_variable *const input = ((ir_instruction *) node)->as_variable(); @@ -79,7 +83,12 @@ cross_validate_outputs_to_inputs(struct gl_shader_program *prog, if (output != NULL) { /* Check that the types match between stages. */ - if (input->type != output->type) { + const glsl_type *type_to_match = input->type; + if (consumer->Type == GL_GEOMETRY_SHADER) { + assert(type_to_match->is_array()); /* Enforced by ast_to_hir */ + type_to_match = type_to_match->element_type(); + } + if (type_to_match != output->type) { /* There is a bit of a special case for gl_TexCoord. This * built-in is unsized by default. Applications that variable * access it must redeclare it with a size. There is some @@ -973,6 +982,9 @@ private: * each of these objects that matches one of the outputs of the * producer. * + * \param gs_input_vertices: if \c consumer is a geometry shader, this is the + * number of input vertices it accepts. Otherwise zero. + * * When num_tfeedback_decls is nonzero, it is permissible for the consumer to * be NULL. In this case, varying locations are assigned solely based on the * requirements of transform feedback. @@ -983,7 +995,8 @@ assign_varying_locations(struct gl_context *ctx, struct gl_shader_program *prog, gl_shader *producer, gl_shader *consumer, unsigned num_tfeedback_decls, - tfeedback_decl *tfeedback_decls) + tfeedback_decl *tfeedback_decls, + unsigned gs_input_vertices) { const unsigned producer_base = VARYING_SLOT_VAR0; const unsigned consumer_base = VARYING_SLOT_VAR0; @@ -1104,10 +1117,10 @@ assign_varying_locations(struct gl_context *ctx, assert(!ctx->Extensions.EXT_transform_feedback); } else { lower_packed_varyings(mem_ctx, producer_base, slots_used, - ir_var_shader_out, producer); + ir_var_shader_out, 0, producer); if (consumer) { lower_packed_varyings(mem_ctx, consumer_base, slots_used, - ir_var_shader_in, consumer); + ir_var_shader_in, gs_input_vertices, consumer); } } @@ -1164,7 +1177,7 @@ check_against_varying_limit(struct gl_context *ctx, /* The packing rules used for vertex shader inputs are also * used for fragment shader inputs. */ - varying_vectors += count_attribute_slots(var->type); + varying_vectors += var->type->count_attribute_slots(); } } diff --git a/mesalib/src/glsl/link_varyings.h b/mesalib/src/glsl/link_varyings.h index cfc6e474f..302ab5c26 100644 --- a/mesalib/src/glsl/link_varyings.h +++ b/mesalib/src/glsl/link_varyings.h @@ -234,7 +234,8 @@ assign_varying_locations(struct gl_context *ctx, struct gl_shader_program *prog, gl_shader *producer, gl_shader *consumer, unsigned num_tfeedback_decls, - tfeedback_decl *tfeedback_decls); + tfeedback_decl *tfeedback_decls, + unsigned gs_input_vertices); bool check_against_varying_limit(struct gl_context *ctx, 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) diff --git a/mesalib/src/glsl/linker.h b/mesalib/src/glsl/linker.h index 0ce747d6c..64a683d15 100644 --- a/mesalib/src/glsl/linker.h +++ b/mesalib/src/glsl/linker.h @@ -155,7 +155,4 @@ linker_error(gl_shader_program *prog, const char *fmt, ...); void linker_warning(gl_shader_program *prog, const char *fmt, ...); -unsigned -count_attribute_slots(const glsl_type *t); - #endif /* GLSL_LINKER_H */ diff --git a/mesalib/src/glsl/lower_output_reads.cpp b/mesalib/src/glsl/lower_output_reads.cpp index b93e254ec..5ba9720d0 100644 --- a/mesalib/src/glsl/lower_output_reads.cpp +++ b/mesalib/src/glsl/lower_output_reads.cpp @@ -50,6 +50,7 @@ public: output_read_remover(); ~output_read_remover(); virtual ir_visitor_status visit(class ir_dereference_variable *); + virtual ir_visitor_status visit(class ir_emit_vertex *); virtual ir_visitor_status visit_leave(class ir_return *); virtual ir_visitor_status visit_leave(class ir_function_signature *); }; @@ -117,7 +118,9 @@ copy(void *ctx, ir_variable *output, ir_variable *temp) return new(ctx) ir_assignment(lhs, rhs); } -/** Insert a copy-back assignment before a "return" statement */ +/** Insert a copy-back assignment before a "return" statement or a call to + * EmitVertex(). + */ static void emit_return_copy(const void *key, void *data, void *closure) { @@ -141,6 +144,14 @@ output_read_remover::visit_leave(ir_return *ir) } ir_visitor_status +output_read_remover::visit(ir_emit_vertex *ir) +{ + hash_table_call_foreach(replacements, emit_return_copy, ir); + hash_table_clear(replacements); + return visit_continue; +} + +ir_visitor_status output_read_remover::visit_leave(ir_function_signature *sig) { if (strcmp(sig->function_name(), "main") != 0) diff --git a/mesalib/src/glsl/lower_packed_varyings.cpp b/mesalib/src/glsl/lower_packed_varyings.cpp index cdf2289b4..31a50bba5 100644 --- a/mesalib/src/glsl/lower_packed_varyings.cpp +++ b/mesalib/src/glsl/lower_packed_varyings.cpp @@ -74,6 +74,74 @@ * This lowering pass also handles varyings whose type is a struct or an array * of struct. Structs are packed in order and with no gaps, so there may be a * performance penalty due to structure elements being double-parked. + * + * Lowering of geometry shader inputs is slightly more complex, since geometry + * inputs are always arrays, so we need to lower arrays to arrays. For + * example, the following input: + * + * in struct Foo { + * float f; + * vec3 v; + * vec2 a[2]; + * } arr[3]; // location=4, location_frac=0 + * + * Would get lowered like this if it occurred in a fragment shader: + * + * struct Foo { + * float f; + * vec3 v; + * vec2 a[2]; + * } arr[3]; + * in vec4 packed4; // location=4, location_frac=0 + * in vec4 packed5; // location=5, location_frac=0 + * in vec4 packed6; // location=6, location_frac=0 + * in vec4 packed7; // location=7, location_frac=0 + * in vec4 packed8; // location=8, location_frac=0 + * in vec4 packed9; // location=9, location_frac=0 + * + * main() + * { + * arr[0].f = packed4.x; + * arr[0].v = packed4.yzw; + * arr[0].a[0] = packed5.xy; + * arr[0].a[1] = packed5.zw; + * arr[1].f = packed6.x; + * arr[1].v = packed6.yzw; + * arr[1].a[0] = packed7.xy; + * arr[1].a[1] = packed7.zw; + * arr[2].f = packed8.x; + * arr[2].v = packed8.yzw; + * arr[2].a[0] = packed9.xy; + * arr[2].a[1] = packed9.zw; + * ... + * } + * + * But it would get lowered like this if it occurred in a geometry shader: + * + * struct Foo { + * float f; + * vec3 v; + * vec2 a[2]; + * } arr[3]; + * in vec4 packed4[3]; // location=4, location_frac=0 + * in vec4 packed5[3]; // location=5, location_frac=0 + * + * main() + * { + * arr[0].f = packed4[0].x; + * arr[0].v = packed4[0].yzw; + * arr[0].a[0] = packed5[0].xy; + * arr[0].a[1] = packed5[0].zw; + * arr[1].f = packed4[1].x; + * arr[1].v = packed4[1].yzw; + * arr[1].a[0] = packed5[1].xy; + * arr[1].a[1] = packed5[1].zw; + * arr[2].f = packed4[2].x; + * arr[2].v = packed4[2].yzw; + * arr[2].a[0] = packed5[2].xy; + * arr[2].a[1] = packed5[2].zw; + * ... + * } */ #include "glsl_symbol_table.h" @@ -93,7 +161,8 @@ public: lower_packed_varyings_visitor(void *mem_ctx, unsigned location_base, unsigned locations_used, ir_variable_mode mode, - exec_list *main_instructions); + unsigned gs_input_vertices, + exec_list *out_instructions); void run(exec_list *instructions); @@ -101,13 +170,16 @@ private: ir_assignment *bitwise_assign_pack(ir_rvalue *lhs, ir_rvalue *rhs); ir_assignment *bitwise_assign_unpack(ir_rvalue *lhs, ir_rvalue *rhs); unsigned lower_rvalue(ir_rvalue *rvalue, unsigned fine_location, - ir_variable *unpacked_var, const char *name); + ir_variable *unpacked_var, const char *name, + bool gs_input_toplevel, unsigned vertex_index); unsigned lower_arraylike(ir_rvalue *rvalue, unsigned array_size, unsigned fine_location, - ir_variable *unpacked_var, const char *name); - ir_variable *get_packed_varying(unsigned location, - ir_variable *unpacked_var, - const char *name); + ir_variable *unpacked_var, const char *name, + bool gs_input_toplevel, unsigned vertex_index); + ir_dereference *get_packed_varying_deref(unsigned location, + ir_variable *unpacked_var, + const char *name, + unsigned vertex_index); bool needs_lowering(ir_variable *var); /** @@ -145,15 +217,23 @@ private: const ir_variable_mode mode; /** - * List of instructions corresponding to the main() function. This is - * where we add instructions to pack or unpack the varyings. + * If we are currently lowering geometry shader inputs, the number of input + * vertices the geometry shader accepts. Otherwise zero. */ - exec_list *main_instructions; + const unsigned gs_input_vertices; + + /** + * Exec list into which the visitor should insert the packing instructions. + * Caller provides this list; it should insert the instructions into the + * appropriate place in the shader once the visitor has finished running. + */ + exec_list *out_instructions; }; lower_packed_varyings_visitor::lower_packed_varyings_visitor( void *mem_ctx, unsigned location_base, unsigned locations_used, - ir_variable_mode mode, exec_list *main_instructions) + ir_variable_mode mode, unsigned gs_input_vertices, + exec_list *out_instructions) : mem_ctx(mem_ctx), location_base(location_base), locations_used(locations_used), @@ -161,7 +241,8 @@ lower_packed_varyings_visitor::lower_packed_varyings_visitor( rzalloc_array_size(mem_ctx, sizeof(*packed_varyings), locations_used)), mode(mode), - main_instructions(main_instructions) + gs_input_vertices(gs_input_vertices), + out_instructions(out_instructions) { } @@ -195,7 +276,7 @@ lower_packed_varyings_visitor::run(exec_list *instructions) /* Recursively pack or unpack it. */ this->lower_rvalue(deref, var->location * 4 + var->location_frac, var, - var->name); + var->name, this->gs_input_vertices != 0, 0); } } @@ -277,6 +358,15 @@ lower_packed_varyings_visitor::bitwise_assign_unpack(ir_rvalue *lhs, * in multiples of a float, rather than multiples of a vec4 as is used * elsewhere in Mesa. * + * \param gs_input_toplevel should be set to true if we are lowering geometry + * shader inputs, and we are currently lowering the whole input variable + * (i.e. we are lowering the array whose index selects the vertex). + * + * \param vertex_index: if we are lowering geometry shader inputs, and the + * level of the array that we are currently lowering is *not* the top level, + * then this indicates which vertex we are currently lowering. Otherwise it + * is ignored. + * * \return the location where the next constituent vector (after this one) * should be packed. */ @@ -284,8 +374,15 @@ unsigned lower_packed_varyings_visitor::lower_rvalue(ir_rvalue *rvalue, unsigned fine_location, ir_variable *unpacked_var, - const char *name) + const char *name, + bool gs_input_toplevel, + unsigned vertex_index) { + /* When gs_input_toplevel is set, we should be looking at a geometry shader + * input array. + */ + assert(!gs_input_toplevel || rvalue->type->is_array()); + if (rvalue->type->is_record()) { for (unsigned i = 0; i < rvalue->type->length; i++) { if (i != 0) @@ -296,7 +393,8 @@ lower_packed_varyings_visitor::lower_rvalue(ir_rvalue *rvalue, char *deref_name = ralloc_asprintf(this->mem_ctx, "%s.%s", name, field_name); fine_location = this->lower_rvalue(dereference_record, fine_location, - unpacked_var, deref_name); + unpacked_var, deref_name, false, + vertex_index); } return fine_location; } else if (rvalue->type->is_array()) { @@ -304,13 +402,15 @@ lower_packed_varyings_visitor::lower_rvalue(ir_rvalue *rvalue, * sequence. */ return this->lower_arraylike(rvalue, rvalue->type->array_size(), - fine_location, unpacked_var, name); + fine_location, unpacked_var, name, + gs_input_toplevel, vertex_index); } else if (rvalue->type->is_matrix()) { /* Matrices are packed/unpacked by considering each column vector in * sequence. */ return this->lower_arraylike(rvalue, rvalue->type->matrix_columns, - fine_location, unpacked_var, name); + fine_location, unpacked_var, name, + false, vertex_index); } else if (rvalue->type->vector_elements + fine_location % 4 > 4) { /* This vector is going to be "double parked" across two varying slots, * so handle it as two separate assignments. @@ -340,9 +440,10 @@ lower_packed_varyings_visitor::lower_rvalue(ir_rvalue *rvalue, char *right_name = ralloc_asprintf(this->mem_ctx, "%s.%s", name, right_swizzle_name); fine_location = this->lower_rvalue(left_swizzle, fine_location, - unpacked_var, left_name); + unpacked_var, left_name, false, + vertex_index); return this->lower_rvalue(right_swizzle, fine_location, unpacked_var, - right_name); + right_name, false, vertex_index); } else { /* No special handling is necessary; pack the rvalue into the * varying. @@ -353,19 +454,19 @@ lower_packed_varyings_visitor::lower_rvalue(ir_rvalue *rvalue, unsigned location_frac = fine_location % 4; for (unsigned i = 0; i < components; ++i) swizzle_values[i] = i + location_frac; - ir_dereference_variable *packed_deref = new(this->mem_ctx) - ir_dereference_variable(this->get_packed_varying(location, - unpacked_var, name)); + ir_dereference *packed_deref = + this->get_packed_varying_deref(location, unpacked_var, name, + vertex_index); ir_swizzle *swizzle = new(this->mem_ctx) ir_swizzle(packed_deref, swizzle_values, components); if (this->mode == ir_var_shader_out) { ir_assignment *assignment = this->bitwise_assign_pack(swizzle, rvalue); - this->main_instructions->push_tail(assignment); + this->out_instructions->push_tail(assignment); } else { ir_assignment *assignment = this->bitwise_assign_unpack(rvalue, swizzle); - this->main_instructions->push_head(assignment); + this->out_instructions->push_tail(assignment); } return fine_location + components; } @@ -376,13 +477,24 @@ lower_packed_varyings_visitor::lower_rvalue(ir_rvalue *rvalue, * constituent elements, accessing each one using an ir_dereference_array. * This takes care of both arrays and matrices, since ir_dereference_array * treats a matrix like an array of its column vectors. + * + * \param gs_input_toplevel should be set to true if we are lowering geometry + * shader inputs, and we are currently lowering the whole input variable + * (i.e. we are lowering the array whose index selects the vertex). + * + * \param vertex_index: if we are lowering geometry shader inputs, and the + * level of the array that we are currently lowering is *not* the top level, + * then this indicates which vertex we are currently lowering. Otherwise it + * is ignored. */ unsigned lower_packed_varyings_visitor::lower_arraylike(ir_rvalue *rvalue, unsigned array_size, unsigned fine_location, ir_variable *unpacked_var, - const char *name) + const char *name, + bool gs_input_toplevel, + unsigned vertex_index) { for (unsigned i = 0; i < array_size; i++) { if (i != 0) @@ -392,8 +504,20 @@ lower_packed_varyings_visitor::lower_arraylike(ir_rvalue *rvalue, ir_dereference_array(rvalue, constant); char *subscripted_name = ralloc_asprintf(this->mem_ctx, "%s[%d]", name, i); - fine_location = this->lower_rvalue(dereference_array, fine_location, - unpacked_var, subscripted_name); + if (gs_input_toplevel) { + /* Geometry shader inputs are a special case. Instead of storing + * each element of the array at a different location, all elements + * are at the same location, but with a different vertex index. + */ + (void) this->lower_rvalue(dereference_array, fine_location, + unpacked_var, subscripted_name, + false, i); + } else { + fine_location = + this->lower_rvalue(dereference_array, fine_location, + unpacked_var, subscripted_name, + false, vertex_index); + } } return fine_location; } @@ -406,11 +530,14 @@ lower_packed_varyings_visitor::lower_arraylike(ir_rvalue *rvalue, * The newly created varying inherits its interpolation parameters from \c * unpacked_var. Its base type is ivec4 if we are lowering a flat varying, * vec4 otherwise. + * + * \param vertex_index: if we are lowering geometry shader inputs, then this + * indicates which vertex we are currently lowering. Otherwise it is ignored. */ -ir_variable * -lower_packed_varyings_visitor::get_packed_varying(unsigned location, - ir_variable *unpacked_var, - const char *name) +ir_dereference * +lower_packed_varyings_visitor::get_packed_varying_deref( + unsigned location, ir_variable *unpacked_var, const char *name, + unsigned vertex_index) { unsigned slot = location - this->location_base; assert(slot < locations_used); @@ -421,18 +548,44 @@ lower_packed_varyings_visitor::get_packed_varying(unsigned location, packed_type = glsl_type::ivec4_type; else packed_type = glsl_type::vec4_type; + if (this->gs_input_vertices != 0) { + packed_type = + glsl_type::get_array_instance(packed_type, + this->gs_input_vertices); + } ir_variable *packed_var = new(this->mem_ctx) ir_variable(packed_type, packed_name, this->mode); + if (this->gs_input_vertices != 0) { + /* Prevent update_array_sizes() from messing with the size of the + * array. + */ + packed_var->max_array_access = this->gs_input_vertices - 1; + } packed_var->centroid = unpacked_var->centroid; packed_var->interpolation = unpacked_var->interpolation; packed_var->location = location; unpacked_var->insert_before(packed_var); this->packed_varyings[slot] = packed_var; } else { - ralloc_asprintf_append((char **) &this->packed_varyings[slot]->name, - ",%s", name); + /* For geometry shader inputs, only update the packed variable name the + * first time we visit each component. + */ + if (this->gs_input_vertices == 0 || vertex_index == 0) { + ralloc_asprintf_append((char **) &this->packed_varyings[slot]->name, + ",%s", name); + } + } + + ir_dereference *deref = new(this->mem_ctx) + ir_dereference_variable(this->packed_varyings[slot]); + if (this->gs_input_vertices != 0) { + /* When lowering GS inputs, the packed variable is an array, so we need + * to dereference it using vertex_index. + */ + ir_constant *constant = new(this->mem_ctx) ir_constant(vertex_index); + deref = new(this->mem_ctx) ir_dereference_array(deref, constant); } - return this->packed_varyings[slot]; + return deref; } bool @@ -440,6 +593,10 @@ lower_packed_varyings_visitor::needs_lowering(ir_variable *var) { /* Things composed of vec4's don't need lowering. Everything else does. */ const glsl_type *type = var->type; + if (this->gs_input_vertices != 0) { + assert(type->is_array()); + type = type->element_type(); + } if (type->is_array()) type = type->fields.array; if (type->vector_elements == 4) @@ -447,19 +604,81 @@ lower_packed_varyings_visitor::needs_lowering(ir_variable *var) return true; } + +/** + * Visitor that splices varying packing code before every use of EmitVertex() + * in a geometry shader. + */ +class lower_packed_varyings_gs_splicer : public ir_hierarchical_visitor +{ +public: + explicit lower_packed_varyings_gs_splicer(void *mem_ctx, + const exec_list *instructions); + + virtual ir_visitor_status visit(ir_emit_vertex *ev); + +private: + /** + * Memory context used to allocate new instructions for the shader. + */ + void * const mem_ctx; + + /** + * Instructions that should be spliced into place before each EmitVertex() + * call. + */ + const exec_list *instructions; +}; + + +lower_packed_varyings_gs_splicer::lower_packed_varyings_gs_splicer( + void *mem_ctx, const exec_list *instructions) + : mem_ctx(mem_ctx), instructions(instructions) +{ +} + + +ir_visitor_status +lower_packed_varyings_gs_splicer::visit(ir_emit_vertex *ev) +{ + foreach_list(node, this->instructions) { + ir_instruction *ir = (ir_instruction *) node; + ev->insert_before(ir->clone(this->mem_ctx, NULL)); + } + return visit_continue; +} + + void lower_packed_varyings(void *mem_ctx, unsigned location_base, unsigned locations_used, ir_variable_mode mode, - gl_shader *shader) + unsigned gs_input_vertices, gl_shader *shader) { exec_list *instructions = shader->ir; ir_function *main_func = shader->symbols->get_function("main"); exec_list void_parameters; ir_function_signature *main_func_sig = main_func->matching_signature(&void_parameters); - exec_list *main_instructions = &main_func_sig->body; + exec_list new_instructions; lower_packed_varyings_visitor visitor(mem_ctx, location_base, locations_used, mode, - main_instructions); + gs_input_vertices, &new_instructions); visitor.run(instructions); + if (mode == ir_var_shader_out) { + if (shader->Type == GL_GEOMETRY_SHADER) { + /* For geometry shaders, outputs need to be lowered before each call + * to EmitVertex() + */ + lower_packed_varyings_gs_splicer splicer(mem_ctx, &new_instructions); + splicer.run(instructions); + } else { + /* For other shader types, outputs need to be lowered at the end of + * main() + */ + main_func_sig->body.append_list(&new_instructions); + } + } else { + /* Shader inputs need to be lowered at the beginning of main() */ + main_func_sig->body.head->insert_before(&new_instructions); + } } diff --git a/mesalib/src/glsl/opt_dead_builtin_varyings.cpp b/mesalib/src/glsl/opt_dead_builtin_varyings.cpp index 2e813d24e..6745d5c64 100644 --- a/mesalib/src/glsl/opt_dead_builtin_varyings.cpp +++ b/mesalib/src/glsl/opt_dead_builtin_varyings.cpp @@ -409,7 +409,7 @@ lower_texcoord_array(exec_list *ir, const varying_info_visitor *info) void do_dead_builtin_varyings(struct gl_context *ctx, - exec_list *producer, exec_list *consumer, + gl_shader *producer, gl_shader *consumer, unsigned num_tfeedback_decls, tfeedback_decl *tfeedback_decls) { @@ -431,44 +431,55 @@ do_dead_builtin_varyings(struct gl_context *ctx, varying_info_visitor consumer_info(ir_var_shader_in); if (producer) { - producer_info.get(producer, num_tfeedback_decls, tfeedback_decls); + producer_info.get(producer->ir, num_tfeedback_decls, tfeedback_decls); if (!consumer) { /* At least eliminate unused gl_TexCoord elements. */ if (producer_info.lower_texcoord_array) { - lower_texcoord_array(producer, &producer_info); + lower_texcoord_array(producer->ir, &producer_info); } return; } } if (consumer) { - consumer_info.get(consumer, 0, NULL); + consumer_info.get(consumer->ir, 0, NULL); if (!producer) { /* At least eliminate unused gl_TexCoord elements. */ if (consumer_info.lower_texcoord_array) { - lower_texcoord_array(consumer, &consumer_info); + lower_texcoord_array(consumer->ir, &consumer_info); } return; } } - /* Eliminate the varyings unused by the other shader. */ + /* Eliminate the outputs unused by the consumer. */ if (producer_info.lower_texcoord_array || producer_info.color_usage || producer_info.has_fog) { - replace_varyings_visitor(producer, + replace_varyings_visitor(producer->ir, &producer_info, consumer_info.texcoord_usage, consumer_info.color_usage, consumer_info.has_fog); } + /* The gl_TexCoord fragment shader inputs can be initialized + * by GL_COORD_REPLACE, so we can't eliminate them. + * + * This doesn't prevent elimination of the gl_TexCoord elements which + * are not read by the fragment shader. We want to eliminate those anyway. + */ + if (consumer->Type == GL_FRAGMENT_SHADER) { + producer_info.texcoord_usage = (1 << MAX_TEXTURE_COORD_UNITS) - 1; + } + + /* Eliminate the inputs uninitialized by the producer. */ if (consumer_info.lower_texcoord_array || consumer_info.color_usage || consumer_info.has_fog) { - replace_varyings_visitor(consumer, + replace_varyings_visitor(consumer->ir, &consumer_info, producer_info.texcoord_usage, producer_info.color_usage, diff --git a/mesalib/src/glsl/opt_dead_code_local.cpp b/mesalib/src/glsl/opt_dead_code_local.cpp index 8c31802a6..42a30b3d8 100644 --- a/mesalib/src/glsl/opt_dead_code_local.cpp +++ b/mesalib/src/glsl/opt_dead_code_local.cpp @@ -114,6 +114,23 @@ public: return visit_continue_with_parent; } + virtual ir_visitor_status visit(ir_emit_vertex *ir) + { + /* For the purpose of dead code elimination, emitting a vertex counts as + * "reading" all of the currently assigned output variables. + */ + foreach_iter(exec_list_iterator, iter, *this->assignments) { + assignment_entry *entry = (assignment_entry *)iter.get(); + if (entry->lhs->mode == ir_var_shader_out) { + if (debug) + printf("kill %s\n", entry->lhs->name); + entry->remove(); + } + } + + return visit_continue; + } + private: exec_list *assignments; }; |