2 * Copyright (C) 2019 Alyssa Rosenzweig
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
27 * Implements the fragment pipeline (blending and writeout) in software, to be
28 * run as a dedicated "blend shader" stage on Midgard/Bifrost, or as a fragment
29 * shader variant on typical GPUs. This pass is useful if hardware lacks
30 * fixed-function blending in part or in full.
33 #include "compiler/nir/nir.h"
34 #include "compiler/nir/nir_builder.h"
35 #include "compiler/nir/nir_format_convert.h"
36 #include "nir_lower_blend.h"
38 /* Given processed factors, combine them per a blend function */
44 nir_ssa_def
*src
, nir_ssa_def
*dst
)
48 return nir_fadd(b
, src
, dst
);
49 case BLEND_FUNC_SUBTRACT
:
50 return nir_fsub(b
, src
, dst
);
51 case BLEND_FUNC_REVERSE_SUBTRACT
:
52 return nir_fsub(b
, dst
, src
);
54 return nir_fmin(b
, src
, dst
);
56 return nir_fmax(b
, src
, dst
);
59 unreachable("Invalid blend function");
62 /* Does this blend function multiply by a blend factor? */
65 nir_blend_factored(enum blend_func func
)
69 case BLEND_FUNC_SUBTRACT
:
70 case BLEND_FUNC_REVERSE_SUBTRACT
:
77 /* Compute a src_alpha_saturate factor */
81 nir_ssa_def
*src
, nir_ssa_def
*dst
,
85 nir_ssa_def
*Asrc
= nir_channel(b
, src
, 3);
86 nir_ssa_def
*Adst
= nir_channel(b
, dst
, 3);
87 nir_ssa_def
*one
= half
? nir_imm_float16(b
, 1.0) : nir_imm_float(b
, 1.0);
88 nir_ssa_def
*Adsti
= nir_fsub(b
, one
, Adst
);
90 return (chan
< 3) ? nir_fmin(b
, Asrc
, Adsti
) : one
;
93 /* Returns a scalar single factor, unmultiplied */
96 nir_blend_factor_value(
98 nir_ssa_def
*src
, nir_ssa_def
*dst
, nir_ssa_def
*bconst
,
100 enum blend_factor factor
,
104 case BLEND_FACTOR_ZERO
:
105 return half
? nir_imm_float16(b
, 0.0) : nir_imm_float(b
, 0.0);
106 case BLEND_FACTOR_SRC_COLOR
:
107 return nir_channel(b
, src
, chan
);
108 case BLEND_FACTOR_DST_COLOR
:
109 return nir_channel(b
, dst
, chan
);
110 case BLEND_FACTOR_SRC_ALPHA
:
111 return nir_channel(b
, src
, 3);
112 case BLEND_FACTOR_DST_ALPHA
:
113 return nir_channel(b
, dst
, 3);
114 case BLEND_FACTOR_CONSTANT_COLOR
:
115 return nir_channel(b
, bconst
, chan
);
116 case BLEND_FACTOR_CONSTANT_ALPHA
:
117 return nir_channel(b
, bconst
, 3);
118 case BLEND_FACTOR_SRC_ALPHA_SATURATE
:
119 return nir_alpha_saturate(b
, src
, dst
, chan
, half
);
122 unreachable("Invalid blend factor");
128 nir_ssa_def
*raw_scalar
,
129 nir_ssa_def
*src
, nir_ssa_def
*dst
, nir_ssa_def
*bconst
,
131 enum blend_factor factor
,
136 nir_blend_factor_value(b
, src
, dst
, bconst
, chan
, factor
, half
);
138 nir_ssa_def
*unity
= half
? nir_imm_float16(b
, 1.0) : nir_imm_float(b
, 1.0);
141 f
= nir_fsub(b
, unity
, f
);
143 return nir_fmul(b
, raw_scalar
, f
);
146 /* Given a colormask, "blend" with the destination */
155 nir_ssa_def
*masked
[4];
157 for (unsigned c
= 0; c
< 4; ++c
) {
158 bool enab
= (mask
& (1 << c
));
159 masked
[c
] = enab
? nir_channel(b
, src
, c
) : nir_channel(b
, dst
, c
);
162 return nir_vec(b
, masked
, 4);
169 nir_ssa_def
*src
, nir_ssa_def
*dst
)
172 case PIPE_LOGICOP_CLEAR
:
173 return nir_imm_ivec4(b
, 0, 0, 0, 0);
174 case PIPE_LOGICOP_NOR
:
175 return nir_inot(b
, nir_ior(b
, src
, dst
));
176 case PIPE_LOGICOP_AND_INVERTED
:
177 return nir_iand(b
, nir_inot(b
, src
), dst
);
178 case PIPE_LOGICOP_COPY_INVERTED
:
179 return nir_inot(b
, src
);
180 case PIPE_LOGICOP_AND_REVERSE
:
181 return nir_iand(b
, src
, nir_inot(b
, dst
));
182 case PIPE_LOGICOP_INVERT
:
183 return nir_inot(b
, dst
);
184 case PIPE_LOGICOP_XOR
:
185 return nir_ixor(b
, src
, dst
);
186 case PIPE_LOGICOP_NAND
:
187 return nir_inot(b
, nir_iand(b
, src
, dst
));
188 case PIPE_LOGICOP_AND
:
189 return nir_iand(b
, src
, dst
);
190 case PIPE_LOGICOP_EQUIV
:
191 return nir_inot(b
, nir_ixor(b
, src
, dst
));
192 case PIPE_LOGICOP_NOOP
:
194 case PIPE_LOGICOP_OR_INVERTED
:
195 return nir_ior(b
, nir_inot(b
, src
), dst
);
196 case PIPE_LOGICOP_COPY
:
198 case PIPE_LOGICOP_OR_REVERSE
:
199 return nir_ior(b
, src
, nir_inot(b
, dst
));
200 case PIPE_LOGICOP_OR
:
201 return nir_ior(b
, src
, dst
);
202 case PIPE_LOGICOP_SET
:
203 return nir_imm_ivec4(b
, ~0, ~0, ~0, ~0);
206 unreachable("Invalid logciop function");
212 nir_lower_blend_options options
,
213 nir_ssa_def
*src
, nir_ssa_def
*dst
)
215 const struct util_format_description
*format_desc
=
216 util_format_description(options
.format
);
219 src
= nir_f2f32(b
, src
);
220 dst
= nir_f2f32(b
, dst
);
223 assert(src
->num_components
<= 4);
224 assert(dst
->num_components
<= 4);
227 for (int i
= 0; i
< 4; ++i
)
228 bits
[i
] = format_desc
->channel
[i
].size
;
230 src
= nir_format_float_to_unorm(b
, src
, bits
);
231 dst
= nir_format_float_to_unorm(b
, dst
, bits
);
233 nir_ssa_def
*out
= nir_logicop_func(b
, options
.logicop_func
, src
, dst
);
236 nir_const_value mask
[4];
237 for (int i
= 0; i
< 4; ++i
)
238 mask
[i
] = nir_const_value_for_int((1u << bits
[i
]) - 1, 32);
240 out
= nir_iand(b
, out
, nir_build_imm(b
, 4, 32, mask
));
243 out
= nir_format_unorm_to_float(b
, out
, bits
);
246 out
= nir_f2f16(b
, out
);
251 /* Given a blend state, the source color, and the destination color,
252 * return the blended color
258 nir_lower_blend_options options
,
259 nir_ssa_def
*src
, nir_ssa_def
*dst
)
261 if (options
.logicop_enable
)
262 return nir_blend_logicop(b
, options
, src
, dst
);
264 /* Grab the blend constant ahead of time */
265 nir_ssa_def
*bconst
= nir_load_blend_const_color_rgba(b
);
268 bconst
= nir_f2f16(b
, bconst
);
270 /* We blend per channel and recombine later */
271 nir_ssa_def
*channels
[4];
273 for (unsigned c
= 0; c
< 4; ++c
) {
274 /* Decide properties based on channel */
275 nir_lower_blend_channel chan
=
276 (c
< 3) ? options
.rgb
: options
.alpha
;
278 nir_ssa_def
*psrc
= nir_channel(b
, src
, c
);
279 nir_ssa_def
*pdst
= nir_channel(b
, dst
, c
);
281 if (nir_blend_factored(chan
.func
)) {
282 psrc
= nir_blend_factor(
285 chan
.src_factor
, chan
.invert_src_factor
, options
.half
);
287 pdst
= nir_blend_factor(
290 chan
.dst_factor
, chan
.invert_dst_factor
, options
.half
);
293 channels
[c
] = nir_blend_func(b
, chan
.func
, psrc
, pdst
);
296 /* Then just recombine with an applied colormask */
297 nir_ssa_def
*blended
= nir_vec(b
, channels
, 4);
298 return nir_color_mask(b
, options
.colormask
, blended
, dst
);
302 nir_is_blend_channel_replace(nir_lower_blend_channel chan
)
305 (chan
.src_factor
== BLEND_FACTOR_ZERO
) &&
306 (chan
.dst_factor
== BLEND_FACTOR_ZERO
) &&
307 (chan
.invert_src_factor
&& !chan
.invert_dst_factor
) &&
308 (chan
.func
== BLEND_FUNC_ADD
|| chan
.func
== BLEND_FUNC_SUBTRACT
|| chan
.func
== BLEND_FUNC_MAX
);
312 nir_is_blend_replace(nir_lower_blend_options options
)
315 nir_is_blend_channel_replace(options
.rgb
) &&
316 nir_is_blend_channel_replace(options
.alpha
);
320 nir_lower_blend(nir_shader
*shader
, nir_lower_blend_options options
)
322 /* Blend shaders are represented as special fragment shaders */
323 assert(shader
->info
.stage
== MESA_SHADER_FRAGMENT
);
325 /* Special case replace, since there's nothing to do and we don't want to
326 * degrade intermediate precision (e.g. for non-blendable R32F targets) */
327 if (nir_is_blend_replace(options
))
330 nir_foreach_function(func
, shader
) {
331 nir_foreach_block(block
, func
->impl
) {
332 nir_foreach_instr_safe(instr
, block
) {
333 if (instr
->type
!= nir_instr_type_intrinsic
)
336 nir_intrinsic_instr
*intr
= nir_instr_as_intrinsic(instr
);
337 if (intr
->intrinsic
!= nir_intrinsic_store_deref
)
340 /* TODO: Extending to MRT */
341 nir_variable
*var
= nir_intrinsic_get_var(intr
, 0);
342 if (var
->data
.location
!= FRAG_RESULT_COLOR
)
346 nir_builder_init(&b
, func
->impl
);
347 b
.cursor
= nir_before_instr(instr
);
349 /* Grab the input color */
350 nir_ssa_def
*src
= nir_ssa_for_src(&b
, intr
->src
[1], 4);
352 /* Grab the tilebuffer color - io lowered to load_output */
353 nir_ssa_def
*dst
= nir_load_var(&b
, var
);
355 /* Blend the two colors per the passed options */
356 nir_ssa_def
*blended
= nir_blend(&b
, options
, src
, dst
);
358 /* Write out the final color instead of the input */
359 nir_instr_rewrite_src(instr
, &intr
->src
[1],
360 nir_src_for_ssa(blended
));
365 nir_metadata_preserve(func
->impl
, nir_metadata_block_index
|
366 nir_metadata_dominance
);