Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | 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 brw_wm_vector_splitting.cpp
  26.  *
  27.  * If a vector is only ever referenced by its components, then
  28.  * split those components out to individual variables so they can be
  29.  * handled normally by other optimization passes.
  30.  *
  31.  * This skips vectors in uniforms and varyings, which need to be
  32.  * accessible as vectors for their access by the GL.  Also, vector
  33.  * results of non-variable-derefs in assignments aren't handled
  34.  * because to do so we would have to store the vector result to a
  35.  * temporary in order to unload each channel, and to do so would just
  36.  * loop us back to where we started.  For the 965, this is exactly the
  37.  * behavior we want for the results of texture lookups, but probably not for
  38.  */
  39.  
  40. #include "main/core.h"
  41. #include "brw_context.h"
  42. #include "glsl/ir.h"
  43. #include "glsl/ir_visitor.h"
  44. #include "glsl/ir_rvalue_visitor.h"
  45. #include "glsl/glsl_types.h"
  46.  
  47. static bool debug = false;
  48.  
  49. class variable_entry : public exec_node
  50. {
  51. public:
  52.    variable_entry(ir_variable *var)
  53.    {
  54.       this->var = var;
  55.       this->whole_vector_access = 0;
  56.       this->mem_ctx = NULL;
  57.    }
  58.  
  59.    ir_variable *var; /* The key: the variable's pointer. */
  60.  
  61.    /** Number of times the variable is referenced, including assignments. */
  62.    unsigned whole_vector_access;
  63.  
  64.    ir_variable *components[4];
  65.  
  66.    /** ralloc_parent(this->var) -- the shader's ralloc context. */
  67.    void *mem_ctx;
  68. };
  69.  
  70. class ir_vector_reference_visitor : public ir_hierarchical_visitor {
  71. public:
  72.    ir_vector_reference_visitor(void)
  73.    {
  74.       this->mem_ctx = ralloc_context(NULL);
  75.       this->variable_list.make_empty();
  76.    }
  77.  
  78.    ~ir_vector_reference_visitor(void)
  79.    {
  80.       ralloc_free(mem_ctx);
  81.    }
  82.  
  83.    virtual ir_visitor_status visit(ir_variable *);
  84.    virtual ir_visitor_status visit(ir_dereference_variable *);
  85.    virtual ir_visitor_status visit_enter(ir_swizzle *);
  86.    virtual ir_visitor_status visit_enter(ir_assignment *);
  87.    virtual ir_visitor_status visit_enter(ir_function_signature *);
  88.  
  89.    variable_entry *get_variable_entry(ir_variable *var);
  90.  
  91.    /* List of variable_entry */
  92.    exec_list variable_list;
  93.  
  94.    void *mem_ctx;
  95. };
  96.  
  97. variable_entry *
  98. ir_vector_reference_visitor::get_variable_entry(ir_variable *var)
  99. {
  100.    assert(var);
  101.  
  102.    if (!var->type->is_vector())
  103.       return NULL;
  104.  
  105.    switch (var->data.mode) {
  106.    case ir_var_uniform:
  107.    case ir_var_shader_in:
  108.    case ir_var_shader_out:
  109.    case ir_var_system_value:
  110.    case ir_var_function_in:
  111.    case ir_var_function_out:
  112.    case ir_var_function_inout:
  113.       /* Can't split varyings or uniforms.  Function in/outs won't get split
  114.        * either.
  115.        */
  116.       return NULL;
  117.    case ir_var_auto:
  118.    case ir_var_temporary:
  119.       break;
  120.    }
  121.  
  122.    foreach_in_list(variable_entry, entry, &variable_list) {
  123.       if (entry->var == var)
  124.          return entry;
  125.    }
  126.  
  127.    variable_entry *entry = new(mem_ctx) variable_entry(var);
  128.    this->variable_list.push_tail(entry);
  129.    return entry;
  130. }
  131.  
  132.  
  133. ir_visitor_status
  134. ir_vector_reference_visitor::visit(ir_variable *ir)
  135. {
  136.    /* Make sure splitting looks at splitting this variable */
  137.    (void)this->get_variable_entry(ir);
  138.  
  139.    return visit_continue;
  140. }
  141.  
  142. ir_visitor_status
  143. ir_vector_reference_visitor::visit(ir_dereference_variable *ir)
  144. {
  145.    ir_variable *const var = ir->var;
  146.    variable_entry *entry = this->get_variable_entry(var);
  147.  
  148.    if (entry)
  149.       entry->whole_vector_access++;
  150.  
  151.    return visit_continue;
  152. }
  153.  
  154. ir_visitor_status
  155. ir_vector_reference_visitor::visit_enter(ir_swizzle *ir)
  156. {
  157.    /* Don't descend into a vector ir_dereference_variable below. */
  158.    if (ir->val->as_dereference_variable() && ir->type->is_scalar())
  159.       return visit_continue_with_parent;
  160.  
  161.    return visit_continue;
  162. }
  163.  
  164. ir_visitor_status
  165. ir_vector_reference_visitor::visit_enter(ir_assignment *ir)
  166. {
  167.    if (ir->lhs->as_dereference_variable() &&
  168.        ir->rhs->as_dereference_variable() &&
  169.        !ir->condition) {
  170.       /* We'll split copies of a vector to copies of channels, so don't
  171.        * descend to the ir_dereference_variables.
  172.        */
  173.       return visit_continue_with_parent;
  174.    }
  175.    if (ir->lhs->as_dereference_variable() &&
  176.        is_power_of_two(ir->write_mask) &&
  177.        !ir->condition) {
  178.       /* If we're writing just a channel, then channel-splitting the LHS is OK.
  179.        */
  180.       ir->rhs->accept(this);
  181.       return visit_continue_with_parent;
  182.    }
  183.    return visit_continue;
  184. }
  185.  
  186. ir_visitor_status
  187. ir_vector_reference_visitor::visit_enter(ir_function_signature *ir)
  188. {
  189.    /* We don't want to descend into the function parameters and
  190.     * split them, so just accept the body here.
  191.     */
  192.    visit_list_elements(this, &ir->body);
  193.    return visit_continue_with_parent;
  194. }
  195.  
  196. class ir_vector_splitting_visitor : public ir_rvalue_visitor {
  197. public:
  198.    ir_vector_splitting_visitor(exec_list *vars)
  199.    {
  200.       this->variable_list = vars;
  201.    }
  202.  
  203.    virtual ir_visitor_status visit_leave(ir_assignment *);
  204.  
  205.    void handle_rvalue(ir_rvalue **rvalue);
  206.    variable_entry *get_splitting_entry(ir_variable *var);
  207.  
  208.    exec_list *variable_list;
  209. };
  210.  
  211. variable_entry *
  212. ir_vector_splitting_visitor::get_splitting_entry(ir_variable *var)
  213. {
  214.    assert(var);
  215.  
  216.    if (!var->type->is_vector())
  217.       return NULL;
  218.  
  219.    foreach_in_list(variable_entry, entry, variable_list) {
  220.       if (entry->var == var) {
  221.          return entry;
  222.       }
  223.    }
  224.  
  225.    return NULL;
  226. }
  227.  
  228. void
  229. ir_vector_splitting_visitor::handle_rvalue(ir_rvalue **rvalue)
  230. {
  231.    if (!*rvalue)
  232.       return;
  233.  
  234.    ir_swizzle *swiz = (*rvalue)->as_swizzle();
  235.    if (!swiz || !swiz->type->is_scalar())
  236.       return;
  237.  
  238.    ir_dereference_variable *deref_var = swiz->val->as_dereference_variable();
  239.    if (!deref_var)
  240.       return;
  241.  
  242.    variable_entry *entry = get_splitting_entry(deref_var->var);
  243.    if (!entry)
  244.       return;
  245.  
  246.    ir_variable *var = entry->components[swiz->mask.x];
  247.    *rvalue = new(entry->mem_ctx) ir_dereference_variable(var);
  248. }
  249.  
  250. ir_visitor_status
  251. ir_vector_splitting_visitor::visit_leave(ir_assignment *ir)
  252. {
  253.    ir_dereference_variable *lhs_deref = ir->lhs->as_dereference_variable();
  254.    ir_dereference_variable *rhs_deref = ir->rhs->as_dereference_variable();
  255.    variable_entry *lhs = lhs_deref ? get_splitting_entry(lhs_deref->var) : NULL;
  256.    variable_entry *rhs = rhs_deref ? get_splitting_entry(rhs_deref->var) : NULL;
  257.  
  258.    if (lhs_deref && rhs_deref && (lhs || rhs) && !ir->condition) {
  259.       unsigned int rhs_chan = 0;
  260.  
  261.       /* Straight assignment of vector variables. */
  262.       for (unsigned int i = 0; i < ir->lhs->type->vector_elements; i++) {
  263.          ir_dereference *new_lhs;
  264.          ir_rvalue *new_rhs;
  265.          void *mem_ctx = lhs ? lhs->mem_ctx : rhs->mem_ctx;
  266.          unsigned int writemask;
  267.  
  268.          if (!(ir->write_mask & (1 << i)))
  269.             continue;
  270.  
  271.          if (lhs) {
  272.             new_lhs = new(mem_ctx) ir_dereference_variable(lhs->components[i]);
  273.             writemask = 1;
  274.          } else {
  275.             new_lhs = ir->lhs->clone(mem_ctx, NULL);
  276.             writemask = 1 << i;
  277.          }
  278.  
  279.          if (rhs) {
  280.             new_rhs =
  281.                new(mem_ctx) ir_dereference_variable(rhs->components[rhs_chan]);
  282.          } else {
  283.             new_rhs = new(mem_ctx) ir_swizzle(ir->rhs->clone(mem_ctx, NULL),
  284.                                               rhs_chan, 0, 0, 0, 1);
  285.          }
  286.  
  287.          ir->insert_before(new(mem_ctx) ir_assignment(new_lhs,
  288.                                                       new_rhs,
  289.                                                       NULL, writemask));
  290.  
  291.          rhs_chan++;
  292.       }
  293.       ir->remove();
  294.    } else if (lhs) {
  295.       void *mem_ctx = lhs->mem_ctx;
  296.       int elem = -1;
  297.  
  298.       switch (ir->write_mask) {
  299.       case (1 << 0):
  300.          elem = 0;
  301.          break;
  302.       case (1 << 1):
  303.          elem = 1;
  304.          break;
  305.       case (1 << 2):
  306.          elem = 2;
  307.          break;
  308.       case (1 << 3):
  309.          elem = 3;
  310.          break;
  311.       default:
  312.          ir->fprint(stderr);
  313.          unreachable("not reached: non-channelwise dereference of LHS.");
  314.       }
  315.  
  316.       ir->lhs = new(mem_ctx) ir_dereference_variable(lhs->components[elem]);
  317.       ir->write_mask = (1 << 0);
  318.  
  319.       handle_rvalue(&ir->rhs);
  320.    } else {
  321.       handle_rvalue(&ir->rhs);
  322.    }
  323.  
  324.    handle_rvalue(&ir->condition);
  325.  
  326.    return visit_continue;
  327. }
  328.  
  329. bool
  330. brw_do_vector_splitting(exec_list *instructions)
  331. {
  332.    ir_vector_reference_visitor refs;
  333.  
  334.    visit_list_elements(&refs, instructions);
  335.  
  336.    /* Trim out variables we can't split. */
  337.    foreach_in_list_safe(variable_entry, entry, &refs.variable_list) {
  338.       if (debug) {
  339.          fprintf(stderr, "vector %s@%p: whole_access %d\n",
  340.                  entry->var->name, (void *) entry->var,
  341.                  entry->whole_vector_access);
  342.       }
  343.  
  344.       if (entry->whole_vector_access) {
  345.          entry->remove();
  346.       }
  347.    }
  348.  
  349.    if (refs.variable_list.is_empty())
  350.       return false;
  351.  
  352.    void *mem_ctx = ralloc_context(NULL);
  353.  
  354.    /* Replace the decls of the vectors to be split with their split
  355.     * components.
  356.     */
  357.    foreach_in_list(variable_entry, entry, &refs.variable_list) {
  358.       const struct glsl_type *type;
  359.       type = glsl_type::get_instance(entry->var->type->base_type, 1, 1);
  360.  
  361.       entry->mem_ctx = ralloc_parent(entry->var);
  362.  
  363.       for (unsigned int i = 0; i < entry->var->type->vector_elements; i++) {
  364.          char *const name = ir_variable::temporaries_allocate_names
  365.             ? ralloc_asprintf(mem_ctx, "%s_%c",
  366.                               entry->var->name,
  367.                               "xyzw"[i])
  368.             : NULL;
  369.  
  370.          entry->components[i] = new(entry->mem_ctx) ir_variable(type, name,
  371.                                                                 ir_var_temporary);
  372.  
  373.          ralloc_free(name);
  374.  
  375.          entry->var->insert_before(entry->components[i]);
  376.       }
  377.  
  378.       entry->var->remove();
  379.    }
  380.  
  381.    ir_vector_splitting_visitor split(&refs.variable_list);
  382.    visit_list_elements(&split, instructions);
  383.  
  384.    ralloc_free(mem_ctx);
  385.  
  386.    return true;
  387. }
  388.