X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fcompiler%2Fglsl%2Fast_function.cpp;h=08a200347af947c7bed1cfeccae4431bffb0817a;hb=8471f7a5fa1d5c00de9f314eaccd23dd0e62e71b;hp=94e0a16a9c0ef1a3680315e4ca946805345ea309;hpb=f09c2cefdd53cd61562a994294e9d0630868d2da;p=mesa.git diff --git a/src/compiler/glsl/ast_function.cpp b/src/compiler/glsl/ast_function.cpp index 94e0a16a9c0..08a200347af 100644 --- a/src/compiler/glsl/ast_function.cpp +++ b/src/compiler/glsl/ast_function.cpp @@ -25,7 +25,7 @@ #include "ast.h" #include "compiler/glsl_types.h" #include "ir.h" -#include "main/core.h" /* for MIN2 */ +#include "main/mtypes.h" #include "main/shaderobj.h" #include "builtin_functions.h" @@ -49,6 +49,10 @@ process_parameters(exec_list *instructions, exec_list *actual_parameters, ast->set_is_lhs(true); ir_rvalue *result = ast->hir(instructions, state); + /* Error happened, bail out. */ + if (state->error) + return 0; + ir_constant *const constant = result->constant_expression_value(mem_ctx); @@ -348,6 +352,47 @@ verify_parameter_modes(_mesa_glsl_parse_state *state, return true; } +struct copy_index_deref_data { + void *mem_ctx; + exec_list *before_instructions; +}; + +static void +copy_index_derefs_to_temps(ir_instruction *ir, void *data) +{ + struct copy_index_deref_data *d = (struct copy_index_deref_data *)data; + + if (ir->ir_type == ir_type_dereference_array) { + ir_dereference_array *a = (ir_dereference_array *) ir; + ir = a->array->as_dereference(); + + ir_rvalue *idx = a->array_index; + ir_variable *var = idx->variable_referenced(); + + /* If the index is read only it cannot change so there is no need + * to copy it. + */ + if (!var || var->data.read_only || var->data.memory_read_only) + return; + + ir_variable *tmp = new(d->mem_ctx) ir_variable(idx->type, "idx_tmp", + ir_var_temporary); + d->before_instructions->push_tail(tmp); + + ir_dereference_variable *const deref_tmp_1 = + new(d->mem_ctx) ir_dereference_variable(tmp); + ir_assignment *const assignment = + new(d->mem_ctx) ir_assignment(deref_tmp_1, + idx->clone(d->mem_ctx, NULL)); + d->before_instructions->push_tail(assignment); + + /* Replace the array index with a dereference of the new temporary */ + ir_dereference_variable *const deref_tmp_2 = + new(d->mem_ctx) ir_dereference_variable(tmp); + a->array_index = deref_tmp_2; + } +} + static void fix_parameter(void *mem_ctx, ir_rvalue *actual, const glsl_type *formal_type, exec_list *before_instructions, exec_list *after_instructions, @@ -359,9 +404,21 @@ fix_parameter(void *mem_ctx, ir_rvalue *actual, const glsl_type *formal_type, * nothing needs to be done to fix the parameter. */ if (formal_type == actual->type - && (expr == NULL || expr->operation != ir_binop_vector_extract)) + && (expr == NULL || expr->operation != ir_binop_vector_extract) + && actual->as_dereference_variable()) return; + /* An array index could also be an out variable so we need to make a copy + * of them before the function is called. + */ + if (!actual->as_dereference_variable()) { + struct copy_index_deref_data data; + data.mem_ctx = mem_ctx; + data.before_instructions = before_instructions; + + visit_tree(actual, copy_index_derefs_to_temps, &data); + } + /* To convert an out parameter, we need to create a temporary variable to * hold the value before conversion, and then perform the conversion after * the function call returns. @@ -402,7 +459,7 @@ fix_parameter(void *mem_ctx, ir_rvalue *actual, const glsl_type *formal_type, ir_dereference_variable *const deref_tmp_1 = new(mem_ctx) ir_dereference_variable(tmp); ir_assignment *const assignment = - new(mem_ctx) ir_assignment(deref_tmp_1, actual); + new(mem_ctx) ir_assignment(deref_tmp_1, actual->clone(mem_ctx, NULL)); before_instructions->push_tail(assignment); } @@ -529,7 +586,8 @@ generate_call(exec_list *instructions, ir_function_signature *sig, * If the function call is a constant expression, don't generate any * instructions; just generate an ir_constant. */ - if (state->is_version(120, 100)) { + if (state->is_version(120, 100) || + state->ctx->Const.AllowGLSLBuiltinConstantExpression) { ir_constant *value = sig->constant_expression_value(ctx, actual_parameters, NULL); @@ -558,11 +616,6 @@ generate_call(exec_list *instructions, ir_function_signature *sig, ir_call *call = new(ctx) ir_call(sig, deref, actual_parameters, sub_var, array_idx); instructions->push_tail(call); - if (sig->is_builtin()) { - /* inline immediately */ - call->generate_inline(call); - call->remove(); - } /* Also emit any necessary out-parameter conversions. */ instructions->append_list(&post_call_conversions); @@ -610,9 +663,13 @@ match_function_by_name(const char *name, } /* Local shader has no exact candidates; check the built-ins. */ - _mesa_glsl_initialize_builtin_functions(); sig = _mesa_glsl_find_builtin_function(state, name, actual_parameters); - return sig; + + /* if _mesa_glsl_find_builtin_function failed, fall back to the result + * of choose_best_inexact_overload() instead. This should only affect + * GLES. + */ + return sig ? sig : local_sig; } static ir_function_signature * @@ -689,6 +746,21 @@ generate_array_index(void *mem_ctx, exec_list *instructions, } } +static bool +function_exists(_mesa_glsl_parse_state *state, + struct glsl_symbol_table *symbols, const char *name) +{ + ir_function *f = symbols->get_function(name); + if (f != NULL) { + foreach_in_list(ir_function_signature, sig, &f->signatures) { + if (sig->is_builtin() && !sig->is_builtin_available(state)) + continue; + return true; + } + } + return false; +} + static void print_function_prototypes(_mesa_glsl_parse_state *state, YYLTYPE *loc, ir_function *f) @@ -719,9 +791,9 @@ no_matching_function_error(const char *name, { gl_shader *sh = _mesa_glsl_get_builtin_function_shader(); - if (state->symbols->get_function(name) == NULL + if (!function_exists(state, state->symbols, name) && (!state->uses_builtin_functions - || sh->symbols->get_function(name) == NULL)) { + || !function_exists(state, sh->symbols, name))) { _mesa_glsl_error(loc, state, "no function with name '%s'", name); } else { char *str = prototype_string(NULL, name, actual_parameters); @@ -2059,7 +2131,7 @@ ast_function_expression::hir(exec_list *instructions, * must have the exact number of arguments with matching types in the * correct order. */ - if (constructor_type->is_record()) { + if (constructor_type->is_struct()) { return process_record_constructor(instructions, constructor_type, &loc, &this->expressions, state); @@ -2328,25 +2400,53 @@ ast_function_expression::hir(exec_list *instructions, new(ctx) ir_dereference_variable(mvp), new(ctx) ir_dereference_variable(vtx)); } else { - if (state->stage == MESA_SHADER_TESS_CTRL && - sig->is_builtin() && strcmp(func_name, "barrier") == 0) { + bool is_begin_interlock = false; + bool is_end_interlock = false; + if (sig->is_builtin() && + state->stage == MESA_SHADER_FRAGMENT && + state->ARB_fragment_shader_interlock_enable) { + is_begin_interlock = strcmp(func_name, "beginInvocationInterlockARB") == 0; + is_end_interlock = strcmp(func_name, "endInvocationInterlockARB") == 0; + } + + if (sig->is_builtin() && + ((state->stage == MESA_SHADER_TESS_CTRL && + strcmp(func_name, "barrier") == 0) || + is_begin_interlock || is_end_interlock)) { if (state->current_function == NULL || strcmp(state->current_function->function_name(), "main") != 0) { _mesa_glsl_error(&loc, state, - "barrier() may only be used in main()"); + "%s() may only be used in main()", func_name); } if (state->found_return) { _mesa_glsl_error(&loc, state, - "barrier() may not be used after return"); + "%s() may not be used after return", func_name); } if (instructions != &state->current_function->body) { _mesa_glsl_error(&loc, state, - "barrier() may not be used in control flow"); + "%s() may not be used in control flow", func_name); } } + /* There can be only one begin/end interlock pair in the function. */ + if (is_begin_interlock) { + if (state->found_begin_interlock) + _mesa_glsl_error(&loc, state, + "beginInvocationInterlockARB may not be used twice"); + state->found_begin_interlock = true; + } else if (is_end_interlock) { + if (!state->found_begin_interlock) + _mesa_glsl_error(&loc, state, + "endInvocationInterlockARB may not be used " + "before beginInvocationInterlockARB"); + if (state->found_end_interlock) + _mesa_glsl_error(&loc, state, + "endInvocationInterlockARB may not be used twice"); + state->found_end_interlock = true; + } + value = generate_call(instructions, sig, &actual_parameters, sub_var, array_idx, state); if (!value) { @@ -2399,7 +2499,7 @@ ast_aggregate_initializer::hir(exec_list *instructions, &this->expressions, state); } - if (constructor_type->is_record()) { + if (constructor_type->is_struct()) { return process_record_constructor(instructions, constructor_type, &loc, &this->expressions, state); }