Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Copyright © 2010 Intel Corporation
  3.  *
  4.  * Permission is hereby granted, free of charge, to any person obtaining a
  5.  * copy of this software and associated documentation files (the "Software"),
  6.  * to deal in the Software without restriction, including without limitation
  7.  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8.  * and/or sell copies of the Software, and to permit persons to whom the
  9.  * Software is furnished to do so, subject to the following conditions:
  10.  *
  11.  * The above copyright notice and this permission notice (including the next
  12.  * paragraph) shall be included in all copies or substantial portions of the
  13.  * Software.
  14.  *
  15.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16.  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  18.  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19.  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  20.  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  21.  * DEALINGS IN THE SOFTWARE.
  22.  */
  23.  
  24. /**
  25.  * \file lower_mat_op_to_vec.cpp
  26.  *
  27.  * Breaks matrix operation expressions down to a series of vector operations.
  28.  *
  29.  * Generally this is how we have to codegen matrix operations for a
  30.  * GPU, so this gives us the chance to constant fold operations on a
  31.  * column or row.
  32.  */
  33.  
  34. #include "ir.h"
  35. #include "ir_expression_flattening.h"
  36. #include "glsl_types.h"
  37.  
  38. class ir_mat_op_to_vec_visitor : public ir_hierarchical_visitor {
  39. public:
  40.    ir_mat_op_to_vec_visitor()
  41.    {
  42.       this->made_progress = false;
  43.       this->mem_ctx = NULL;
  44.    }
  45.  
  46.    ir_visitor_status visit_leave(ir_assignment *);
  47.  
  48.    ir_dereference *get_column(ir_variable *var, int col);
  49.    ir_rvalue *get_element(ir_variable *var, int col, int row);
  50.  
  51.    void do_mul_mat_mat(ir_variable *result_var,
  52.                        ir_variable *a_var, ir_variable *b_var);
  53.    void do_mul_mat_vec(ir_variable *result_var,
  54.                        ir_variable *a_var, ir_variable *b_var);
  55.    void do_mul_vec_mat(ir_variable *result_var,
  56.                        ir_variable *a_var, ir_variable *b_var);
  57.    void do_mul_mat_scalar(ir_variable *result_var,
  58.                           ir_variable *a_var, ir_variable *b_var);
  59.    void do_equal_mat_mat(ir_variable *result_var, ir_variable *a_var,
  60.                          ir_variable *b_var, bool test_equal);
  61.  
  62.    void *mem_ctx;
  63.    bool made_progress;
  64. };
  65.  
  66. static bool
  67. mat_op_to_vec_predicate(ir_instruction *ir)
  68. {
  69.    ir_expression *expr = ir->as_expression();
  70.    unsigned int i;
  71.  
  72.    if (!expr)
  73.       return false;
  74.  
  75.    for (i = 0; i < expr->get_num_operands(); i++) {
  76.       if (expr->operands[i]->type->is_matrix())
  77.          return true;
  78.    }
  79.  
  80.    return false;
  81. }
  82.  
  83. bool
  84. do_mat_op_to_vec(exec_list *instructions)
  85. {
  86.    ir_mat_op_to_vec_visitor v;
  87.  
  88.    /* Pull out any matrix expression to a separate assignment to a
  89.     * temp.  This will make our handling of the breakdown to
  90.     * operations on the matrix's vector components much easier.
  91.     */
  92.    do_expression_flattening(instructions, mat_op_to_vec_predicate);
  93.  
  94.    visit_list_elements(&v, instructions);
  95.  
  96.    return v.made_progress;
  97. }
  98.  
  99. ir_rvalue *
  100. ir_mat_op_to_vec_visitor::get_element(ir_variable *var, int col, int row)
  101. {
  102.    ir_dereference *deref;
  103.  
  104.    deref = new(mem_ctx) ir_dereference_variable(var);
  105.  
  106.    if (var->type->is_matrix()) {
  107.       deref = new(mem_ctx) ir_dereference_array(var,
  108.                                                 new(mem_ctx) ir_constant(col));
  109.    } else {
  110.       assert(col == 0);
  111.    }
  112.  
  113.    return new(mem_ctx) ir_swizzle(deref, row, 0, 0, 0, 1);
  114. }
  115.  
  116. ir_dereference *
  117. ir_mat_op_to_vec_visitor::get_column(ir_variable *var, int row)
  118. {
  119.    ir_dereference *deref;
  120.  
  121.    if (!var->type->is_matrix()) {
  122.       deref = new(mem_ctx) ir_dereference_variable(var);
  123.    } else {
  124.       deref = new(mem_ctx) ir_dereference_variable(var);
  125.       deref = new(mem_ctx) ir_dereference_array(deref,
  126.                                                 new(mem_ctx) ir_constant(row));
  127.    }
  128.  
  129.    return deref;
  130. }
  131.  
  132. void
  133. ir_mat_op_to_vec_visitor::do_mul_mat_mat(ir_variable *result_var,
  134.                                          ir_variable *a_var,
  135.                                          ir_variable *b_var)
  136. {
  137.    int b_col, i;
  138.    ir_assignment *assign;
  139.    ir_expression *expr;
  140.  
  141.    for (b_col = 0; b_col < b_var->type->matrix_columns; b_col++) {
  142.       ir_rvalue *a = get_column(a_var, 0);
  143.       ir_rvalue *b = get_element(b_var, b_col, 0);
  144.  
  145.       /* first column */
  146.       expr = new(mem_ctx) ir_expression(ir_binop_mul,
  147.                                         a->type,
  148.                                         a,
  149.                                         b);
  150.  
  151.       /* following columns */
  152.       for (i = 1; i < a_var->type->matrix_columns; i++) {
  153.          ir_expression *mul_expr;
  154.  
  155.          a = get_column(a_var, i);
  156.          b = get_element(b_var, b_col, i);
  157.  
  158.          mul_expr = new(mem_ctx) ir_expression(ir_binop_mul,
  159.                                                a->type,
  160.                                                a,
  161.                                                b);
  162.          expr = new(mem_ctx) ir_expression(ir_binop_add,
  163.                                            a->type,
  164.                                            expr,
  165.                                            mul_expr);
  166.       }
  167.  
  168.       ir_rvalue *result = get_column(result_var, b_col);
  169.       assign = new(mem_ctx) ir_assignment(result,
  170.                                           expr,
  171.                                           NULL);
  172.       base_ir->insert_before(assign);
  173.    }
  174. }
  175.  
  176. void
  177. ir_mat_op_to_vec_visitor::do_mul_mat_vec(ir_variable *result_var,
  178.                                          ir_variable *a_var,
  179.                                          ir_variable *b_var)
  180. {
  181.    int i;
  182.    ir_rvalue *a = get_column(a_var, 0);
  183.    ir_rvalue *b = get_element(b_var, 0, 0);
  184.    ir_assignment *assign;
  185.    ir_expression *expr;
  186.  
  187.    /* first column */
  188.    expr = new(mem_ctx) ir_expression(ir_binop_mul,
  189.                                      result_var->type,
  190.                                      a,
  191.                                      b);
  192.  
  193.    /* following columns */
  194.    for (i = 1; i < a_var->type->matrix_columns; i++) {
  195.       ir_expression *mul_expr;
  196.  
  197.       a = get_column(a_var, i);
  198.       b = get_element(b_var, 0, i);
  199.  
  200.       mul_expr = new(mem_ctx) ir_expression(ir_binop_mul,
  201.                                             result_var->type,
  202.                                             a,
  203.                                             b);
  204.       expr = new(mem_ctx) ir_expression(ir_binop_add,
  205.                                         result_var->type,
  206.                                         expr,
  207.                                         mul_expr);
  208.    }
  209.  
  210.    ir_rvalue *result = new(mem_ctx) ir_dereference_variable(result_var);
  211.    assign = new(mem_ctx) ir_assignment(result,
  212.                                        expr,
  213.                                        NULL);
  214.    base_ir->insert_before(assign);
  215. }
  216.  
  217. void
  218. ir_mat_op_to_vec_visitor::do_mul_vec_mat(ir_variable *result_var,
  219.                                          ir_variable *a_var,
  220.                                          ir_variable *b_var)
  221. {
  222.    int i;
  223.  
  224.    for (i = 0; i < b_var->type->matrix_columns; i++) {
  225.       ir_rvalue *a = new(mem_ctx) ir_dereference_variable(a_var);
  226.       ir_rvalue *b = get_column(b_var, i);
  227.       ir_rvalue *result;
  228.       ir_expression *column_expr;
  229.       ir_assignment *column_assign;
  230.  
  231.       result = new(mem_ctx) ir_dereference_variable(result_var);
  232.       result = new(mem_ctx) ir_swizzle(result, i, 0, 0, 0, 1);
  233.  
  234.       column_expr = new(mem_ctx) ir_expression(ir_binop_dot,
  235.                                                result->type,
  236.                                                a,
  237.                                                b);
  238.  
  239.       column_assign = new(mem_ctx) ir_assignment(result,
  240.                                                  column_expr,
  241.                                                  NULL);
  242.       base_ir->insert_before(column_assign);
  243.    }
  244. }
  245.  
  246. void
  247. ir_mat_op_to_vec_visitor::do_mul_mat_scalar(ir_variable *result_var,
  248.                                             ir_variable *a_var,
  249.                                             ir_variable *b_var)
  250. {
  251.    int i;
  252.  
  253.    for (i = 0; i < a_var->type->matrix_columns; i++) {
  254.       ir_rvalue *a = get_column(a_var, i);
  255.       ir_rvalue *b = new(mem_ctx) ir_dereference_variable(b_var);
  256.       ir_rvalue *result = get_column(result_var, i);
  257.       ir_expression *column_expr;
  258.       ir_assignment *column_assign;
  259.  
  260.       column_expr = new(mem_ctx) ir_expression(ir_binop_mul,
  261.                                                result->type,
  262.                                                a,
  263.                                                b);
  264.  
  265.       column_assign = new(mem_ctx) ir_assignment(result,
  266.                                                  column_expr,
  267.                                                  NULL);
  268.       base_ir->insert_before(column_assign);
  269.    }
  270. }
  271.  
  272. void
  273. ir_mat_op_to_vec_visitor::do_equal_mat_mat(ir_variable *result_var,
  274.                                            ir_variable *a_var,
  275.                                            ir_variable *b_var,
  276.                                            bool test_equal)
  277. {
  278.    /* This essentially implements the following GLSL:
  279.     *
  280.     * bool equal(mat4 a, mat4 b)
  281.     * {
  282.     *   return !any(bvec4(a[0] != b[0],
  283.     *                     a[1] != b[1],
  284.     *                     a[2] != b[2],
  285.     *                     a[3] != b[3]);
  286.     * }
  287.     *
  288.     * bool nequal(mat4 a, mat4 b)
  289.     * {
  290.     *   return any(bvec4(a[0] != b[0],
  291.     *                    a[1] != b[1],
  292.     *                    a[2] != b[2],
  293.     *                    a[3] != b[3]);
  294.     * }
  295.     */
  296.    const unsigned columns = a_var->type->matrix_columns;
  297.    const glsl_type *const bvec_type =
  298.       glsl_type::get_instance(GLSL_TYPE_BOOL, columns, 1);
  299.  
  300.    ir_variable *const tmp_bvec =
  301.       new(this->mem_ctx) ir_variable(bvec_type, "mat_cmp_bvec",
  302.                                      ir_var_temporary);
  303.    this->base_ir->insert_before(tmp_bvec);
  304.  
  305.    for (unsigned i = 0; i < columns; i++) {
  306.       ir_dereference *const op0 = get_column(a_var, i);
  307.       ir_dereference *const op1 = get_column(b_var, i);
  308.  
  309.       ir_expression *const cmp =
  310.          new(this->mem_ctx) ir_expression(ir_binop_any_nequal,
  311.                                           glsl_type::bool_type, op0, op1);
  312.  
  313.       ir_dereference *const lhs =
  314.          new(this->mem_ctx) ir_dereference_variable(tmp_bvec);
  315.  
  316.       ir_assignment *const assign =
  317.          new(this->mem_ctx) ir_assignment(lhs, cmp, NULL, (1U << i));
  318.  
  319.       this->base_ir->insert_before(assign);
  320.    }
  321.  
  322.    ir_rvalue *const val =
  323.       new(this->mem_ctx) ir_dereference_variable(tmp_bvec);
  324.  
  325.    ir_expression *any =
  326.       new(this->mem_ctx) ir_expression(ir_unop_any, glsl_type::bool_type,
  327.                                        val, NULL);
  328.  
  329.    if (test_equal)
  330.       any = new(this->mem_ctx) ir_expression(ir_unop_logic_not,
  331.                                              glsl_type::bool_type,
  332.                                              any, NULL);
  333.  
  334.    ir_rvalue *const result =
  335.       new(this->mem_ctx) ir_dereference_variable(result_var);
  336.  
  337.    ir_assignment *const assign =
  338.          new(mem_ctx) ir_assignment(result, any, NULL);
  339.    base_ir->insert_before(assign);
  340. }
  341.  
  342. static bool
  343. has_matrix_operand(const ir_expression *expr, unsigned &columns)
  344. {
  345.    for (unsigned i = 0; i < expr->get_num_operands(); i++) {
  346.       if (expr->operands[i]->type->is_matrix()) {
  347.          columns = expr->operands[i]->type->matrix_columns;
  348.          return true;
  349.       }
  350.    }
  351.  
  352.    return false;
  353. }
  354.  
  355.  
  356. ir_visitor_status
  357. ir_mat_op_to_vec_visitor::visit_leave(ir_assignment *orig_assign)
  358. {
  359.    ir_expression *orig_expr = orig_assign->rhs->as_expression();
  360.    unsigned int i, matrix_columns = 1;
  361.    ir_variable *op_var[2];
  362.  
  363.    if (!orig_expr)
  364.       return visit_continue;
  365.  
  366.    if (!has_matrix_operand(orig_expr, matrix_columns))
  367.       return visit_continue;
  368.  
  369.    assert(orig_expr->get_num_operands() <= 2);
  370.  
  371.    mem_ctx = ralloc_parent(orig_assign);
  372.  
  373.    ir_dereference_variable *lhs_deref =
  374.       orig_assign->lhs->as_dereference_variable();
  375.    assert(lhs_deref);
  376.  
  377.    ir_variable *result_var = lhs_deref->var;
  378.  
  379.    /* Store the expression operands in temps so we can use them
  380.     * multiple times.
  381.     */
  382.    for (i = 0; i < orig_expr->get_num_operands(); i++) {
  383.       ir_assignment *assign;
  384.  
  385.       op_var[i] = new(mem_ctx) ir_variable(orig_expr->operands[i]->type,
  386.                                            "mat_op_to_vec",
  387.                                            ir_var_temporary);
  388.       base_ir->insert_before(op_var[i]);
  389.  
  390.       lhs_deref = new(mem_ctx) ir_dereference_variable(op_var[i]);
  391.       assign = new(mem_ctx) ir_assignment(lhs_deref,
  392.                                           orig_expr->operands[i],
  393.                                           NULL);
  394.       base_ir->insert_before(assign);
  395.    }
  396.  
  397.    /* OK, time to break down this matrix operation. */
  398.    switch (orig_expr->operation) {
  399.    case ir_unop_neg: {
  400.       const unsigned mask = (1U << result_var->type->vector_elements) - 1;
  401.  
  402.       /* Apply the operation to each column.*/
  403.       for (i = 0; i < matrix_columns; i++) {
  404.          ir_rvalue *op0 = get_column(op_var[0], i);
  405.          ir_dereference *result = get_column(result_var, i);
  406.          ir_expression *column_expr;
  407.          ir_assignment *column_assign;
  408.  
  409.          column_expr = new(mem_ctx) ir_expression(orig_expr->operation,
  410.                                                   result->type,
  411.                                                   op0,
  412.                                                   NULL);
  413.  
  414.          column_assign = new(mem_ctx) ir_assignment(result,
  415.                                                     column_expr,
  416.                                                     NULL,
  417.                                                     mask);
  418.          assert(column_assign->write_mask != 0);
  419.          base_ir->insert_before(column_assign);
  420.       }
  421.       break;
  422.    }
  423.    case ir_binop_add:
  424.    case ir_binop_sub:
  425.    case ir_binop_div:
  426.    case ir_binop_mod: {
  427.       const unsigned mask = (1U << result_var->type->vector_elements) - 1;
  428.  
  429.       /* For most operations, the matrix version is just going
  430.        * column-wise through and applying the operation to each column
  431.        * if available.
  432.        */
  433.       for (i = 0; i < matrix_columns; i++) {
  434.          ir_rvalue *op0 = get_column(op_var[0], i);
  435.          ir_rvalue *op1 = get_column(op_var[1], i);
  436.          ir_dereference *result = get_column(result_var, i);
  437.          ir_expression *column_expr;
  438.          ir_assignment *column_assign;
  439.  
  440.          column_expr = new(mem_ctx) ir_expression(orig_expr->operation,
  441.                                                   result->type,
  442.                                                   op0,
  443.                                                   op1);
  444.  
  445.          column_assign = new(mem_ctx) ir_assignment(result,
  446.                                                     column_expr,
  447.                                                     NULL,
  448.                                                     mask);
  449.          assert(column_assign->write_mask != 0);
  450.          base_ir->insert_before(column_assign);
  451.       }
  452.       break;
  453.    }
  454.    case ir_binop_mul:
  455.       if (op_var[0]->type->is_matrix()) {
  456.          if (op_var[1]->type->is_matrix()) {
  457.             do_mul_mat_mat(result_var, op_var[0], op_var[1]);
  458.          } else if (op_var[1]->type->is_vector()) {
  459.             do_mul_mat_vec(result_var, op_var[0], op_var[1]);
  460.          } else {
  461.             assert(op_var[1]->type->is_scalar());
  462.             do_mul_mat_scalar(result_var, op_var[0], op_var[1]);
  463.          }
  464.       } else {
  465.          assert(op_var[1]->type->is_matrix());
  466.          if (op_var[0]->type->is_vector()) {
  467.             do_mul_vec_mat(result_var, op_var[0], op_var[1]);
  468.          } else {
  469.             assert(op_var[0]->type->is_scalar());
  470.             do_mul_mat_scalar(result_var, op_var[1], op_var[0]);
  471.          }
  472.       }
  473.       break;
  474.  
  475.    case ir_binop_all_equal:
  476.    case ir_binop_any_nequal:
  477.       do_equal_mat_mat(result_var, op_var[1], op_var[0],
  478.                        (orig_expr->operation == ir_binop_all_equal));
  479.       break;
  480.  
  481.    default:
  482.       printf("FINISHME: Handle matrix operation for %s\n",
  483.              orig_expr->operator_string());
  484.       abort();
  485.    }
  486.    orig_assign->remove();
  487.    this->made_progress = true;
  488.  
  489.    return visit_continue;
  490. }
  491.