• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 /* Check if (factor, invert) represents a constant value of val, assuming
310  * src_alpha is the given constant.
311  */
312 
313 static inline bool
is_factor_01(unsigned factor,bool invert,unsigned val,unsigned srca)314 is_factor_01(unsigned factor, bool invert, unsigned val, unsigned srca)
315 {
316         assert(val == 0 || val == 1);
317         assert(srca == 0 || srca == 1);
318 
319         return ((invert ^ !val) && factor == BLEND_FACTOR_ZERO) ||
320                ((invert ^ srca ^ !val) && factor == BLEND_FACTOR_SRC_ALPHA);
321 }
322 
323 /* Returns if src alpha = 0 implies the blended colour equals the destination
324  * colour. Suppose source alpha = 0 and consider cases.
325  *
326  * Additive blending: Equivalent to D = S * f_s + D * f_d for all D and all S
327  * with S_a = 0, for each component. For the alpha component (if it unmasked),
328  * we have S_a = 0 so this reduces to D = D * f_d <===> f_d = 1. For RGB
329  * components (if unmasked), we need f_s = 0 and f_d = 1.
330  *
331  * Subtractive blending: Fails in general (D = S * f_S - D * f_D). We
332  * would need f_S = 0 and f_D = -1, which is not valid in the APIs.
333  *
334  * Reverse subtractive blending (D = D * f_D - S * f_S), we need f_D = 1
335  * and f_S = 0 up to masking. This is the same as additive blending.
336  *
337  * Min/max: Fails in general on the RGB components.
338  */
339 
340 bool
pan_blend_alpha_zero_nop(const struct pan_blend_equation eq)341 pan_blend_alpha_zero_nop(const struct pan_blend_equation eq)
342 {
343         if (eq.rgb_func != BLEND_FUNC_ADD &&
344             eq.rgb_func != BLEND_FUNC_REVERSE_SUBTRACT)
345                 return false;
346 
347         if (eq.color_mask & 0x8) {
348                 if (!is_factor_01(eq.alpha_dst_factor, eq.alpha_invert_dst_factor, 1, 0))
349                         return false;
350         }
351 
352         if (eq.color_mask & 0x7) {
353                 if (!is_factor_01(eq.rgb_dst_factor, eq.rgb_invert_dst_factor, 1, 0))
354                         return false;
355 
356                 if (!is_factor_01(eq.rgb_src_factor, eq.rgb_invert_src_factor, 0, 0))
357                         return false;
358         }
359 
360         return true;
361 }
362 
363 /* Returns if src alpha = 1 implies the blended colour equals the source
364  * colour. Suppose source alpha = 1 and consider cases.
365  *
366  * Additive blending: S = S * f_s + D * f_d. We need f_s = 1 and f_d = 0.
367  *
368  * Subtractive blending: S = S * f_s - D * f_d. Same as additive blending.
369  *
370  * Reverse subtractive blending: S = D * f_d - S * f_s. Fails in general since
371  * it would require f_s = -1, which is not valid in the APIs.
372  *
373  * Min/max: Fails in general on the RGB components.
374  *
375  * Note if any component is masked, we can't use a store.
376  */
377 
378 bool
pan_blend_alpha_one_store(const struct pan_blend_equation eq)379 pan_blend_alpha_one_store(const struct pan_blend_equation eq)
380 {
381         if (eq.rgb_func != BLEND_FUNC_ADD &&
382             eq.rgb_func != BLEND_FUNC_SUBTRACT)
383                 return false;
384 
385         if (eq.color_mask != 0xf)
386                 return false;
387 
388         return is_factor_01(eq.rgb_src_factor, eq.rgb_invert_src_factor, 1, 1) &&
389                is_factor_01(eq.alpha_src_factor, eq.alpha_invert_src_factor, 1, 1) &&
390                is_factor_01(eq.rgb_dst_factor, eq.rgb_invert_dst_factor, 0, 1) &&
391                is_factor_01(eq.alpha_dst_factor, eq.alpha_invert_dst_factor, 0, 1);
392 }
393 
394 static bool
is_dest_factor(enum blend_factor factor,bool alpha)395 is_dest_factor(enum blend_factor factor, bool alpha)
396 {
397       return factor == BLEND_FACTOR_DST_ALPHA ||
398              factor == BLEND_FACTOR_DST_COLOR ||
399              (factor == BLEND_FACTOR_SRC_ALPHA_SATURATE && !alpha);
400 }
401 
402 /* Determines if a blend equation reads back the destination. This can occur by
403  * explicitly referencing the destination in the blend equation, or by using a
404  * partial writemask. */
405 
406 bool
pan_blend_reads_dest(const struct pan_blend_equation equation)407 pan_blend_reads_dest(const struct pan_blend_equation equation)
408 {
409         return (equation.color_mask && equation.color_mask != 0xF) ||
410                 is_dest_factor(equation.rgb_src_factor, false) ||
411                 is_dest_factor(equation.alpha_src_factor, true) ||
412                 equation.rgb_dst_factor != BLEND_FACTOR_ZERO ||
413                 equation.rgb_invert_dst_factor ||
414                 equation.alpha_dst_factor != BLEND_FACTOR_ZERO ||
415                 equation.alpha_invert_dst_factor;
416 }
417 
418 /* Create the descriptor for a fixed blend mode given the corresponding API
419  * state. Assumes the equation can be represented as fixed-function. */
420 
421 void
pan_blend_to_fixed_function_equation(const struct pan_blend_equation equation,struct MALI_BLEND_EQUATION * out)422 pan_blend_to_fixed_function_equation(const struct pan_blend_equation equation,
423                                      struct MALI_BLEND_EQUATION *out)
424 {
425         /* If no blending is enabled, default back on `replace` mode */
426         if (!equation.blend_enable) {
427                 out->color_mask = equation.color_mask;
428                 out->rgb.a = MALI_BLEND_OPERAND_A_SRC;
429                 out->rgb.b = MALI_BLEND_OPERAND_B_SRC;
430                 out->rgb.c = MALI_BLEND_OPERAND_C_ZERO;
431                 out->alpha.a = MALI_BLEND_OPERAND_A_SRC;
432                 out->alpha.b = MALI_BLEND_OPERAND_B_SRC;
433                 out->alpha.c = MALI_BLEND_OPERAND_C_ZERO;
434                 return;
435         }
436 
437         /* Compile the fixed-function blend */
438         to_panfrost_function(equation.rgb_func,
439                              equation.rgb_src_factor,
440                              equation.rgb_invert_src_factor,
441                              equation.rgb_dst_factor,
442                              equation.rgb_invert_dst_factor,
443                              false, &out->rgb);
444 
445         to_panfrost_function(equation.alpha_func,
446                              equation.alpha_src_factor,
447                              equation.alpha_invert_src_factor,
448                              equation.alpha_dst_factor,
449                              equation.alpha_invert_dst_factor,
450                              true, &out->alpha);
451         out->color_mask = equation.color_mask;
452 }
453 
454 uint32_t
pan_pack_blend(const struct pan_blend_equation equation)455 pan_pack_blend(const struct pan_blend_equation equation)
456 {
457         STATIC_ASSERT(sizeof(uint32_t) == MALI_BLEND_EQUATION_LENGTH);
458 
459         uint32_t out = 0;
460 
461         pan_pack(&out, BLEND_EQUATION, cfg) {
462                 pan_blend_to_fixed_function_equation(equation, &cfg);
463         }
464 
465         return out;
466 }
467 
pan_blend_shader_key_hash(const void * key)468 static uint32_t pan_blend_shader_key_hash(const void *key)
469 {
470         return _mesa_hash_data(key, sizeof(struct pan_blend_shader_key));
471 }
472 
pan_blend_shader_key_equal(const void * a,const void * b)473 static bool pan_blend_shader_key_equal(const void *a, const void *b)
474 {
475         return !memcmp(a, b, sizeof(struct pan_blend_shader_key));
476 }
477 
478 void
pan_blend_shaders_init(struct panfrost_device * dev)479 pan_blend_shaders_init(struct panfrost_device *dev)
480 {
481         dev->blend_shaders.shaders =
482                 _mesa_hash_table_create(NULL, pan_blend_shader_key_hash,
483                                         pan_blend_shader_key_equal);
484         pthread_mutex_init(&dev->blend_shaders.lock, NULL);
485 }
486 
487 void
pan_blend_shaders_cleanup(struct panfrost_device * dev)488 pan_blend_shaders_cleanup(struct panfrost_device *dev)
489 {
490         _mesa_hash_table_destroy(dev->blend_shaders.shaders, NULL);
491 }
492 
493 #else /* ifndef PAN_ARCH */
494 
495 static const char *
logicop_str(enum pipe_logicop logicop)496 logicop_str(enum pipe_logicop logicop)
497 {
498         switch (logicop) {
499         case PIPE_LOGICOP_CLEAR: return "clear";
500         case PIPE_LOGICOP_NOR: return "nor";
501         case PIPE_LOGICOP_AND_INVERTED: return "and-inverted";
502         case PIPE_LOGICOP_COPY_INVERTED: return "copy-inverted";
503         case PIPE_LOGICOP_AND_REVERSE: return "and-reverse";
504         case PIPE_LOGICOP_INVERT: return "invert";
505         case PIPE_LOGICOP_XOR: return "xor";
506         case PIPE_LOGICOP_NAND: return "nand";
507         case PIPE_LOGICOP_AND: return "and";
508         case PIPE_LOGICOP_EQUIV: return "equiv";
509         case PIPE_LOGICOP_NOOP: return "noop";
510         case PIPE_LOGICOP_OR_INVERTED: return "or-inverted";
511         case PIPE_LOGICOP_COPY: return "copy";
512         case PIPE_LOGICOP_OR_REVERSE: return "or-reverse";
513         case PIPE_LOGICOP_OR: return "or";
514         case PIPE_LOGICOP_SET: return "set";
515         default: unreachable("Invalid logicop\n");
516         }
517 }
518 
519 static void
get_equation_str(const struct pan_blend_rt_state * rt_state,char * str,unsigned len)520 get_equation_str(const struct pan_blend_rt_state *rt_state,
521                  char *str, unsigned len)
522 {
523         const char *funcs[] = {
524                 "add", "sub", "reverse_sub", "min", "max",
525         };
526         const char *factors[] = {
527                 "zero", "src_color", "src1_color", "dst_color",
528                 "src_alpha", "src1_alpha", "dst_alpha",
529                 "const_color", "const_alpha", "src_alpha_sat",
530         };
531         int ret;
532 
533         if (!rt_state->equation.blend_enable) {
534 		ret = snprintf(str, len, "replace");
535                 assert(ret > 0);
536                 return;
537         }
538 
539         if (rt_state->equation.color_mask & 7) {
540                 assert(rt_state->equation.rgb_func < ARRAY_SIZE(funcs));
541                 assert(rt_state->equation.rgb_src_factor < ARRAY_SIZE(factors));
542                 assert(rt_state->equation.rgb_dst_factor < ARRAY_SIZE(factors));
543                 ret = snprintf(str, len, "%s%s%s(func=%s,src_factor=%s%s,dst_factor=%s%s)%s",
544                                (rt_state->equation.color_mask & 1) ? "R" : "",
545                                (rt_state->equation.color_mask & 2) ? "G" : "",
546                                (rt_state->equation.color_mask & 4) ? "B" : "",
547                                funcs[rt_state->equation.rgb_func],
548                                rt_state->equation.rgb_invert_src_factor ? "-" : "",
549                                factors[rt_state->equation.rgb_src_factor],
550                                rt_state->equation.rgb_invert_dst_factor ? "-" : "",
551                                factors[rt_state->equation.rgb_dst_factor],
552                                rt_state->equation.color_mask & 8 ? ";" : "");
553                 assert(ret > 0);
554                 str += ret;
555                 len -= ret;
556          }
557 
558         if (rt_state->equation.color_mask & 8) {
559                 assert(rt_state->equation.alpha_func < ARRAY_SIZE(funcs));
560                 assert(rt_state->equation.alpha_src_factor < ARRAY_SIZE(factors));
561                 assert(rt_state->equation.alpha_dst_factor < ARRAY_SIZE(factors));
562                 ret = snprintf(str, len, "A(func=%s,src_factor=%s%s,dst_factor=%s%s)",
563                                funcs[rt_state->equation.alpha_func],
564                                rt_state->equation.alpha_invert_src_factor ? "-" : "",
565                                factors[rt_state->equation.alpha_src_factor],
566                                rt_state->equation.alpha_invert_dst_factor ? "-" : "",
567                                factors[rt_state->equation.alpha_dst_factor]);
568                 assert(ret > 0);
569                 str += ret;
570                 len -= ret;
571          }
572 }
573 
574 static bool
pan_inline_blend_constants(nir_builder * b,nir_instr * instr,void * data)575 pan_inline_blend_constants(nir_builder *b, nir_instr *instr, void *data)
576 {
577         if (instr->type != nir_instr_type_intrinsic)
578                 return false;
579 
580         nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
581         if (intr->intrinsic != nir_intrinsic_load_blend_const_color_rgba)
582                 return false;
583 
584         float *floats = data;
585         const nir_const_value constants[4] = {
586                 { .f32 = floats[0] },
587                 { .f32 = floats[1] },
588                 { .f32 = floats[2] },
589                 { .f32 = floats[3] }
590         };
591 
592         b->cursor = nir_after_instr(instr);
593         nir_ssa_def *constant = nir_build_imm(b, 4, 32, constants);
594         nir_ssa_def_rewrite_uses(&intr->dest.ssa, constant);
595         nir_instr_remove(instr);
596         return true;
597 }
598 
599 nir_shader *
GENX(pan_blend_create_shader)600 GENX(pan_blend_create_shader)(const struct panfrost_device *dev,
601                               const struct pan_blend_state *state,
602                               nir_alu_type src0_type,
603                               nir_alu_type src1_type,
604                               unsigned rt)
605 {
606         const struct pan_blend_rt_state *rt_state = &state->rts[rt];
607         char equation_str[128] = { 0 };
608 
609         get_equation_str(rt_state, equation_str, sizeof(equation_str));
610 
611         nir_builder b =
612                 nir_builder_init_simple_shader(MESA_SHADER_FRAGMENT,
613                                                GENX(pan_shader_get_compiler_options)(),
614                                                "pan_blend(rt=%d,fmt=%s,nr_samples=%d,%s=%s)",
615                                                rt, util_format_name(rt_state->format),
616                                                rt_state->nr_samples,
617                                                state->logicop_enable ? "logicop" : "equation",
618                                                state->logicop_enable ?
619                                                logicop_str(state->logicop_func) : equation_str);
620 
621         const struct util_format_description *format_desc =
622                 util_format_description(rt_state->format);
623         nir_alu_type nir_type = pan_unpacked_type_for_format(format_desc);
624         enum glsl_base_type glsl_type = nir_get_glsl_base_type_for_nir_type(nir_type);
625 
626         nir_lower_blend_options options = {
627                 .logicop_enable = state->logicop_enable,
628                 .logicop_func = state->logicop_func,
629                 .rt[0].colormask = rt_state->equation.color_mask,
630                 .format[0] = rt_state->format
631         };
632 
633         if (!rt_state->equation.blend_enable) {
634                 static const nir_lower_blend_channel replace = {
635                         .func = BLEND_FUNC_ADD,
636                         .src_factor = BLEND_FACTOR_ZERO,
637                         .invert_src_factor = true,
638                         .dst_factor = BLEND_FACTOR_ZERO,
639                         .invert_dst_factor = false,
640                 };
641 
642                 options.rt[0].rgb = replace;
643                 options.rt[0].alpha = replace;
644         } else {
645                 options.rt[0].rgb.func = rt_state->equation.rgb_func;
646                 options.rt[0].rgb.src_factor = rt_state->equation.rgb_src_factor;
647                 options.rt[0].rgb.invert_src_factor = rt_state->equation.rgb_invert_src_factor;
648                 options.rt[0].rgb.dst_factor = rt_state->equation.rgb_dst_factor;
649                 options.rt[0].rgb.invert_dst_factor = rt_state->equation.rgb_invert_dst_factor;
650                 options.rt[0].alpha.func = rt_state->equation.alpha_func;
651                 options.rt[0].alpha.src_factor = rt_state->equation.alpha_src_factor;
652                 options.rt[0].alpha.invert_src_factor = rt_state->equation.alpha_invert_src_factor;
653                 options.rt[0].alpha.dst_factor = rt_state->equation.alpha_dst_factor;
654                 options.rt[0].alpha.invert_dst_factor = rt_state->equation.alpha_invert_dst_factor;
655         }
656 
657         nir_alu_type src_types[] = { src0_type ?: nir_type_float32, src1_type ?: nir_type_float32 };
658 
659         /* HACK: workaround buggy TGSI shaders (u_blitter) */
660         for (unsigned i = 0; i < ARRAY_SIZE(src_types); ++i) {
661                 src_types[i] = nir_alu_type_get_base_type(nir_type) |
662                         nir_alu_type_get_type_size(src_types[i]);
663         }
664 
665 	nir_variable *c_src =
666                 nir_variable_create(b.shader, nir_var_shader_in,
667                                     glsl_vector_type(nir_get_glsl_base_type_for_nir_type(src_types[0]), 4),
668                                     "gl_Color");
669         c_src->data.location = VARYING_SLOT_COL0;
670         nir_variable *c_src1 =
671                 nir_variable_create(b.shader, nir_var_shader_in,
672                                     glsl_vector_type(nir_get_glsl_base_type_for_nir_type(src_types[1]), 4),
673                                     "gl_Color1");
674         c_src1->data.location = VARYING_SLOT_VAR0;
675         c_src1->data.driver_location = 1;
676         nir_variable *c_out =
677                 nir_variable_create(b.shader, nir_var_shader_out,
678                                     glsl_vector_type(glsl_type, 4),
679                                     "gl_FragColor");
680         c_out->data.location = FRAG_RESULT_DATA0;
681 
682         nir_ssa_def *s_src[] = {nir_load_var(&b, c_src), nir_load_var(&b, c_src1)};
683 
684         /* Saturate integer conversions */
685         for (int i = 0; i < ARRAY_SIZE(s_src); ++i) {
686                 nir_alu_type T = nir_alu_type_get_base_type(nir_type);
687                 s_src[i] = nir_convert_with_rounding(&b, s_src[i],
688                                 src_types[i], nir_type,
689                                 nir_rounding_mode_undef,
690                                 T != nir_type_float);
691         }
692 
693         /* Build a trivial blend shader */
694         nir_store_var(&b, c_out, s_src[0], 0xFF);
695 
696         options.src1 = s_src[1];
697 
698         NIR_PASS_V(b.shader, nir_lower_blend, &options);
699         nir_shader_instructions_pass(b.shader, pan_inline_blend_constants,
700                         nir_metadata_block_index | nir_metadata_dominance,
701                         (void *) state->constants);
702 
703         return b.shader;
704 }
705 
706 #if PAN_ARCH >= 6
707 uint64_t
GENX(pan_blend_get_internal_desc)708 GENX(pan_blend_get_internal_desc)(const struct panfrost_device *dev,
709                                   enum pipe_format fmt, unsigned rt,
710                                   unsigned force_size, bool dithered)
711 {
712         const struct util_format_description *desc = util_format_description(fmt);
713         uint64_t res;
714 
715         pan_pack(&res, INTERNAL_BLEND, cfg) {
716                 cfg.mode = MALI_BLEND_MODE_OPAQUE;
717                 cfg.fixed_function.num_comps = desc->nr_channels;
718                 cfg.fixed_function.rt = rt;
719 
720                 nir_alu_type T = pan_unpacked_type_for_format(desc);
721 
722                 if (force_size)
723                         T = nir_alu_type_get_base_type(T) | force_size;
724 
725                 switch (T) {
726                 case nir_type_float16:
727                         cfg.fixed_function.conversion.register_format =
728                                 MALI_REGISTER_FILE_FORMAT_F16;
729                         break;
730                 case nir_type_float32:
731                         cfg.fixed_function.conversion.register_format =
732                                 MALI_REGISTER_FILE_FORMAT_F32;
733                         break;
734                 case nir_type_int8:
735                 case nir_type_int16:
736                         cfg.fixed_function.conversion.register_format =
737                                 MALI_REGISTER_FILE_FORMAT_I16;
738                         break;
739                 case nir_type_int32:
740                         cfg.fixed_function.conversion.register_format =
741                                 MALI_REGISTER_FILE_FORMAT_I32;
742                         break;
743                 case nir_type_uint8:
744                 case nir_type_uint16:
745                         cfg.fixed_function.conversion.register_format =
746                                 MALI_REGISTER_FILE_FORMAT_U16;
747                         break;
748                 case nir_type_uint32:
749                         cfg.fixed_function.conversion.register_format =
750                                 MALI_REGISTER_FILE_FORMAT_U32;
751                         break;
752                 default:
753                         unreachable("Invalid format");
754                 }
755 
756                 cfg.fixed_function.conversion.memory_format =
757                          panfrost_format_to_bifrost_blend(dev, fmt, dithered);
758         }
759 
760         return res;
761 }
762 #endif
763 
764 struct pan_blend_shader_variant *
GENX(pan_blend_get_shader_locked)765 GENX(pan_blend_get_shader_locked)(const struct panfrost_device *dev,
766                                   const struct pan_blend_state *state,
767                                   nir_alu_type src0_type,
768                                   nir_alu_type src1_type,
769                                   unsigned rt)
770 {
771         struct pan_blend_shader_key key = {
772                 .format = state->rts[rt].format,
773                 .src0_type = src0_type,
774                 .src1_type = src1_type,
775                 .rt = rt,
776                 .has_constants = pan_blend_constant_mask(state->rts[rt].equation) != 0,
777                 .logicop_enable = state->logicop_enable,
778                 .logicop_func = state->logicop_func,
779                 .nr_samples = state->rts[rt].nr_samples,
780                 .equation = state->rts[rt].equation,
781         };
782 
783         struct hash_entry *he = _mesa_hash_table_search(dev->blend_shaders.shaders, &key);
784         struct pan_blend_shader *shader = he ? he->data : NULL;
785 
786         if (!shader) {
787                 shader = rzalloc(dev->blend_shaders.shaders, struct pan_blend_shader);
788                 shader->key = key;
789                 list_inithead(&shader->variants);
790                 _mesa_hash_table_insert(dev->blend_shaders.shaders, &shader->key, shader);
791         }
792 
793         list_for_each_entry(struct pan_blend_shader_variant, iter,
794                             &shader->variants, node) {
795                 if (!key.has_constants ||
796                     !memcmp(iter->constants, state->constants, sizeof(iter->constants))) {
797                         return iter;
798                 }
799         }
800 
801         struct pan_blend_shader_variant *variant = NULL;
802 
803         if (shader->nvariants < PAN_BLEND_SHADER_MAX_VARIANTS) {
804                 variant = rzalloc(shader, struct pan_blend_shader_variant);
805                 util_dynarray_init(&variant->binary, variant);
806                 list_add(&variant->node, &shader->variants);
807                 shader->nvariants++;
808         } else {
809                 variant = list_last_entry(&shader->variants, struct pan_blend_shader_variant, node);
810                 list_del(&variant->node);
811                 list_add(&variant->node, &shader->variants);
812                 util_dynarray_clear(&variant->binary);
813         }
814 
815         memcpy(variant->constants, state->constants, sizeof(variant->constants));
816 
817         nir_shader *nir =
818                 GENX(pan_blend_create_shader)(dev, state, src0_type, src1_type, rt);
819 
820         /* Compile the NIR shader */
821         struct panfrost_compile_inputs inputs = {
822                 .gpu_id = dev->gpu_id,
823                 .is_blend = true,
824                 .blend.rt = shader->key.rt,
825                 .blend.nr_samples = key.nr_samples,
826                 .fixed_sysval_ubo = -1,
827                 .rt_formats = { key.format },
828         };
829 
830 #if PAN_ARCH >= 6
831         inputs.blend.bifrost_blend_desc =
832                 GENX(pan_blend_get_internal_desc)(dev, key.format, key.rt, 0, false);
833 #endif
834 
835         struct pan_shader_info info;
836 
837         GENX(pan_shader_compile)(nir, &inputs, &variant->binary, &info);
838 
839         /* Blend shaders can't have sysvals */
840         assert(info.sysvals.sysval_count == 0);
841 
842         variant->work_reg_count = info.work_reg_count;
843 
844 #if PAN_ARCH <= 5
845         variant->first_tag = info.midgard.first_tag;
846 #endif
847 
848         ralloc_free(nir);
849 
850         return variant;
851 }
852 #endif /* ifndef PAN_ARCH */
853