Home | History | Annotate | Download | only in glsl
      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 bitfield, 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 "program/hash_table.h"
     42 #include "ir.h"
     43 #include "ir_visitor.h"
     44 #include "glsl_types.h"
     45 
     46 class ir_set_program_inouts_visitor : public ir_hierarchical_visitor {
     47 public:
     48    ir_set_program_inouts_visitor(struct gl_program *prog,
     49                                  bool is_fragment_shader)
     50    {
     51       this->prog = prog;
     52       this->is_fragment_shader = is_fragment_shader;
     53       this->ht = hash_table_ctor(0,
     54 				 hash_table_pointer_hash,
     55 				 hash_table_pointer_compare);
     56    }
     57    ~ir_set_program_inouts_visitor()
     58    {
     59       hash_table_dtor(this->ht);
     60    }
     61 
     62    virtual ir_visitor_status visit_enter(ir_dereference_array *);
     63    virtual ir_visitor_status visit_enter(ir_function_signature *);
     64    virtual ir_visitor_status visit_enter(ir_expression *);
     65    virtual ir_visitor_status visit_enter(ir_discard *);
     66    virtual ir_visitor_status visit(ir_dereference_variable *);
     67    virtual ir_visitor_status visit(ir_variable *);
     68 
     69    struct gl_program *prog;
     70    struct hash_table *ht;
     71    bool is_fragment_shader;
     72 };
     73 
     74 static void
     75 mark(struct gl_program *prog, ir_variable *var, int offset, int len,
     76      bool is_fragment_shader)
     77 {
     78    /* As of GLSL 1.20, varyings can only be floats, floating-point
     79     * vectors or matrices, or arrays of them.  For Mesa programs using
     80     * InputsRead/OutputsWritten, everything but matrices uses one
     81     * slot, while matrices use a slot per column.  Presumably
     82     * something doing a more clever packing would use something other
     83     * than InputsRead/OutputsWritten.
     84     */
     85 
     86    for (int i = 0; i < len; i++) {
     87       GLbitfield64 bitfield = BITFIELD64_BIT(var->location + var->index + offset + i);
     88       if (var->mode == ir_var_in) {
     89 	 prog->InputsRead |= bitfield;
     90          if (is_fragment_shader) {
     91             gl_fragment_program *fprog = (gl_fragment_program *) prog;
     92             fprog->InterpQualifier[var->location + var->index + offset + i] =
     93                (glsl_interp_qualifier) var->interpolation;
     94             if (var->centroid)
     95                fprog->IsCentroid |= bitfield;
     96          }
     97       } else if (var->mode == ir_var_system_value) {
     98          prog->SystemValuesRead |= bitfield;
     99       } else {
    100 	 prog->OutputsWritten |= bitfield;
    101       }
    102    }
    103 }
    104 
    105 /* Default handler: Mark all the locations in the variable as used. */
    106 ir_visitor_status
    107 ir_set_program_inouts_visitor::visit(ir_dereference_variable *ir)
    108 {
    109    if (hash_table_find(this->ht, ir->var) == NULL)
    110       return visit_continue;
    111 
    112    if (ir->type->is_array()) {
    113       mark(this->prog, ir->var, 0,
    114 	   ir->type->length * ir->type->fields.array->matrix_columns,
    115            this->is_fragment_shader);
    116    } else {
    117       mark(this->prog, ir->var, 0, ir->type->matrix_columns,
    118            this->is_fragment_shader);
    119    }
    120 
    121    return visit_continue;
    122 }
    123 
    124 ir_visitor_status
    125 ir_set_program_inouts_visitor::visit_enter(ir_dereference_array *ir)
    126 {
    127    ir_dereference_variable *deref_var;
    128    ir_constant *index = ir->array_index->as_constant();
    129    deref_var = ir->array->as_dereference_variable();
    130    ir_variable *var = NULL;
    131 
    132    /* Check that we're dereferencing a shader in or out */
    133    if (deref_var)
    134       var = (ir_variable *)hash_table_find(this->ht, deref_var->var);
    135 
    136    if (index && var) {
    137       int width = 1;
    138 
    139       if (deref_var->type->is_array() &&
    140 	  deref_var->type->fields.array->is_matrix()) {
    141 	 width = deref_var->type->fields.array->matrix_columns;
    142       }
    143 
    144       mark(this->prog, var, index->value.i[0] * width, width,
    145            this->is_fragment_shader);
    146       return visit_continue_with_parent;
    147    }
    148 
    149    return visit_continue;
    150 }
    151 
    152 ir_visitor_status
    153 ir_set_program_inouts_visitor::visit(ir_variable *ir)
    154 {
    155    if (ir->mode == ir_var_in ||
    156        ir->mode == ir_var_out ||
    157        ir->mode == ir_var_system_value) {
    158       hash_table_insert(this->ht, ir, ir);
    159    }
    160 
    161    return visit_continue;
    162 }
    163 
    164 ir_visitor_status
    165 ir_set_program_inouts_visitor::visit_enter(ir_function_signature *ir)
    166 {
    167    /* We don't want to descend into the function parameters and
    168     * consider them as shader inputs or outputs.
    169     */
    170    visit_list_elements(this, &ir->body);
    171    return visit_continue_with_parent;
    172 }
    173 
    174 ir_visitor_status
    175 ir_set_program_inouts_visitor::visit_enter(ir_expression *ir)
    176 {
    177    if (is_fragment_shader && ir->operation == ir_unop_dFdy) {
    178       gl_fragment_program *fprog = (gl_fragment_program *) prog;
    179       fprog->UsesDFdy = true;
    180    }
    181    return visit_continue;
    182 }
    183 
    184 ir_visitor_status
    185 ir_set_program_inouts_visitor::visit_enter(ir_discard *)
    186 {
    187    /* discards are only allowed in fragment shaders. */
    188    assert(is_fragment_shader);
    189 
    190    gl_fragment_program *fprog = (gl_fragment_program *) prog;
    191    fprog->UsesKill = true;
    192 
    193    return visit_continue;
    194 }
    195 
    196 void
    197 do_set_program_inouts(exec_list *instructions, struct gl_program *prog,
    198                       bool is_fragment_shader)
    199 {
    200    ir_set_program_inouts_visitor v(prog, is_fragment_shader);
    201 
    202    prog->InputsRead = 0;
    203    prog->OutputsWritten = 0;
    204    prog->SystemValuesRead = 0;
    205    if (is_fragment_shader) {
    206       gl_fragment_program *fprog = (gl_fragment_program *) prog;
    207       memset(fprog->InterpQualifier, 0, sizeof(fprog->InterpQualifier));
    208       fprog->IsCentroid = 0;
    209       fprog->UsesDFdy = false;
    210       fprog->UsesKill = false;
    211    }
    212    visit_list_elements(&v, instructions);
    213 }
    214