Subversion Repositories Kolibri OS

Rev

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