From e13ed3ffb4d5267e7b79eece448abf1db1438ea1 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Thu, 17 Sep 2015 13:17:08 -0400 Subject: [PATCH] nir: add two-sided-color lowering pass Signed-off-by: Rob Clark Reviewed-by: Eric Anholt --- src/glsl/Makefile.sources | 1 + src/glsl/nir/nir.h | 2 + src/glsl/nir/nir_lower_two_sided_color.c | 208 +++++++++++++++++++++++ 3 files changed, 211 insertions(+) create mode 100644 src/glsl/nir/nir_lower_two_sided_color.c diff --git a/src/glsl/Makefile.sources b/src/glsl/Makefile.sources index b539b45e432..1aaa062adea 100644 --- a/src/glsl/Makefile.sources +++ b/src/glsl/Makefile.sources @@ -47,6 +47,7 @@ NIR_FILES = \ nir/nir_lower_system_values.c \ nir/nir_lower_tex.c \ nir/nir_lower_to_source_mods.c \ + nir/nir_lower_two_sided_color.c \ nir/nir_lower_vars_to_ssa.c \ nir/nir_lower_var_copies.c \ nir/nir_lower_vec_to_movs.c \ diff --git a/src/glsl/nir/nir.h b/src/glsl/nir/nir.h index 255d45585db..63b0b514c50 100644 --- a/src/glsl/nir/nir.h +++ b/src/glsl/nir/nir.h @@ -1878,6 +1878,8 @@ void nir_lower_idiv(nir_shader *shader); void nir_lower_clip_vs(nir_shader *shader, unsigned ucp_enables); void nir_lower_clip_fs(nir_shader *shader, unsigned ucp_enables); +void nir_lower_two_sided_color(nir_shader *shader); + void nir_lower_atomics(nir_shader *shader); void nir_lower_to_source_mods(nir_shader *shader); diff --git a/src/glsl/nir/nir_lower_two_sided_color.c b/src/glsl/nir/nir_lower_two_sided_color.c new file mode 100644 index 00000000000..131feef90af --- /dev/null +++ b/src/glsl/nir/nir_lower_two_sided_color.c @@ -0,0 +1,208 @@ +/* + * Copyright © 2015 Red Hat + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Authors: + * Rob Clark + */ + +#include "nir.h" +#include "nir_builder.h" + +#define MAX_COLORS 2 /* VARYING_SLOT_COL0/COL1 */ + +typedef struct { + nir_builder b; + nir_shader *shader; + nir_variable *face; + struct { + nir_variable *front; /* COLn */ + nir_variable *back; /* BFCn */ + } colors[MAX_COLORS]; + int colors_count; +} lower_2side_state; + + +/* Lowering pass for fragment shaders to emulated two-sided-color. For + * each COLOR input, a corresponding BCOLOR input is created, and bcsel + * instruction used to select front or back color based on FACE. + */ + +static nir_variable * +create_input(nir_shader *shader, unsigned drvloc, gl_varying_slot slot) +{ + nir_variable *var = rzalloc(shader, nir_variable); + + var->data.driver_location = drvloc; + var->type = glsl_vec4_type(); + var->data.mode = nir_var_shader_in; + var->name = ralloc_asprintf(var, "in_%d", drvloc); + var->data.index = 0; + var->data.location = slot; + + exec_list_push_tail(&shader->inputs, &var->node); + + return var; +} + +static nir_ssa_def * +load_input(nir_builder *b, nir_variable *in) +{ + nir_intrinsic_instr *load; + + load = nir_intrinsic_instr_create(b->shader, nir_intrinsic_load_input); + load->num_components = 4; + load->const_index[0] = in->data.driver_location; + nir_ssa_dest_init(&load->instr, &load->dest, 4, NULL); + nir_builder_instr_insert(b, &load->instr); + + return &load->dest.ssa; +} + +static int +setup_inputs(lower_2side_state *state) +{ + int maxloc = -1; + + /* find color/face inputs: */ + foreach_list_typed(nir_variable, var, node, &state->shader->inputs) { + int loc = var->data.driver_location; + + /* keep track of last used driver-location.. we'll be + * appending BCLr/FACE after last existing input: + */ + maxloc = MAX2(maxloc, loc); + + switch (var->data.location) { + case VARYING_SLOT_COL0: + case VARYING_SLOT_COL1: + assert(state->colors_count < ARRAY_SIZE(state->colors)); + state->colors[state->colors_count].front = var; + state->colors_count++; + break; + case VARYING_SLOT_FACE: + state->face = var; + break; + } + } + + /* if we don't have any color inputs, nothing to do: */ + if (state->colors_count == 0) + return -1; + + /* if we don't already have one, insert a FACE input: */ + if (!state->face) { + state->face = create_input(state->shader, ++maxloc, VARYING_SLOT_FACE); + state->face->data.interpolation = INTERP_QUALIFIER_FLAT; + } + + /* add required back-face color inputs: */ + for (int i = 0; i < state->colors_count; i++) { + gl_varying_slot slot; + + if (state->colors[i].front->data.location == VARYING_SLOT_COL0) + slot = VARYING_SLOT_BFC0; + else + slot = VARYING_SLOT_BFC1; + + state->colors[i].back = create_input(state->shader, ++maxloc, slot); + } + + return 0; +} + +static bool +nir_lower_two_sided_color_block(nir_block *block, void *void_state) +{ + lower_2side_state *state = void_state; + nir_builder *b = &state->b; + + nir_foreach_instr_safe(block, instr) { + if (instr->type != nir_instr_type_intrinsic) + continue; + + nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr); + + if (intr->intrinsic != nir_intrinsic_load_input) + continue; + + int idx; + for (idx = 0; idx < state->colors_count; idx++) { + unsigned drvloc = + state->colors[idx].front->data.driver_location; + if (intr->const_index[0] == drvloc) { + break; + } + } + + if (idx == state->colors_count) + continue; + + /* replace load_input(COLn) with + * bcsel(load_input(FACE), load_input(COLn), load_input(BFCn)) + */ + b->cursor = nir_before_instr(&intr->instr); + nir_ssa_def *face = nir_channel(b, load_input(b, state->face), 0); + nir_ssa_def *front = load_input(b, state->colors[idx].front); + nir_ssa_def *back = load_input(b, state->colors[idx].back); + nir_ssa_def *cond = nir_flt(b, face, nir_imm_float(b, 0.0)); + nir_ssa_def *color = nir_bcsel(b, cond, back, front); + + assert(intr->dest.is_ssa); + nir_ssa_def_rewrite_uses(&intr->dest.ssa, nir_src_for_ssa(color)); + } + + return true; +} + +static void +nir_lower_two_sided_color_impl(nir_function_impl *impl, + lower_2side_state *state) +{ + nir_builder *b = &state->b; + + nir_builder_init(b, impl); + + nir_foreach_block(impl, nir_lower_two_sided_color_block, state); + + nir_metadata_preserve(impl, nir_metadata_block_index | + nir_metadata_dominance); +} + +void +nir_lower_two_sided_color(nir_shader *shader) +{ + lower_2side_state state = { + .shader = shader, + }; + + if (shader->stage != MESA_SHADER_FRAGMENT) + return; + + if (setup_inputs(&state) != 0) + return; + + nir_foreach_overload(shader, overload) { + if (overload->impl) + nir_lower_two_sided_color_impl(overload->impl, &state); + } + +} -- 2.30.2