Home | History | Annotate | Download | only in nir
      1 /*
      2  * Copyright  2015 Red Hat
      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 FROM,
     20  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     21  * SOFTWARE.
     22  */
     23 
     24 
     25 #include "nir.h"
     26 #include "nir_builder.h"
     27 
     28 typedef struct {
     29    nir_shader *shader;
     30    nir_builder b;
     31 } lower_state;
     32 
     33 static bool
     34 is_color_output(lower_state *state, nir_variable *out)
     35 {
     36    switch (state->shader->stage) {
     37    case MESA_SHADER_VERTEX:
     38    case MESA_SHADER_GEOMETRY:
     39       switch (out->data.location) {
     40       case VARYING_SLOT_COL0:
     41       case VARYING_SLOT_COL1:
     42       case VARYING_SLOT_BFC0:
     43       case VARYING_SLOT_BFC1:
     44          return true;
     45       default:
     46          return false;
     47       }
     48       break;
     49    case MESA_SHADER_FRAGMENT:
     50       switch (out->data.location) {
     51       case FRAG_RESULT_COLOR:
     52          return true;
     53       default:
     54          return false;
     55       }
     56       break;
     57    default:
     58       return false;
     59    }
     60 }
     61 
     62 static void
     63 lower_intrinsic(lower_state *state, nir_intrinsic_instr *intr)
     64 {
     65    nir_variable *out = NULL;
     66    nir_builder *b = &state->b;
     67    nir_ssa_def *s;
     68 
     69    switch (intr->intrinsic) {
     70    case nir_intrinsic_store_var:
     71       out = intr->variables[0]->var;
     72       break;
     73    case nir_intrinsic_store_output:
     74       /* already had i/o lowered.. lookup the matching output var: */
     75       nir_foreach_variable(var, &state->shader->outputs) {
     76          int drvloc = var->data.driver_location;
     77          if (nir_intrinsic_base(intr) == drvloc) {
     78             out = var;
     79             break;
     80          }
     81       }
     82       assume(out);
     83       break;
     84    default:
     85       return;
     86    }
     87 
     88    if (out->data.mode != nir_var_shader_out)
     89       return;
     90 
     91    if (is_color_output(state, out)) {
     92       b->cursor = nir_before_instr(&intr->instr);
     93       s = nir_ssa_for_src(b, intr->src[0], intr->num_components);
     94       s = nir_fsat(b, s);
     95       nir_instr_rewrite_src(&intr->instr, &intr->src[0], nir_src_for_ssa(s));
     96    }
     97 }
     98 
     99 static bool
    100 lower_block(lower_state *state, nir_block *block)
    101 {
    102    nir_foreach_instr_safe(instr, block) {
    103       if (instr->type == nir_instr_type_intrinsic)
    104          lower_intrinsic(state, nir_instr_as_intrinsic(instr));
    105    }
    106 
    107    return true;
    108 }
    109 static void
    110 lower_impl(lower_state *state, nir_function_impl *impl)
    111 {
    112    nir_builder_init(&state->b, impl);
    113 
    114    nir_foreach_block(block, impl) {
    115       lower_block(state, block);
    116    }
    117    nir_metadata_preserve(impl, nir_metadata_block_index |
    118                                nir_metadata_dominance);
    119 }
    120 
    121 void nir_lower_clamp_color_outputs(nir_shader *shader)
    122 {
    123    lower_state state = {
    124       .shader = shader,
    125    };
    126 
    127    nir_foreach_function(function, shader) {
    128       if (function->impl)
    129          lower_impl(&state, function->impl);
    130    }
    131 }
    132