diff options
Diffstat (limited to 'mesalib/src/glsl')
31 files changed, 511 insertions, 160 deletions
diff --git a/mesalib/src/glsl/Makefile.sources b/mesalib/src/glsl/Makefile.sources index cb8d5a6f7..bfb699353 100644 --- a/mesalib/src/glsl/Makefile.sources +++ b/mesalib/src/glsl/Makefile.sources @@ -87,6 +87,7 @@ LIBGLSL_FILES = \ $(GLSL_SRCDIR)/opt_copy_propagation.cpp \ $(GLSL_SRCDIR)/opt_copy_propagation_elements.cpp \ $(GLSL_SRCDIR)/opt_cse.cpp \ + $(GLSL_SRCDIR)/opt_dead_builtin_variables.cpp \ $(GLSL_SRCDIR)/opt_dead_builtin_varyings.cpp \ $(GLSL_SRCDIR)/opt_dead_code.cpp \ $(GLSL_SRCDIR)/opt_dead_code_local.cpp \ diff --git a/mesalib/src/glsl/ast_array_index.cpp b/mesalib/src/glsl/ast_array_index.cpp index 5ca85f6ab..49a8574f2 100644 --- a/mesalib/src/glsl/ast_array_index.cpp +++ b/mesalib/src/glsl/ast_array_index.cpp @@ -88,8 +88,14 @@ update_max_array_access(ir_rvalue *ir, unsigned idx, YYLTYPE *loc, unsigned field_index = deref_record->record->type->field_index(deref_record->field); assert(field_index < interface_type->length); - if (idx > deref_var->var->max_ifc_array_access[field_index]) { - deref_var->var->max_ifc_array_access[field_index] = idx; + + unsigned *const max_ifc_array_access = + deref_var->var->get_max_ifc_array_access(); + + assert(max_ifc_array_access != NULL); + + if (idx > max_ifc_array_access[field_index]) { + max_ifc_array_access[field_index] = idx; /* Check whether this access will, as a side effect, implicitly * cause the size of a built-in array to be too large. diff --git a/mesalib/src/glsl/ast_function.cpp b/mesalib/src/glsl/ast_function.cpp index 7130d6162..cbff9d8b4 100644 --- a/mesalib/src/glsl/ast_function.cpp +++ b/mesalib/src/glsl/ast_function.cpp @@ -408,14 +408,17 @@ generate_call(exec_list *instructions, ir_function_signature *sig, ir_dereference_variable *deref = NULL; if (!sig->return_type->is_void()) { /* Create a new temporary to hold the return value. */ + char *const name = ir_variable::temporaries_allocate_names + ? ralloc_asprintf(ctx, "%s_retval", sig->function_name()) + : NULL; + ir_variable *var; - var = new(ctx) ir_variable(sig->return_type, - ralloc_asprintf(ctx, "%s_retval", - sig->function_name()), - ir_var_temporary); + var = new(ctx) ir_variable(sig->return_type, name, ir_var_temporary); instructions->push_tail(var); + ralloc_free(name); + deref = new(ctx) ir_dereference_variable(var); } ir_call *call = new(ctx) ir_call(sig, deref, actual_parameters); diff --git a/mesalib/src/glsl/ast_to_hir.cpp b/mesalib/src/glsl/ast_to_hir.cpp index 5ec1614be..068af295a 100644 --- a/mesalib/src/glsl/ast_to_hir.cpp +++ b/mesalib/src/glsl/ast_to_hir.cpp @@ -912,7 +912,6 @@ get_lvalue_copy(exec_list *instructions, ir_rvalue *lvalue) var = new(ctx) ir_variable(lvalue->type, "_post_incdec_tmp", ir_var_temporary); instructions->push_tail(var); - var->data.mode = ir_var_auto; instructions->push_tail(new(ctx) ir_assignment(new(ctx) ir_dereference_variable(var), lvalue)); @@ -2499,6 +2498,7 @@ apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual, /* If there is no qualifier that changes the mode of the variable, leave * the setting alone. */ + assert(var->data.mode != ir_var_temporary); if (qual->flags.q.in && qual->flags.q.out) var->data.mode = ir_var_function_inout; else if (qual->flags.q.in) @@ -5031,7 +5031,7 @@ ast_type_specifier::hir(exec_list *instructions, */ ir_variable *const junk = new(state) ir_variable(type, "#default precision", - ir_var_temporary); + ir_var_auto); state->symbols->add_variable(junk); } diff --git a/mesalib/src/glsl/builtin_functions.cpp b/mesalib/src/glsl/builtin_functions.cpp index a1473d270..2cdaddea7 100755 --- a/mesalib/src/glsl/builtin_functions.cpp +++ b/mesalib/src/glsl/builtin_functions.cpp @@ -1882,8 +1882,8 @@ builtin_builder::create_builtins() NULL); add_function("texture2DProjLod", - _texture(ir_txl, v110_lod, glsl_type::vec4_type, glsl_type::sampler2D_type, glsl_type::vec3_type, TEX_PROJECT), - _texture(ir_txl, v110_lod, glsl_type::vec4_type, glsl_type::sampler2D_type, glsl_type::vec4_type, TEX_PROJECT), + _texture(ir_txl, lod_exists_in_stage, glsl_type::vec4_type, glsl_type::sampler2D_type, glsl_type::vec3_type, TEX_PROJECT), + _texture(ir_txl, lod_exists_in_stage, glsl_type::vec4_type, glsl_type::sampler2D_type, glsl_type::vec4_type, TEX_PROJECT), NULL); add_function("texture3D", @@ -1910,7 +1910,7 @@ builtin_builder::create_builtins() NULL); add_function("textureCubeLod", - _texture(ir_txl, v110_lod, glsl_type::vec4_type, glsl_type::samplerCube_type, glsl_type::vec3_type), + _texture(ir_txl, lod_exists_in_stage, glsl_type::vec4_type, glsl_type::samplerCube_type, glsl_type::vec3_type), NULL); add_function("texture2DRect", diff --git a/mesalib/src/glsl/builtin_variables.cpp b/mesalib/src/glsl/builtin_variables.cpp index 5b6f4ae62..c36d19831 100644 --- a/mesalib/src/glsl/builtin_variables.cpp +++ b/mesalib/src/glsl/builtin_variables.cpp @@ -478,12 +478,9 @@ builtin_variable_generator::add_uniform(const glsl_type *type, &_mesa_builtin_uniform_desc[i]; const unsigned array_count = type->is_array() ? type->length : 1; - uni->num_state_slots = array_count * statevar->num_elements; ir_state_slot *slots = - ralloc_array(uni, ir_state_slot, uni->num_state_slots); - - uni->state_slots = slots; + uni->allocate_state_slots(array_count * statevar->num_elements); for (unsigned a = 0; a < array_count; a++) { for (unsigned j = 0; j < statevar->num_elements; j++) { @@ -908,14 +905,14 @@ builtin_variable_generator::generate_fs_special_vars() ir_variable *const var = add_output(FRAG_RESULT_STENCIL, int_t, "gl_FragStencilRefARB"); if (state->ARB_shader_stencil_export_warn) - var->warn_extension = "GL_ARB_shader_stencil_export"; + var->enable_extension_warning("GL_ARB_shader_stencil_export"); } if (state->AMD_shader_stencil_export_enable) { ir_variable *const var = add_output(FRAG_RESULT_STENCIL, int_t, "gl_FragStencilRefAMD"); if (state->AMD_shader_stencil_export_warn) - var->warn_extension = "GL_AMD_shader_stencil_export"; + var->enable_extension_warning("GL_AMD_shader_stencil_export"); } if (state->ARB_sample_shading_enable) { diff --git a/mesalib/src/glsl/glsl_lexer.ll b/mesalib/src/glsl/glsl_lexer.ll index b7c4aad3a..e66a93591 100644 --- a/mesalib/src/glsl/glsl_lexer.ll +++ b/mesalib/src/glsl/glsl_lexer.ll @@ -81,7 +81,8 @@ static int classify_identifier(struct _mesa_glsl_parse_state *, const char *); "illegal use of reserved word `%s'", yytext); \ return ERROR_TOK; \ } else { \ - yylval->identifier = strdup(yytext); \ + void *mem_ctx = yyextra; \ + yylval->identifier = ralloc_strdup(mem_ctx, yytext); \ return classify_identifier(yyextra, yytext); \ } \ } while (0) @@ -232,7 +233,8 @@ HASH ^{SPC}#{SPC} <PP>[ \t\r]* { } <PP>: return COLON; <PP>[_a-zA-Z][_a-zA-Z0-9]* { - yylval->identifier = strdup(yytext); + void *mem_ctx = yyextra; + yylval->identifier = ralloc_strdup(mem_ctx, yytext); return IDENTIFIER; } <PP>[1-9][0-9]* { @@ -409,7 +411,8 @@ layout { || yyextra->ARB_compute_shader_enable) { return LAYOUT_TOK; } else { - yylval->identifier = strdup(yytext); + void *mem_ctx = yyextra; + yylval->identifier = ralloc_strdup(mem_ctx, yytext); return classify_identifier(yyextra, yytext); } } diff --git a/mesalib/src/glsl/glsl_parser_extras.cpp b/mesalib/src/glsl/glsl_parser_extras.cpp index 490c3c8ee..cc7d2d746 100644 --- a/mesalib/src/glsl/glsl_parser_extras.cpp +++ b/mesalib/src/glsl/glsl_parser_extras.cpp @@ -1440,6 +1440,9 @@ _mesa_glsl_compile_shader(struct gl_context *ctx, struct gl_shader *shader, new(shader) _mesa_glsl_parse_state(ctx, shader->Stage, shader); const char *source = shader->Source; + if (ctx->Const.GenerateTemporaryNames) + ir_variable::temporaries_allocate_names = true; + state->error = glcpp_preprocess(state, &source, &state->info_log, &ctx->Extensions, ctx); @@ -1483,6 +1486,26 @@ _mesa_glsl_compile_shader(struct gl_context *ctx, struct gl_shader *shader, ; validate_ir_tree(shader->ir); + + enum ir_variable_mode other; + switch (shader->Stage) { + case MESA_SHADER_VERTEX: + other = ir_var_shader_in; + break; + case MESA_SHADER_FRAGMENT: + other = ir_var_shader_out; + break; + default: + /* Something invalid to ensure optimize_dead_builtin_uniforms + * doesn't remove anything other than uniforms or constants. + */ + other = ir_var_mode_count; + break; + } + + optimize_dead_builtin_variables(shader->ir, other); + + validate_ir_tree(shader->ir); } if (shader->InfoLog) @@ -1516,9 +1539,13 @@ _mesa_glsl_compile_shader(struct gl_context *ctx, struct gl_shader *shader, case ir_type_function: shader->symbols->add_function((ir_function *) ir); break; - case ir_type_variable: - shader->symbols->add_variable((ir_variable *) ir); + case ir_type_variable: { + ir_variable *const var = (ir_variable *) ir; + + if (var->data.mode != ir_var_temporary) + shader->symbols->add_variable(var); break; + } default: break; } diff --git a/mesalib/src/glsl/glsl_symbol_table.cpp b/mesalib/src/glsl/glsl_symbol_table.cpp index d17a5e66f..2a2c465ed 100755 --- a/mesalib/src/glsl/glsl_symbol_table.cpp +++ b/mesalib/src/glsl/glsl_symbol_table.cpp @@ -128,6 +128,8 @@ bool glsl_symbol_table::name_declared_this_scope(const char *name) bool glsl_symbol_table::add_variable(ir_variable *v) { + assert(v->data.mode != ir_var_temporary); + if (this->separate_function_namespace) { /* In 1.10, functions and variables have separate namespaces. */ symbol_table_entry *existing = get_entry(v->name); diff --git a/mesalib/src/glsl/glsl_types.cpp b/mesalib/src/glsl/glsl_types.cpp index 66e9b1330..c11d86482 100644 --- a/mesalib/src/glsl/glsl_types.cpp +++ b/mesalib/src/glsl/glsl_types.cpp @@ -490,6 +490,20 @@ glsl_type::record_compare(const glsl_type *b) const if (this->interface_packing != b->interface_packing) return false; + /* From the GLSL 4.20 specification (Sec 4.2): + * + * "Structures must have the same name, sequence of type names, and + * type definitions, and field names to be considered the same type." + * + * GLSL ES behaves the same (Ver 1.00 Sec 4.2.4, Ver 3.00 Sec 4.2.5). + * + * Note that we cannot force type name check when comparing unnamed + * structure types, these have a unique name assigned during parsing. + */ + if (!this->is_anonymous() && !b->is_anonymous()) + if (strcmp(this->name, b->name) != 0) + return false; + for (unsigned i = 0; i < this->length; i++) { if (this->fields.structure[i].type != b->fields.structure[i].type) return false; @@ -678,12 +692,17 @@ glsl_type::component_slots() const unsigned glsl_type::uniform_locations() const { - if (this->is_matrix()) - return 1; - unsigned size = 0; switch (this->base_type) { + case GLSL_TYPE_UINT: + case GLSL_TYPE_INT: + case GLSL_TYPE_FLOAT: + case GLSL_TYPE_BOOL: + case GLSL_TYPE_SAMPLER: + case GLSL_TYPE_IMAGE: + return 1; + case GLSL_TYPE_STRUCT: case GLSL_TYPE_INTERFACE: for (unsigned i = 0; i < this->length; i++) @@ -692,13 +711,8 @@ glsl_type::uniform_locations() const case GLSL_TYPE_ARRAY: return this->length * this->fields.array->uniform_locations(); default: - break; + return 0; } - - /* The location count for many types match with component_slots() result, - * all expections should be handled above. - */ - return component_slots(); } bool @@ -965,7 +979,7 @@ glsl_type::std140_size(bool row_major) const if (field_type->is_record() && (i + 1 < this->length)) size = glsl_align(size, 16); } - size = glsl_align(size, max_align); + size = glsl_align(size, MAX2(max_align, 16)); return size; } diff --git a/mesalib/src/glsl/glsl_types.h b/mesalib/src/glsl/glsl_types.h index d545533dc..eeb14c274 100644 --- a/mesalib/src/glsl/glsl_types.h +++ b/mesalib/src/glsl/glsl_types.h @@ -279,6 +279,9 @@ struct glsl_type { /** * Calculate the number of unique values from glGetUniformLocation for the * elements of the type. + * + * This is used to allocate slots in the UniformRemapTable, the amount of + * locations may not match with actual used storage space by the driver. */ unsigned uniform_locations() const; @@ -486,6 +489,14 @@ struct glsl_type { } /** + * Query if a type is unnamed/anonymous (named by the parser) + */ + bool is_anonymous() const + { + return !strncmp(name, "#anon", 5); + } + + /** * Get the type stripped of any arrays * * \return diff --git a/mesalib/src/glsl/ir.cpp b/mesalib/src/glsl/ir.cpp index 4229a2bf4..5907854f6 100755 --- a/mesalib/src/glsl/ir.cpp +++ b/mesalib/src/glsl/ir.cpp @@ -1543,18 +1543,44 @@ ir_swizzle::variable_referenced() const } +bool ir_variable::temporaries_allocate_names = false; + +const char ir_variable::tmp_name[] = "compiler_temp"; + ir_variable::ir_variable(const struct glsl_type *type, const char *name, ir_variable_mode mode) - : ir_instruction(ir_type_variable), max_ifc_array_access(NULL) + : ir_instruction(ir_type_variable) { this->type = type; - this->name = ralloc_strdup(this, name); + + if (mode == ir_var_temporary && !ir_variable::temporaries_allocate_names) + name = NULL; + + /* The ir_variable clone method may call this constructor with name set to + * tmp_name. + */ + assert(name != NULL + || mode == ir_var_temporary + || mode == ir_var_function_in + || mode == ir_var_function_out + || mode == ir_var_function_inout); + assert(name != ir_variable::tmp_name + || mode == ir_var_temporary); + if (mode == ir_var_temporary + && (name == NULL || name == ir_variable::tmp_name)) { + this->name = ir_variable::tmp_name; + } else { + this->name = ralloc_strdup(this, name); + } + + this->u.max_ifc_array_access = NULL; + this->data.explicit_location = false; this->data.has_initializer = false; this->data.location = -1; this->data.location_frac = 0; this->data.binding = 0; - this->warn_extension = NULL; + this->data.warn_extension_index = 0; this->constant_value = NULL; this->constant_initializer = NULL; this->data.origin_upper_left = false; @@ -1617,6 +1643,32 @@ ir_variable::determine_interpolation_mode(bool flat_shade) return INTERP_QUALIFIER_SMOOTH; } +const char *const ir_variable::warn_extension_table[] = { + "", + "GL_ARB_shader_stencil_export", + "GL_AMD_shader_stencil_export", +}; + +void +ir_variable::enable_extension_warning(const char *extension) +{ + for (unsigned i = 0; i < Elements(warn_extension_table); i++) { + if (strcmp(warn_extension_table[i], extension) == 0) { + this->data.warn_extension_index = i; + return; + } + } + + assert(!"Should not get here."); + this->data.warn_extension_index = 0; +} + +const char * +ir_variable::get_extension_warning() const +{ + return this->data.warn_extension_index == 0 + ? NULL : warn_extension_table[this->data.warn_extension_index]; +} ir_function_signature::ir_function_signature(const glsl_type *return_type, builtin_available_predicate b) diff --git a/mesalib/src/glsl/ir.h b/mesalib/src/glsl/ir.h index 8003f88ce..90c443c3d 100644 --- a/mesalib/src/glsl/ir.h +++ b/mesalib/src/glsl/ir.h @@ -475,7 +475,7 @@ public: assert(this->interface_type == NULL); this->interface_type = type; if (this->is_interface_instance()) { - this->max_ifc_array_access = + this->u.max_ifc_array_access = rzalloc_array(this, unsigned, type->length); } } @@ -487,7 +487,7 @@ public: */ void change_interface_type(const struct glsl_type *type) { - if (this->max_ifc_array_access != NULL) { + if (this->u.max_ifc_array_access != NULL) { /* max_ifc_array_access has already been allocated, so make sure the * new interface has the same number of fields as the old one. */ @@ -504,7 +504,7 @@ public: */ void reinit_interface_type(const struct glsl_type *type) { - if (this->max_ifc_array_access != NULL) { + if (this->u.max_ifc_array_access != NULL) { #ifndef NDEBUG /* Redeclaring gl_PerVertex is only allowed if none of the built-ins * it defines have been accessed yet; so it's safe to throw away the @@ -512,10 +512,10 @@ public: * zero. */ for (unsigned i = 0; i < this->interface_type->length; i++) - assert(this->max_ifc_array_access[i] == 0); + assert(this->u.max_ifc_array_access[i] == 0); #endif - ralloc_free(this->max_ifc_array_access); - this->max_ifc_array_access = NULL; + ralloc_free(this->u.max_ifc_array_access); + this->u.max_ifc_array_access = NULL; } this->interface_type = NULL; init_interface_type(type); @@ -527,27 +527,80 @@ public: } /** - * Declared type of the variable + * Get the max_ifc_array_access pointer + * + * A "set" function is not needed because the array is dynmically allocated + * as necessary. */ - const struct glsl_type *type; + inline unsigned *get_max_ifc_array_access() + { + assert(this->data._num_state_slots == 0); + return this->u.max_ifc_array_access; + } + + inline unsigned get_num_state_slots() const + { + assert(!this->is_interface_instance() + || this->data._num_state_slots == 0); + return this->data._num_state_slots; + } + + inline void set_num_state_slots(unsigned n) + { + assert(!this->is_interface_instance() + || n == 0); + this->data._num_state_slots = n; + } + + inline ir_state_slot *get_state_slots() + { + return this->is_interface_instance() ? NULL : this->u.state_slots; + } + + inline const ir_state_slot *get_state_slots() const + { + return this->is_interface_instance() ? NULL : this->u.state_slots; + } + + inline ir_state_slot *allocate_state_slots(unsigned n) + { + assert(!this->is_interface_instance()); + + this->u.state_slots = ralloc_array(this, ir_state_slot, n); + this->data._num_state_slots = 0; + + if (this->u.state_slots != NULL) + this->data._num_state_slots = n; + + return this->u.state_slots; + } + + inline bool is_name_ralloced() const + { + return this->name != ir_variable::tmp_name; + } /** - * Declared name of the variable + * Enable emitting extension warnings for this variable */ - const char *name; + void enable_extension_warning(const char *extension); /** - * For variables which satisfy the is_interface_instance() predicate, this - * points to an array of integers such that if the ith member of the - * interface block is an array, max_ifc_array_access[i] is the maximum - * array element of that member that has been accessed. If the ith member - * of the interface block is not an array, max_ifc_array_access[i] is - * unused. + * Get the extension warning string for this variable * - * For variables whose type is not an interface block, this pointer is - * NULL. + * If warnings are not enabled, \c NULL is returned. + */ + const char *get_extension_warning() const; + + /** + * Declared type of the variable + */ + const struct glsl_type *type; + + /** + * Declared name of the variable */ - unsigned *max_ifc_array_access; + const char *name; struct ir_variable_data { @@ -697,6 +750,13 @@ public: */ unsigned index:1; + /** + * \brief Layout qualifier for gl_FragDepth. + * + * This is not equal to \c ir_depth_layout_none if and only if this + * variable is \c gl_FragDepth and a layout qualifier is specified. + */ + ir_depth_layout depth_layout:3; /** * ARB_shader_image_load_store qualifiers. @@ -707,16 +767,34 @@ public: unsigned image_volatile:1; unsigned image_restrict:1; + /** + * Emit a warning if this variable is accessed. + */ + private: + uint8_t warn_extension_index; + + public: /** Image internal format if specified explicitly, otherwise GL_NONE. */ uint16_t image_format; + private: /** - * \brief Layout qualifier for gl_FragDepth. + * Number of state slots used * - * This is not equal to \c ir_depth_layout_none if and only if this - * variable is \c gl_FragDepth and a layout qualifier is specified. + * \note + * This could be stored in as few as 7-bits, if necessary. If it is made + * smaller, add an assertion to \c ir_variable::allocate_state_slots to + * be safe. */ - ir_depth_layout depth_layout; + uint16_t _num_state_slots; + + public: + /** + * Initial binding point for a sampler, atomic, or UBO. + * + * For array types, this represents the binding point for the first element. + */ + int16_t binding; /** * Storage location of the base of this variable @@ -744,13 +822,6 @@ public: unsigned stream; /** - * Initial binding point for a sampler, atomic, or UBO. - * - * For array types, this represents the binding point for the first element. - */ - int binding; - - /** * Location an atomic counter is stored at. */ struct { @@ -764,30 +835,13 @@ public: */ unsigned max_array_access; + /** + * Allow (only) ir_variable direct access private members. + */ + friend class ir_variable; } data; /** - * Built-in state that backs this uniform - * - * Once set at variable creation, \c state_slots must remain invariant. - * This is because, ideally, this array would be shared by all clones of - * this variable in the IR tree. In other words, we'd really like for it - * to be a fly-weight. - * - * If the variable is not a uniform, \c num_state_slots will be zero and - * \c state_slots will be \c NULL. - */ - /*@{*/ - unsigned num_state_slots; /**< Number of state slots used */ - ir_state_slot *state_slots; /**< State descriptors. */ - /*@}*/ - - /** - * Emit a warning if this variable is accessed. - */ - const char *warn_extension; - - /** * Value assigned in the initializer of a variable declared "const" */ ir_constant *constant_value; @@ -803,6 +857,33 @@ public: ir_constant *constant_initializer; private: + static const char *const warn_extension_table[]; + + union { + /** + * For variables which satisfy the is_interface_instance() predicate, + * this points to an array of integers such that if the ith member of + * the interface block is an array, max_ifc_array_access[i] is the + * maximum array element of that member that has been accessed. If the + * ith member of the interface block is not an array, + * max_ifc_array_access[i] is unused. + * + * For variables whose type is not an interface block, this pointer is + * NULL. + */ + unsigned *max_ifc_array_access; + + /** + * Built-in state that backs this uniform + * + * Once set at variable creation, \c state_slots must remain invariant. + * + * If the variable is not a uniform, \c _num_state_slots will be zero + * and \c state_slots will be \c NULL. + */ + ir_state_slot *state_slots; + } u; + /** * For variables that are in an interface block or are an instance of an * interface block, this is the \c GLSL_TYPE_INTERFACE type for that block. @@ -810,6 +891,30 @@ private: * \sa ir_variable::location */ const glsl_type *interface_type; + + /** + * Name used for anonymous compiler temporaries + */ + static const char tmp_name[]; + +public: + /** + * Should the construct keep names for ir_var_temporary variables? + * + * When this global is false, names passed to the constructor for + * \c ir_var_temporary variables will be dropped. Instead, the variable will + * be named "compiler_temp". This name will be in static storage. + * + * \warning + * \b NEVER change the mode of an \c ir_var_temporary. + * + * \warning + * This variable is \b not thread-safe. It is global, \b not + * per-context. It begins life false. A context can, at some point, make + * it true. From that point on, it will be true forever. This should be + * okay since it will only be set true while debugging. + */ + static bool temporaries_allocate_names; }; /** diff --git a/mesalib/src/glsl/ir_clone.cpp b/mesalib/src/glsl/ir_clone.cpp index 4b444d468..dffa57844 100644 --- a/mesalib/src/glsl/ir_clone.cpp +++ b/mesalib/src/glsl/ir_clone.cpp @@ -45,25 +45,18 @@ ir_variable::clone(void *mem_ctx, struct hash_table *ht) const var->data.max_array_access = this->data.max_array_access; if (this->is_interface_instance()) { - var->max_ifc_array_access = + var->u.max_ifc_array_access = rzalloc_array(var, unsigned, this->interface_type->length); - memcpy(var->max_ifc_array_access, this->max_ifc_array_access, + memcpy(var->u.max_ifc_array_access, this->u.max_ifc_array_access, this->interface_type->length * sizeof(unsigned)); } memcpy(&var->data, &this->data, sizeof(var->data)); - var->warn_extension = this->warn_extension; - - var->num_state_slots = this->num_state_slots; - if (this->state_slots) { - /* FINISHME: This really wants to use something like talloc_reference, but - * FINISHME: ralloc doesn't have any similar function. - */ - var->state_slots = ralloc_array(var, ir_state_slot, - this->num_state_slots); - memcpy(var->state_slots, this->state_slots, - sizeof(this->state_slots[0]) * var->num_state_slots); + if (this->get_state_slots()) { + ir_state_slot *s = var->allocate_state_slots(this->get_num_state_slots()); + memcpy(s, this->get_state_slots(), + sizeof(s[0]) * var->get_num_state_slots()); } if (this->constant_value) diff --git a/mesalib/src/glsl/ir_function.cpp b/mesalib/src/glsl/ir_function.cpp index 98bec45ce..2b2643c64 100644 --- a/mesalib/src/glsl/ir_function.cpp +++ b/mesalib/src/glsl/ir_function.cpp @@ -24,6 +24,7 @@ #include "glsl_types.h" #include "ir.h" #include "glsl_parser_extras.h" +#include "main/errors.h" typedef enum { PARAMETER_LIST_NO_MATCH, @@ -296,6 +297,7 @@ ir_function::matching_signature(_mesa_glsl_parse_state *state, bool *is_exact) { ir_function_signature **inexact_matches = NULL; + ir_function_signature **inexact_matches_temp; ir_function_signature *match = NULL; int num_inexact_matches = 0; @@ -321,11 +323,16 @@ ir_function::matching_signature(_mesa_glsl_parse_state *state, free(inexact_matches); return sig; case PARAMETER_LIST_INEXACT_MATCH: - inexact_matches = (ir_function_signature **) + inexact_matches_temp = (ir_function_signature **) realloc(inexact_matches, sizeof(*inexact_matches) * (num_inexact_matches + 1)); - assert(inexact_matches); + if (inexact_matches_temp == NULL) { + _mesa_error_no_memory(__func__); + free(inexact_matches); + return NULL; + } + inexact_matches = inexact_matches_temp; inexact_matches[num_inexact_matches++] = sig; continue; case PARAMETER_LIST_NO_MATCH: diff --git a/mesalib/src/glsl/ir_optimization.h b/mesalib/src/glsl/ir_optimization.h index 369dcd15b..0c3a63831 100644 --- a/mesalib/src/glsl/ir_optimization.h +++ b/mesalib/src/glsl/ir_optimization.h @@ -125,6 +125,8 @@ void lower_named_interface_blocks(void *mem_ctx, gl_shader *shader); bool optimize_redundant_jumps(exec_list *instructions); bool optimize_split_arrays(exec_list *instructions, bool linked); bool lower_offset_arrays(exec_list *instructions); +void optimize_dead_builtin_variables(exec_list *instructions, + enum ir_variable_mode other); bool lower_vertex_id(gl_shader *shader); diff --git a/mesalib/src/glsl/ir_validate.cpp b/mesalib/src/glsl/ir_validate.cpp index 97a581dc2..5a6f8bbf5 100644 --- a/mesalib/src/glsl/ir_validate.cpp +++ b/mesalib/src/glsl/ir_validate.cpp @@ -654,7 +654,7 @@ ir_validate::visit(ir_variable *ir) * in the ir_dereference_variable handler to ensure that a variable is * declared before it is dereferenced. */ - if (ir->name) + if (ir->name && ir->is_name_ralloced()) assert(ralloc_parent(ir->name) == ir); hash_table_insert(ht, ir, ir); @@ -682,10 +682,15 @@ ir_validate::visit(ir_variable *ir) ir->get_interface_type()->fields.structure; for (unsigned i = 0; i < ir->get_interface_type()->length; i++) { if (fields[i].type->array_size() > 0) { - if (ir->max_ifc_array_access[i] >= fields[i].type->length) { + const unsigned *const max_ifc_array_access = + ir->get_max_ifc_array_access(); + + assert(max_ifc_array_access != NULL); + + if (max_ifc_array_access[i] >= fields[i].type->length) { printf("ir_variable has maximum access out of bounds for " "field %s (%d vs %d)\n", fields[i].name, - ir->max_ifc_array_access[i], fields[i].type->length); + max_ifc_array_access[i], fields[i].type->length); ir->print(); abort(); } @@ -700,6 +705,14 @@ ir_validate::visit(ir_variable *ir) abort(); } + if (ir->data.mode == ir_var_uniform + && strncmp(ir->name, "gl_", 3) == 0 + && ir->get_state_slots() == NULL) { + printf("built-in uniform has no state\n"); + ir->print(); + abort(); + } + return visit_continue; } diff --git a/mesalib/src/glsl/link_functions.cpp b/mesalib/src/glsl/link_functions.cpp index d62c16853..537f4dc77 100644 --- a/mesalib/src/glsl/link_functions.cpp +++ b/mesalib/src/glsl/link_functions.cpp @@ -245,11 +245,19 @@ public: /* Similarly, we need implicit sizes of arrays within interface * blocks to be sized by the maximal access in *any* shader. */ + unsigned *const linked_max_ifc_array_access = + var->get_max_ifc_array_access(); + unsigned *const ir_max_ifc_array_access = + ir->var->get_max_ifc_array_access(); + + assert(linked_max_ifc_array_access != NULL); + assert(ir_max_ifc_array_access != NULL); + for (unsigned i = 0; i < var->get_interface_type()->length; i++) { - var->max_ifc_array_access[i] = - MAX2(var->max_ifc_array_access[i], - ir->var->max_ifc_array_access[i]); + linked_max_ifc_array_access[i] = + MAX2(linked_max_ifc_array_access[i], + ir_max_ifc_array_access[i]); } } } diff --git a/mesalib/src/glsl/link_uniforms.cpp b/mesalib/src/glsl/link_uniforms.cpp index 1d5b62d71..f613abc99 100644 --- a/mesalib/src/glsl/link_uniforms.cpp +++ b/mesalib/src/glsl/link_uniforms.cpp @@ -749,7 +749,7 @@ link_update_uniform_buffer_variables(struct gl_shader *shader) if (end == NULL) continue; - if (l != (end - begin)) + if ((ptrdiff_t) l != (end - begin)) continue; if (strncmp(var->name, begin, l) == 0) { @@ -771,40 +771,6 @@ link_update_uniform_buffer_variables(struct gl_shader *shader) } } -void -link_assign_uniform_block_offsets(struct gl_shader *shader) -{ - for (unsigned b = 0; b < shader->NumUniformBlocks; b++) { - struct gl_uniform_block *block = &shader->UniformBlocks[b]; - - unsigned offset = 0; - for (unsigned int i = 0; i < block->NumUniforms; i++) { - struct gl_uniform_buffer_variable *ubo_var = &block->Uniforms[i]; - const struct glsl_type *type = ubo_var->Type; - - unsigned alignment = type->std140_base_alignment(ubo_var->RowMajor); - unsigned size = type->std140_size(ubo_var->RowMajor); - - offset = glsl_align(offset, alignment); - ubo_var->Offset = offset; - offset += size; - } - - /* From the GL_ARB_uniform_buffer_object spec: - * - * "For uniform blocks laid out according to [std140] rules, - * the minimum buffer object size returned by the - * UNIFORM_BLOCK_DATA_SIZE query is derived by taking the - * offset of the last basic machine unit consumed by the - * last uniform of the uniform block (including any - * end-of-array or end-of-structure padding), adding one, - * and rounding up to the next multiple of the base - * alignment required for a vec4." - */ - block->UniformBufferSize = glsl_align(offset, 16); - } -} - /** * Scan the program for image uniforms and store image unit access * information into the gl_shader data structure. diff --git a/mesalib/src/glsl/link_varyings.cpp b/mesalib/src/glsl/link_varyings.cpp index 54ceae1b9..a738e2f38 100644 --- a/mesalib/src/glsl/link_varyings.cpp +++ b/mesalib/src/glsl/link_varyings.cpp @@ -318,6 +318,11 @@ tfeedback_decl::init(struct gl_context *ctx, const void *mem_ctx, const char *base_name_end; long subscript = parse_program_resource_name(input, &base_name_end); this->var_name = ralloc_strndup(mem_ctx, input, base_name_end - input); + if (this->var_name == NULL) { + _mesa_error_no_memory(__func__); + return; + } + if (subscript >= 0) { this->array_subscript = subscript; this->is_subscripted = true; diff --git a/mesalib/src/glsl/linker.cpp b/mesalib/src/glsl/linker.cpp index 7689198b0..47a722d9d 100644 --- a/mesalib/src/glsl/linker.cpp +++ b/mesalib/src/glsl/linker.cpp @@ -976,7 +976,8 @@ populate_symbol_table(gl_shader *sh) if ((func = inst->as_function()) != NULL) { sh->symbols->add_function(func); } else if ((var = inst->as_variable()) != NULL) { - sh->symbols->add_variable(var); + if (var->data.mode != ir_var_temporary) + sh->symbols->add_variable(var); } } } @@ -1173,7 +1174,8 @@ public: if (var->type->is_interface()) { if (interface_contains_unsized_arrays(var->type)) { const glsl_type *new_type = - resize_interface_members(var->type, var->max_ifc_array_access); + resize_interface_members(var->type, + var->get_max_ifc_array_access()); var->type = new_type; var->change_interface_type(new_type); } @@ -1182,7 +1184,7 @@ public: if (interface_contains_unsized_arrays(var->type->fields.array)) { const glsl_type *new_type = resize_interface_members(var->type->fields.array, - var->max_ifc_array_access); + var->get_max_ifc_array_access()); var->change_interface_type(new_type); var->type = glsl_type::get_array_instance(new_type, var->type->length); @@ -1714,12 +1716,19 @@ link_intrastage_shaders(void *mem_ctx, */ gl_shader **linking_shaders = (gl_shader **) calloc(num_shaders + 1, sizeof(gl_shader *)); - memcpy(linking_shaders, shader_list, num_shaders * sizeof(gl_shader *)); - linking_shaders[num_shaders] = _mesa_glsl_get_builtin_function_shader(); - ok = link_function_calls(prog, linked, linking_shaders, num_shaders + 1); + ok = linking_shaders != NULL; - free(linking_shaders); + if (ok) { + memcpy(linking_shaders, shader_list, num_shaders * sizeof(gl_shader *)); + linking_shaders[num_shaders] = _mesa_glsl_get_builtin_function_shader(); + + ok = link_function_calls(prog, linked, linking_shaders, num_shaders + 1); + + free(linking_shaders); + } else { + _mesa_error_no_memory(__func__); + } } else { ok = link_function_calls(prog, linked, shader_list, num_shaders); } @@ -1824,9 +1833,10 @@ update_array_sizes(struct gl_shader_program *prog) * Determine the number of slots per array element by dividing by * the old (total) size. */ - if (var->num_state_slots > 0) { - var->num_state_slots = (size + 1) - * (var->num_state_slots / var->type->length); + const unsigned num_slots = var->get_num_state_slots(); + if (num_slots > 0) { + var->set_num_state_slots((size + 1) + * (num_slots / var->type->length)); } var->type = glsl_type::get_array_instance(var->type->fields.array, @@ -2176,6 +2186,7 @@ demote_shader_inputs_and_outputs(gl_shader *sh, enum ir_variable_mode mode) * to have a location assigned. */ if (var->data.is_unmatched_generic_inout) { + assert(var->data.mode != ir_var_temporary); var->data.mode = ir_var_auto; } } diff --git a/mesalib/src/glsl/linker.h b/mesalib/src/glsl/linker.h index 9440794e2..6ee585898 100644 --- a/mesalib/src/glsl/linker.h +++ b/mesalib/src/glsl/linker.h @@ -50,9 +50,6 @@ link_cross_validate_uniform_block(void *mem_ctx, unsigned int *num_linked_blocks, struct gl_uniform_block *new_block); -void -link_assign_uniform_block_offsets(struct gl_shader *shader); - extern bool link_uniform_blocks_are_compatible(const gl_uniform_block *a, const gl_uniform_block *b); diff --git a/mesalib/src/glsl/lower_offset_array.cpp b/mesalib/src/glsl/lower_offset_array.cpp index 0c235eda3..5b48526db 100644 --- a/mesalib/src/glsl/lower_offset_array.cpp +++ b/mesalib/src/glsl/lower_offset_array.cpp @@ -63,7 +63,8 @@ brw_lower_offset_array_visitor::handle_rvalue(ir_rvalue **rv) void *mem_ctx = ralloc_parent(ir); - ir_variable *var = new (mem_ctx) ir_variable(ir->type, "result", ir_var_auto); + ir_variable *var = + new (mem_ctx) ir_variable(ir->type, "result", ir_var_temporary); base_ir->insert_before(var); for (int i = 0; i < 4; i++) { diff --git a/mesalib/src/glsl/lower_packed_varyings.cpp b/mesalib/src/glsl/lower_packed_varyings.cpp index 780148315..5e844c792 100644 --- a/mesalib/src/glsl/lower_packed_varyings.cpp +++ b/mesalib/src/glsl/lower_packed_varyings.cpp @@ -261,6 +261,7 @@ lower_packed_varyings_visitor::run(exec_list *instructions) !var->type->contains_integer()); /* Change the old varying into an ordinary global. */ + assert(var->data.mode != ir_var_temporary); var->data.mode = ir_var_auto; /* Create a reference to the old varying. */ diff --git a/mesalib/src/glsl/lower_texture_projection.cpp b/mesalib/src/glsl/lower_texture_projection.cpp index 16d637680..95df106d9 100644 --- a/mesalib/src/glsl/lower_texture_projection.cpp +++ b/mesalib/src/glsl/lower_texture_projection.cpp @@ -62,7 +62,7 @@ lower_texture_projection_visitor::visit_leave(ir_texture *ir) void *mem_ctx = ralloc_parent(ir); ir_variable *var = new(mem_ctx) ir_variable(ir->projector->type, - "projector", ir_var_auto); + "projector", ir_var_temporary); base_ir->insert_before(var); ir_dereference *deref = new(mem_ctx) ir_dereference_variable(var); ir_expression *expr = new(mem_ctx) ir_expression(ir_unop_rcp, diff --git a/mesalib/src/glsl/lower_ubo_reference.cpp b/mesalib/src/glsl/lower_ubo_reference.cpp index 3cdfc04ac..43dd067fa 100644 --- a/mesalib/src/glsl/lower_ubo_reference.cpp +++ b/mesalib/src/glsl/lower_ubo_reference.cpp @@ -111,7 +111,7 @@ is_dereferenced_thing_row_major(const ir_dereference *deref) case GLSL_MATRIX_LAYOUT_COLUMN_MAJOR: return false; case GLSL_MATRIX_LAYOUT_ROW_MAJOR: - return matrix || deref->type->is_record(); + return matrix || deref->type->without_array()->is_record(); } unreachable("invalid matrix layout"); @@ -301,7 +301,14 @@ lower_ubo_reference_visitor::handle_rvalue(ir_rvalue **rvalue) deref = deref_array->array->as_dereference(); break; } else { - array_stride = deref_array->type->std140_size(row_major); + /* Whether or not the field is row-major (because it might be a + * bvec2 or something) does not affect the array itself. We need + * to know whether an array element in its entirety is row-major. + */ + const bool array_row_major = + is_dereferenced_thing_row_major(deref_array); + + array_stride = deref_array->type->std140_size(array_row_major); array_stride = glsl_align(array_stride, 16); } @@ -327,6 +334,15 @@ lower_ubo_reference_visitor::handle_rvalue(ir_rvalue **rvalue) const glsl_type *struct_type = deref_record->record->type; unsigned intra_struct_offset = 0; + /* glsl_type::std140_base_alignment doesn't grok interfaces. Use + * 16-bytes for the alignment because that is the general minimum of + * std140. + */ + const unsigned struct_alignment = struct_type->is_interface() + ? 16 + : struct_type->std140_base_alignment(row_major); + + for (unsigned int i = 0; i < struct_type->length; i++) { const glsl_type *type = struct_type->fields.structure[i].type; @@ -346,6 +362,19 @@ lower_ubo_reference_visitor::handle_rvalue(ir_rvalue **rvalue) deref_record->field) == 0) break; intra_struct_offset += type->std140_size(field_row_major); + + /* If the field just examined was itself a structure, apply rule + * #9: + * + * "The structure may have padding at the end; the base offset + * of the member following the sub-structure is rounded up to + * the next multiple of the base alignment of the structure." + */ + if (type->without_array()->is_record()) { + intra_struct_offset = glsl_align(intra_struct_offset, + struct_alignment); + + } } const_offset += intra_struct_offset; diff --git a/mesalib/src/glsl/main.cpp b/mesalib/src/glsl/main.cpp index 6c229465c..afc458b44 100644 --- a/mesalib/src/glsl/main.cpp +++ b/mesalib/src/glsl/main.cpp @@ -221,6 +221,7 @@ initialize_context(struct gl_context *ctx, gl_api api) break; } + ctx->Const.GenerateTemporaryNames = true; ctx->Driver.NewShader = _mesa_new_shader; } diff --git a/mesalib/src/glsl/opt_algebraic.cpp b/mesalib/src/glsl/opt_algebraic.cpp index 447618f9e..0cdb8ecfc 100644 --- a/mesalib/src/glsl/opt_algebraic.cpp +++ b/mesalib/src/glsl/opt_algebraic.cpp @@ -357,6 +357,20 @@ ir_algebraic_visitor::handle_expression(ir_expression *ir) if (op_expr[0]->operation == ir_unop_log2) { return op_expr[0]->operands[0]; } + + if (!options->EmitNoPow && op_expr[0]->operation == ir_binop_mul) { + for (int log2_pos = 0; log2_pos < 2; log2_pos++) { + ir_expression *log2_expr = + op_expr[0]->operands[log2_pos]->as_expression(); + + if (log2_expr && log2_expr->operation == ir_unop_log2) { + return new(mem_ctx) ir_expression(ir_binop_pow, + ir->type, + log2_expr->operands[0], + op_expr[0]->operands[1 - log2_pos]); + } + } + } break; case ir_unop_log2: diff --git a/mesalib/src/glsl/opt_cse.cpp b/mesalib/src/glsl/opt_cse.cpp index 0e720cc26..9c96835dd 100644 --- a/mesalib/src/glsl/opt_cse.cpp +++ b/mesalib/src/glsl/opt_cse.cpp @@ -276,7 +276,7 @@ cse_visitor::try_cse(ir_rvalue *rvalue) ir_variable *var = new(rvalue) ir_variable(rvalue->type, "cse", - ir_var_auto); + ir_var_temporary); /* Write the previous expression result into a new variable. */ base_ir->insert_before(var); diff --git a/mesalib/src/glsl/opt_dead_builtin_variables.cpp b/mesalib/src/glsl/opt_dead_builtin_variables.cpp new file mode 100644 index 000000000..85c75d6f2 --- /dev/null +++ b/mesalib/src/glsl/opt_dead_builtin_variables.cpp @@ -0,0 +1,81 @@ +/* + * Copyright © 2014 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "ir.h" +#include "ir_visitor.h" +#include "ir_optimization.h" + +/** + * Pre-linking, optimize unused built-in variables + * + * Uniforms, constants, system values, inputs (vertex shader only), and + * outputs (fragment shader only) that are not used can be removed. + */ +void +optimize_dead_builtin_variables(exec_list *instructions, + enum ir_variable_mode other) +{ + foreach_in_list_safe(ir_variable, var, instructions) { + if (var->ir_type != ir_type_variable || var->data.used) + continue; + + if (var->data.mode != ir_var_uniform + && var->data.mode != ir_var_auto + && var->data.mode != ir_var_system_value + && var->data.mode != other) + continue; + + /* So that linker rules can later be enforced, we cannot elimate + * variables that were redeclared in the shader code. + */ + if ((var->data.mode == other || var->data.mode == ir_var_system_value) + && var->data.how_declared != ir_var_declared_implicitly) + continue; + + if (strncmp(var->name, "gl_", 3) != 0) + continue; + + /* gl_ModelViewProjectionMatrix and gl_Vertex are special because they + * are used by ftransform. No other built-in variable is used by a + * built-in function. The forward declarations of these variables in + * the built-in function shader does not have the "state slot" + * information, so removing these variables from the user shader will + * cause problems later. + * + * Matrix uniforms with "Transpose" are not eliminated because there's + * an optimization pass that can turn references to the regular matrix + * into references to the transpose matrix. Eliminating the transpose + * matrix would cause that pass to generate references to undeclareds + * variables (thank you, ir_validate). + * + * It doesn't seem worth the effort to track when the transpose could be + * eliminated (i.e., when the non-transpose was eliminated). + */ + if (strcmp(var->name, "gl_ModelViewProjectionMatrix") == 0 + || strcmp(var->name, "gl_Vertex") == 0 + || strstr(var->name, "Transpose") != NULL) + continue; + + var->remove(); + } +} diff --git a/mesalib/src/glsl/test_optpass.cpp b/mesalib/src/glsl/test_optpass.cpp index 24c06f11b..ac3e3f48c 100644 --- a/mesalib/src/glsl/test_optpass.cpp +++ b/mesalib/src/glsl/test_optpass.cpp @@ -200,6 +200,7 @@ int test_optpass(int argc, char **argv) initialize_context_to_defaults(ctx, API_OPENGL_COMPAT); ctx->Driver.NewShader = _mesa_new_shader; + ir_variable::temporaries_allocate_names = true; struct gl_shader *shader = rzalloc(NULL, struct gl_shader); shader->Type = shader_type; |