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 */
36 nir_variable
*front
; /* COLn */
37 nir_variable
*back
; /* BFCn */
43 /* Lowering pass for fragment shaders to emulated two-sided-color. For
44 * each COLOR input, a corresponding BCOLOR input is created, and bcsel
45 * instruction used to select front or back color based on FACE.
49 create_input(nir_shader
*shader
, gl_varying_slot slot
,
50 enum glsl_interp_mode interpolation
)
52 nir_variable
*var
= rzalloc(shader
, nir_variable
);
54 var
->data
.driver_location
= shader
->num_inputs
++;
55 var
->type
= glsl_vec4_type();
56 var
->data
.mode
= nir_var_shader_in
;
57 var
->name
= ralloc_asprintf(var
, "in_%d", var
->data
.driver_location
);
59 var
->data
.location
= slot
;
60 var
->data
.interpolation
= interpolation
;
62 exec_list_push_tail(&shader
->inputs
, &var
->node
);
68 load_input(nir_builder
*b
, nir_variable
*in
)
70 nir_intrinsic_instr
*load
;
72 load
= nir_intrinsic_instr_create(b
->shader
, nir_intrinsic_load_input
);
73 load
->num_components
= 4;
74 nir_intrinsic_set_base(load
, in
->data
.driver_location
);
75 load
->src
[0] = nir_src_for_ssa(nir_imm_int(b
, 0));
76 nir_ssa_dest_init(&load
->instr
, &load
->dest
, 4, 32, NULL
);
77 nir_builder_instr_insert(b
, &load
->instr
);
79 return &load
->dest
.ssa
;
83 setup_inputs(lower_2side_state
*state
)
85 /* find color inputs: */
86 nir_foreach_variable(var
, &state
->shader
->inputs
) {
87 switch (var
->data
.location
) {
88 case VARYING_SLOT_COL0
:
89 case VARYING_SLOT_COL1
:
90 assert(state
->colors_count
< ARRAY_SIZE(state
->colors
));
91 state
->colors
[state
->colors_count
].front
= var
;
92 state
->colors_count
++;
97 /* if we don't have any color inputs, nothing to do: */
98 if (state
->colors_count
== 0)
101 /* add required back-face color inputs: */
102 for (int i
= 0; i
< state
->colors_count
; i
++) {
103 gl_varying_slot slot
;
105 if (state
->colors
[i
].front
->data
.location
== VARYING_SLOT_COL0
)
106 slot
= VARYING_SLOT_BFC0
;
108 slot
= VARYING_SLOT_BFC1
;
110 state
->colors
[i
].back
= create_input(
112 state
->colors
[i
].front
->data
.interpolation
);
119 nir_lower_two_sided_color_block(nir_block
*block
,
120 lower_2side_state
*state
)
122 nir_builder
*b
= &state
->b
;
124 nir_foreach_instr_safe(instr
, block
) {
125 if (instr
->type
!= nir_instr_type_intrinsic
)
128 nir_intrinsic_instr
*intr
= nir_instr_as_intrinsic(instr
);
131 if (intr
->intrinsic
== nir_intrinsic_load_input
) {
132 for (idx
= 0; idx
< state
->colors_count
; idx
++) {
134 state
->colors
[idx
].front
->data
.driver_location
;
135 if (nir_intrinsic_base(intr
) == drvloc
) {
136 assert(nir_src_is_const(intr
->src
[0]));
140 } else if (intr
->intrinsic
== nir_intrinsic_load_deref
) {
141 nir_variable
*var
= nir_intrinsic_get_var(intr
, 0);
142 if (var
->data
.mode
!= nir_var_shader_in
)
145 for (idx
= 0; idx
< state
->colors_count
; idx
++) {
146 unsigned loc
= state
->colors
[idx
].front
->data
.location
;
147 if (var
->data
.location
== loc
)
153 if (idx
== state
->colors_count
)
156 /* replace load_input(COLn) with
157 * bcsel(load_system_value(FACE), load_input(COLn), load_input(BFCn))
159 b
->cursor
= nir_before_instr(&intr
->instr
);
160 /* gl_FrontFace is a boolean but the intrinsic constructor creates
161 * 32-bit value by default.
163 nir_ssa_def
*face
= nir_load_front_face(b
, 1);
164 nir_ssa_def
*front
, *back
;
165 if (intr
->intrinsic
== nir_intrinsic_load_deref
) {
166 front
= nir_load_var(b
, state
->colors
[idx
].front
);
167 back
= nir_load_var(b
, state
->colors
[idx
].back
);
169 front
= load_input(b
, state
->colors
[idx
].front
);
170 back
= load_input(b
, state
->colors
[idx
].back
);
172 nir_ssa_def
*color
= nir_bcsel(b
, face
, front
, back
);
174 assert(intr
->dest
.is_ssa
);
175 nir_ssa_def_rewrite_uses(&intr
->dest
.ssa
, nir_src_for_ssa(color
));
182 nir_lower_two_sided_color_impl(nir_function_impl
*impl
,
183 lower_2side_state
*state
)
185 nir_builder
*b
= &state
->b
;
187 nir_builder_init(b
, impl
);
189 nir_foreach_block(block
, impl
) {
190 nir_lower_two_sided_color_block(block
, state
);
193 nir_metadata_preserve(impl
, nir_metadata_block_index
|
194 nir_metadata_dominance
);
198 nir_lower_two_sided_color(nir_shader
*shader
, bool face_sysval
)
200 lower_2side_state state
= {
204 if (shader
->info
.stage
!= MESA_SHADER_FRAGMENT
)
207 if (setup_inputs(&state
) != 0)
210 nir_foreach_function(function
, shader
) {
212 nir_lower_two_sided_color_impl(function
->impl
, &state
);