At least the following need more thought: 1) Converting right-hand-side of assignments from 16-bits to 32-bits - More correct thing to do is to treat rhs as 32-bits latest in the expression producing the value
2) Texture arguments except coordinates are not handled at all - Moreover, coordinates are always converted into 32-bits due to logic missing in the Intel compiler backend. Signed-off-by: Topi Pohjolainen <topi.pohjolai...@intel.com> --- src/compiler/Makefile.sources | 1 + src/compiler/glsl/ir_optimization.h | 1 + src/compiler/glsl/lower_mediump.cpp | 273 ++++++++++++++++++++++++++++++++++++ 3 files changed, 275 insertions(+) create mode 100644 src/compiler/glsl/lower_mediump.cpp diff --git a/src/compiler/Makefile.sources b/src/compiler/Makefile.sources index 2ab8e163a2..47bde4fb78 100644 --- a/src/compiler/Makefile.sources +++ b/src/compiler/Makefile.sources @@ -94,6 +94,7 @@ LIBGLSL_FILES = \ glsl/lower_int64.cpp \ glsl/lower_jumps.cpp \ glsl/lower_mat_op_to_vec.cpp \ + glsl/lower_mediump.cpp \ glsl/lower_noise.cpp \ glsl/lower_offset_array.cpp \ glsl/lower_packed_varyings.cpp \ diff --git a/src/compiler/glsl/ir_optimization.h b/src/compiler/glsl/ir_optimization.h index 2b8c195151..09c4d664e0 100644 --- a/src/compiler/glsl/ir_optimization.h +++ b/src/compiler/glsl/ir_optimization.h @@ -132,6 +132,7 @@ bool do_vec_index_to_swizzle(exec_list *instructions); bool lower_discard(exec_list *instructions); void lower_discard_flow(exec_list *instructions); bool lower_instructions(exec_list *instructions, unsigned what_to_lower); +bool lower_mediump(struct gl_linked_shader *shader); bool lower_noise(exec_list *instructions); bool lower_variable_index_to_cond_assign(gl_shader_stage stage, exec_list *instructions, bool lower_input, bool lower_output, diff --git a/src/compiler/glsl/lower_mediump.cpp b/src/compiler/glsl/lower_mediump.cpp new file mode 100644 index 0000000000..89eed8b294 --- /dev/null +++ b/src/compiler/glsl/lower_mediump.cpp @@ -0,0 +1,273 @@ +/* + * Copyright 2017 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. + */ + +/** + * \file lower_mediump.cpp + * + */ + +#include "compiler/glsl_types.h" +#include "ir.h" +#include "ir_rvalue_visitor.h" +#include "ast.h" + +static const glsl_type * +get_mediump(const glsl_type *highp) +{ + if (highp->is_float()) + return glsl_type::get_instance(GLSL_TYPE_FLOAT16, + highp->vector_elements, + highp->matrix_columns); + + if (highp->is_array() && highp->fields.array->is_float()) + return glsl_type::get_array_instance( + glsl_type::get_instance(GLSL_TYPE_FLOAT16, + highp->fields.array->vector_elements, + highp->fields.array->matrix_columns), + highp->length); + + return highp; +} + +static bool +is_16_bit(const ir_rvalue *ir) +{ + return ir->type->get_scalar_type()->base_type == GLSL_TYPE_FLOAT16; +} + +static bool +refers_16_bit_float(const ir_rvalue *ir) +{ + ir_variable *var = ir->variable_referenced(); + + /* Only variables have the mediump property, constants need conversion. */ + if (!var) + return false; + + return var->type->get_scalar_type()->base_type == GLSL_TYPE_FLOAT16; +} + +static ir_rvalue * +convert(ir_rvalue *ir, enum ir_expression_operation op) +{ + if (ir->ir_type == ir_type_constant) { + assert(op == ir_unop_f2h); + ir->type = get_mediump(ir->type); + return ir; + } + + void *ctx = ralloc_parent(ir); + return new(ctx) ir_expression(op, ir); +} + +class lower_mediump_visitor : public ir_rvalue_visitor { +public: + lower_mediump_visitor() : progress(false) {} + + virtual ir_visitor_status visit(ir_variable *ir); + virtual ir_visitor_status visit(ir_dereference_variable *ir); + + virtual ir_visitor_status visit_leave(ir_assignment *ir); + virtual ir_visitor_status visit_leave(ir_expression *ir); + virtual ir_visitor_status visit_leave(ir_swizzle *ir); + + virtual void handle_rvalue(ir_rvalue **rvalue); + + bool progress; + +private: + bool can_be_lowered(const ir_variable *var) const; + + void retype_to_float16(const glsl_type **t); +}; + +bool +lower_mediump_visitor::can_be_lowered(const ir_variable *var) const +{ + if (!var->type->get_scalar_type()->is_float()) + return false; + + return var->data.precision == ast_precision_low || + var->data.precision == ast_precision_medium; +} + +void +lower_mediump_visitor::retype_to_float16(const glsl_type **t) +{ + const glsl_type * const mediump = get_mediump(*t); + progress = mediump != *t; + *t = mediump; +} + +ir_visitor_status +lower_mediump_visitor::visit(ir_variable *ir) +{ + if (!can_be_lowered(ir)) + return visit_continue; + + const glsl_type * const mediump = get_mediump(ir->type); + progress = mediump != ir->type; + ir->type = mediump; + + return visit_continue; +} + +ir_visitor_status +lower_mediump_visitor::visit(ir_dereference_variable *ir) +{ + if (!refers_16_bit_float(ir)) + return visit_continue; + + const glsl_type * const mediump = get_mediump(ir->type); + progress = mediump != ir->type; + ir->type = mediump; + + return visit_continue; +} + +ir_visitor_status +lower_mediump_visitor::visit_leave(ir_assignment *ir) +{ + ir_rvalue_visitor::visit_leave(ir); + + if (!ir->lhs || !ir->rhs) + return visit_continue; + + ir_variable *lhs = ir->lhs->variable_referenced(); + if (lhs == NULL) + return visit_continue; + + /* Consider if the dereference targets 16-bit variable. In such case lower + * the dereference type and emit conversion for the source if needed. + */ + if (refers_16_bit_float(ir->lhs)) { + retype_to_float16(&ir->lhs->type); + + /* Consider if source needs conversion to float16. */ + if (!is_16_bit(ir->rhs)) + ir->rhs = convert(ir->rhs, ir_unop_f2h); + + return visit_continue; + } + + /* If in turn target is 32-bit but source is 16-bit, emit conversion. */ + if (is_16_bit(ir->rhs)) + ir->rhs = convert(ir->rhs, ir_unop_h2f); + + return visit_continue; +} + +ir_visitor_status +lower_mediump_visitor::visit_leave(ir_swizzle *ir) +{ + ir_rvalue_visitor::visit_leave(ir); + + if (is_16_bit(ir->val)) + retype_to_float16(&ir->type); + + return visit_continue; +} + +/* Consider expressions in depth-first order according to the rules found in + * GLES 3.2 Specification, 4.7.3 Precision Qualifiers: + * + * In cases where operands do not have a precision qualifier, the precision + * qualification will come from the other operands. If no operands have a + * precision qualifier, then the precision qualifications of the operands of + * the next consuming operation in the expression will be used. This rule can + * be applied recursively until a precision qualified operand is found. If + * necessary, it will also include the precision qualification of l-values for + * assignments, of the declared variable for initializers, of formal + * parameters for function call arguments, or of function return types for + * function return values. If the precision cannot be determined by this + * method e.g. if an entire expression is composed only of operands with no + * precision qualifier, and the result is not assigned or passed as an + * argument, then it is evaluated at the default precision of the type or + * greater. When this occurs in the fragment shader, the default precision + * must be defined. + * + * For example, consider the statements: + * + * uniform highp float h1; + * highp float h2 = 2.3 * 4.7; // operation and result are highp precision + * mediump float m; + * m = 3.7 * h1 * h2; // all operations are highp precision + * h2 = m * h1; // operation is highp precision + * m = h2 - h1; // operation is highp precision + * h2 = m + m; // addition and result at mediump precision + * void f(highp float p); + * f(3.3); // 3.3 will be passed in at highp precisi + */ +ir_visitor_status +lower_mediump_visitor::visit_leave(ir_expression *ir) +{ + ir_rvalue_visitor::visit_leave(ir); + + bool has_32_bit_src = false; + bool has_16_bit_src = false; + for (unsigned i = 0; i < ir->num_operands; i++) { + if (is_16_bit(ir->operands[i])) + has_16_bit_src = true; + else + has_32_bit_src = true; + } + + if (!has_16_bit_src) + return visit_continue; + + /* If there are no 32-bit source operands the expression can be evaluated + * in lower precision. + */ + if (!has_32_bit_src && + ir->operation != ir_triop_lrp) { + retype_to_float16(&ir->type); + return visit_continue; + } + + /* All other 16-bit operands need to be converted to 32-bits in order to + * perform the operation in 32-bits. + */ + for (unsigned i = 0; i < ir->num_operands; i++) { + if (is_16_bit(ir->operands[i])) + ir->operands[i] = convert(ir->operands[i], ir_unop_h2f); + } + + return visit_continue; +} + +void +lower_mediump_visitor::handle_rvalue(ir_rvalue **rvalue) +{ + if (*rvalue == NULL || !refers_16_bit_float(*rvalue)) + return; + + retype_to_float16(&(*rvalue)->type); +} + +bool +lower_mediump(struct gl_linked_shader *shader) +{ + lower_mediump_visitor v; + visit_list_elements(&v, shader->ir); + return v.progress; +} -- 2.11.0 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev