diff --git a/src/compiler/glsl/builtin_functions.cpp b/src/compiler/glsl/builtin_functions.cpp index e07ac611718..4d1f67fcb05 100644 --- a/src/compiler/glsl/builtin_functions.cpp +++ b/src/compiler/glsl/builtin_functions.cpp @@ -1017,7 +1017,11 @@ private: * member available. */ ir_variable *in_var(const glsl_type *type, const char *name); + ir_variable *in_mediump_var(const glsl_type *type, const char *name); + ir_variable *in_highp_var(const glsl_type *type, const char *name); ir_variable *out_var(const glsl_type *type, const char *name); + ir_variable *out_lowp_var(const glsl_type *type, const char *name); + ir_variable *out_highp_var(const glsl_type *type, const char *name); ir_constant *imm(float f, unsigned vector_elements=1); ir_constant *imm(bool b, unsigned vector_elements=1); ir_constant *imm(int i, unsigned vector_elements=1); @@ -1079,6 +1083,10 @@ private: ir_expression_operation opcode, const glsl_type *return_type, const glsl_type *param_type); + ir_function_signature *unop_precision(builtin_available_predicate avail, + ir_expression_operation opcode, + const glsl_type *return_type, + const glsl_type *param_type, uint32_t precision); ir_function_signature *binop(builtin_available_predicate avail, ir_expression_operation opcode, const glsl_type *return_type, @@ -5650,12 +5658,44 @@ builtin_builder::in_var(const glsl_type *type, const char *name) return new(mem_ctx) ir_variable(type, name, ir_var_function_in); } +ir_variable * +builtin_builder::in_highp_var(const glsl_type *type, const char *name) +{ + ir_variable *var = in_var(type, name); + var->data.precision = GLSL_PRECISION_HIGH; + return var; +} + +ir_variable * +builtin_builder::in_mediump_var(const glsl_type *type, const char *name) +{ + ir_variable *var = in_var(type, name); + var->data.precision = GLSL_PRECISION_MEDIUM; + return var; +} + ir_variable * builtin_builder::out_var(const glsl_type *type, const char *name) { return new(mem_ctx) ir_variable(type, name, ir_var_function_out); } +ir_variable * +builtin_builder::out_lowp_var(const glsl_type *type, const char *name) +{ + ir_variable *var = out_var(type, name); + var->data.precision = GLSL_PRECISION_LOW; + return var; +} + +ir_variable * +builtin_builder::out_highp_var(const glsl_type *type, const char *name) +{ + ir_variable *var = out_var(type, name); + var->data.precision = GLSL_PRECISION_HIGH; + return var; +} + ir_constant * builtin_builder::imm(bool b, unsigned vector_elements) { @@ -6290,8 +6330,9 @@ builtin_builder::_uint64BitsToDouble(builtin_available_predicate avail, const gl ir_function_signature * builtin_builder::_packUnorm2x16(builtin_available_predicate avail) { - ir_variable *v = in_var(glsl_type::vec2_type, "v"); + ir_variable *v = in_highp_var(glsl_type::vec2_type, "v"); MAKE_SIG(glsl_type::uint_type, avail, 1, v); + sig->return_precision = GLSL_PRECISION_HIGH; body.emit(ret(expr(ir_unop_pack_unorm_2x16, v))); return sig; } @@ -6301,6 +6342,7 @@ builtin_builder::_packSnorm2x16(builtin_available_predicate avail) { ir_variable *v = in_var(glsl_type::vec2_type, "v"); MAKE_SIG(glsl_type::uint_type, avail, 1, v); + sig->return_precision = GLSL_PRECISION_HIGH; body.emit(ret(expr(ir_unop_pack_snorm_2x16, v))); return sig; } @@ -6308,8 +6350,9 @@ builtin_builder::_packSnorm2x16(builtin_available_predicate avail) ir_function_signature * builtin_builder::_packUnorm4x8(builtin_available_predicate avail) { - ir_variable *v = in_var(glsl_type::vec4_type, "v"); + ir_variable *v = in_mediump_var(glsl_type::vec4_type, "v"); MAKE_SIG(glsl_type::uint_type, avail, 1, v); + sig->return_precision = GLSL_PRECISION_HIGH; body.emit(ret(expr(ir_unop_pack_unorm_4x8, v))); return sig; } @@ -6317,8 +6360,9 @@ builtin_builder::_packUnorm4x8(builtin_available_predicate avail) ir_function_signature * builtin_builder::_packSnorm4x8(builtin_available_predicate avail) { - ir_variable *v = in_var(glsl_type::vec4_type, "v"); + ir_variable *v = in_mediump_var(glsl_type::vec4_type, "v"); MAKE_SIG(glsl_type::uint_type, avail, 1, v); + sig->return_precision = GLSL_PRECISION_HIGH; body.emit(ret(expr(ir_unop_pack_snorm_4x8, v))); return sig; } @@ -6326,8 +6370,9 @@ builtin_builder::_packSnorm4x8(builtin_available_predicate avail) ir_function_signature * builtin_builder::_unpackUnorm2x16(builtin_available_predicate avail) { - ir_variable *p = in_var(glsl_type::uint_type, "p"); + ir_variable *p = in_highp_var(glsl_type::uint_type, "p"); MAKE_SIG(glsl_type::vec2_type, avail, 1, p); + sig->return_precision = GLSL_PRECISION_HIGH; body.emit(ret(expr(ir_unop_unpack_unorm_2x16, p))); return sig; } @@ -6335,8 +6380,9 @@ builtin_builder::_unpackUnorm2x16(builtin_available_predicate avail) ir_function_signature * builtin_builder::_unpackSnorm2x16(builtin_available_predicate avail) { - ir_variable *p = in_var(glsl_type::uint_type, "p"); + ir_variable *p = in_highp_var(glsl_type::uint_type, "p"); MAKE_SIG(glsl_type::vec2_type, avail, 1, p); + sig->return_precision = GLSL_PRECISION_HIGH; body.emit(ret(expr(ir_unop_unpack_snorm_2x16, p))); return sig; } @@ -6345,8 +6391,9 @@ builtin_builder::_unpackSnorm2x16(builtin_available_predicate avail) ir_function_signature * builtin_builder::_unpackUnorm4x8(builtin_available_predicate avail) { - ir_variable *p = in_var(glsl_type::uint_type, "p"); + ir_variable *p = in_highp_var(glsl_type::uint_type, "p"); MAKE_SIG(glsl_type::vec4_type, avail, 1, p); + sig->return_precision = GLSL_PRECISION_MEDIUM; body.emit(ret(expr(ir_unop_unpack_unorm_4x8, p))); return sig; } @@ -6354,8 +6401,9 @@ builtin_builder::_unpackUnorm4x8(builtin_available_predicate avail) ir_function_signature * builtin_builder::_unpackSnorm4x8(builtin_available_predicate avail) { - ir_variable *p = in_var(glsl_type::uint_type, "p"); + ir_variable *p = in_highp_var(glsl_type::uint_type, "p"); MAKE_SIG(glsl_type::vec4_type, avail, 1, p); + sig->return_precision = GLSL_PRECISION_MEDIUM; body.emit(ret(expr(ir_unop_unpack_snorm_4x8, p))); return sig; } @@ -6363,8 +6411,9 @@ builtin_builder::_unpackSnorm4x8(builtin_available_predicate avail) ir_function_signature * builtin_builder::_packHalf2x16(builtin_available_predicate avail) { - ir_variable *v = in_var(glsl_type::vec2_type, "v"); + ir_variable *v = in_mediump_var(glsl_type::vec2_type, "v"); MAKE_SIG(glsl_type::uint_type, avail, 1, v); + sig->return_precision = GLSL_PRECISION_HIGH; body.emit(ret(expr(ir_unop_pack_half_2x16, v))); return sig; } @@ -6372,8 +6421,9 @@ builtin_builder::_packHalf2x16(builtin_available_predicate avail) ir_function_signature * builtin_builder::_unpackHalf2x16(builtin_available_predicate avail) { - ir_variable *p = in_var(glsl_type::uint_type, "p"); + ir_variable *p = in_highp_var(glsl_type::uint_type, "p"); MAKE_SIG(glsl_type::vec2_type, avail, 1, p); + sig->return_precision = GLSL_PRECISION_MEDIUM; body.emit(ret(expr(ir_unop_unpack_half_2x16, p))); return sig; } @@ -7072,6 +7122,7 @@ builtin_builder::_textureSize(builtin_available_predicate avail, ir_variable *s = in_var(sampler_type, "sampler"); /* The sampler always exists; add optional lod later. */ MAKE_SIG(return_type, avail, 1, s); + sig->return_precision = GLSL_PRECISION_HIGH; ir_texture *tex = new(mem_ctx) ir_texture(ir_txs); tex->set_sampler(new(mem_ctx) ir_dereference_variable(s), return_type); @@ -7621,27 +7672,44 @@ builtin_builder::_bitfieldInsert(const glsl_type *type) return sig; } -UNOP(bitfieldReverse, ir_unop_bitfield_reverse, gpu_shader5_or_es31_or_integer_functions) +ir_function_signature * +builtin_builder::_bitfieldReverse(const glsl_type *type) +{ + ir_variable *x = in_highp_var(type, "x"); + MAKE_SIG(type, gpu_shader5_or_es31_or_integer_functions, 1, x); + sig->return_precision = GLSL_PRECISION_HIGH; + body.emit(ret(expr(ir_unop_bitfield_reverse, x))); + return sig; +} ir_function_signature * builtin_builder::_bitCount(const glsl_type *type) { - return unop(gpu_shader5_or_es31_or_integer_functions, ir_unop_bit_count, - glsl_type::ivec(type->vector_elements), type); + ir_variable *x = in_var(type, "x"); + MAKE_SIG(glsl_type::ivec(type->vector_elements), gpu_shader5_or_es31_or_integer_functions, 1, x); + sig->return_precision = GLSL_PRECISION_LOW; + body.emit(ret(expr(ir_unop_bit_count, x))); + return sig; } ir_function_signature * builtin_builder::_findLSB(const glsl_type *type) { - return unop(gpu_shader5_or_es31_or_integer_functions, ir_unop_find_lsb, - glsl_type::ivec(type->vector_elements), type); + ir_variable *x = in_highp_var(type, "x"); + MAKE_SIG(glsl_type::ivec(type->vector_elements), gpu_shader5_or_es31_or_integer_functions, 1, x); + sig->return_precision = GLSL_PRECISION_LOW; + body.emit(ret(expr(ir_unop_find_lsb, x))); + return sig; } ir_function_signature * builtin_builder::_findMSB(const glsl_type *type) { - return unop(gpu_shader5_or_es31_or_integer_functions, ir_unop_find_msb, - glsl_type::ivec(type->vector_elements), type); + ir_variable *x = in_highp_var(type, "x"); + MAKE_SIG(glsl_type::ivec(type->vector_elements), gpu_shader5_or_es31_or_integer_functions, 1, x); + sig->return_precision = GLSL_PRECISION_LOW; + body.emit(ret(expr(ir_unop_find_msb, x))); + return sig; } ir_function_signature * @@ -7682,14 +7750,18 @@ builtin_builder::_fma(builtin_available_predicate avail, const glsl_type *type) ir_function_signature * builtin_builder::_ldexp(const glsl_type *x_type, const glsl_type *exp_type) { - return binop(x_type->is_double() ? fp64 : gpu_shader5_or_es31_or_integer_functions, - ir_binop_ldexp, x_type, x_type, exp_type); + ir_variable *x = in_highp_var(x_type, "x"); + ir_variable *y = in_highp_var(exp_type, "y"); + MAKE_SIG(x_type, x_type->is_double() ? fp64 : gpu_shader5_or_es31_or_integer_functions, 2, x, y); + sig->return_precision = GLSL_PRECISION_HIGH; + body.emit(ret(expr(ir_binop_ldexp, x, y))); + return sig; } ir_function_signature * builtin_builder::_dfrexp(const glsl_type *x_type, const glsl_type *exp_type) { - ir_variable *x = in_var(x_type, "x"); + ir_variable *x = in_highp_var(x_type, "x"); ir_variable *exponent = out_var(exp_type, "exp"); MAKE_SIG(x_type, fp64, 2, x, exponent); @@ -7702,9 +7774,10 @@ builtin_builder::_dfrexp(const glsl_type *x_type, const glsl_type *exp_type) ir_function_signature * builtin_builder::_frexp(const glsl_type *x_type, const glsl_type *exp_type) { - ir_variable *x = in_var(x_type, "x"); - ir_variable *exponent = out_var(exp_type, "exp"); + ir_variable *x = in_highp_var(x_type, "x"); + ir_variable *exponent = out_highp_var(exp_type, "exp"); MAKE_SIG(x_type, gpu_shader5_or_es31_or_integer_functions, 2, x, exponent); + sig->return_precision = GLSL_PRECISION_HIGH; const unsigned vec_elem = x_type->vector_elements; const glsl_type *bvec = glsl_type::get_instance(GLSL_TYPE_BOOL, vec_elem, 1); @@ -7750,10 +7823,11 @@ builtin_builder::_frexp(const glsl_type *x_type, const glsl_type *exp_type) ir_function_signature * builtin_builder::_uaddCarry(const glsl_type *type) { - ir_variable *x = in_var(type, "x"); - ir_variable *y = in_var(type, "y"); - ir_variable *carry = out_var(type, "carry"); + ir_variable *x = in_highp_var(type, "x"); + ir_variable *y = in_highp_var(type, "y"); + ir_variable *carry = out_lowp_var(type, "carry"); MAKE_SIG(type, gpu_shader5_or_es31_or_integer_functions, 3, x, y, carry); + sig->return_precision = GLSL_PRECISION_HIGH; body.emit(assign(carry, ir_builder::carry(x, y))); body.emit(ret(add(x, y))); @@ -7771,10 +7845,11 @@ builtin_builder::_addSaturate(builtin_available_predicate avail, ir_function_signature * builtin_builder::_usubBorrow(const glsl_type *type) { - ir_variable *x = in_var(type, "x"); - ir_variable *y = in_var(type, "y"); - ir_variable *borrow = out_var(type, "borrow"); + ir_variable *x = in_highp_var(type, "x"); + ir_variable *y = in_highp_var(type, "y"); + ir_variable *borrow = out_lowp_var(type, "borrow"); MAKE_SIG(type, gpu_shader5_or_es31_or_integer_functions, 3, x, y, borrow); + sig->return_precision = GLSL_PRECISION_HIGH; body.emit(assign(borrow, ir_builder::borrow(x, y))); body.emit(ret(sub(x, y))); @@ -7835,10 +7910,10 @@ builtin_builder::_mulExtended(const glsl_type *type) unpack_type = glsl_type::uvec2_type; } - ir_variable *x = in_var(type, "x"); - ir_variable *y = in_var(type, "y"); - ir_variable *msb = out_var(type, "msb"); - ir_variable *lsb = out_var(type, "lsb"); + ir_variable *x = in_highp_var(type, "x"); + ir_variable *y = in_highp_var(type, "y"); + ir_variable *msb = out_highp_var(type, "msb"); + ir_variable *lsb = out_highp_var(type, "lsb"); MAKE_SIG(glsl_type::void_type, gpu_shader5_or_es31_or_integer_functions, 4, x, y, msb, lsb); ir_variable *unpack_val = body.make_temp(unpack_type, "_unpack_val"); @@ -8303,6 +8378,10 @@ builtin_builder::_image(image_prototype_ctr prototype, } else { ir_variable *ret_val = body.make_temp(sig->return_type, "_ret_val"); + /* all non-void image functions return highp, so make our temporary and return + * value in the signature highp. + */ + ret_val->data.precision = GLSL_PRECISION_HIGH; body.emit(call(f, ret_val, sig->parameters)); body.emit(ret(ret_val)); } @@ -8312,6 +8391,7 @@ builtin_builder::_image(image_prototype_ctr prototype, } else { sig->intrinsic_id = id; } + sig->return_precision = GLSL_PRECISION_HIGH; return sig; } diff --git a/src/compiler/glsl/lower_precision.cpp b/src/compiler/glsl/lower_precision.cpp index 2b01b9a86c2..1912270297d 100644 --- a/src/compiler/glsl/lower_precision.cpp +++ b/src/compiler/glsl/lower_precision.cpp @@ -431,7 +431,7 @@ handle_call(ir_call *ir, const struct set *lowerable_rvalues) ir_rvalue *param = (ir_rvalue*)ir->actual_parameters.get_head(); ir_variable *resource = param->variable_referenced(); - assert(ir->callee->return_precision == GLSL_PRECISION_NONE); + assert(ir->callee->return_precision == GLSL_PRECISION_HIGH); assert(resource->type->without_array()->is_image()); /* GLSL ES 3.20 requires that images have a precision modifier, but if @@ -460,7 +460,7 @@ handle_call(ir_call *ir, const struct set *lowerable_rvalues) } /* Return the declared precision for user-defined functions. */ - if (!ir->callee->is_builtin()) + if (!ir->callee->is_builtin() || ir->callee->return_precision != GLSL_PRECISION_NONE) return ir->callee->return_precision; /* Handle special calls. */ @@ -476,10 +476,6 @@ handle_call(ir_call *ir, const struct set *lowerable_rvalues) * uses lower precision. The function parameters don't matter. */ if (var && var->type->without_array()->is_sampler()) { - /* textureSize always returns highp. */ - if (!strcmp(ir->callee_name(), "textureSize")) - return GLSL_PRECISION_HIGH; - /* textureGatherOffsets always takes a highp array of constants. As * per the discussion https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/16547#note_1393704 * trying to lower the precision results in segfault later on @@ -493,40 +489,18 @@ handle_call(ir_call *ir, const struct set *lowerable_rvalues) } } - if (/* Parameters are always highp: */ + if (ir->callee->return_precision != GLSL_PRECISION_NONE) + return ir->callee->return_precision; + + if (/* Parameters are always implicitly promoted to highp: */ !strcmp(ir->callee_name(), "floatBitsToInt") || !strcmp(ir->callee_name(), "floatBitsToUint") || !strcmp(ir->callee_name(), "intBitsToFloat") || !strcmp(ir->callee_name(), "uintBitsToFloat") || - !strcmp(ir->callee_name(), "bitfieldReverse") || - !strcmp(ir->callee_name(), "frexp") || - !strcmp(ir->callee_name(), "ldexp") || - /* Parameters and outputs are always highp: */ - /* TODO: The operations are highp, but carry and borrow outputs are lowp. */ - !strcmp(ir->callee_name(), "uaddCarry") || - !strcmp(ir->callee_name(), "usubBorrow") || - !strcmp(ir->callee_name(), "imulExtended") || - !strcmp(ir->callee_name(), "umulExtended") || - !strcmp(ir->callee_name(), "unpackUnorm2x16") || - !strcmp(ir->callee_name(), "unpackSnorm2x16") || - /* Outputs are highp: */ - !strcmp(ir->callee_name(), "packUnorm2x16") || - !strcmp(ir->callee_name(), "packSnorm2x16") || - /* Parameters are mediump and outputs are highp. The parameters should - * be optimized in NIR, not here, e.g: - * - packHalf2x16 can just be a bitcast from f16vec2 to uint32 - * - Other opcodes don't have to convert parameters to highp if the hw - * has f16 versions. Optimize in NIR accordingly. - */ - !strcmp(ir->callee_name(), "packHalf2x16") || - !strcmp(ir->callee_name(), "packUnorm4x8") || - !strcmp(ir->callee_name(), "packSnorm4x8") || /* Atomic functions are not lowered. */ strstr(ir->callee_name(), "atomic") == ir->callee_name()) return GLSL_PRECISION_HIGH; - assert(ir->callee->return_precision == GLSL_PRECISION_NONE); - /* Number of parameters to check if they are lowerable. */ unsigned check_parameters = ir->actual_parameters.length(); @@ -538,11 +512,6 @@ handle_call(ir_call *ir, const struct set *lowerable_rvalues) check_parameters = 1; } else if (!strcmp(ir->callee_name(), "bitfieldInsert")) { check_parameters = 2; - } if (function_always_returns_mediump_or_lowp(ir->callee_name())) { - /* These only lower the return value. Parameters keep their precision, - * which is preserved in map_builtin. - */ - check_parameters = 0; } /* If the call is to a builtin, then the function won’t have a return @@ -587,10 +556,12 @@ find_lowerable_rvalues_visitor::visit_leave(ir_call *ir) handle_precision(var->type, return_precision); if (lower_state == SHOULD_LOWER) { - /* There probably shouldn’t be any situations where multiple ir_call - * instructions write to the same temporary? + /* Function calls always write to a temporary return value in the caller, + * which has no other users. That temp may start with the precision of + * the function's signature, but if we're inferring the precision of an + * unqualified builtin operation (particularly the imageLoad overrides!) + * then we need to update it. */ - assert(var->data.precision == GLSL_PRECISION_NONE); var->data.precision = GLSL_PRECISION_MEDIUM; } else { var->data.precision = GLSL_PRECISION_HIGH;