diff options
Diffstat (limited to 'mesalib/src/glsl')
-rw-r--r-- | mesalib/src/glsl/ast_to_hir.cpp | 229 | ||||
-rw-r--r-- | mesalib/src/glsl/builtin_variables.cpp | 8 | ||||
-rw-r--r-- | mesalib/src/glsl/glsl_types.cpp | 10 | ||||
-rw-r--r-- | mesalib/src/glsl/glsl_types.h | 12 | ||||
-rw-r--r-- | mesalib/src/glsl/ir.cpp | 4 | ||||
-rw-r--r-- | mesalib/src/glsl/ir.h | 48 | ||||
-rw-r--r-- | mesalib/src/glsl/link_uniforms.cpp | 58 | ||||
-rw-r--r-- | mesalib/src/glsl/link_varyings.cpp | 6 | ||||
-rw-r--r-- | mesalib/src/glsl/linker.cpp | 2 | ||||
-rw-r--r-- | mesalib/src/glsl/lower_named_interface_blocks.cpp | 6 |
10 files changed, 315 insertions, 68 deletions
diff --git a/mesalib/src/glsl/ast_to_hir.cpp b/mesalib/src/glsl/ast_to_hir.cpp index b644b22c7..3551a5956 100644 --- a/mesalib/src/glsl/ast_to_hir.cpp +++ b/mesalib/src/glsl/ast_to_hir.cpp @@ -60,6 +60,10 @@ static void detect_conflicting_assignments(struct _mesa_glsl_parse_state *state, exec_list *instructions); +static void +remove_per_vertex_blocks(exec_list *instructions, + _mesa_glsl_parse_state *state, ir_variable_mode mode); + void _mesa_ast_to_hir(exec_list *instructions, struct _mesa_glsl_parse_state *state) @@ -114,6 +118,40 @@ _mesa_ast_to_hir(exec_list *instructions, struct _mesa_glsl_parse_state *state) var->remove(); instructions->push_head(var); } + + /* From section 7.1 (Built-In Language Variables) of the GLSL 4.10 spec: + * + * If multiple shaders using members of a built-in block belonging to + * the same interface are linked together in the same program, they + * must all redeclare the built-in block in the same way, as described + * in section 4.3.7 "Interface Blocks" for interface block matching, or + * a link error will result. + * + * The phrase "using members of a built-in block" implies that if two + * shaders are linked together and one of them *does not use* any members + * of the built-in block, then that shader does not need to have a matching + * redeclaration of the built-in block. + * + * This appears to be a clarification to the behaviour established for + * gl_PerVertex by GLSL 1.50, therefore implement it regardless of GLSL + * version. + * + * The definition of "interface" in section 4.3.7 that applies here is as + * follows: + * + * The boundary between adjacent programmable pipeline stages: This + * spans all the outputs in all compilation units of the first stage + * and all the inputs in all compilation units of the second stage. + * + * Therefore this rule applies to both inter- and intra-stage linking. + * + * The easiest way to implement this is to check whether the shader uses + * gl_PerVertex right after ast-to-ir conversion, and if it doesn't, simply + * remove all the relevant variable declaration from the IR, so that the + * linker won't see them and complain about mismatches. + */ + remove_per_vertex_blocks(instructions, state, ir_var_shader_in); + remove_per_vertex_blocks(instructions, state, ir_var_shader_out); } @@ -1961,6 +1999,45 @@ validate_binding_qualifier(struct _mesa_glsl_parse_state *state, return true; } + +static glsl_interp_qualifier +interpret_interpolation_qualifier(const struct ast_type_qualifier *qual, + ir_variable_mode mode, + struct _mesa_glsl_parse_state *state, + YYLTYPE *loc) +{ + glsl_interp_qualifier interpolation; + if (qual->flags.q.flat) + interpolation = INTERP_QUALIFIER_FLAT; + else if (qual->flags.q.noperspective) + interpolation = INTERP_QUALIFIER_NOPERSPECTIVE; + else if (qual->flags.q.smooth) + interpolation = INTERP_QUALIFIER_SMOOTH; + else + interpolation = INTERP_QUALIFIER_NONE; + + if (interpolation != INTERP_QUALIFIER_NONE) { + 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.", + interpolation_string(interpolation)); + + } + + 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", + interpolation_string(interpolation)); + } + } + + return interpolation; +} + + static void apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual, ir_variable *var, @@ -2095,34 +2172,9 @@ apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual, } } - if (qual->flags.q.flat) - var->interpolation = INTERP_QUALIFIER_FLAT; - else if (qual->flags.q.noperspective) - var->interpolation = INTERP_QUALIFIER_NOPERSPECTIVE; - else if (qual->flags.q.smooth) - var->interpolation = INTERP_QUALIFIER_SMOOTH; - else - var->interpolation = INTERP_QUALIFIER_NONE; - - 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->interpolation = + interpret_interpolation_qualifier(qual, (ir_variable_mode) var->mode, + state, loc); var->pixel_center_integer = qual->flags.q.pixel_center_integer; var->origin_upper_left = qual->flags.q.origin_upper_left; @@ -4410,6 +4462,10 @@ ast_type_specifier::hir(exec_list *instructions, * AST for each can be processed the same way into a set of * \c glsl_struct_field to describe the members. * + * If we're processing an interface block, var_mode should be the type of the + * interface block (ir_var_shader_in, ir_var_shader_out, or ir_var_uniform). + * If we're processing a structure, var_mode should be ir_var_auto. + * * \return * The number of fields processed. A pointer to the array structure fields is * stored in \c *fields_ret. @@ -4422,7 +4478,8 @@ ast_process_structure_or_interface_block(exec_list *instructions, glsl_struct_field **fields_ret, bool is_interface, bool block_row_major, - bool allow_reserved_names) + bool allow_reserved_names, + ir_variable_mode var_mode) { unsigned decl_count = 0; @@ -4506,6 +4563,9 @@ ast_process_structure_or_interface_block(exec_list *instructions, fields[i].type = field_type; fields[i].name = decl->identifier; fields[i].location = -1; + fields[i].interpolation = + interpret_interpolation_qualifier(qual, var_mode, state, &loc); + fields[i].centroid = qual->flags.q.centroid ? 1 : 0; if (qual->flags.q.row_major || qual->flags.q.column_major) { if (!qual->flags.q.uniform) { @@ -4584,7 +4644,8 @@ ast_struct_specifier::hir(exec_list *instructions, &fields, false, false, - false /* allow_reserved_names */); + false /* allow_reserved_names */, + ir_var_auto); validate_identifier(this->name, loc, state); @@ -4665,20 +4726,6 @@ ast_interface_block::hir(exec_list *instructions, packing = GLSL_INTERFACE_PACKING_STD140; } - bool redeclaring_per_vertex = strcmp(this->block_name, "gl_PerVertex") == 0; - bool block_row_major = this->layout.flags.q.row_major; - exec_list declared_variables; - glsl_struct_field *fields; - unsigned int num_variables = - ast_process_structure_or_interface_block(&declared_variables, - state, - &this->declarations, - loc, - &fields, - true, - block_row_major, - redeclaring_per_vertex); - ir_variable_mode var_mode; const char *iface_type_name; if (this->layout.flags.q.in) { @@ -4696,6 +4743,21 @@ ast_interface_block::hir(exec_list *instructions, assert(!"interface block layout qualifier not found!"); } + bool redeclaring_per_vertex = strcmp(this->block_name, "gl_PerVertex") == 0; + bool block_row_major = this->layout.flags.q.row_major; + exec_list declared_variables; + glsl_struct_field *fields; + unsigned int num_variables = + ast_process_structure_or_interface_block(&declared_variables, + state, + &this->declarations, + loc, + &fields, + true, + block_row_major, + redeclaring_per_vertex, + var_mode); + if (!redeclaring_per_vertex) validate_identifier(this->block_name, loc, state); @@ -4768,6 +4830,10 @@ ast_interface_block::hir(exec_list *instructions, } else { fields[i].location = earlier_per_vertex->fields.structure[j].location; + fields[i].interpolation = + earlier_per_vertex->fields.structure[j].interpolation; + fields[i].centroid = + earlier_per_vertex->fields.structure[j].centroid; } } @@ -4831,8 +4897,24 @@ ast_interface_block::hir(exec_list *instructions, * field selector ( . ) operator (analogously to structures)." */ if (this->instance_name) { - if (!redeclaring_per_vertex) + if (redeclaring_per_vertex) { + /* When a built-in in an unnamed interface block is redeclared, + * get_variable_being_redeclared() calls + * check_builtin_array_max_size() to make sure that built-in array + * variables aren't redeclared to illegal sizes. But we're looking + * at a redeclaration of a named built-in interface block. So we + * have to manually call check_builtin_array_max_size() for all parts + * of the interface that are arrays. + */ + for (unsigned i = 0; i < num_variables; i++) { + if (fields[i].type->is_array()) { + const unsigned size = fields[i].type->array_size(); + check_builtin_array_max_size(fields[i].name, size, loc, state); + } + } + } else { validate_identifier(this->instance_name, loc, state); + } ir_variable *var; @@ -4903,6 +4985,8 @@ ast_interface_block::hir(exec_list *instructions, new(state) ir_variable(fields[i].type, ralloc_strdup(state, fields[i].name), var_mode); + var->interpolation = fields[i].interpolation; + var->centroid = fields[i].centroid; var->init_interface_type(block_type); if (redeclaring_per_vertex) { @@ -4958,7 +5042,8 @@ ast_interface_block::hir(exec_list *instructions, foreach_list_safe(node, instructions) { ir_variable *const var = ((ir_instruction *) node)->as_variable(); if (var != NULL && - var->get_interface_type() == earlier_per_vertex) { + var->get_interface_type() == earlier_per_vertex && + var->mode == var_mode) { state->symbols->disable_variable(var->name); var->remove(); } @@ -5095,3 +5180,55 @@ detect_conflicting_assignments(struct _mesa_glsl_parse_state *state, user_defined_fs_output->name); } } + + +static void +remove_per_vertex_blocks(exec_list *instructions, + _mesa_glsl_parse_state *state, ir_variable_mode mode) +{ + /* Find the gl_PerVertex interface block of the appropriate (in/out) mode, + * if it exists in this shader type. + */ + const glsl_type *per_vertex = NULL; + switch (mode) { + case ir_var_shader_in: + if (ir_variable *gl_in = state->symbols->get_variable("gl_in")) + per_vertex = gl_in->get_interface_type(); + break; + case ir_var_shader_out: + if (ir_variable *gl_Position = + state->symbols->get_variable("gl_Position")) { + per_vertex = gl_Position->get_interface_type(); + } + break; + default: + assert(!"Unexpected mode"); + break; + } + + /* If we didn't find a built-in gl_PerVertex interface block, then we don't + * need to do anything. + */ + if (per_vertex == NULL) + return; + + /* If the interface block is used by the shader, then we don't need to do + * anything. + */ + interface_block_usage_visitor v(mode, per_vertex); + v.run(instructions); + if (v.usage_found()) + return; + + /* Remove any ir_variable declarations that refer to the interface block + * we're removing. + */ + foreach_list_safe(node, instructions) { + ir_variable *const var = ((ir_instruction *) node)->as_variable(); + if (var != NULL && var->get_interface_type() == per_vertex && + var->mode == mode) { + state->symbols->disable_variable(var->name); + var->remove(); + } + } +} diff --git a/mesalib/src/glsl/builtin_variables.cpp b/mesalib/src/glsl/builtin_variables.cpp index fc1115bc4..018daf67f 100644 --- a/mesalib/src/glsl/builtin_variables.cpp +++ b/mesalib/src/glsl/builtin_variables.cpp @@ -326,6 +326,8 @@ per_vertex_accumulator::add_field(int slot, const glsl_type *type, this->fields[this->num_fields].name = name; this->fields[this->num_fields].row_major = false; this->fields[this->num_fields].location = slot; + this->fields[this->num_fields].interpolation = INTERP_QUALIFIER_NONE; + this->fields[this->num_fields].centroid = 0; this->num_fields++; } @@ -888,8 +890,8 @@ builtin_variable_generator::generate_varyings() if (state->target == geometry_shader) { const glsl_type *per_vertex_in_type = this->per_vertex_in.construct_interface_instance(); - ir_variable *var = add_variable("gl_in", array(per_vertex_in_type, 0), - ir_var_shader_in, -1); + add_variable("gl_in", array(per_vertex_in_type, 0), + ir_var_shader_in, -1); } if (state->target == vertex_shader || state->target == geometry_shader) { const glsl_type *per_vertex_out_type = @@ -899,6 +901,8 @@ builtin_variable_generator::generate_varyings() ir_variable *var = add_variable(fields[i].name, fields[i].type, ir_var_shader_out, fields[i].location); + var->interpolation = fields[i].interpolation; + var->centroid = fields[i].centroid; var->init_interface_type(per_vertex_out_type); } } diff --git a/mesalib/src/glsl/glsl_types.cpp b/mesalib/src/glsl/glsl_types.cpp index 80a6e71a7..bc8d87f5f 100644 --- a/mesalib/src/glsl/glsl_types.cpp +++ b/mesalib/src/glsl/glsl_types.cpp @@ -101,6 +101,8 @@ glsl_type::glsl_type(const glsl_struct_field *fields, unsigned num_fields, this->fields.structure[i].name = ralloc_strdup(this->fields.structure, fields[i].name); this->fields.structure[i].location = fields[i].location; + this->fields.structure[i].interpolation = fields[i].interpolation; + this->fields.structure[i].centroid = fields[i].centroid; this->fields.structure[i].row_major = fields[i].row_major; } } @@ -126,6 +128,8 @@ glsl_type::glsl_type(const glsl_struct_field *fields, unsigned num_fields, this->fields.structure[i].name = ralloc_strdup(this->fields.structure, fields[i].name); this->fields.structure[i].location = fields[i].location; + this->fields.structure[i].interpolation = fields[i].interpolation; + this->fields.structure[i].centroid = fields[i].centroid; this->fields.structure[i].row_major = fields[i].row_major; } } @@ -455,6 +459,12 @@ glsl_type::record_key_compare(const void *a, const void *b) if (key1->fields.structure[i].location != key2->fields.structure[i].location) return 1; + if (key1->fields.structure[i].interpolation + != key2->fields.structure[i].interpolation) + return 1; + if (key1->fields.structure[i].centroid + != key2->fields.structure[i].centroid) + return 1; } return 0; diff --git a/mesalib/src/glsl/glsl_types.h b/mesalib/src/glsl/glsl_types.h index e60c19132..4b5b6efb3 100644 --- a/mesalib/src/glsl/glsl_types.h +++ b/mesalib/src/glsl/glsl_types.h @@ -590,6 +590,18 @@ struct glsl_struct_field { * Ignored for structs. */ int location; + + /** + * For interface blocks, the interpolation mode (as in + * ir_variable::interpolation). 0 otherwise. + */ + unsigned interpolation:2; + + /** + * For interface blocks, 1 if this variable uses centroid interpolation (as + * in ir_variable::centroid). 0 otherwise. + */ + unsigned centroid:1; }; static inline unsigned int diff --git a/mesalib/src/glsl/ir.cpp b/mesalib/src/glsl/ir.cpp index 54a8e400c..c682e3ed5 100644 --- a/mesalib/src/glsl/ir.cpp +++ b/mesalib/src/glsl/ir.cpp @@ -1616,9 +1616,9 @@ ir_variable::ir_variable(const struct glsl_type *type, const char *name, const char * -ir_variable::interpolation_string() const +interpolation_string(unsigned interpolation) { - switch (this->interpolation) { + switch (interpolation) { case INTERP_QUALIFIER_NONE: return "no"; case INTERP_QUALIFIER_SMOOTH: return "smooth"; case INTERP_QUALIFIER_FLAT: return "flat"; diff --git a/mesalib/src/glsl/ir.h b/mesalib/src/glsl/ir.h index aac8cbb7d..8d5bec9c1 100644 --- a/mesalib/src/glsl/ir.h +++ b/mesalib/src/glsl/ir.h @@ -312,6 +312,22 @@ struct ir_state_slot { int swizzle; }; + +/** + * Get the string value for an interpolation qualifier + * + * \return The string that would be used in a shader to specify \c + * mode will be returned. + * + * This function is used to generate error messages of the form "shader + * uses %s interpolation qualifier", so in the case where there is no + * interpolation qualifier, it returns "no". + * + * This function should only be used on a shader input or output variable. + */ +const char *interpolation_string(unsigned interpolation); + + class ir_variable : public ir_instruction { public: ir_variable(const struct glsl_type *, const char *, ir_variable_mode); @@ -332,20 +348,6 @@ public: /** - * Get the string value for the interpolation qualifier - * - * \return The string that would be used in a shader to specify \c - * mode will be returned. - * - * This function is used to generate error messages of the form "shader - * uses %s interpolation qualifier", so in the case where there is no - * interpolation qualifier, it returns "no". - * - * This function should only be used on a shader input or output variable. - */ - const char *interpolation_string() const; - - /** * Determine how this variable should be interpolated based on its * interpolation qualifier (if present), whether it is gl_Color or * gl_SecondaryColor, and whether flatshading is enabled in the current GL @@ -579,6 +581,24 @@ public: unsigned location_frac:2; /** + * Non-zero if this variable was created by lowering a named interface + * block which was not an array. + * + * Note that this variable and \c from_named_ifc_block_array will never + * both be non-zero. + */ + unsigned from_named_ifc_block_nonarray:1; + + /** + * Non-zero if this variable was created by lowering a named interface + * block which was an array. + * + * Note that this variable and \c from_named_ifc_block_nonarray will never + * both be non-zero. + */ + unsigned from_named_ifc_block_array:1; + + /** * \brief Layout qualifier for gl_FragDepth. * * This is not equal to \c ir_depth_layout_none if and only if this diff --git a/mesalib/src/glsl/link_uniforms.cpp b/mesalib/src/glsl/link_uniforms.cpp index 4bd4034a0..ea71b3063 100644 --- a/mesalib/src/glsl/link_uniforms.cpp +++ b/mesalib/src/glsl/link_uniforms.cpp @@ -75,7 +75,63 @@ program_resource_visitor::process(ir_variable *var) */ /* Only strdup the name if we actually will need to modify it. */ - if (t->is_record() || (t->is_array() && t->fields.array->is_record())) { + if (var->from_named_ifc_block_array) { + /* lower_named_interface_blocks created this variable by lowering an + * interface block array to an array variable. For example if the + * original source code was: + * + * out Blk { vec4 bar } foo[3]; + * + * Then the variable is now: + * + * out vec4 bar[3]; + * + * We need to visit each array element using the names constructed like + * so: + * + * Blk[0].bar + * Blk[1].bar + * Blk[2].bar + */ + assert(t->is_array()); + const glsl_type *ifc_type = var->get_interface_type(); + char *name = ralloc_strdup(NULL, ifc_type->name); + size_t name_length = strlen(name); + for (unsigned i = 0; i < t->length; i++) { + size_t new_length = name_length; + ralloc_asprintf_rewrite_tail(&name, &new_length, "[%u].%s", i, + var->name); + /* Note: row_major is only meaningful for uniform blocks, and + * lowering is only applied to non-uniform interface blocks, so we + * can safely pass false for row_major. + */ + recursion(var->type, &name, new_length, false, NULL); + } + ralloc_free(name); + } else if (var->from_named_ifc_block_nonarray) { + /* lower_named_interface_blocks created this variable by lowering a + * named interface block (non-array) to an ordinary variable. For + * example if the original source code was: + * + * out Blk { vec4 bar } foo; + * + * Then the variable is now: + * + * out vec4 bar; + * + * We need to visit this variable using the name: + * + * Blk.bar + */ + const glsl_type *ifc_type = var->get_interface_type(); + char *name = ralloc_asprintf(NULL, "%s.%s", ifc_type->name, var->name); + /* Note: row_major is only meaningful for uniform blocks, and lowering + * is only applied to non-uniform interface blocks, so we can safely + * pass false for row_major. + */ + recursion(var->type, &name, strlen(name), false, NULL); + ralloc_free(name); + } else if (t->is_record() || (t->is_array() && t->fields.array->is_record())) { char *name = ralloc_strdup(NULL, var->name); recursion(var->type, &name, strlen(name), false, NULL); ralloc_free(name); diff --git a/mesalib/src/glsl/link_varyings.cpp b/mesalib/src/glsl/link_varyings.cpp index 4ba6d8a20..be36b5f8f 100644 --- a/mesalib/src/glsl/link_varyings.cpp +++ b/mesalib/src/glsl/link_varyings.cpp @@ -125,9 +125,9 @@ cross_validate_types_and_qualifiers(struct gl_shader_program *prog, "interpolation qualifier\n", _mesa_glsl_shader_target_name(producer_type), output->name, - output->interpolation_string(), + interpolation_string(output->interpolation), _mesa_glsl_shader_target_name(consumer_type), - input->interpolation_string()); + interpolation_string(input->interpolation)); return; } } @@ -328,7 +328,7 @@ tfeedback_decl::assign_location(struct gl_context *ctx, const unsigned vector_elements = this->matched_candidate->type->fields.array->vector_elements; unsigned actual_array_size = this->is_clip_distance_mesa ? - prog->Vert.ClipDistanceArraySize : + prog->LastClipDistanceArraySize : this->matched_candidate->type->array_size(); if (this->is_subscripted) { diff --git a/mesalib/src/glsl/linker.cpp b/mesalib/src/glsl/linker.cpp index b23c31a16..d8f655c39 100644 --- a/mesalib/src/glsl/linker.cpp +++ b/mesalib/src/glsl/linker.cpp @@ -2100,6 +2100,7 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog) validate_vertex_shader_executable(prog, sh); if (!prog->LinkStatus) goto done; + prog->LastClipDistanceArraySize = prog->Vert.ClipDistanceArraySize; _mesa_reference_shader(ctx, &prog->_LinkedShaders[MESA_SHADER_VERTEX], sh); @@ -2132,6 +2133,7 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog) validate_geometry_shader_executable(prog, sh); if (!prog->LinkStatus) goto done; + prog->LastClipDistanceArraySize = prog->Geom.ClipDistanceArraySize; _mesa_reference_shader(ctx, &prog->_LinkedShaders[MESA_SHADER_GEOMETRY], sh); diff --git a/mesalib/src/glsl/lower_named_interface_blocks.cpp b/mesalib/src/glsl/lower_named_interface_blocks.cpp index f415252ba..d59d11150 100644 --- a/mesalib/src/glsl/lower_named_interface_blocks.cpp +++ b/mesalib/src/glsl/lower_named_interface_blocks.cpp @@ -140,6 +140,7 @@ flatten_named_interface_blocks_declarations::run(exec_list *instructions) new(mem_ctx) ir_variable(iface_t->fields.structure[i].type, var_name, (ir_variable_mode) var->mode); + new_var->from_named_ifc_block_nonarray = 1; } else { const glsl_type *new_array_type = glsl_type::get_array_instance( @@ -149,8 +150,13 @@ flatten_named_interface_blocks_declarations::run(exec_list *instructions) new(mem_ctx) ir_variable(new_array_type, var_name, (ir_variable_mode) var->mode); + new_var->from_named_ifc_block_array = 1; } new_var->location = iface_t->fields.structure[i].location; + new_var->explicit_location = (new_var->location >= 0); + new_var->interpolation = + iface_t->fields.structure[i].interpolation; + new_var->centroid = iface_t->fields.structure[i].centroid; new_var->init_interface_type(iface_t); hash_table_insert(interface_namespace, new_var, |