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
, unsigned drvloc
, gl_varying_slot slot
)
51 nir_variable
*var
= rzalloc(shader
, nir_variable
);
53 var
->data
.driver_location
= drvloc
;
54 var
->type
= glsl_vec4_type();
55 var
->data
.mode
= nir_var_shader_in
;
56 var
->name
= ralloc_asprintf(var
, "in_%d", drvloc
);
58 var
->data
.location
= slot
;
60 exec_list_push_tail(&shader
->inputs
, &var
->node
);
62 shader
->num_inputs
++; /* TODO use type_size() */
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
)
87 /* find color 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 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
++;
106 /* if we don't have any color inputs, nothing to do: */
107 if (state
->colors_count
== 0)
110 /* add required back-face color inputs: */
111 for (int i
= 0; i
< state
->colors_count
; i
++) {
112 gl_varying_slot slot
;
114 if (state
->colors
[i
].front
->data
.location
== VARYING_SLOT_COL0
)
115 slot
= VARYING_SLOT_BFC0
;
117 slot
= VARYING_SLOT_BFC1
;
119 state
->colors
[i
].back
= create_input(state
->shader
, ++maxloc
, slot
);
126 nir_lower_two_sided_color_block(nir_block
*block
,
127 lower_2side_state
*state
)
129 nir_builder
*b
= &state
->b
;
131 nir_foreach_instr_safe(instr
, block
) {
132 if (instr
->type
!= nir_instr_type_intrinsic
)
135 nir_intrinsic_instr
*intr
= nir_instr_as_intrinsic(instr
);
137 if (intr
->intrinsic
!= nir_intrinsic_load_input
)
141 for (idx
= 0; idx
< state
->colors_count
; idx
++) {
143 state
->colors
[idx
].front
->data
.driver_location
;
144 if (nir_intrinsic_base(intr
) == drvloc
) {
145 assert(nir_src_as_const_value(intr
->src
[0]));
150 if (idx
== state
->colors_count
)
153 /* replace load_input(COLn) with
154 * bcsel(load_system_value(FACE), load_input(COLn), load_input(BFCn))
156 b
->cursor
= nir_before_instr(&intr
->instr
);
157 nir_ssa_def
*face
= nir_load_system_value(b
,
158 nir_intrinsic_load_front_face
,
160 nir_ssa_def
*front
= load_input(b
, state
->colors
[idx
].front
);
161 nir_ssa_def
*back
= load_input(b
, state
->colors
[idx
].back
);
162 nir_ssa_def
*color
= nir_bcsel(b
, face
, front
, back
);
164 assert(intr
->dest
.is_ssa
);
165 nir_ssa_def_rewrite_uses(&intr
->dest
.ssa
, nir_src_for_ssa(color
));
172 nir_lower_two_sided_color_impl(nir_function_impl
*impl
,
173 lower_2side_state
*state
)
175 nir_builder
*b
= &state
->b
;
177 nir_builder_init(b
, impl
);
179 nir_foreach_block(block
, impl
) {
180 nir_lower_two_sided_color_block(block
, state
);
183 nir_metadata_preserve(impl
, nir_metadata_block_index
|
184 nir_metadata_dominance
);
188 nir_lower_two_sided_color(nir_shader
*shader
)
190 lower_2side_state state
= {
194 if (shader
->stage
!= MESA_SHADER_FRAGMENT
)
197 if (setup_inputs(&state
) != 0)
200 nir_foreach_function(function
, shader
) {
202 nir_lower_two_sided_color_impl(function
->impl
, &state
);