2 * Copyright © 2015 Red Hat
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:
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
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 DEALINGS
24 * Rob Clark <robclark@freedesktop.org>
28 #include "nir_builder.h"
30 #define MAX_COLORS 2 /* VARYING_SLOT_COL0/COL1 */
37 nir_variable
*front
; /* COLn */
38 nir_variable
*back
; /* BFCn */
44 /* Lowering pass for fragment shaders to emulated two-sided-color. For
45 * each COLOR input, a corresponding BCOLOR input is created, and bcsel
46 * instruction used to select front or back color based on FACE.
50 create_input(nir_shader
*shader
, unsigned drvloc
, gl_varying_slot slot
)
52 nir_variable
*var
= rzalloc(shader
, nir_variable
);
54 var
->data
.driver_location
= drvloc
;
55 var
->type
= glsl_vec4_type();
56 var
->data
.mode
= nir_var_shader_in
;
57 var
->name
= ralloc_asprintf(var
, "in_%d", drvloc
);
59 var
->data
.location
= slot
;
61 exec_list_push_tail(&shader
->inputs
, &var
->node
);
63 shader
->num_inputs
++; /* TODO use type_size() */
69 load_input(nir_builder
*b
, nir_variable
*in
)
71 nir_intrinsic_instr
*load
;
73 load
= nir_intrinsic_instr_create(b
->shader
, nir_intrinsic_load_input
);
74 load
->num_components
= 4;
75 load
->const_index
[0] = in
->data
.driver_location
;
76 nir_ssa_dest_init(&load
->instr
, &load
->dest
, 4, NULL
);
77 nir_builder_instr_insert(b
, &load
->instr
);
79 return &load
->dest
.ssa
;
83 setup_inputs(lower_2side_state
*state
)
87 /* find color/face inputs: */
88 nir_foreach_variable(var
, &state
->shader
->inputs
) {
89 int loc
= var
->data
.driver_location
;
91 /* keep track of last used driver-location.. we'll be
92 * appending BCLr/FACE after last existing input:
94 maxloc
= MAX2(maxloc
, loc
);
96 switch (var
->data
.location
) {
97 case VARYING_SLOT_COL0
:
98 case VARYING_SLOT_COL1
:
99 assert(state
->colors_count
< ARRAY_SIZE(state
->colors
));
100 state
->colors
[state
->colors_count
].front
= var
;
101 state
->colors_count
++;
103 case VARYING_SLOT_FACE
:
109 /* if we don't have any color inputs, nothing to do: */
110 if (state
->colors_count
== 0)
113 /* if we don't already have one, insert a FACE input: */
115 state
->face
= create_input(state
->shader
, ++maxloc
, VARYING_SLOT_FACE
);
116 state
->face
->data
.interpolation
= INTERP_QUALIFIER_FLAT
;
119 /* add required back-face color inputs: */
120 for (int i
= 0; i
< state
->colors_count
; i
++) {
121 gl_varying_slot slot
;
123 if (state
->colors
[i
].front
->data
.location
== VARYING_SLOT_COL0
)
124 slot
= VARYING_SLOT_BFC0
;
126 slot
= VARYING_SLOT_BFC1
;
128 state
->colors
[i
].back
= create_input(state
->shader
, ++maxloc
, slot
);
135 nir_lower_two_sided_color_block(nir_block
*block
, void *void_state
)
137 lower_2side_state
*state
= void_state
;
138 nir_builder
*b
= &state
->b
;
140 nir_foreach_instr_safe(block
, instr
) {
141 if (instr
->type
!= nir_instr_type_intrinsic
)
144 nir_intrinsic_instr
*intr
= nir_instr_as_intrinsic(instr
);
146 if (intr
->intrinsic
!= nir_intrinsic_load_input
)
150 for (idx
= 0; idx
< state
->colors_count
; idx
++) {
152 state
->colors
[idx
].front
->data
.driver_location
;
153 if (intr
->const_index
[0] == drvloc
) {
158 if (idx
== state
->colors_count
)
161 /* replace load_input(COLn) with
162 * bcsel(load_input(FACE), load_input(COLn), load_input(BFCn))
164 b
->cursor
= nir_before_instr(&intr
->instr
);
165 nir_ssa_def
*face
= nir_channel(b
, load_input(b
, state
->face
), 0);
166 nir_ssa_def
*front
= load_input(b
, state
->colors
[idx
].front
);
167 nir_ssa_def
*back
= load_input(b
, state
->colors
[idx
].back
);
168 nir_ssa_def
*cond
= nir_flt(b
, face
, nir_imm_float(b
, 0.0));
169 nir_ssa_def
*color
= nir_bcsel(b
, cond
, back
, front
);
171 assert(intr
->dest
.is_ssa
);
172 nir_ssa_def_rewrite_uses(&intr
->dest
.ssa
, nir_src_for_ssa(color
));
179 nir_lower_two_sided_color_impl(nir_function_impl
*impl
,
180 lower_2side_state
*state
)
182 nir_builder
*b
= &state
->b
;
184 nir_builder_init(b
, impl
);
186 nir_foreach_block(impl
, nir_lower_two_sided_color_block
, state
);
188 nir_metadata_preserve(impl
, nir_metadata_block_index
|
189 nir_metadata_dominance
);
193 nir_lower_two_sided_color(nir_shader
*shader
)
195 lower_2side_state state
= {
199 if (shader
->stage
!= MESA_SHADER_FRAGMENT
)
202 if (setup_inputs(&state
) != 0)
205 nir_foreach_overload(shader
, overload
) {
207 nir_lower_two_sided_color_impl(overload
->impl
, &state
);