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
,
50 enum glsl_interp_mode interpolation
)
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
;
60 var
->data
.interpolation
= interpolation
;
62 exec_list_push_tail(&shader
->inputs
, &var
->node
);
64 shader
->num_inputs
++; /* TODO use type_size() */
70 load_input(nir_builder
*b
, nir_variable
*in
)
72 nir_intrinsic_instr
*load
;
74 load
= nir_intrinsic_instr_create(b
->shader
, nir_intrinsic_load_input
);
75 load
->num_components
= 4;
76 nir_intrinsic_set_base(load
, in
->data
.driver_location
);
77 load
->src
[0] = nir_src_for_ssa(nir_imm_int(b
, 0));
78 nir_ssa_dest_init(&load
->instr
, &load
->dest
, 4, 32, NULL
);
79 nir_builder_instr_insert(b
, &load
->instr
);
81 return &load
->dest
.ssa
;
85 setup_inputs(lower_2side_state
*state
)
89 /* find color inputs: */
90 nir_foreach_variable(var
, &state
->shader
->inputs
) {
91 int loc
= var
->data
.driver_location
;
93 /* keep track of last used driver-location.. we'll be
94 * appending BCLr after last existing input:
96 maxloc
= MAX2(maxloc
, loc
);
98 switch (var
->data
.location
) {
99 case VARYING_SLOT_COL0
:
100 case VARYING_SLOT_COL1
:
101 assert(state
->colors_count
< ARRAY_SIZE(state
->colors
));
102 state
->colors
[state
->colors_count
].front
= var
;
103 state
->colors_count
++;
108 /* if we don't have any color inputs, nothing to do: */
109 if (state
->colors_count
== 0)
112 /* add required back-face color inputs: */
113 for (int i
= 0; i
< state
->colors_count
; i
++) {
114 gl_varying_slot slot
;
116 if (state
->colors
[i
].front
->data
.location
== VARYING_SLOT_COL0
)
117 slot
= VARYING_SLOT_BFC0
;
119 slot
= VARYING_SLOT_BFC1
;
121 state
->colors
[i
].back
= create_input(
122 state
->shader
, ++maxloc
, slot
,
123 state
->colors
[i
].front
->data
.interpolation
);
130 nir_lower_two_sided_color_block(nir_block
*block
,
131 lower_2side_state
*state
)
133 nir_builder
*b
= &state
->b
;
135 nir_foreach_instr_safe(instr
, block
) {
136 if (instr
->type
!= nir_instr_type_intrinsic
)
139 nir_intrinsic_instr
*intr
= nir_instr_as_intrinsic(instr
);
141 if (intr
->intrinsic
!= nir_intrinsic_load_input
)
145 for (idx
= 0; idx
< state
->colors_count
; idx
++) {
147 state
->colors
[idx
].front
->data
.driver_location
;
148 if (nir_intrinsic_base(intr
) == drvloc
) {
149 assert(nir_src_is_const(intr
->src
[0]));
154 if (idx
== state
->colors_count
)
157 /* replace load_input(COLn) with
158 * bcsel(load_system_value(FACE), load_input(COLn), load_input(BFCn))
160 b
->cursor
= nir_before_instr(&intr
->instr
);
161 /* gl_FrontFace is a boolean but the intrinsic constructor creates
162 * 32-bit value by default.
164 nir_ssa_def
*face
= nir_load_front_face(b
, 1);
165 nir_ssa_def
*front
= load_input(b
, state
->colors
[idx
].front
);
166 nir_ssa_def
*back
= load_input(b
, state
->colors
[idx
].back
);
167 nir_ssa_def
*color
= nir_bcsel(b
, face
, front
, back
);
169 assert(intr
->dest
.is_ssa
);
170 nir_ssa_def_rewrite_uses(&intr
->dest
.ssa
, nir_src_for_ssa(color
));
177 nir_lower_two_sided_color_impl(nir_function_impl
*impl
,
178 lower_2side_state
*state
)
180 nir_builder
*b
= &state
->b
;
182 nir_builder_init(b
, impl
);
184 nir_foreach_block(block
, impl
) {
185 nir_lower_two_sided_color_block(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
->info
.stage
!= MESA_SHADER_FRAGMENT
)
202 if (setup_inputs(&state
) != 0)
205 nir_foreach_function(function
, shader
) {
207 nir_lower_two_sided_color_impl(function
->impl
, &state
);