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