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 */
45 /* Lowering pass for fragment shaders to emulated two-sided-color. For
46 * each COLOR input, a corresponding BCOLOR input is created, and bcsel
47 * instruction used to select front or back color based on FACE.
51 create_input(nir_shader
*shader
, gl_varying_slot slot
,
52 enum glsl_interp_mode interpolation
)
54 nir_variable
*var
= nir_variable_create(shader
, nir_var_shader_in
,
55 glsl_vec4_type(), NULL
);
57 var
->data
.driver_location
= shader
->num_inputs
++;
58 var
->name
= ralloc_asprintf(var
, "in_%d", var
->data
.driver_location
);
60 var
->data
.location
= slot
;
61 var
->data
.interpolation
= interpolation
;
67 create_face_input(nir_shader
*shader
)
70 nir_find_variable_with_location(shader
, nir_var_shader_in
,
74 var
= nir_variable_create(shader
, nir_var_shader_in
,
75 glsl_bool_type(), "gl_FrontFacing");
77 var
->data
.driver_location
= shader
->num_inputs
++;
79 var
->data
.location
= VARYING_SLOT_FACE
;
80 var
->data
.interpolation
= INTERP_MODE_FLAT
;
87 load_input(nir_builder
*b
, nir_variable
*in
)
89 nir_intrinsic_instr
*load
;
91 load
= nir_intrinsic_instr_create(b
->shader
, nir_intrinsic_load_input
);
92 load
->num_components
= 4;
93 nir_intrinsic_set_base(load
, in
->data
.driver_location
);
94 load
->src
[0] = nir_src_for_ssa(nir_imm_int(b
, 0));
95 nir_ssa_dest_init(&load
->instr
, &load
->dest
, 4, 32, NULL
);
96 nir_builder_instr_insert(b
, &load
->instr
);
98 return &load
->dest
.ssa
;
102 setup_inputs(lower_2side_state
*state
)
104 /* find color inputs: */
105 nir_foreach_shader_in_variable(var
, state
->shader
) {
106 switch (var
->data
.location
) {
107 case VARYING_SLOT_COL0
:
108 case VARYING_SLOT_COL1
:
109 assert(state
->colors_count
< ARRAY_SIZE(state
->colors
));
110 state
->colors
[state
->colors_count
].front
= var
;
111 state
->colors_count
++;
116 /* if we don't have any color inputs, nothing to do: */
117 if (state
->colors_count
== 0)
120 /* add required back-face color inputs: */
121 for (int i
= 0; i
< state
->colors_count
; i
++) {
122 gl_varying_slot slot
;
124 if (state
->colors
[i
].front
->data
.location
== VARYING_SLOT_COL0
)
125 slot
= VARYING_SLOT_BFC0
;
127 slot
= VARYING_SLOT_BFC1
;
129 state
->colors
[i
].back
= create_input(
131 state
->colors
[i
].front
->data
.interpolation
);
134 if (!state
->face_sysval
)
135 state
->face
= create_face_input(state
->shader
);
141 nir_lower_two_sided_color_block(nir_block
*block
,
142 lower_2side_state
*state
)
144 nir_builder
*b
= &state
->b
;
146 nir_foreach_instr_safe(instr
, block
) {
147 if (instr
->type
!= nir_instr_type_intrinsic
)
150 nir_intrinsic_instr
*intr
= nir_instr_as_intrinsic(instr
);
153 if (intr
->intrinsic
== nir_intrinsic_load_input
) {
154 for (idx
= 0; idx
< state
->colors_count
; idx
++) {
156 state
->colors
[idx
].front
->data
.driver_location
;
157 if (nir_intrinsic_base(intr
) == drvloc
) {
158 assert(nir_src_is_const(intr
->src
[0]));
162 } else if (intr
->intrinsic
== nir_intrinsic_load_deref
) {
163 nir_variable
*var
= nir_intrinsic_get_var(intr
, 0);
164 if (var
->data
.mode
!= nir_var_shader_in
)
167 for (idx
= 0; idx
< state
->colors_count
; idx
++) {
168 unsigned loc
= state
->colors
[idx
].front
->data
.location
;
169 if (var
->data
.location
== loc
)
175 if (idx
== state
->colors_count
)
178 /* replace load_input(COLn) with
179 * bcsel(load_system_value(FACE), load_input(COLn), load_input(BFCn))
181 b
->cursor
= nir_before_instr(&intr
->instr
);
182 /* gl_FrontFace is a boolean but the intrinsic constructor creates
183 * 32-bit value by default.
186 if (state
->face_sysval
)
187 face
= nir_load_front_face(b
, 1);
189 face
= nir_load_var(b
, state
->face
);
191 nir_ssa_def
*front
, *back
;
192 if (intr
->intrinsic
== nir_intrinsic_load_deref
) {
193 front
= nir_load_var(b
, state
->colors
[idx
].front
);
194 back
= nir_load_var(b
, state
->colors
[idx
].back
);
196 front
= load_input(b
, state
->colors
[idx
].front
);
197 back
= load_input(b
, state
->colors
[idx
].back
);
199 nir_ssa_def
*color
= nir_bcsel(b
, face
, front
, back
);
201 assert(intr
->dest
.is_ssa
);
202 nir_ssa_def_rewrite_uses(&intr
->dest
.ssa
, nir_src_for_ssa(color
));
209 nir_lower_two_sided_color_impl(nir_function_impl
*impl
,
210 lower_2side_state
*state
)
212 nir_builder
*b
= &state
->b
;
214 nir_builder_init(b
, impl
);
216 nir_foreach_block(block
, impl
) {
217 nir_lower_two_sided_color_block(block
, state
);
220 nir_metadata_preserve(impl
, nir_metadata_block_index
|
221 nir_metadata_dominance
);
225 nir_lower_two_sided_color(nir_shader
*shader
, bool face_sysval
)
227 lower_2side_state state
= {
229 .face_sysval
= face_sysval
,
232 if (shader
->info
.stage
!= MESA_SHADER_FRAGMENT
)
235 if (setup_inputs(&state
) != 0)
238 nir_foreach_function(function
, shader
) {
240 nir_lower_two_sided_color_impl(function
->impl
, &state
);