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 ir_set_program_inouts.cpp
  26.  *
  27.  * Sets the InputsRead and OutputsWritten of Mesa programs.
  28.  *
  29.  * Additionally, for fragment shaders, sets the InterpQualifier array, the
  30.  * IsCentroid and IsSample bitfields, and the UsesDFdy flag.
  31.  *
  32.  * Mesa programs (gl_program, not gl_shader_program) have a set of
  33.  * flags indicating which varyings are read and written.  Computing
  34.  * which are actually read from some sort of backend code can be
  35.  * tricky when variable array indexing involved.  So this pass
  36.  * provides support for setting InputsRead and OutputsWritten right
  37.  * from the GLSL IR.
  38.  */
  39.  
  40. #include "main/core.h" /* for struct gl_program */
  41. #include "ir.h"
  42. #include "ir_visitor.h"
  43. #include "glsl_types.h"
  44.  
  45. namespace {
  46.  
  47. class ir_set_program_inouts_visitor : public ir_hierarchical_visitor {
  48. public:
  49.    ir_set_program_inouts_visitor(struct gl_program *prog,
  50.                                  gl_shader_stage shader_stage)
  51.    {
  52.       this->prog = prog;
  53.       this->shader_stage = shader_stage;
  54.    }
  55.    ~ir_set_program_inouts_visitor()
  56.    {
  57.    }
  58.  
  59.    virtual ir_visitor_status visit_enter(ir_dereference_array *);
  60.    virtual ir_visitor_status visit_enter(ir_function_signature *);
  61.    virtual ir_visitor_status visit_enter(ir_expression *);
  62.    virtual ir_visitor_status visit_enter(ir_discard *);
  63.    virtual ir_visitor_status visit_enter(ir_texture *);
  64.    virtual ir_visitor_status visit(ir_dereference_variable *);
  65.  
  66. private:
  67.    void mark_whole_variable(ir_variable *var);
  68.    bool try_mark_partial_variable(ir_variable *var, ir_rvalue *index);
  69.  
  70.    struct gl_program *prog;
  71.    gl_shader_stage shader_stage;
  72. };
  73.  
  74. } /* anonymous namespace */
  75.  
  76. static inline bool
  77. is_shader_inout(ir_variable *var)
  78. {
  79.    return var->data.mode == ir_var_shader_in ||
  80.           var->data.mode == ir_var_shader_out ||
  81.           var->data.mode == ir_var_system_value;
  82. }
  83.  
  84. static inline bool
  85. is_dual_slot(ir_variable *var)
  86. {
  87.    const glsl_type *type = var->type->without_array();
  88.    return type == glsl_type::dvec4_type || type == glsl_type::dvec3_type;
  89. }
  90.  
  91. static void
  92. mark(struct gl_program *prog, ir_variable *var, int offset, int len,
  93.      bool is_fragment_shader)
  94. {
  95.    /* As of GLSL 1.20, varyings can only be floats, floating-point
  96.     * vectors or matrices, or arrays of them.  For Mesa programs using
  97.     * InputsRead/OutputsWritten, everything but matrices uses one
  98.     * slot, while matrices use a slot per column.  Presumably
  99.     * something doing a more clever packing would use something other
  100.     * than InputsRead/OutputsWritten.
  101.     */
  102.  
  103.    for (int i = 0; i < len; i++) {
  104.       bool dual_slot = is_dual_slot(var);
  105.       int idx = var->data.location + var->data.index + offset + i;
  106.       GLbitfield64 bitfield = BITFIELD64_BIT(idx);
  107.  
  108.       if (var->data.mode == ir_var_shader_in) {
  109.          prog->InputsRead |= bitfield;
  110.          if (dual_slot)
  111.             prog->DoubleInputsRead |= bitfield;
  112.          if (is_fragment_shader) {
  113.             gl_fragment_program *fprog = (gl_fragment_program *) prog;
  114.             fprog->InterpQualifier[idx] =
  115.                (glsl_interp_qualifier) var->data.interpolation;
  116.             if (var->data.centroid)
  117.                fprog->IsCentroid |= bitfield;
  118.             if (var->data.sample)
  119.                fprog->IsSample |= bitfield;
  120.          }
  121.       } else if (var->data.mode == ir_var_system_value) {
  122.          prog->SystemValuesRead |= bitfield;
  123.       } else {
  124.          assert(var->data.mode == ir_var_shader_out);
  125.          prog->OutputsWritten |= bitfield;
  126.       }
  127.    }
  128. }
  129.  
  130. /**
  131.  * Mark an entire variable as used.  Caller must ensure that the variable
  132.  * represents a shader input or output.
  133.  */
  134. void
  135. ir_set_program_inouts_visitor::mark_whole_variable(ir_variable *var)
  136. {
  137.    const glsl_type *type = var->type;
  138.    if (this->shader_stage == MESA_SHADER_GEOMETRY &&
  139.        var->data.mode == ir_var_shader_in && type->is_array()) {
  140.       type = type->fields.array;
  141.    }
  142.  
  143.    mark(this->prog, var, 0, type->count_attribute_slots(),
  144.         this->shader_stage == MESA_SHADER_FRAGMENT);
  145. }
  146.  
  147. /* Default handler: Mark all the locations in the variable as used. */
  148. ir_visitor_status
  149. ir_set_program_inouts_visitor::visit(ir_dereference_variable *ir)
  150. {
  151.    if (!is_shader_inout(ir->var))
  152.       return visit_continue;
  153.  
  154.    mark_whole_variable(ir->var);
  155.  
  156.    return visit_continue;
  157. }
  158.  
  159. /**
  160.  * Try to mark a portion of the given variable as used.  Caller must ensure
  161.  * that the variable represents a shader input or output which can be indexed
  162.  * into in array fashion (an array or matrix).  For the purpose of geometry
  163.  * shader inputs (which are always arrays*), this means that the array element
  164.  * must be something that can be indexed into in array fashion.
  165.  *
  166.  * *Except gl_PrimitiveIDIn, as noted below.
  167.  *
  168.  * If the index can't be interpreted as a constant, or some other problem
  169.  * occurs, then nothing will be marked and false will be returned.
  170.  */
  171. bool
  172. ir_set_program_inouts_visitor::try_mark_partial_variable(ir_variable *var,
  173.                                                          ir_rvalue *index)
  174. {
  175.    const glsl_type *type = var->type;
  176.  
  177.    if (this->shader_stage == MESA_SHADER_GEOMETRY &&
  178.        var->data.mode == ir_var_shader_in) {
  179.       /* The only geometry shader input that is not an array is
  180.        * gl_PrimitiveIDIn, and in that case, this code will never be reached,
  181.        * because gl_PrimitiveIDIn can't be indexed into in array fashion.
  182.        */
  183.       assert(type->is_array());
  184.       type = type->fields.array;
  185.    }
  186.  
  187.    /* The code below only handles:
  188.     *
  189.     * - Indexing into matrices
  190.     * - Indexing into arrays of (matrices, vectors, or scalars)
  191.     *
  192.     * All other possibilities are either prohibited by GLSL (vertex inputs and
  193.     * fragment outputs can't be structs) or should have been eliminated by
  194.     * lowering passes (do_vec_index_to_swizzle() gets rid of indexing into
  195.     * vectors, and lower_packed_varyings() gets rid of structs that occur in
  196.     * varyings).
  197.     */
  198.    if (!(type->is_matrix() ||
  199.         (type->is_array() &&
  200.          (type->fields.array->is_numeric() ||
  201.           type->fields.array->is_boolean())))) {
  202.       assert(!"Unexpected indexing in ir_set_program_inouts");
  203.  
  204.       /* For safety in release builds, in case we ever encounter unexpected
  205.        * indexing, give up and let the caller mark the whole variable as used.
  206.        */
  207.       return false;
  208.    }
  209.  
  210.    ir_constant *index_as_constant = index->as_constant();
  211.    if (!index_as_constant)
  212.       return false;
  213.  
  214.    unsigned elem_width;
  215.    unsigned num_elems;
  216.    if (type->is_array()) {
  217.       num_elems = type->length;
  218.       if (type->fields.array->is_matrix())
  219.          elem_width = type->fields.array->matrix_columns;
  220.       else
  221.          elem_width = 1;
  222.    } else {
  223.       num_elems = type->matrix_columns;
  224.       elem_width = 1;
  225.    }
  226.  
  227.    if (index_as_constant->value.u[0] >= num_elems) {
  228.       /* Constant index outside the bounds of the matrix/array.  This could
  229.        * arise as a result of constant folding of a legal GLSL program.
  230.        *
  231.        * Even though the spec says that indexing outside the bounds of a
  232.        * matrix/array results in undefined behaviour, we don't want to pass
  233.        * out-of-range values to mark() (since this could result in slots that
  234.        * don't exist being marked as used), so just let the caller mark the
  235.        * whole variable as used.
  236.        */
  237.       return false;
  238.    }
  239.  
  240.    mark(this->prog, var, index_as_constant->value.u[0] * elem_width,
  241.         elem_width, this->shader_stage == MESA_SHADER_FRAGMENT);
  242.    return true;
  243. }
  244.  
  245. ir_visitor_status
  246. ir_set_program_inouts_visitor::visit_enter(ir_dereference_array *ir)
  247. {
  248.    /* Note: for geometry shader inputs, lower_named_interface_blocks may
  249.     * create 2D arrays, so we need to be able to handle those.  2D arrays
  250.     * shouldn't be able to crop up for any other reason.
  251.     */
  252.    if (ir_dereference_array * const inner_array =
  253.        ir->array->as_dereference_array()) {
  254.       /*          ir => foo[i][j]
  255.        * inner_array => foo[i]
  256.        */
  257.       if (ir_dereference_variable * const deref_var =
  258.           inner_array->array->as_dereference_variable()) {
  259.          if (this->shader_stage == MESA_SHADER_GEOMETRY &&
  260.              deref_var->var->data.mode == ir_var_shader_in) {
  261.             /* foo is a geometry shader input, so i is the vertex, and j the
  262.              * part of the input we're accessing.
  263.              */
  264.             if (try_mark_partial_variable(deref_var->var, ir->array_index))
  265.             {
  266.                /* We've now taken care of foo and j, but i might contain a
  267.                 * subexpression that accesses shader inputs.  So manually
  268.                 * visit i and then continue with the parent.
  269.                 */
  270.                inner_array->array_index->accept(this);
  271.                return visit_continue_with_parent;
  272.             }
  273.          }
  274.       }
  275.    } else if (ir_dereference_variable * const deref_var =
  276.               ir->array->as_dereference_variable()) {
  277.       /* ir => foo[i], where foo is a variable. */
  278.       if (this->shader_stage == MESA_SHADER_GEOMETRY &&
  279.           deref_var->var->data.mode == ir_var_shader_in) {
  280.          /* foo is a geometry shader input, so i is the vertex, and we're
  281.           * accessing the entire input.
  282.           */
  283.          mark_whole_variable(deref_var->var);
  284.          /* We've now taken care of foo, but i might contain a subexpression
  285.           * that accesses shader inputs.  So manually visit i and then
  286.           * continue with the parent.
  287.           */
  288.          ir->array_index->accept(this);
  289.          return visit_continue_with_parent;
  290.       } else if (is_shader_inout(deref_var->var)) {
  291.          /* foo is a shader input/output, but not a geometry shader input,
  292.           * so i is the part of the input we're accessing.
  293.           */
  294.          if (try_mark_partial_variable(deref_var->var, ir->array_index))
  295.             return visit_continue_with_parent;
  296.       }
  297.    }
  298.  
  299.    /* The expression is something we don't recognize.  Just visit its
  300.     * subexpressions.
  301.     */
  302.    return visit_continue;
  303. }
  304.  
  305. ir_visitor_status
  306. ir_set_program_inouts_visitor::visit_enter(ir_function_signature *ir)
  307. {
  308.    /* We don't want to descend into the function parameters and
  309.     * consider them as shader inputs or outputs.
  310.     */
  311.    visit_list_elements(this, &ir->body);
  312.    return visit_continue_with_parent;
  313. }
  314.  
  315. ir_visitor_status
  316. ir_set_program_inouts_visitor::visit_enter(ir_expression *ir)
  317. {
  318.    if (this->shader_stage == MESA_SHADER_FRAGMENT &&
  319.        (ir->operation == ir_unop_dFdy ||
  320.         ir->operation == ir_unop_dFdy_coarse ||
  321.         ir->operation == ir_unop_dFdy_fine)) {
  322.       gl_fragment_program *fprog = (gl_fragment_program *) prog;
  323.       fprog->UsesDFdy = true;
  324.    }
  325.    return visit_continue;
  326. }
  327.  
  328. ir_visitor_status
  329. ir_set_program_inouts_visitor::visit_enter(ir_discard *)
  330. {
  331.    /* discards are only allowed in fragment shaders. */
  332.    assert(this->shader_stage == MESA_SHADER_FRAGMENT);
  333.  
  334.    gl_fragment_program *fprog = (gl_fragment_program *) prog;
  335.    fprog->UsesKill = true;
  336.  
  337.    return visit_continue;
  338. }
  339.  
  340. ir_visitor_status
  341. ir_set_program_inouts_visitor::visit_enter(ir_texture *ir)
  342. {
  343.    if (ir->op == ir_tg4)
  344.       prog->UsesGather = true;
  345.    return visit_continue;
  346. }
  347.  
  348. void
  349. do_set_program_inouts(exec_list *instructions, struct gl_program *prog,
  350.                       gl_shader_stage shader_stage)
  351. {
  352.    ir_set_program_inouts_visitor v(prog, shader_stage);
  353.  
  354.    prog->InputsRead = 0;
  355.    prog->OutputsWritten = 0;
  356.    prog->SystemValuesRead = 0;
  357.    if (shader_stage == MESA_SHADER_FRAGMENT) {
  358.       gl_fragment_program *fprog = (gl_fragment_program *) prog;
  359.       memset(fprog->InterpQualifier, 0, sizeof(fprog->InterpQualifier));
  360.       fprog->IsCentroid = 0;
  361.       fprog->IsSample = 0;
  362.       fprog->UsesDFdy = false;
  363.       fprog->UsesKill = false;
  364.    }
  365.    visit_list_elements(&v, instructions);
  366. }
  367.