1 /*
2 * Copyright (C) 2018 Alyssa Rosenzweig
3 * Copyright (C) 2019-2021 Collabora, Ltd.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
24
25 #include "pan_blend.h"
26
27 #ifdef PAN_ARCH
28 #include "pan_shader.h"
29 #endif
30
31 #include "pan_texture.h"
32 #include "panfrost/util/pan_lower_framebuffer.h"
33 #include "util/format/u_format.h"
34 #include "compiler/nir/nir.h"
35 #include "compiler/nir/nir_builder.h"
36 #include "compiler/nir/nir_conversion_builder.h"
37 #include "compiler/nir/nir_lower_blend.h"
38
39 #ifndef PAN_ARCH
40
41 /* Fixed function blending */
42
43 static bool
factor_is_supported(enum blend_factor factor)44 factor_is_supported(enum blend_factor factor)
45 {
46 return factor != BLEND_FACTOR_SRC_ALPHA_SATURATE &&
47 factor != BLEND_FACTOR_SRC1_COLOR &&
48 factor != BLEND_FACTOR_SRC1_ALPHA;
49 }
50
51 /* OpenGL allows encoding (src*dest + dest*src) which is incompatiblle with
52 * Midgard style blending since there are two multiplies. However, it may be
53 * factored as 2*src*dest = dest*(2*src), which can be encoded on Bifrost as 0
54 * + dest * (2*src) wih the new source_2 value of C. Detect this case. */
55
56 static bool
is_2srcdest(enum blend_func blend_func,enum blend_factor src_factor,bool invert_src,enum blend_factor dest_factor,bool invert_dest,bool is_alpha)57 is_2srcdest(enum blend_func blend_func,
58 enum blend_factor src_factor,
59 bool invert_src,
60 enum blend_factor dest_factor,
61 bool invert_dest,
62 bool is_alpha)
63 {
64 return (blend_func == BLEND_FUNC_ADD) &&
65 ((src_factor == BLEND_FACTOR_DST_COLOR) ||
66 ((src_factor == BLEND_FACTOR_DST_ALPHA) && is_alpha)) &&
67 ((dest_factor == BLEND_FACTOR_SRC_COLOR) ||
68 ((dest_factor == BLEND_FACTOR_SRC_ALPHA) && is_alpha)) &&
69 !invert_src && !invert_dest;
70 }
71
72 static bool
can_fixed_function_equation(enum blend_func blend_func,enum blend_factor src_factor,bool invert_src,enum blend_factor dest_factor,bool invert_dest,bool is_alpha,bool supports_2src)73 can_fixed_function_equation(enum blend_func blend_func,
74 enum blend_factor src_factor,
75 bool invert_src,
76 enum blend_factor dest_factor,
77 bool invert_dest,
78 bool is_alpha,
79 bool supports_2src)
80 {
81 if (is_2srcdest(blend_func, src_factor, invert_src,
82 dest_factor, invert_dest, is_alpha)) {
83
84 return supports_2src;
85 }
86
87 if (blend_func != BLEND_FUNC_ADD &&
88 blend_func != BLEND_FUNC_SUBTRACT &&
89 blend_func != BLEND_FUNC_REVERSE_SUBTRACT)
90 return false;
91
92 if (!factor_is_supported(src_factor) ||
93 !factor_is_supported(dest_factor))
94 return false;
95
96 if (src_factor != dest_factor &&
97 src_factor != BLEND_FACTOR_ZERO &&
98 dest_factor != BLEND_FACTOR_ZERO)
99 return false;
100
101 return true;
102 }
103
104 static unsigned
blend_factor_constant_mask(enum blend_factor factor)105 blend_factor_constant_mask(enum blend_factor factor)
106 {
107 if (factor == BLEND_FACTOR_CONSTANT_COLOR)
108 return 0b0111; /* RGB */
109 else if (factor == BLEND_FACTOR_CONSTANT_ALPHA)
110 return 0b1000; /* A */
111 else
112 return 0b0000; /* - */
113 }
114
115 unsigned
pan_blend_constant_mask(const struct pan_blend_equation eq)116 pan_blend_constant_mask(const struct pan_blend_equation eq)
117 {
118 return blend_factor_constant_mask(eq.rgb_src_factor) |
119 blend_factor_constant_mask(eq.rgb_dst_factor) |
120 blend_factor_constant_mask(eq.alpha_src_factor) |
121 blend_factor_constant_mask(eq.alpha_dst_factor);
122 }
123
124 /* Only "homogenous" (scalar or vector with all components equal) constants are
125 * valid for fixed-function, so check for this condition */
126
127 bool
pan_blend_is_homogenous_constant(unsigned mask,const float * constants)128 pan_blend_is_homogenous_constant(unsigned mask, const float *constants)
129 {
130 float constant = pan_blend_get_constant(mask, constants);
131
132 u_foreach_bit(i, mask) {
133 if (constants[i] != constant)
134 return false;
135 }
136
137 return true;
138 }
139
140 /* Determines if an equation can run in fixed function */
141
142 bool
pan_blend_can_fixed_function(const struct pan_blend_equation equation,bool supports_2src)143 pan_blend_can_fixed_function(const struct pan_blend_equation equation,
144 bool supports_2src)
145 {
146 return !equation.blend_enable ||
147 (can_fixed_function_equation(equation.rgb_func,
148 equation.rgb_src_factor,
149 equation.rgb_invert_src_factor,
150 equation.rgb_dst_factor,
151 equation.rgb_invert_dst_factor,
152 false, supports_2src) &&
153 can_fixed_function_equation(equation.alpha_func,
154 equation.alpha_src_factor,
155 equation.alpha_invert_src_factor,
156 equation.alpha_dst_factor,
157 equation.alpha_invert_dst_factor,
158 true, supports_2src));
159 }
160
161 static enum mali_blend_operand_c
to_c_factor(enum blend_factor factor)162 to_c_factor(enum blend_factor factor)
163 {
164 switch (factor) {
165 case BLEND_FACTOR_ZERO:
166 return MALI_BLEND_OPERAND_C_ZERO;
167
168 case BLEND_FACTOR_SRC_ALPHA:
169 return MALI_BLEND_OPERAND_C_SRC_ALPHA;
170
171 case BLEND_FACTOR_DST_ALPHA:
172 return MALI_BLEND_OPERAND_C_DEST_ALPHA;
173
174 case BLEND_FACTOR_SRC_COLOR:
175 return MALI_BLEND_OPERAND_C_SRC;
176
177 case BLEND_FACTOR_DST_COLOR:
178 return MALI_BLEND_OPERAND_C_DEST;
179
180 case BLEND_FACTOR_CONSTANT_COLOR:
181 case BLEND_FACTOR_CONSTANT_ALPHA:
182 return MALI_BLEND_OPERAND_C_CONSTANT;
183
184 default:
185 unreachable("Unsupported blend factor");
186 }
187 }
188
189 static void
to_panfrost_function(enum blend_func blend_func,enum blend_factor src_factor,bool invert_src,enum blend_factor dest_factor,bool invert_dest,bool is_alpha,struct MALI_BLEND_FUNCTION * function)190 to_panfrost_function(enum blend_func blend_func,
191 enum blend_factor src_factor,
192 bool invert_src,
193 enum blend_factor dest_factor,
194 bool invert_dest,
195 bool is_alpha,
196 struct MALI_BLEND_FUNCTION *function)
197 {
198 assert(can_fixed_function_equation(blend_func, src_factor, invert_src,
199 dest_factor, invert_dest, is_alpha, true));
200
201 if (src_factor == BLEND_FACTOR_ZERO && !invert_src) {
202 function->a = MALI_BLEND_OPERAND_A_ZERO;
203 function->b = MALI_BLEND_OPERAND_B_DEST;
204 if (blend_func == BLEND_FUNC_SUBTRACT)
205 function->negate_b = true;
206 function->invert_c = invert_dest;
207 function->c = to_c_factor(dest_factor);
208 } else if (src_factor == BLEND_FACTOR_ZERO && invert_src) {
209 function->a = MALI_BLEND_OPERAND_A_SRC;
210 function->b = MALI_BLEND_OPERAND_B_DEST;
211 if (blend_func == BLEND_FUNC_SUBTRACT)
212 function->negate_b = true;
213 else if (blend_func == BLEND_FUNC_REVERSE_SUBTRACT)
214 function->negate_a = true;
215 function->invert_c = invert_dest;
216 function->c = to_c_factor(dest_factor);
217 } else if (dest_factor == BLEND_FACTOR_ZERO && !invert_dest) {
218 function->a = MALI_BLEND_OPERAND_A_ZERO;
219 function->b = MALI_BLEND_OPERAND_B_SRC;
220 if (blend_func == BLEND_FUNC_REVERSE_SUBTRACT)
221 function->negate_b = true;
222 function->invert_c = invert_src;
223 function->c = to_c_factor(src_factor);
224 } else if (dest_factor == BLEND_FACTOR_ZERO && invert_dest) {
225 function->a = MALI_BLEND_OPERAND_A_DEST;
226 function->b = MALI_BLEND_OPERAND_B_SRC;
227 if (blend_func == BLEND_FUNC_SUBTRACT)
228 function->negate_a = true;
229 else if (blend_func == BLEND_FUNC_REVERSE_SUBTRACT)
230 function->negate_b = true;
231 function->invert_c = invert_src;
232 function->c = to_c_factor(src_factor);
233 } else if (src_factor == dest_factor && invert_src == invert_dest) {
234 function->a = MALI_BLEND_OPERAND_A_ZERO;
235 function->invert_c = invert_src;
236 function->c = to_c_factor(src_factor);
237
238 switch (blend_func) {
239 case BLEND_FUNC_ADD:
240 function->b = MALI_BLEND_OPERAND_B_SRC_PLUS_DEST;
241 break;
242 case BLEND_FUNC_REVERSE_SUBTRACT:
243 function->negate_b = true;
244 FALLTHROUGH;
245 case BLEND_FUNC_SUBTRACT:
246 function->b = MALI_BLEND_OPERAND_B_SRC_MINUS_DEST;
247 break;
248 default:
249 unreachable("Invalid blend function");
250 }
251 } else if (is_2srcdest(blend_func, src_factor, invert_src, dest_factor,
252 invert_dest, is_alpha)) {
253 /* src*dest + dest*src = 2*src*dest = 0 + dest*(2*src) */
254 function->a = MALI_BLEND_OPERAND_A_ZERO;
255 function->b = MALI_BLEND_OPERAND_B_DEST;
256 function->c = MALI_BLEND_OPERAND_C_SRC_X_2;
257 } else {
258 assert(src_factor == dest_factor && invert_src != invert_dest);
259
260 function->a = MALI_BLEND_OPERAND_A_DEST;
261 function->invert_c = invert_src;
262 function->c = to_c_factor(src_factor);
263
264 switch (blend_func) {
265 case BLEND_FUNC_ADD:
266 function->b = MALI_BLEND_OPERAND_B_SRC_MINUS_DEST;
267 break;
268 case BLEND_FUNC_REVERSE_SUBTRACT:
269 function->b = MALI_BLEND_OPERAND_B_SRC_PLUS_DEST;
270 function->negate_b = true;
271 break;
272 case BLEND_FUNC_SUBTRACT:
273 function->b = MALI_BLEND_OPERAND_B_SRC_PLUS_DEST;
274 function->negate_a = true;
275 break;
276 default:
277 unreachable("Invalid blend function\n");
278 }
279 }
280 }
281
282 bool
pan_blend_is_opaque(const struct pan_blend_equation equation)283 pan_blend_is_opaque(const struct pan_blend_equation equation)
284 {
285 /* If a channel is masked out, we can't use opaque mode even if
286 * blending is disabled, since we need a tilebuffer read in there */
287 if (equation.color_mask != 0xF)
288 return false;
289
290 /* With nothing masked out, disabled bledning is opaque */
291 if (!equation.blend_enable)
292 return true;
293
294 /* Also detect open-coded opaque blending */
295 return equation.rgb_src_factor == BLEND_FACTOR_ZERO &&
296 equation.rgb_invert_src_factor &&
297 equation.rgb_dst_factor == BLEND_FACTOR_ZERO &&
298 !equation.rgb_invert_dst_factor &&
299 (equation.rgb_func == BLEND_FUNC_ADD ||
300 equation.rgb_func == BLEND_FUNC_SUBTRACT) &&
301 equation.alpha_src_factor == BLEND_FACTOR_ZERO &&
302 equation.alpha_invert_src_factor &&
303 equation.alpha_dst_factor == BLEND_FACTOR_ZERO &&
304 !equation.alpha_invert_dst_factor &&
305 (equation.alpha_func == BLEND_FUNC_ADD ||
306 equation.alpha_func == BLEND_FUNC_SUBTRACT);
307 }
308
309 static bool
is_dest_factor(enum blend_factor factor,bool alpha)310 is_dest_factor(enum blend_factor factor, bool alpha)
311 {
312 return factor == BLEND_FACTOR_DST_ALPHA ||
313 factor == BLEND_FACTOR_DST_COLOR ||
314 (factor == BLEND_FACTOR_SRC_ALPHA_SATURATE && !alpha);
315 }
316
317 /* Determines if a blend equation reads back the destination. This can occur by
318 * explicitly referencing the destination in the blend equation, or by using a
319 * partial writemask. */
320
321 bool
pan_blend_reads_dest(const struct pan_blend_equation equation)322 pan_blend_reads_dest(const struct pan_blend_equation equation)
323 {
324 return (equation.color_mask && equation.color_mask != 0xF) ||
325 is_dest_factor(equation.rgb_src_factor, false) ||
326 is_dest_factor(equation.alpha_src_factor, true) ||
327 equation.rgb_dst_factor != BLEND_FACTOR_ZERO ||
328 equation.rgb_invert_dst_factor ||
329 equation.alpha_dst_factor != BLEND_FACTOR_ZERO ||
330 equation.alpha_invert_dst_factor;
331 }
332
333 /* Create the descriptor for a fixed blend mode given the corresponding API
334 * state. Assumes the equation can be represented as fixed-function. */
335
336 void
pan_blend_to_fixed_function_equation(const struct pan_blend_equation equation,struct MALI_BLEND_EQUATION * out)337 pan_blend_to_fixed_function_equation(const struct pan_blend_equation equation,
338 struct MALI_BLEND_EQUATION *out)
339 {
340 /* If no blending is enabled, default back on `replace` mode */
341 if (!equation.blend_enable) {
342 out->color_mask = equation.color_mask;
343 out->rgb.a = MALI_BLEND_OPERAND_A_SRC;
344 out->rgb.b = MALI_BLEND_OPERAND_B_SRC;
345 out->rgb.c = MALI_BLEND_OPERAND_C_ZERO;
346 out->alpha.a = MALI_BLEND_OPERAND_A_SRC;
347 out->alpha.b = MALI_BLEND_OPERAND_B_SRC;
348 out->alpha.c = MALI_BLEND_OPERAND_C_ZERO;
349 return;
350 }
351
352 /* Compile the fixed-function blend */
353 to_panfrost_function(equation.rgb_func,
354 equation.rgb_src_factor,
355 equation.rgb_invert_src_factor,
356 equation.rgb_dst_factor,
357 equation.rgb_invert_dst_factor,
358 false, &out->rgb);
359
360 to_panfrost_function(equation.alpha_func,
361 equation.alpha_src_factor,
362 equation.alpha_invert_src_factor,
363 equation.alpha_dst_factor,
364 equation.alpha_invert_dst_factor,
365 true, &out->alpha);
366 out->color_mask = equation.color_mask;
367 }
368
369 uint32_t
pan_pack_blend(const struct pan_blend_equation equation)370 pan_pack_blend(const struct pan_blend_equation equation)
371 {
372 STATIC_ASSERT(sizeof(uint32_t) == MALI_BLEND_EQUATION_LENGTH);
373
374 uint32_t out = 0;
375
376 pan_pack(&out, BLEND_EQUATION, cfg) {
377 pan_blend_to_fixed_function_equation(equation, &cfg);
378 }
379
380 return out;
381 }
382
pan_blend_shader_key_hash(const void * key)383 static uint32_t pan_blend_shader_key_hash(const void *key)
384 {
385 return _mesa_hash_data(key, sizeof(struct pan_blend_shader_key));
386 }
387
pan_blend_shader_key_equal(const void * a,const void * b)388 static bool pan_blend_shader_key_equal(const void *a, const void *b)
389 {
390 return !memcmp(a, b, sizeof(struct pan_blend_shader_key));
391 }
392
393 void
pan_blend_shaders_init(struct panfrost_device * dev)394 pan_blend_shaders_init(struct panfrost_device *dev)
395 {
396 dev->blend_shaders.shaders =
397 _mesa_hash_table_create(NULL, pan_blend_shader_key_hash,
398 pan_blend_shader_key_equal);
399 pthread_mutex_init(&dev->blend_shaders.lock, NULL);
400 }
401
402 void
pan_blend_shaders_cleanup(struct panfrost_device * dev)403 pan_blend_shaders_cleanup(struct panfrost_device *dev)
404 {
405 _mesa_hash_table_destroy(dev->blend_shaders.shaders, NULL);
406 }
407
408 #else /* ifndef PAN_ARCH */
409
410 static const char *
logicop_str(enum pipe_logicop logicop)411 logicop_str(enum pipe_logicop logicop)
412 {
413 switch (logicop) {
414 case PIPE_LOGICOP_CLEAR: return "clear";
415 case PIPE_LOGICOP_NOR: return "nor";
416 case PIPE_LOGICOP_AND_INVERTED: return "and-inverted";
417 case PIPE_LOGICOP_COPY_INVERTED: return "copy-inverted";
418 case PIPE_LOGICOP_AND_REVERSE: return "and-reverse";
419 case PIPE_LOGICOP_INVERT: return "invert";
420 case PIPE_LOGICOP_XOR: return "xor";
421 case PIPE_LOGICOP_NAND: return "nand";
422 case PIPE_LOGICOP_AND: return "and";
423 case PIPE_LOGICOP_EQUIV: return "equiv";
424 case PIPE_LOGICOP_NOOP: return "noop";
425 case PIPE_LOGICOP_OR_INVERTED: return "or-inverted";
426 case PIPE_LOGICOP_COPY: return "copy";
427 case PIPE_LOGICOP_OR_REVERSE: return "or-reverse";
428 case PIPE_LOGICOP_OR: return "or";
429 case PIPE_LOGICOP_SET: return "set";
430 default: unreachable("Invalid logicop\n");
431 }
432 }
433
434 static void
get_equation_str(const struct pan_blend_rt_state * rt_state,char * str,unsigned len)435 get_equation_str(const struct pan_blend_rt_state *rt_state,
436 char *str, unsigned len)
437 {
438 const char *funcs[] = {
439 "add", "sub", "reverse_sub", "min", "max",
440 };
441 const char *factors[] = {
442 "zero", "src_color", "src1_color", "dst_color",
443 "src_alpha", "src1_alpha", "dst_alpha",
444 "const_color", "const_alpha", "src_alpha_sat",
445 };
446 int ret;
447
448 if (!rt_state->equation.blend_enable) {
449 ret = snprintf(str, len, "replace");
450 assert(ret > 0);
451 return;
452 }
453
454 if (rt_state->equation.color_mask & 7) {
455 assert(rt_state->equation.rgb_func < ARRAY_SIZE(funcs));
456 assert(rt_state->equation.rgb_src_factor < ARRAY_SIZE(factors));
457 assert(rt_state->equation.rgb_dst_factor < ARRAY_SIZE(factors));
458 ret = snprintf(str, len, "%s%s%s(func=%s,src_factor=%s%s,dst_factor=%s%s)%s",
459 (rt_state->equation.color_mask & 1) ? "R" : "",
460 (rt_state->equation.color_mask & 2) ? "G" : "",
461 (rt_state->equation.color_mask & 4) ? "B" : "",
462 funcs[rt_state->equation.rgb_func],
463 rt_state->equation.rgb_invert_src_factor ? "-" : "",
464 factors[rt_state->equation.rgb_src_factor],
465 rt_state->equation.rgb_invert_dst_factor ? "-" : "",
466 factors[rt_state->equation.rgb_dst_factor],
467 rt_state->equation.color_mask & 8 ? ";" : "");
468 assert(ret > 0);
469 str += ret;
470 len -= ret;
471 }
472
473 if (rt_state->equation.color_mask & 8) {
474 assert(rt_state->equation.alpha_func < ARRAY_SIZE(funcs));
475 assert(rt_state->equation.alpha_src_factor < ARRAY_SIZE(factors));
476 assert(rt_state->equation.alpha_dst_factor < ARRAY_SIZE(factors));
477 ret = snprintf(str, len, "A(func=%s,src_factor=%s%s,dst_factor=%s%s)",
478 funcs[rt_state->equation.alpha_func],
479 rt_state->equation.alpha_invert_src_factor ? "-" : "",
480 factors[rt_state->equation.alpha_src_factor],
481 rt_state->equation.alpha_invert_dst_factor ? "-" : "",
482 factors[rt_state->equation.alpha_dst_factor]);
483 assert(ret > 0);
484 str += ret;
485 len -= ret;
486 }
487 }
488
489 static bool
pan_inline_blend_constants(nir_builder * b,nir_instr * instr,void * data)490 pan_inline_blend_constants(nir_builder *b, nir_instr *instr, void *data)
491 {
492 if (instr->type != nir_instr_type_intrinsic)
493 return false;
494
495 nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
496 if (intr->intrinsic != nir_intrinsic_load_blend_const_color_rgba)
497 return false;
498
499 float *floats = data;
500 const nir_const_value constants[4] = {
501 { .f32 = floats[0] },
502 { .f32 = floats[1] },
503 { .f32 = floats[2] },
504 { .f32 = floats[3] }
505 };
506
507 b->cursor = nir_after_instr(instr);
508 nir_ssa_def *constant = nir_build_imm(b, 4, 32, constants);
509 nir_ssa_def_rewrite_uses(&intr->dest.ssa, constant);
510 nir_instr_remove(instr);
511 return true;
512 }
513
514 nir_shader *
GENX(pan_blend_create_shader)515 GENX(pan_blend_create_shader)(const struct panfrost_device *dev,
516 const struct pan_blend_state *state,
517 nir_alu_type src0_type,
518 nir_alu_type src1_type,
519 unsigned rt)
520 {
521 const struct pan_blend_rt_state *rt_state = &state->rts[rt];
522 char equation_str[128] = { 0 };
523
524 get_equation_str(rt_state, equation_str, sizeof(equation_str));
525
526 nir_builder b =
527 nir_builder_init_simple_shader(MESA_SHADER_FRAGMENT,
528 GENX(pan_shader_get_compiler_options)(),
529 "pan_blend(rt=%d,fmt=%s,nr_samples=%d,%s=%s)",
530 rt, util_format_name(rt_state->format),
531 rt_state->nr_samples,
532 state->logicop_enable ? "logicop" : "equation",
533 state->logicop_enable ?
534 logicop_str(state->logicop_func) : equation_str);
535
536 const struct util_format_description *format_desc =
537 util_format_description(rt_state->format);
538 nir_alu_type nir_type = pan_unpacked_type_for_format(format_desc);
539 enum glsl_base_type glsl_type = nir_get_glsl_base_type_for_nir_type(nir_type);
540
541 nir_lower_blend_options options = {
542 .logicop_enable = state->logicop_enable,
543 .logicop_func = state->logicop_func,
544 .rt[0].colormask = rt_state->equation.color_mask,
545 .format[0] = rt_state->format
546 };
547
548 if (!rt_state->equation.blend_enable) {
549 static const nir_lower_blend_channel replace = {
550 .func = BLEND_FUNC_ADD,
551 .src_factor = BLEND_FACTOR_ZERO,
552 .invert_src_factor = true,
553 .dst_factor = BLEND_FACTOR_ZERO,
554 .invert_dst_factor = false,
555 };
556
557 options.rt[0].rgb = replace;
558 options.rt[0].alpha = replace;
559 } else {
560 options.rt[0].rgb.func = rt_state->equation.rgb_func;
561 options.rt[0].rgb.src_factor = rt_state->equation.rgb_src_factor;
562 options.rt[0].rgb.invert_src_factor = rt_state->equation.rgb_invert_src_factor;
563 options.rt[0].rgb.dst_factor = rt_state->equation.rgb_dst_factor;
564 options.rt[0].rgb.invert_dst_factor = rt_state->equation.rgb_invert_dst_factor;
565 options.rt[0].alpha.func = rt_state->equation.alpha_func;
566 options.rt[0].alpha.src_factor = rt_state->equation.alpha_src_factor;
567 options.rt[0].alpha.invert_src_factor = rt_state->equation.alpha_invert_src_factor;
568 options.rt[0].alpha.dst_factor = rt_state->equation.alpha_dst_factor;
569 options.rt[0].alpha.invert_dst_factor = rt_state->equation.alpha_invert_dst_factor;
570 }
571
572 nir_alu_type src_types[] = { src0_type ?: nir_type_float32, src1_type ?: nir_type_float32 };
573
574 /* HACK: workaround buggy TGSI shaders (u_blitter) */
575 for (unsigned i = 0; i < ARRAY_SIZE(src_types); ++i) {
576 src_types[i] = nir_alu_type_get_base_type(nir_type) |
577 nir_alu_type_get_type_size(src_types[i]);
578 }
579
580 nir_variable *c_src =
581 nir_variable_create(b.shader, nir_var_shader_in,
582 glsl_vector_type(nir_get_glsl_base_type_for_nir_type(src_types[0]), 4),
583 "gl_Color");
584 c_src->data.location = VARYING_SLOT_COL0;
585 nir_variable *c_src1 =
586 nir_variable_create(b.shader, nir_var_shader_in,
587 glsl_vector_type(nir_get_glsl_base_type_for_nir_type(src_types[1]), 4),
588 "gl_Color1");
589 c_src1->data.location = VARYING_SLOT_VAR0;
590 c_src1->data.driver_location = 1;
591 nir_variable *c_out =
592 nir_variable_create(b.shader, nir_var_shader_out,
593 glsl_vector_type(glsl_type, 4),
594 "gl_FragColor");
595 c_out->data.location = FRAG_RESULT_DATA0;
596
597 nir_ssa_def *s_src[] = {nir_load_var(&b, c_src), nir_load_var(&b, c_src1)};
598
599 /* Saturate integer conversions */
600 for (int i = 0; i < ARRAY_SIZE(s_src); ++i) {
601 nir_alu_type T = nir_alu_type_get_base_type(nir_type);
602 s_src[i] = nir_convert_with_rounding(&b, s_src[i],
603 src_types[i], nir_type,
604 nir_rounding_mode_undef,
605 T != nir_type_float);
606 }
607
608 /* Build a trivial blend shader */
609 nir_store_var(&b, c_out, s_src[0], 0xFF);
610
611 options.src1 = s_src[1];
612
613 NIR_PASS_V(b.shader, nir_lower_blend, options);
614 nir_shader_instructions_pass(b.shader, pan_inline_blend_constants,
615 nir_metadata_block_index | nir_metadata_dominance,
616 (void *) state->constants);
617
618 return b.shader;
619 }
620
621 #if PAN_ARCH >= 6
622 uint64_t
GENX(pan_blend_get_internal_desc)623 GENX(pan_blend_get_internal_desc)(const struct panfrost_device *dev,
624 enum pipe_format fmt, unsigned rt,
625 unsigned force_size, bool dithered)
626 {
627 const struct util_format_description *desc = util_format_description(fmt);
628 uint64_t res;
629
630 pan_pack(&res, INTERNAL_BLEND, cfg) {
631 cfg.mode = MALI_BLEND_MODE_OPAQUE;
632 cfg.fixed_function.num_comps = desc->nr_channels;
633 cfg.fixed_function.rt = rt;
634
635 nir_alu_type T = pan_unpacked_type_for_format(desc);
636
637 if (force_size)
638 T = nir_alu_type_get_base_type(T) | force_size;
639
640 switch (T) {
641 case nir_type_float16:
642 cfg.fixed_function.conversion.register_format =
643 MALI_REGISTER_FILE_FORMAT_F16;
644 break;
645 case nir_type_float32:
646 cfg.fixed_function.conversion.register_format =
647 MALI_REGISTER_FILE_FORMAT_F32;
648 break;
649 case nir_type_int8:
650 case nir_type_int16:
651 cfg.fixed_function.conversion.register_format =
652 MALI_REGISTER_FILE_FORMAT_I16;
653 break;
654 case nir_type_int32:
655 cfg.fixed_function.conversion.register_format =
656 MALI_REGISTER_FILE_FORMAT_I32;
657 break;
658 case nir_type_uint8:
659 case nir_type_uint16:
660 cfg.fixed_function.conversion.register_format =
661 MALI_REGISTER_FILE_FORMAT_U16;
662 break;
663 case nir_type_uint32:
664 cfg.fixed_function.conversion.register_format =
665 MALI_REGISTER_FILE_FORMAT_U32;
666 break;
667 default:
668 unreachable("Invalid format");
669 }
670
671 cfg.fixed_function.conversion.memory_format =
672 panfrost_format_to_bifrost_blend(dev, fmt, dithered);
673 }
674
675 return res;
676 }
677 #endif
678
679 struct pan_blend_shader_variant *
GENX(pan_blend_get_shader_locked)680 GENX(pan_blend_get_shader_locked)(const struct panfrost_device *dev,
681 const struct pan_blend_state *state,
682 nir_alu_type src0_type,
683 nir_alu_type src1_type,
684 unsigned rt)
685 {
686 struct pan_blend_shader_key key = {
687 .format = state->rts[rt].format,
688 .src0_type = src0_type,
689 .src1_type = src1_type,
690 .rt = rt,
691 .has_constants = pan_blend_constant_mask(state->rts[rt].equation) != 0,
692 .logicop_enable = state->logicop_enable,
693 .logicop_func = state->logicop_func,
694 .nr_samples = state->rts[rt].nr_samples,
695 .equation = state->rts[rt].equation,
696 };
697
698 struct hash_entry *he = _mesa_hash_table_search(dev->blend_shaders.shaders, &key);
699 struct pan_blend_shader *shader = he ? he->data : NULL;
700
701 if (!shader) {
702 shader = rzalloc(dev->blend_shaders.shaders, struct pan_blend_shader);
703 shader->key = key;
704 list_inithead(&shader->variants);
705 _mesa_hash_table_insert(dev->blend_shaders.shaders, &shader->key, shader);
706 }
707
708 list_for_each_entry(struct pan_blend_shader_variant, iter,
709 &shader->variants, node) {
710 if (!key.has_constants ||
711 !memcmp(iter->constants, state->constants, sizeof(iter->constants))) {
712 return iter;
713 }
714 }
715
716 struct pan_blend_shader_variant *variant = NULL;
717
718 if (shader->nvariants < PAN_BLEND_SHADER_MAX_VARIANTS) {
719 variant = rzalloc(shader, struct pan_blend_shader_variant);
720 memcpy(variant->constants, state->constants, sizeof(variant->constants));
721 util_dynarray_init(&variant->binary, variant);
722 list_add(&variant->node, &shader->variants);
723 shader->nvariants++;
724 } else {
725 variant = list_last_entry(&shader->variants, struct pan_blend_shader_variant, node);
726 list_del(&variant->node);
727 list_add(&variant->node, &shader->variants);
728 util_dynarray_clear(&variant->binary);
729 }
730
731 nir_shader *nir =
732 GENX(pan_blend_create_shader)(dev, state, src0_type, src1_type, rt);
733
734 /* Compile the NIR shader */
735 struct panfrost_compile_inputs inputs = {
736 .gpu_id = dev->gpu_id,
737 .is_blend = true,
738 .blend.rt = shader->key.rt,
739 .blend.nr_samples = key.nr_samples,
740 .rt_formats = { key.format },
741 };
742
743 #if PAN_ARCH >= 6
744 inputs.blend.bifrost_blend_desc =
745 GENX(pan_blend_get_internal_desc)(dev, key.format, key.rt, 0, false);
746 #endif
747
748 struct pan_shader_info info;
749
750 GENX(pan_shader_compile)(nir, &inputs, &variant->binary, &info);
751
752 variant->work_reg_count = info.work_reg_count;
753
754 #if PAN_ARCH <= 5
755 variant->first_tag = info.midgard.first_tag;
756 #endif
757
758 ralloc_free(nir);
759
760 return variant;
761 }
762 #endif /* ifndef PAN_ARCH */
763