diff options
Diffstat (limited to 'mesalib/src/glsl')
-rw-r--r-- | mesalib/src/glsl/ast.h | 13 | ||||
-rw-r--r-- | mesalib/src/glsl/ast_to_hir.cpp | 180 | ||||
-rw-r--r-- | mesalib/src/glsl/glsl_parser_extras.cpp | 21 | ||||
-rw-r--r-- | mesalib/src/glsl/glsl_parser_extras.h | 4 | ||||
-rw-r--r-- | mesalib/src/glsl/ir.cpp | 9 | ||||
-rw-r--r-- | mesalib/src/glsl/ir.h | 15 | ||||
-rw-r--r-- | mesalib/src/glsl/ir_optimization.h | 6 | ||||
-rw-r--r-- | mesalib/src/glsl/ir_validate.cpp | 3 | ||||
-rw-r--r-- | mesalib/src/glsl/link_uniform_block_active_visitor.cpp | 8 | ||||
-rw-r--r-- | mesalib/src/glsl/link_uniform_block_active_visitor.h | 3 | ||||
-rw-r--r-- | mesalib/src/glsl/link_uniform_blocks.cpp | 14 | ||||
-rw-r--r-- | mesalib/src/glsl/link_uniform_initializers.cpp | 117 | ||||
-rw-r--r-- | mesalib/src/glsl/linker.cpp | 6 | ||||
-rw-r--r-- | mesalib/src/glsl/loop_analysis.h | 3 | ||||
-rw-r--r-- | mesalib/src/glsl/loop_unroll.cpp | 86 | ||||
-rw-r--r-- | mesalib/src/glsl/lower_ubo_reference.cpp | 10 | ||||
-rw-r--r-- | mesalib/src/glsl/opt_algebraic.cpp | 30 | ||||
-rw-r--r-- | mesalib/src/glsl/opt_tree_grafting.cpp | 30 | ||||
-rw-r--r-- | mesalib/src/glsl/opt_vectorize.cpp | 1 | ||||
-rw-r--r-- | mesalib/src/glsl/test_optpass.cpp | 7 |
20 files changed, 413 insertions, 153 deletions
diff --git a/mesalib/src/glsl/ast.h b/mesalib/src/glsl/ast.h index ae70b003c..6b136f518 100644 --- a/mesalib/src/glsl/ast.h +++ b/mesalib/src/glsl/ast.h @@ -217,6 +217,13 @@ public: virtual ir_rvalue *hir(exec_list *instructions, struct _mesa_glsl_parse_state *state); + virtual void hir_no_rvalue(exec_list *instructions, + struct _mesa_glsl_parse_state *state); + + ir_rvalue *do_hir(exec_list *instructions, + struct _mesa_glsl_parse_state *state, + bool needs_rvalue); + virtual void print(void) const; enum ast_operators oper; @@ -287,6 +294,9 @@ public: virtual ir_rvalue *hir(exec_list *instructions, struct _mesa_glsl_parse_state *state); + virtual void hir_no_rvalue(exec_list *instructions, + struct _mesa_glsl_parse_state *state); + private: /** * Is this function call actually a constructor? @@ -359,6 +369,9 @@ public: virtual ir_rvalue *hir(exec_list *instructions, struct _mesa_glsl_parse_state *state); + + virtual void hir_no_rvalue(exec_list *instructions, + struct _mesa_glsl_parse_state *state); }; /** diff --git a/mesalib/src/glsl/ast_to_hir.cpp b/mesalib/src/glsl/ast_to_hir.cpp index 8f6e90174..717dc68ea 100644 --- a/mesalib/src/glsl/ast_to_hir.cpp +++ b/mesalib/src/glsl/ast_to_hir.cpp @@ -56,6 +56,9 @@ #include "glsl_types.h" #include "program/hash_table.h" #include "ir.h" +#include "ir_builder.h" + +using namespace ir_builder; static void detect_conflicting_assignments(struct _mesa_glsl_parse_state *state, @@ -733,10 +736,12 @@ mark_whole_array_access(ir_rvalue *access) } } -ir_rvalue * +static bool do_assignment(exec_list *instructions, struct _mesa_glsl_parse_state *state, const char *non_lvalue_description, - ir_rvalue *lhs, ir_rvalue *rhs, bool is_initializer, + ir_rvalue *lhs, ir_rvalue *rhs, + ir_rvalue **out_rvalue, bool needs_rvalue, + bool is_initializer, YYLTYPE lhs_loc) { void *ctx = state; @@ -855,27 +860,33 @@ do_assignment(exec_list *instructions, struct _mesa_glsl_parse_state *state, * to handle things like: * * i = j += 1; - * - * So we always just store the computed value being assigned to a - * temporary and return a deref of that temporary. If the rvalue - * ends up not being used, the temp will get copy-propagated out. */ - ir_variable *var = new(ctx) ir_variable(rhs->type, "assignment_tmp", - ir_var_temporary); - ir_dereference_variable *deref_var = new(ctx) ir_dereference_variable(var); - instructions->push_tail(var); - instructions->push_tail(new(ctx) ir_assignment(deref_var, rhs)); - deref_var = new(ctx) ir_dereference_variable(var); + if (needs_rvalue) { + ir_variable *var = new(ctx) ir_variable(rhs->type, "assignment_tmp", + ir_var_temporary); + instructions->push_tail(var); + instructions->push_tail(assign(var, rhs)); + + if (!error_emitted) { + ir_dereference_variable *deref_var = new(ctx) ir_dereference_variable(var); + instructions->push_tail(new(ctx) ir_assignment(lhs, deref_var)); + } + ir_rvalue *rvalue = new(ctx) ir_dereference_variable(var); - if (!error_emitted) - instructions->push_tail(new(ctx) ir_assignment(lhs, deref_var)); + if (extract_channel) { + rvalue = new(ctx) ir_expression(ir_binop_vector_extract, + rvalue, + extract_channel->clone(ctx, NULL)); + } - if (extract_channel) { - return new(ctx) ir_expression(ir_binop_vector_extract, - new(ctx) ir_dereference_variable(var), - extract_channel->clone(ctx, NULL)); + *out_rvalue = rvalue; + } else { + if (!error_emitted) + instructions->push_tail(new(ctx) ir_assignment(lhs, rhs)); + *out_rvalue = NULL; } - return new(ctx) ir_dereference_variable(var); + + return error_emitted; } static ir_rvalue * @@ -906,6 +917,20 @@ ast_node::hir(exec_list *instructions, return NULL; } +void +ast_function_expression::hir_no_rvalue(exec_list *instructions, + struct _mesa_glsl_parse_state *state) +{ + (void)hir(instructions, state); +} + +void +ast_aggregate_initializer::hir_no_rvalue(exec_list *instructions, + struct _mesa_glsl_parse_state *state) +{ + (void)hir(instructions, state); +} + static ir_rvalue * do_comparison(void *mem_ctx, int operation, ir_rvalue *op0, ir_rvalue *op1) { @@ -1075,6 +1100,21 @@ ir_rvalue * ast_expression::hir(exec_list *instructions, struct _mesa_glsl_parse_state *state) { + return do_hir(instructions, state, true); +} + +void +ast_expression::hir_no_rvalue(exec_list *instructions, + struct _mesa_glsl_parse_state *state) +{ + do_hir(instructions, state, false); +} + +ir_rvalue * +ast_expression::do_hir(exec_list *instructions, + struct _mesa_glsl_parse_state *state, + bool needs_rvalue) +{ void *ctx = state; static const int operations[AST_NUM_OPERATORS] = { -1, /* ast_assign doesn't convert to ir_expression. */ @@ -1148,11 +1188,11 @@ ast_expression::hir(exec_list *instructions, op[0] = this->subexpressions[0]->hir(instructions, state); op[1] = this->subexpressions[1]->hir(instructions, state); - result = do_assignment(instructions, state, - this->subexpressions[0]->non_lvalue_description, - op[0], op[1], false, - this->subexpressions[0]->get_location()); - error_emitted = result->type->is_error(); + error_emitted = + do_assignment(instructions, state, + this->subexpressions[0]->non_lvalue_description, + op[0], op[1], &result, needs_rvalue, false, + this->subexpressions[0]->get_location()); break; } @@ -1418,11 +1458,12 @@ ast_expression::hir(exec_list *instructions, ir_rvalue *temp_rhs = new(ctx) ir_expression(operations[this->oper], type, op[0], op[1]); - result = do_assignment(instructions, state, - this->subexpressions[0]->non_lvalue_description, - op[0]->clone(ctx, NULL), temp_rhs, false, - this->subexpressions[0]->get_location()); - error_emitted = (op[0]->type->is_error()); + error_emitted = + do_assignment(instructions, state, + this->subexpressions[0]->non_lvalue_description, + op[0]->clone(ctx, NULL), temp_rhs, + &result, needs_rvalue, false, + this->subexpressions[0]->get_location()); /* GLSL 1.10 does not allow array assignment. However, we don't have to * explicitly test for this because none of the binary expression @@ -1444,11 +1485,12 @@ ast_expression::hir(exec_list *instructions, temp_rhs = new(ctx) ir_expression(operations[this->oper], type, op[0], op[1]); - result = do_assignment(instructions, state, - this->subexpressions[0]->non_lvalue_description, - op[0]->clone(ctx, NULL), temp_rhs, false, - this->subexpressions[0]->get_location()); - error_emitted = type->is_error(); + error_emitted = + do_assignment(instructions, state, + this->subexpressions[0]->non_lvalue_description, + op[0]->clone(ctx, NULL), temp_rhs, + &result, needs_rvalue, false, + this->subexpressions[0]->get_location()); break; } @@ -1460,11 +1502,12 @@ ast_expression::hir(exec_list *instructions, &loc); ir_rvalue *temp_rhs = new(ctx) ir_expression(operations[this->oper], type, op[0], op[1]); - result = do_assignment(instructions, state, - this->subexpressions[0]->non_lvalue_description, - op[0]->clone(ctx, NULL), temp_rhs, false, - this->subexpressions[0]->get_location()); - error_emitted = op[0]->type->is_error() || op[1]->type->is_error(); + error_emitted = + do_assignment(instructions, state, + this->subexpressions[0]->non_lvalue_description, + op[0]->clone(ctx, NULL), temp_rhs, + &result, needs_rvalue, false, + this->subexpressions[0]->get_location()); break; } @@ -1477,11 +1520,12 @@ ast_expression::hir(exec_list *instructions, state, &loc); ir_rvalue *temp_rhs = new(ctx) ir_expression(operations[this->oper], type, op[0], op[1]); - result = do_assignment(instructions, state, - this->subexpressions[0]->non_lvalue_description, - op[0]->clone(ctx, NULL), temp_rhs, false, - this->subexpressions[0]->get_location()); - error_emitted = op[0]->type->is_error() || op[1]->type->is_error(); + error_emitted = + do_assignment(instructions, state, + this->subexpressions[0]->non_lvalue_description, + op[0]->clone(ctx, NULL), temp_rhs, + &result, needs_rvalue, false, + this->subexpressions[0]->get_location()); break; } @@ -1589,11 +1633,12 @@ ast_expression::hir(exec_list *instructions, temp_rhs = new(ctx) ir_expression(operations[this->oper], type, op[0], op[1]); - result = do_assignment(instructions, state, - this->subexpressions[0]->non_lvalue_description, - op[0]->clone(ctx, NULL), temp_rhs, false, - this->subexpressions[0]->get_location()); - error_emitted = op[0]->type->is_error(); + error_emitted = + do_assignment(instructions, state, + this->subexpressions[0]->non_lvalue_description, + op[0]->clone(ctx, NULL), temp_rhs, + &result, needs_rvalue, false, + this->subexpressions[0]->get_location()); break; } @@ -1617,12 +1662,14 @@ ast_expression::hir(exec_list *instructions, */ result = get_lvalue_copy(instructions, op[0]->clone(ctx, NULL)); - (void)do_assignment(instructions, state, - this->subexpressions[0]->non_lvalue_description, - op[0]->clone(ctx, NULL), temp_rhs, false, - this->subexpressions[0]->get_location()); + ir_rvalue *junk_rvalue; + error_emitted = + do_assignment(instructions, state, + this->subexpressions[0]->non_lvalue_description, + op[0]->clone(ctx, NULL), temp_rhs, + &junk_rvalue, false, false, + this->subexpressions[0]->get_location()); - error_emitted = op[0]->type->is_error(); break; } @@ -1744,9 +1791,9 @@ ast_expression::hir(exec_list *instructions, } } type = NULL; /* use result->type, not type. */ - assert(result != NULL); + assert(result != NULL || !needs_rvalue); - if (result->type->is_error() && !error_emitted) + if (result && result->type->is_error() && !error_emitted) _mesa_glsl_error(& loc, state, "type mismatch"); return result; @@ -1767,7 +1814,7 @@ ast_expression_statement::hir(exec_list *instructions, * anything in that case. */ if (expression != NULL) - expression->hir(instructions, state); + expression->hir_no_rvalue(instructions, state); /* Statements do not have r-values. */ @@ -2831,10 +2878,12 @@ process_initializer(ir_variable *var, ast_declaration *decl, */ const glsl_type *initializer_type; if (!type->qualifier.flags.q.uniform) { - result = do_assignment(initializer_instructions, state, - NULL, - lhs, rhs, true, - type->get_location()); + do_assignment(initializer_instructions, state, + NULL, + lhs, rhs, + &result, true, + true, + type->get_location()); initializer_type = result->type; } else initializer_type = rhs->type; @@ -5267,12 +5316,19 @@ ast_interface_block::hir(exec_list *instructions, earlier->reinit_interface_type(block_type); delete var; } else { + /* Propagate the "binding" keyword into this UBO's fields; + * the UBO declaration itself doesn't get an ir_variable unless it + * has an instance name. This is ugly. + */ + var->data.explicit_binding = this->layout.flags.q.explicit_binding; + var->data.binding = this->layout.binding; + 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. + * an instance name. */ assert(this->array_specifier == NULL); diff --git a/mesalib/src/glsl/glsl_parser_extras.cpp b/mesalib/src/glsl/glsl_parser_extras.cpp index 61ae62150..03c2a972a 100644 --- a/mesalib/src/glsl/glsl_parser_extras.cpp +++ b/mesalib/src/glsl/glsl_parser_extras.cpp @@ -66,10 +66,6 @@ _mesa_glsl_parse_state::_mesa_glsl_parse_state(struct gl_context *_ctx, this->translation_unit.make_empty(); this->symbols = new(mem_ctx) glsl_symbol_table; - this->num_uniform_blocks = 0; - this->uniform_block_array_size = 0; - this->uniform_blocks = NULL; - this->info_log = ralloc_strdup(mem_ctx, ""); this->error = false; this->loop_nesting_ast = NULL; @@ -1448,7 +1444,8 @@ _mesa_glsl_compile_shader(struct gl_context *ctx, struct gl_shader *shader, /* Do some optimization at compile time to reduce shader IR size * and reduce later work if the same shader is linked multiple times */ - while (do_common_optimization(shader->ir, false, false, 32, options)) + while (do_common_optimization(shader->ir, false, false, options, + ctx->Const.NativeIntegers)) ; validate_ir_tree(shader->ir); @@ -1464,12 +1461,6 @@ _mesa_glsl_compile_shader(struct gl_context *ctx, struct gl_shader *shader, shader->IsES = state->es_shader; shader->uses_builtin_functions = state->uses_builtin_functions; - if (shader->UniformBlocks) - ralloc_free(shader->UniformBlocks); - shader->NumUniformBlocks = state->num_uniform_blocks; - shader->UniformBlocks = state->uniform_blocks; - ralloc_steal(shader, shader->UniformBlocks); - if (!state->error) set_shader_inout_layout(shader, state); @@ -1501,8 +1492,8 @@ _mesa_glsl_compile_shader(struct gl_context *ctx, struct gl_shader *shader, bool do_common_optimization(exec_list *ir, bool linked, bool uniform_locations_assigned, - unsigned max_unroll_iterations, - const struct gl_shader_compiler_options *options) + const struct gl_shader_compiler_options *options, + bool native_integers) { GLboolean progress = GL_FALSE; @@ -1538,7 +1529,7 @@ do_common_optimization(exec_list *ir, bool linked, progress = do_constant_variable_unlinked(ir) || progress; progress = do_constant_folding(ir) || progress; progress = do_cse(ir) || progress; - progress = do_algebraic(ir) || progress; + progress = do_algebraic(ir, native_integers) || progress; progress = do_lower_jumps(ir) || progress; progress = do_vec_index_to_swizzle(ir) || progress; progress = lower_vector_insert(ir, false) || progress; @@ -1551,7 +1542,7 @@ do_common_optimization(exec_list *ir, bool linked, loop_state *ls = analyze_loop_variables(ir); if (ls->loop_found) { progress = set_loop_controls(ir, ls) || progress; - progress = unroll_loops(ir, ls, max_unroll_iterations) || progress; + progress = unroll_loops(ir, ls, options) || progress; } delete ls; diff --git a/mesalib/src/glsl/glsl_parser_extras.h b/mesalib/src/glsl/glsl_parser_extras.h index 300d90051..3ad205c07 100644 --- a/mesalib/src/glsl/glsl_parser_extras.h +++ b/mesalib/src/glsl/glsl_parser_extras.h @@ -175,10 +175,6 @@ struct _mesa_glsl_parse_state { exec_list translation_unit; glsl_symbol_table *symbols; - unsigned num_uniform_blocks; - unsigned uniform_block_array_size; - struct gl_uniform_block *uniform_blocks; - unsigned num_supported_versions; struct { unsigned ver; diff --git a/mesalib/src/glsl/ir.cpp b/mesalib/src/glsl/ir.cpp index a41eddfcb..1a18b47f7 100644 --- a/mesalib/src/glsl/ir.cpp +++ b/mesalib/src/glsl/ir.cpp @@ -1223,6 +1223,15 @@ ir_constant::is_basis() const return ones == 1; } +bool +ir_constant::is_uint16_constant() const +{ + if (!type->is_integer()) + return false; + + return value.u[0] < (1 << 16); +} + ir_loop::ir_loop() { this->ir_type = ir_type_loop; diff --git a/mesalib/src/glsl/ir.h b/mesalib/src/glsl/ir.h index ee276d2be..6c7c60a27 100644 --- a/mesalib/src/glsl/ir.h +++ b/mesalib/src/glsl/ir.h @@ -265,6 +265,13 @@ public: */ virtual bool is_basis() const; + /** + * Determine if an r-value is an unsigned integer constant which can be + * stored in 16 bits. + * + * \sa ir_constant::is_uint16_constant. + */ + virtual bool is_uint16_constant() const { return false; } /** * Return a generic value of error_type. @@ -2165,6 +2172,14 @@ public: virtual bool is_basis() const; /** + * Return true for constants that could be stored as 16-bit unsigned values. + * + * Note that this will return true even for signed integer ir_constants, as + * long as the value is non-negative and fits in 16-bits. + */ + virtual bool is_uint16_constant() const; + + /** * Value of the constant. * * The field used to back the values supplied by the constant is determined diff --git a/mesalib/src/glsl/ir_optimization.h b/mesalib/src/glsl/ir_optimization.h index 5f4a2f405..40bb61392 100644 --- a/mesalib/src/glsl/ir_optimization.h +++ b/mesalib/src/glsl/ir_optimization.h @@ -66,10 +66,10 @@ enum lower_packing_builtins_op { bool do_common_optimization(exec_list *ir, bool linked, bool uniform_locations_assigned, - unsigned max_unroll_iterations, - const struct gl_shader_compiler_options *options); + const struct gl_shader_compiler_options *options, + bool native_integers); -bool do_algebraic(exec_list *instructions); +bool do_algebraic(exec_list *instructions, bool native_integers); bool do_constant_folding(exec_list *instructions); bool do_constant_variable(exec_list *instructions); bool do_constant_variable_unlinked(exec_list *instructions); diff --git a/mesalib/src/glsl/ir_validate.cpp b/mesalib/src/glsl/ir_validate.cpp index 527acea4c..71defc815 100644 --- a/mesalib/src/glsl/ir_validate.cpp +++ b/mesalib/src/glsl/ir_validate.cpp @@ -381,6 +381,9 @@ ir_validate::visit_leave(ir_expression *ir) case ir_binop_min: case ir_binop_max: case ir_binop_pow: + assert(ir->operands[0]->type->base_type == + ir->operands[1]->type->base_type); + if (ir->operands[0]->type->is_scalar()) assert(ir->operands[1]->type == ir->type); else if (ir->operands[1]->type->is_scalar()) diff --git a/mesalib/src/glsl/link_uniform_block_active_visitor.cpp b/mesalib/src/glsl/link_uniform_block_active_visitor.cpp index f2f46a211..d19ce20c7 100644 --- a/mesalib/src/glsl/link_uniform_block_active_visitor.cpp +++ b/mesalib/src/glsl/link_uniform_block_active_visitor.cpp @@ -46,6 +46,14 @@ process_block(void *mem_ctx, struct hash_table *ht, ir_variable *var) b->type = block_type; b->has_instance_name = var->is_interface_instance(); + if (var->data.explicit_binding) { + b->has_binding = true; + b->binding = var->data.binding; + } else { + b->has_binding = false; + b->binding = 0; + } + _mesa_hash_table_insert(ht, h, var->get_interface_type()->name, (void *) b); return b; diff --git a/mesalib/src/glsl/link_uniform_block_active_visitor.h b/mesalib/src/glsl/link_uniform_block_active_visitor.h index fba628a8f..d76dbcaf1 100644 --- a/mesalib/src/glsl/link_uniform_block_active_visitor.h +++ b/mesalib/src/glsl/link_uniform_block_active_visitor.h @@ -36,7 +36,10 @@ struct link_uniform_block_active { unsigned *array_elements; unsigned num_array_elements; + unsigned binding; + bool has_instance_name; + bool has_binding; }; class link_uniform_block_active_visitor : public ir_hierarchical_visitor { diff --git a/mesalib/src/glsl/link_uniform_blocks.cpp b/mesalib/src/glsl/link_uniform_blocks.cpp index 72d6c5323..1a0e64318 100644 --- a/mesalib/src/glsl/link_uniform_blocks.cpp +++ b/mesalib/src/glsl/link_uniform_blocks.cpp @@ -251,7 +251,17 @@ link_uniform_blocks(void *mem_ctx, blocks[i].Name = ralloc_asprintf(blocks, "%s[%u]", name, b->array_elements[j]); blocks[i].Uniforms = &variables[parcel.index]; - blocks[i].Binding = 0; + + /* The GL_ARB_shading_language_420pack spec says: + * + * "If the binding identifier is used with a uniform block + * instanced as an array then the first element of the array + * takes the specified block binding and each subsequent + * element takes the next consecutive uniform block binding + * point." + */ + blocks[i].Binding = (b->has_binding) ? b->binding + j : 0; + blocks[i].UniformBufferSize = 0; blocks[i]._Packing = gl_uniform_block_packing(block_type->interface_packing); @@ -269,7 +279,7 @@ link_uniform_blocks(void *mem_ctx, } else { blocks[i].Name = ralloc_strdup(blocks, block_type->name); blocks[i].Uniforms = &variables[parcel.index]; - blocks[i].Binding = 0; + blocks[i].Binding = (b->has_binding) ? b->binding : 0; blocks[i].UniformBufferSize = 0; blocks[i]._Packing = gl_uniform_block_packing(block_type->interface_packing); diff --git a/mesalib/src/glsl/link_uniform_initializers.cpp b/mesalib/src/glsl/link_uniform_initializers.cpp index 9d6977d57..e60bb64bc 100644 --- a/mesalib/src/glsl/link_uniform_initializers.cpp +++ b/mesalib/src/glsl/link_uniform_initializers.cpp @@ -46,6 +46,18 @@ get_storage(gl_uniform_storage *storage, unsigned num_storage, return NULL; } +static unsigned +get_uniform_block_index(const gl_shader_program *shProg, + const char *uniformBlockName) +{ + for (unsigned i = 0; i < shProg->NumUniformBlocks; i++) { + if (!strcmp(shProg->UniformBlocks[i].Name, uniformBlockName)) + return i; + } + + return GL_INVALID_INDEX; +} + void copy_constant_to_storage(union gl_constant_value *storage, const ir_constant *val, @@ -84,8 +96,7 @@ copy_constant_to_storage(union gl_constant_value *storage, } void -set_uniform_binding(void *mem_ctx, gl_shader_program *prog, - const char *name, const glsl_type *type, int binding) +set_sampler_binding(gl_shader_program *prog, const char *name, int binding) { struct gl_uniform_storage *const storage = get_storage(prog->UniformStorage, prog->NumUserUniformStorage, name); @@ -95,42 +106,53 @@ set_uniform_binding(void *mem_ctx, gl_shader_program *prog, return; } - if (storage->type->is_sampler()) { - unsigned elements = MAX2(storage->array_elements, 1); + const unsigned elements = MAX2(storage->array_elements, 1); - /* From section 4.4.4 of the GLSL 4.20 specification: - * "If the binding identifier is used with an array, the first element - * of the array takes the specified unit and each subsequent element - * takes the next consecutive unit." - */ - for (unsigned int i = 0; i < elements; i++) { - storage->storage[i].i = binding + i; - } + /* Section 4.4.4 (Opaque-Uniform Layout Qualifiers) of the GLSL 4.20 spec + * says: + * + * "If the binding identifier is used with an array, the first element + * of the array takes the specified unit and each subsequent element + * takes the next consecutive unit." + */ + for (unsigned int i = 0; i < elements; i++) { + storage->storage[i].i = binding + i; + } - for (int sh = 0; sh < MESA_SHADER_STAGES; sh++) { - gl_shader *shader = prog->_LinkedShaders[sh]; + for (int sh = 0; sh < MESA_SHADER_STAGES; sh++) { + gl_shader *shader = prog->_LinkedShaders[sh]; - if (shader && storage->sampler[sh].active) { - for (unsigned i = 0; i < elements; i++) { - unsigned index = storage->sampler[sh].index + i; + if (shader && storage->sampler[sh].active) { + for (unsigned i = 0; i < elements; i++) { + unsigned index = storage->sampler[sh].index + i; - shader->SamplerUnits[index] = storage->storage[i].i; - } + shader->SamplerUnits[index] = storage->storage[i].i; } } - } else if (storage->block_index != -1) { + } + + storage->initialized = true; +} + +void +set_block_binding(gl_shader_program *prog, const char *block_name, int binding) +{ + const unsigned block_index = get_uniform_block_index(prog, block_name); + + if (block_index == GL_INVALID_INDEX) { + assert(block_index != GL_INVALID_INDEX); + return; + } + /* This is a field of a UBO. val is the binding index. */ for (int i = 0; i < MESA_SHADER_STAGES; i++) { - int stage_index = prog->UniformBlockStageIndex[i][storage->block_index]; + int stage_index = prog->UniformBlockStageIndex[i][block_index]; if (stage_index != -1) { struct gl_shader *sh = prog->_LinkedShaders[i]; sh->UniformBlocks[stage_index].Binding = binding; } } - } - - storage->initialized = true; } void @@ -232,8 +254,51 @@ link_set_uniform_initializers(struct gl_shader_program *prog) mem_ctx = ralloc_context(NULL); if (var->data.explicit_binding) { - linker::set_uniform_binding(mem_ctx, prog, var->name, - var->type, var->data.binding); + const glsl_type *const type = var->type; + + if (type->is_sampler() + || (type->is_array() && type->fields.array->is_sampler())) { + linker::set_sampler_binding(prog, var->name, var->data.binding); + } else if (var->is_in_uniform_block()) { + const glsl_type *const iface_type = var->get_interface_type(); + + /* If the variable is an array and it is an interface instance, + * we need to set the binding for each array element. Just + * checking that the variable is an array is not sufficient. + * The variable could be an array element of a uniform block + * that lacks an instance name. For example: + * + * uniform U { + * float f[4]; + * }; + * + * In this case "f" would pass is_in_uniform_block (above) and + * type->is_array(), but it will fail is_interface_instance(). + */ + if (var->is_interface_instance() && var->type->is_array()) { + for (unsigned i = 0; i < var->type->length; i++) { + const char *name = + ralloc_asprintf(mem_ctx, "%s[%u]", iface_type->name, i); + + /* Section 4.4.3 (Uniform Block Layout Qualifiers) of the + * GLSL 4.20 spec says: + * + * "If the binding identifier is used with a uniform + * block instanced as an array then the first element + * of the array takes the specified block binding and + * each subsequent element takes the next consecutive + * uniform block binding point." + */ + linker::set_block_binding(prog, name, + var->data.binding + i); + } + } else { + linker::set_block_binding(prog, iface_type->name, + var->data.binding); + } + } else { + assert(!"Explicit binding not on a sampler or UBO."); + } } else if (var->constant_value) { linker::set_uniform_initializer(mem_ctx, prog, var->name, var->type, var->constant_value); diff --git a/mesalib/src/glsl/linker.cpp b/mesalib/src/glsl/linker.cpp index 3bf278965..c8dc0661d 100644 --- a/mesalib/src/glsl/linker.cpp +++ b/mesalib/src/glsl/linker.cpp @@ -2296,9 +2296,9 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog) lower_clip_distance(prog->_LinkedShaders[i]); } - unsigned max_unroll = ctx->ShaderCompilerOptions[i].MaxUnrollIterations; - - while (do_common_optimization(prog->_LinkedShaders[i]->ir, true, false, max_unroll, &ctx->ShaderCompilerOptions[i])) + while (do_common_optimization(prog->_LinkedShaders[i]->ir, true, false, + &ctx->ShaderCompilerOptions[i], + ctx->Const.NativeIntegers)) ; } diff --git a/mesalib/src/glsl/loop_analysis.h b/mesalib/src/glsl/loop_analysis.h index f841042f0..295dc797c 100644 --- a/mesalib/src/glsl/loop_analysis.h +++ b/mesalib/src/glsl/loop_analysis.h @@ -53,7 +53,8 @@ set_loop_controls(exec_list *instructions, loop_state *ls); extern bool -unroll_loops(exec_list *instructions, loop_state *ls, unsigned max_iterations); +unroll_loops(exec_list *instructions, loop_state *ls, + const struct gl_shader_compiler_options *options); ir_rvalue * find_initial_value(ir_loop *loop, ir_variable *var); diff --git a/mesalib/src/glsl/loop_unroll.cpp b/mesalib/src/glsl/loop_unroll.cpp index 789655ebd..da532804a 100644 --- a/mesalib/src/glsl/loop_unroll.cpp +++ b/mesalib/src/glsl/loop_unroll.cpp @@ -25,15 +25,18 @@ #include "loop_analysis.h" #include "ir_hierarchical_visitor.h" +#include "main/mtypes.h" + namespace { class loop_unroll_visitor : public ir_hierarchical_visitor { public: - loop_unroll_visitor(loop_state *state, unsigned max_iterations) + loop_unroll_visitor(loop_state *state, + const struct gl_shader_compiler_options *options) { this->state = state; this->progress = false; - this->max_iterations = max_iterations; + this->options = options; } virtual ir_visitor_status visit_leave(ir_loop *ir); @@ -45,7 +48,7 @@ public: loop_state *state; bool progress; - unsigned max_iterations; + const struct gl_shader_compiler_options *options; }; } /* anonymous namespace */ @@ -60,12 +63,17 @@ is_break(ir_instruction *ir) class loop_unroll_count : public ir_hierarchical_visitor { public: int nodes; - bool fail; + bool unsupported_variable_indexing; + /* If there are nested loops, the node count will be inaccurate. */ + bool nested_loop; - loop_unroll_count(exec_list *list) + loop_unroll_count(exec_list *list, loop_variable_state *ls, + const struct gl_shader_compiler_options *options) + : ls(ls), options(options) { nodes = 0; - fail = false; + nested_loop = false; + unsupported_variable_indexing = false; run(list); } @@ -84,9 +92,57 @@ public: virtual ir_visitor_status visit_enter(ir_loop *) { - fail = true; + nested_loop = true; + return visit_continue; + } + + virtual ir_visitor_status visit_enter(ir_dereference_array *ir) + { + /* Check for arrays variably-indexed by a loop induction variable. + * Unrolling the loop may convert that access into constant-indexing. + * + * Many drivers don't support particular kinds of variable indexing, + * and have to resort to using lower_variable_index_to_cond_assign to + * handle it. This results in huge amounts of horrible code, so we'd + * like to avoid that if possible. Here, we just note that it will + * happen. + */ + if ((ir->array->type->is_array() || ir->array->type->is_matrix()) && + !ir->array_index->as_constant()) { + ir_variable *array = ir->array->variable_referenced(); + loop_variable *lv = ls->get(ir->array_index->variable_referenced()); + if (array && lv && lv->is_induction_var()) { + switch (array->data.mode) { + case ir_var_auto: + case ir_var_temporary: + case ir_var_const_in: + case ir_var_function_in: + case ir_var_function_out: + case ir_var_function_inout: + if (options->EmitNoIndirectTemp) + unsupported_variable_indexing = true; + break; + case ir_var_uniform: + if (options->EmitNoIndirectUniform) + unsupported_variable_indexing = true; + break; + case ir_var_shader_in: + if (options->EmitNoIndirectInput) + unsupported_variable_indexing = true; + break; + case ir_var_shader_out: + if (options->EmitNoIndirectOutput) + unsupported_variable_indexing = true; + break; + } + } + } return visit_continue; } + +private: + loop_variable_state *ls; + const struct gl_shader_compiler_options *options; }; @@ -244,16 +300,21 @@ loop_unroll_visitor::visit_leave(ir_loop *ir) iterations = ls->limiting_terminator->iterations; + const int max_iterations = options->MaxUnrollIterations; + /* Don't try to unroll loops that have zillions of iterations either. */ - if (iterations > (int) max_iterations) + if (iterations > max_iterations) return visit_continue; /* Don't try to unroll nested loops and loops with a huge body. */ - loop_unroll_count count(&ir->body_instructions); + loop_unroll_count count(&ir->body_instructions, ls, options); + + bool loop_too_large = + count.nested_loop || count.nodes * iterations > max_iterations * 5; - if (count.fail || count.nodes * iterations > (int)max_iterations * 5) + if (loop_too_large && !count.unsupported_variable_indexing) return visit_continue; /* Note: the limiting terminator contributes 1 to ls->num_loop_jumps. @@ -338,9 +399,10 @@ loop_unroll_visitor::visit_leave(ir_loop *ir) bool -unroll_loops(exec_list *instructions, loop_state *ls, unsigned max_iterations) +unroll_loops(exec_list *instructions, loop_state *ls, + const struct gl_shader_compiler_options *options) { - loop_unroll_visitor v(ls, max_iterations); + loop_unroll_visitor v(ls, options); v.run(instructions); diff --git a/mesalib/src/glsl/lower_ubo_reference.cpp b/mesalib/src/glsl/lower_ubo_reference.cpp index c73b148b0..90e65bd0e 100644 --- a/mesalib/src/glsl/lower_ubo_reference.cpp +++ b/mesalib/src/glsl/lower_ubo_reference.cpp @@ -194,12 +194,16 @@ lower_ubo_reference_visitor::handle_rvalue(ir_rvalue **rvalue) array_stride = glsl_align(array_stride, 16); } - ir_constant *const_index = deref_array->array_index->as_constant(); + ir_rvalue *array_index = deref_array->array_index; + if (array_index->type->base_type == GLSL_TYPE_INT) + array_index = i2u(array_index); + + ir_constant *const_index = array_index->as_constant(); if (const_index) { - const_offset += array_stride * const_index->value.i[0]; + const_offset += array_stride * const_index->value.u[0]; } else { offset = add(offset, - mul(deref_array->array_index, + mul(array_index, new(mem_ctx) ir_constant(array_stride))); } deref = deref_array->array->as_dereference(); diff --git a/mesalib/src/glsl/opt_algebraic.cpp b/mesalib/src/glsl/opt_algebraic.cpp index 8494bd9ec..9d5539252 100644 --- a/mesalib/src/glsl/opt_algebraic.cpp +++ b/mesalib/src/glsl/opt_algebraic.cpp @@ -45,10 +45,11 @@ namespace { class ir_algebraic_visitor : public ir_rvalue_visitor { public: - ir_algebraic_visitor() + ir_algebraic_visitor(bool native_integers) { this->progress = false; this->mem_ctx = NULL; + this->native_integers = native_integers; } virtual ~ir_algebraic_visitor() @@ -70,6 +71,7 @@ public: void *mem_ctx; + bool native_integers; bool progress; }; @@ -445,6 +447,28 @@ ir_algebraic_visitor::handle_expression(ir_expression *ir) } break; + case ir_binop_less: + case ir_binop_lequal: + case ir_binop_greater: + case ir_binop_gequal: + case ir_binop_equal: + case ir_binop_nequal: + for (int add_pos = 0; add_pos < 2; add_pos++) { + ir_expression *add = op_expr[add_pos]; + + if (!add || add->operation != ir_binop_add) + continue; + + ir_constant *zero = op_const[1 - add_pos]; + if (!is_vec_zero(zero)) + continue; + + return new(mem_ctx) ir_expression(ir->operation, + add->operands[0], + neg(add->operands[1])); + } + break; + case ir_binop_rshift: case ir_binop_lshift: /* 0 >> x == 0 */ @@ -623,9 +647,9 @@ ir_algebraic_visitor::handle_rvalue(ir_rvalue **rvalue) } bool -do_algebraic(exec_list *instructions) +do_algebraic(exec_list *instructions, bool native_integers) { - ir_algebraic_visitor v; + ir_algebraic_visitor v(native_integers); visit_list_elements(&v, instructions); diff --git a/mesalib/src/glsl/opt_tree_grafting.cpp b/mesalib/src/glsl/opt_tree_grafting.cpp index f3bd580af..d47613c21 100644 --- a/mesalib/src/glsl/opt_tree_grafting.cpp +++ b/mesalib/src/glsl/opt_tree_grafting.cpp @@ -127,12 +127,12 @@ ir_tree_grafting_visitor::do_graft(ir_rvalue **rvalue) return false; if (debug) { - printf("GRAFTING:\n"); - this->graft_assign->print(); - printf("\n"); - printf("TO:\n"); - (*rvalue)->print(); - printf("\n"); + fprintf(stderr, "GRAFTING:\n"); + this->graft_assign->fprint(stderr); + fprintf(stderr, "\n"); + fprintf(stderr, "TO:\n"); + (*rvalue)->fprint(stderr); + fprintf(stderr, "\n"); } this->graft_assign->remove(); @@ -164,9 +164,9 @@ ir_tree_grafting_visitor::check_graft(ir_instruction *ir, ir_variable *var) { if (dereferences_variable(this->graft_assign->rhs, var)) { if (debug) { - printf("graft killed by: "); - ir->print(); - printf("\n"); + fprintf(stderr, "graft killed by: "); + ir->fprint(stderr); + fprintf(stderr, "\n"); } return visit_stop; } @@ -316,9 +316,9 @@ try_tree_grafting(ir_assignment *start, ir_tree_grafting_visitor v(start, lhs_var); if (debug) { - printf("trying to graft: "); - lhs_var->print(); - printf("\n"); + fprintf(stderr, "trying to graft: "); + lhs_var->fprint(stderr); + fprintf(stderr, "\n"); } for (ir_instruction *ir = (ir_instruction *)start->next; @@ -326,9 +326,9 @@ try_tree_grafting(ir_assignment *start, ir = (ir_instruction *)ir->next) { if (debug) { - printf("- "); - ir->print(); - printf("\n"); + fprintf(stderr, "- "); + ir->fprint(stderr); + fprintf(stderr, "\n"); } ir_visitor_status s = ir->accept(&v); diff --git a/mesalib/src/glsl/opt_vectorize.cpp b/mesalib/src/glsl/opt_vectorize.cpp index 3306397fd..f9a3b6183 100644 --- a/mesalib/src/glsl/opt_vectorize.cpp +++ b/mesalib/src/glsl/opt_vectorize.cpp @@ -260,6 +260,7 @@ ir_vectorize_visitor::visit_enter(ir_assignment *ir) if (ir->condition || this->channels >= 4 || !single_channel_write_mask(ir->write_mask) || + this->assignment[write_mask_to_swizzle(ir->write_mask)] != NULL || (lhs && !ir->lhs->equals(lhs)) || (rhs && !ir->rhs->equals(rhs, ir_type_swizzle))) { try_vectorize(); diff --git a/mesalib/src/glsl/test_optpass.cpp b/mesalib/src/glsl/test_optpass.cpp index f1b9579cd..db5cb2662 100644 --- a/mesalib/src/glsl/test_optpass.cpp +++ b/mesalib/src/glsl/test_optpass.cpp @@ -62,11 +62,10 @@ do_optimization(struct exec_list *ir, const char *optimization, int int_3; int int_4; - if (sscanf(optimization, "do_common_optimization ( %d , %d ) ", - &int_0, &int_1) == 2) { - return do_common_optimization(ir, int_0 != 0, false, int_1, options); + if (sscanf(optimization, "do_common_optimization ( %d ) ", &int_0) == 1) { + return do_common_optimization(ir, int_0 != 0, false, options, true); } else if (strcmp(optimization, "do_algebraic") == 0) { - return do_algebraic(ir); + return do_algebraic(ir, true); } else if (strcmp(optimization, "do_constant_folding") == 0) { return do_constant_folding(ir); } else if (strcmp(optimization, "do_constant_variable") == 0) { |