Home | History | Annotate | Line # | Download | only in lib
      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
     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
     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
     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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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 
    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 
    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
    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
    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 *
    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
    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
    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 *
    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
    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 *
    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