xref: /aosp_15_r20/external/mesa3d/src/panfrost/lib/pan_blend.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1*61046927SAndroid Build Coastguard Worker /*
2*61046927SAndroid Build Coastguard Worker  * Copyright (C) 2018 Alyssa Rosenzweig
3*61046927SAndroid Build Coastguard Worker  * Copyright (C) 2019-2021 Collabora, Ltd.
4*61046927SAndroid Build Coastguard Worker  *
5*61046927SAndroid Build Coastguard Worker  * Permission is hereby granted, free of charge, to any person obtaining a
6*61046927SAndroid Build Coastguard Worker  * copy of this software and associated documentation files (the "Software"),
7*61046927SAndroid Build Coastguard Worker  * to deal in the Software without restriction, including without limitation
8*61046927SAndroid Build Coastguard Worker  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9*61046927SAndroid Build Coastguard Worker  * and/or sell copies of the Software, and to permit persons to whom the
10*61046927SAndroid Build Coastguard Worker  * Software is furnished to do so, subject to the following conditions:
11*61046927SAndroid Build Coastguard Worker  *
12*61046927SAndroid Build Coastguard Worker  * The above copyright notice and this permission notice (including the next
13*61046927SAndroid Build Coastguard Worker  * paragraph) shall be included in all copies or substantial portions of the
14*61046927SAndroid Build Coastguard Worker  * Software.
15*61046927SAndroid Build Coastguard Worker  *
16*61046927SAndroid Build Coastguard Worker  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17*61046927SAndroid Build Coastguard Worker  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18*61046927SAndroid Build Coastguard Worker  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19*61046927SAndroid Build Coastguard Worker  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20*61046927SAndroid Build Coastguard Worker  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21*61046927SAndroid Build Coastguard Worker  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22*61046927SAndroid Build Coastguard Worker  * SOFTWARE.
23*61046927SAndroid Build Coastguard Worker  */
24*61046927SAndroid Build Coastguard Worker 
25*61046927SAndroid Build Coastguard Worker #include "pan_blend.h"
26*61046927SAndroid Build Coastguard Worker #include "util/blend.h"
27*61046927SAndroid Build Coastguard Worker 
28*61046927SAndroid Build Coastguard Worker #ifdef PAN_ARCH
29*61046927SAndroid Build Coastguard Worker #include "pan_shader.h"
30*61046927SAndroid Build Coastguard Worker #endif
31*61046927SAndroid Build Coastguard Worker 
32*61046927SAndroid Build Coastguard Worker #include "compiler/nir/nir.h"
33*61046927SAndroid Build Coastguard Worker #include "compiler/nir/nir_builder.h"
34*61046927SAndroid Build Coastguard Worker #include "compiler/nir/nir_conversion_builder.h"
35*61046927SAndroid Build Coastguard Worker #include "compiler/nir/nir_lower_blend.h"
36*61046927SAndroid Build Coastguard Worker #include "panfrost/util/pan_lower_framebuffer.h"
37*61046927SAndroid Build Coastguard Worker #include "util/format/u_format.h"
38*61046927SAndroid Build Coastguard Worker #include "pan_texture.h"
39*61046927SAndroid Build Coastguard Worker 
40*61046927SAndroid Build Coastguard Worker #ifndef PAN_ARCH
41*61046927SAndroid Build Coastguard Worker 
42*61046927SAndroid Build Coastguard Worker /* Fixed function blending */
43*61046927SAndroid Build Coastguard Worker 
44*61046927SAndroid Build Coastguard Worker static bool
factor_is_supported(enum pipe_blendfactor factor)45*61046927SAndroid Build Coastguard Worker factor_is_supported(enum pipe_blendfactor factor)
46*61046927SAndroid Build Coastguard Worker {
47*61046927SAndroid Build Coastguard Worker    factor = util_blendfactor_without_invert(factor);
48*61046927SAndroid Build Coastguard Worker 
49*61046927SAndroid Build Coastguard Worker    return factor != PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE &&
50*61046927SAndroid Build Coastguard Worker           factor != PIPE_BLENDFACTOR_SRC1_COLOR &&
51*61046927SAndroid Build Coastguard Worker           factor != PIPE_BLENDFACTOR_SRC1_ALPHA;
52*61046927SAndroid Build Coastguard Worker }
53*61046927SAndroid Build Coastguard Worker 
54*61046927SAndroid Build Coastguard Worker /* OpenGL allows encoding (src*dest + dest*src) which is incompatiblle with
55*61046927SAndroid Build Coastguard Worker  * Midgard style blending since there are two multiplies. However, it may be
56*61046927SAndroid Build Coastguard Worker  * factored as 2*src*dest = dest*(2*src), which can be encoded on Bifrost as 0
57*61046927SAndroid Build Coastguard Worker  * + dest * (2*src) wih the new source_2 value of C. Detect this case. */
58*61046927SAndroid Build Coastguard Worker 
59*61046927SAndroid Build Coastguard Worker static bool
is_2srcdest(enum pipe_blend_func blend_func,enum pipe_blendfactor src_factor,enum pipe_blendfactor dest_factor,bool is_alpha)60*61046927SAndroid Build Coastguard Worker is_2srcdest(enum pipe_blend_func blend_func, enum pipe_blendfactor src_factor,
61*61046927SAndroid Build Coastguard Worker             enum pipe_blendfactor dest_factor, bool is_alpha)
62*61046927SAndroid Build Coastguard Worker {
63*61046927SAndroid Build Coastguard Worker    return (blend_func == PIPE_BLEND_ADD) &&
64*61046927SAndroid Build Coastguard Worker           ((src_factor == PIPE_BLENDFACTOR_DST_COLOR) ||
65*61046927SAndroid Build Coastguard Worker            ((src_factor == PIPE_BLENDFACTOR_DST_ALPHA) && is_alpha)) &&
66*61046927SAndroid Build Coastguard Worker           ((dest_factor == PIPE_BLENDFACTOR_SRC_COLOR) ||
67*61046927SAndroid Build Coastguard Worker            ((dest_factor == PIPE_BLENDFACTOR_SRC_ALPHA) && is_alpha));
68*61046927SAndroid Build Coastguard Worker }
69*61046927SAndroid Build Coastguard Worker 
70*61046927SAndroid Build Coastguard Worker static bool
can_fixed_function_equation(enum pipe_blend_func blend_func,enum pipe_blendfactor src_factor,enum pipe_blendfactor dest_factor,bool is_alpha,bool supports_2src)71*61046927SAndroid Build Coastguard Worker can_fixed_function_equation(enum pipe_blend_func blend_func,
72*61046927SAndroid Build Coastguard Worker                             enum pipe_blendfactor src_factor,
73*61046927SAndroid Build Coastguard Worker                             enum pipe_blendfactor dest_factor, bool is_alpha,
74*61046927SAndroid Build Coastguard Worker                             bool supports_2src)
75*61046927SAndroid Build Coastguard Worker {
76*61046927SAndroid Build Coastguard Worker    if (is_2srcdest(blend_func, src_factor, dest_factor, is_alpha))
77*61046927SAndroid Build Coastguard Worker       return supports_2src;
78*61046927SAndroid Build Coastguard Worker 
79*61046927SAndroid Build Coastguard Worker    if (blend_func != PIPE_BLEND_ADD && blend_func != PIPE_BLEND_SUBTRACT &&
80*61046927SAndroid Build Coastguard Worker        blend_func != PIPE_BLEND_REVERSE_SUBTRACT)
81*61046927SAndroid Build Coastguard Worker       return false;
82*61046927SAndroid Build Coastguard Worker 
83*61046927SAndroid Build Coastguard Worker    if (!factor_is_supported(src_factor) || !factor_is_supported(dest_factor))
84*61046927SAndroid Build Coastguard Worker       return false;
85*61046927SAndroid Build Coastguard Worker 
86*61046927SAndroid Build Coastguard Worker    /* Fixed function requires src/dest factors to match (up to invert) or be
87*61046927SAndroid Build Coastguard Worker     * zero/one.
88*61046927SAndroid Build Coastguard Worker     */
89*61046927SAndroid Build Coastguard Worker    enum pipe_blendfactor src = util_blendfactor_without_invert(src_factor);
90*61046927SAndroid Build Coastguard Worker    enum pipe_blendfactor dest = util_blendfactor_without_invert(dest_factor);
91*61046927SAndroid Build Coastguard Worker 
92*61046927SAndroid Build Coastguard Worker    return (src == dest) || (src == PIPE_BLENDFACTOR_ONE) ||
93*61046927SAndroid Build Coastguard Worker           (dest == PIPE_BLENDFACTOR_ONE);
94*61046927SAndroid Build Coastguard Worker }
95*61046927SAndroid Build Coastguard Worker 
96*61046927SAndroid Build Coastguard Worker static unsigned
blend_factor_constant_mask(enum pipe_blendfactor factor)97*61046927SAndroid Build Coastguard Worker blend_factor_constant_mask(enum pipe_blendfactor factor)
98*61046927SAndroid Build Coastguard Worker {
99*61046927SAndroid Build Coastguard Worker    factor = util_blendfactor_without_invert(factor);
100*61046927SAndroid Build Coastguard Worker 
101*61046927SAndroid Build Coastguard Worker    if (factor == PIPE_BLENDFACTOR_CONST_COLOR)
102*61046927SAndroid Build Coastguard Worker       return 0b0111; /* RGB */
103*61046927SAndroid Build Coastguard Worker    else if (factor == PIPE_BLENDFACTOR_CONST_ALPHA)
104*61046927SAndroid Build Coastguard Worker       return 0b1000; /* A */
105*61046927SAndroid Build Coastguard Worker    else
106*61046927SAndroid Build Coastguard Worker       return 0b0000; /* - */
107*61046927SAndroid Build Coastguard Worker }
108*61046927SAndroid Build Coastguard Worker 
109*61046927SAndroid Build Coastguard Worker unsigned
pan_blend_constant_mask(const struct pan_blend_equation eq)110*61046927SAndroid Build Coastguard Worker pan_blend_constant_mask(const struct pan_blend_equation eq)
111*61046927SAndroid Build Coastguard Worker {
112*61046927SAndroid Build Coastguard Worker    return blend_factor_constant_mask(eq.rgb_src_factor) |
113*61046927SAndroid Build Coastguard Worker           blend_factor_constant_mask(eq.rgb_dst_factor) |
114*61046927SAndroid Build Coastguard Worker           blend_factor_constant_mask(eq.alpha_src_factor) |
115*61046927SAndroid Build Coastguard Worker           blend_factor_constant_mask(eq.alpha_dst_factor);
116*61046927SAndroid Build Coastguard Worker }
117*61046927SAndroid Build Coastguard Worker 
118*61046927SAndroid Build Coastguard Worker /* Only "homogenous" (scalar or vector with all components equal) constants are
119*61046927SAndroid Build Coastguard Worker  * valid for fixed-function, so check for this condition */
120*61046927SAndroid Build Coastguard Worker 
121*61046927SAndroid Build Coastguard Worker bool
pan_blend_is_homogenous_constant(unsigned mask,const float * constants)122*61046927SAndroid Build Coastguard Worker pan_blend_is_homogenous_constant(unsigned mask, const float *constants)
123*61046927SAndroid Build Coastguard Worker {
124*61046927SAndroid Build Coastguard Worker    float constant = pan_blend_get_constant(mask, constants);
125*61046927SAndroid Build Coastguard Worker 
126*61046927SAndroid Build Coastguard Worker    u_foreach_bit(i, mask) {
127*61046927SAndroid Build Coastguard Worker       if (constants[i] != constant)
128*61046927SAndroid Build Coastguard Worker          return false;
129*61046927SAndroid Build Coastguard Worker    }
130*61046927SAndroid Build Coastguard Worker 
131*61046927SAndroid Build Coastguard Worker    return true;
132*61046927SAndroid Build Coastguard Worker }
133*61046927SAndroid Build Coastguard Worker 
134*61046927SAndroid Build Coastguard Worker /* Determines if an equation can run in fixed function */
135*61046927SAndroid Build Coastguard Worker 
136*61046927SAndroid Build Coastguard Worker bool
pan_blend_can_fixed_function(const struct pan_blend_equation equation,bool supports_2src)137*61046927SAndroid Build Coastguard Worker pan_blend_can_fixed_function(const struct pan_blend_equation equation,
138*61046927SAndroid Build Coastguard Worker                              bool supports_2src)
139*61046927SAndroid Build Coastguard Worker {
140*61046927SAndroid Build Coastguard Worker    return !equation.blend_enable ||
141*61046927SAndroid Build Coastguard Worker           (can_fixed_function_equation(
142*61046927SAndroid Build Coastguard Worker               equation.rgb_func, equation.rgb_src_factor,
143*61046927SAndroid Build Coastguard Worker               equation.rgb_dst_factor, false, supports_2src) &&
144*61046927SAndroid Build Coastguard Worker            can_fixed_function_equation(
145*61046927SAndroid Build Coastguard Worker               equation.alpha_func, equation.alpha_src_factor,
146*61046927SAndroid Build Coastguard Worker               equation.alpha_dst_factor, true, supports_2src));
147*61046927SAndroid Build Coastguard Worker }
148*61046927SAndroid Build Coastguard Worker 
149*61046927SAndroid Build Coastguard Worker static enum mali_blend_operand_c
to_c_factor(enum pipe_blendfactor factor)150*61046927SAndroid Build Coastguard Worker to_c_factor(enum pipe_blendfactor factor)
151*61046927SAndroid Build Coastguard Worker {
152*61046927SAndroid Build Coastguard Worker    switch (util_blendfactor_without_invert(factor)) {
153*61046927SAndroid Build Coastguard Worker    case PIPE_BLENDFACTOR_ONE:
154*61046927SAndroid Build Coastguard Worker       /* Extra invert to flip back in caller */
155*61046927SAndroid Build Coastguard Worker       return MALI_BLEND_OPERAND_C_ZERO;
156*61046927SAndroid Build Coastguard Worker 
157*61046927SAndroid Build Coastguard Worker    case PIPE_BLENDFACTOR_SRC_ALPHA:
158*61046927SAndroid Build Coastguard Worker       return MALI_BLEND_OPERAND_C_SRC_ALPHA;
159*61046927SAndroid Build Coastguard Worker 
160*61046927SAndroid Build Coastguard Worker    case PIPE_BLENDFACTOR_DST_ALPHA:
161*61046927SAndroid Build Coastguard Worker       return MALI_BLEND_OPERAND_C_DEST_ALPHA;
162*61046927SAndroid Build Coastguard Worker 
163*61046927SAndroid Build Coastguard Worker    case PIPE_BLENDFACTOR_SRC_COLOR:
164*61046927SAndroid Build Coastguard Worker       return MALI_BLEND_OPERAND_C_SRC;
165*61046927SAndroid Build Coastguard Worker 
166*61046927SAndroid Build Coastguard Worker    case PIPE_BLENDFACTOR_DST_COLOR:
167*61046927SAndroid Build Coastguard Worker       return MALI_BLEND_OPERAND_C_DEST;
168*61046927SAndroid Build Coastguard Worker 
169*61046927SAndroid Build Coastguard Worker    case PIPE_BLENDFACTOR_CONST_COLOR:
170*61046927SAndroid Build Coastguard Worker    case PIPE_BLENDFACTOR_CONST_ALPHA:
171*61046927SAndroid Build Coastguard Worker       return MALI_BLEND_OPERAND_C_CONSTANT;
172*61046927SAndroid Build Coastguard Worker 
173*61046927SAndroid Build Coastguard Worker    default:
174*61046927SAndroid Build Coastguard Worker       unreachable("Unsupported blend factor");
175*61046927SAndroid Build Coastguard Worker    }
176*61046927SAndroid Build Coastguard Worker }
177*61046927SAndroid Build Coastguard Worker 
178*61046927SAndroid Build Coastguard Worker static void
to_panfrost_function(enum pipe_blend_func blend_func,enum pipe_blendfactor src_factor,enum pipe_blendfactor dest_factor,bool is_alpha,struct MALI_BLEND_FUNCTION * function)179*61046927SAndroid Build Coastguard Worker to_panfrost_function(enum pipe_blend_func blend_func,
180*61046927SAndroid Build Coastguard Worker                      enum pipe_blendfactor src_factor,
181*61046927SAndroid Build Coastguard Worker                      enum pipe_blendfactor dest_factor, bool is_alpha,
182*61046927SAndroid Build Coastguard Worker                      struct MALI_BLEND_FUNCTION *function)
183*61046927SAndroid Build Coastguard Worker {
184*61046927SAndroid Build Coastguard Worker    assert(can_fixed_function_equation(blend_func, src_factor, dest_factor,
185*61046927SAndroid Build Coastguard Worker                                       is_alpha, true));
186*61046927SAndroid Build Coastguard Worker 
187*61046927SAndroid Build Coastguard Worker    /* We handle ZERO/ONE specially since it's the hardware has 0 and can invert
188*61046927SAndroid Build Coastguard Worker     * to 1 but Gallium has 0 as the uninverted version.
189*61046927SAndroid Build Coastguard Worker     */
190*61046927SAndroid Build Coastguard Worker    bool src_inverted =
191*61046927SAndroid Build Coastguard Worker       util_blendfactor_is_inverted(src_factor) ^
192*61046927SAndroid Build Coastguard Worker       (util_blendfactor_without_invert(src_factor) == PIPE_BLENDFACTOR_ONE);
193*61046927SAndroid Build Coastguard Worker 
194*61046927SAndroid Build Coastguard Worker    bool dest_inverted =
195*61046927SAndroid Build Coastguard Worker       util_blendfactor_is_inverted(dest_factor) ^
196*61046927SAndroid Build Coastguard Worker       (util_blendfactor_without_invert(dest_factor) == PIPE_BLENDFACTOR_ONE);
197*61046927SAndroid Build Coastguard Worker 
198*61046927SAndroid Build Coastguard Worker    if (src_factor == PIPE_BLENDFACTOR_ZERO) {
199*61046927SAndroid Build Coastguard Worker       function->a = MALI_BLEND_OPERAND_A_ZERO;
200*61046927SAndroid Build Coastguard Worker       function->b = MALI_BLEND_OPERAND_B_DEST;
201*61046927SAndroid Build Coastguard Worker       if (blend_func == PIPE_BLEND_SUBTRACT)
202*61046927SAndroid Build Coastguard Worker          function->negate_b = true;
203*61046927SAndroid Build Coastguard Worker       function->invert_c = dest_inverted;
204*61046927SAndroid Build Coastguard Worker       function->c = to_c_factor(dest_factor);
205*61046927SAndroid Build Coastguard Worker    } else if (src_factor == PIPE_BLENDFACTOR_ONE) {
206*61046927SAndroid Build Coastguard Worker       function->a = MALI_BLEND_OPERAND_A_SRC;
207*61046927SAndroid Build Coastguard Worker       function->b = MALI_BLEND_OPERAND_B_DEST;
208*61046927SAndroid Build Coastguard Worker       if (blend_func == PIPE_BLEND_SUBTRACT)
209*61046927SAndroid Build Coastguard Worker          function->negate_b = true;
210*61046927SAndroid Build Coastguard Worker       else if (blend_func == PIPE_BLEND_REVERSE_SUBTRACT)
211*61046927SAndroid Build Coastguard Worker          function->negate_a = true;
212*61046927SAndroid Build Coastguard Worker       function->invert_c = dest_inverted;
213*61046927SAndroid Build Coastguard Worker       function->c = to_c_factor(dest_factor);
214*61046927SAndroid Build Coastguard Worker    } else if (dest_factor == PIPE_BLENDFACTOR_ZERO) {
215*61046927SAndroid Build Coastguard Worker       function->a = MALI_BLEND_OPERAND_A_ZERO;
216*61046927SAndroid Build Coastguard Worker       function->b = MALI_BLEND_OPERAND_B_SRC;
217*61046927SAndroid Build Coastguard Worker       if (blend_func == PIPE_BLEND_REVERSE_SUBTRACT)
218*61046927SAndroid Build Coastguard Worker          function->negate_b = true;
219*61046927SAndroid Build Coastguard Worker       function->invert_c = src_inverted;
220*61046927SAndroid Build Coastguard Worker       function->c = to_c_factor(src_factor);
221*61046927SAndroid Build Coastguard Worker    } else if (dest_factor == PIPE_BLENDFACTOR_ONE) {
222*61046927SAndroid Build Coastguard Worker       function->a = MALI_BLEND_OPERAND_A_DEST;
223*61046927SAndroid Build Coastguard Worker       function->b = MALI_BLEND_OPERAND_B_SRC;
224*61046927SAndroid Build Coastguard Worker       if (blend_func == PIPE_BLEND_SUBTRACT)
225*61046927SAndroid Build Coastguard Worker          function->negate_a = true;
226*61046927SAndroid Build Coastguard Worker       else if (blend_func == PIPE_BLEND_REVERSE_SUBTRACT)
227*61046927SAndroid Build Coastguard Worker          function->negate_b = true;
228*61046927SAndroid Build Coastguard Worker       function->invert_c = src_inverted;
229*61046927SAndroid Build Coastguard Worker       function->c = to_c_factor(src_factor);
230*61046927SAndroid Build Coastguard Worker    } else if (src_factor == dest_factor) {
231*61046927SAndroid Build Coastguard Worker       function->a = MALI_BLEND_OPERAND_A_ZERO;
232*61046927SAndroid Build Coastguard Worker       function->invert_c = src_inverted;
233*61046927SAndroid Build Coastguard Worker       function->c = to_c_factor(src_factor);
234*61046927SAndroid Build Coastguard Worker 
235*61046927SAndroid Build Coastguard Worker       switch (blend_func) {
236*61046927SAndroid Build Coastguard Worker       case PIPE_BLEND_ADD:
237*61046927SAndroid Build Coastguard Worker          function->b = MALI_BLEND_OPERAND_B_SRC_PLUS_DEST;
238*61046927SAndroid Build Coastguard Worker          break;
239*61046927SAndroid Build Coastguard Worker       case PIPE_BLEND_REVERSE_SUBTRACT:
240*61046927SAndroid Build Coastguard Worker          function->negate_b = true;
241*61046927SAndroid Build Coastguard Worker          FALLTHROUGH;
242*61046927SAndroid Build Coastguard Worker       case PIPE_BLEND_SUBTRACT:
243*61046927SAndroid Build Coastguard Worker          function->b = MALI_BLEND_OPERAND_B_SRC_MINUS_DEST;
244*61046927SAndroid Build Coastguard Worker          break;
245*61046927SAndroid Build Coastguard Worker       default:
246*61046927SAndroid Build Coastguard Worker          unreachable("Invalid blend function");
247*61046927SAndroid Build Coastguard Worker       }
248*61046927SAndroid Build Coastguard Worker    } else if (is_2srcdest(blend_func, src_factor, dest_factor, is_alpha)) {
249*61046927SAndroid Build Coastguard Worker       /* src*dest + dest*src = 2*src*dest = 0 + dest*(2*src) */
250*61046927SAndroid Build Coastguard Worker       function->a = MALI_BLEND_OPERAND_A_ZERO;
251*61046927SAndroid Build Coastguard Worker       function->b = MALI_BLEND_OPERAND_B_DEST;
252*61046927SAndroid Build Coastguard Worker       function->c = MALI_BLEND_OPERAND_C_SRC_X_2;
253*61046927SAndroid Build Coastguard Worker    } else {
254*61046927SAndroid Build Coastguard Worker       assert(util_blendfactor_without_invert(src_factor) ==
255*61046927SAndroid Build Coastguard Worker                 util_blendfactor_without_invert(dest_factor) &&
256*61046927SAndroid Build Coastguard Worker              src_inverted != dest_inverted);
257*61046927SAndroid Build Coastguard Worker 
258*61046927SAndroid Build Coastguard Worker       function->a = MALI_BLEND_OPERAND_A_DEST;
259*61046927SAndroid Build Coastguard Worker       function->invert_c = src_inverted;
260*61046927SAndroid Build Coastguard Worker       function->c = to_c_factor(src_factor);
261*61046927SAndroid Build Coastguard Worker 
262*61046927SAndroid Build Coastguard Worker       switch (blend_func) {
263*61046927SAndroid Build Coastguard Worker       case PIPE_BLEND_ADD:
264*61046927SAndroid Build Coastguard Worker          function->b = MALI_BLEND_OPERAND_B_SRC_MINUS_DEST;
265*61046927SAndroid Build Coastguard Worker          break;
266*61046927SAndroid Build Coastguard Worker       case PIPE_BLEND_REVERSE_SUBTRACT:
267*61046927SAndroid Build Coastguard Worker          function->b = MALI_BLEND_OPERAND_B_SRC_PLUS_DEST;
268*61046927SAndroid Build Coastguard Worker          function->negate_b = true;
269*61046927SAndroid Build Coastguard Worker          break;
270*61046927SAndroid Build Coastguard Worker       case PIPE_BLEND_SUBTRACT:
271*61046927SAndroid Build Coastguard Worker          function->b = MALI_BLEND_OPERAND_B_SRC_PLUS_DEST;
272*61046927SAndroid Build Coastguard Worker          function->negate_a = true;
273*61046927SAndroid Build Coastguard Worker          break;
274*61046927SAndroid Build Coastguard Worker       default:
275*61046927SAndroid Build Coastguard Worker          unreachable("Invalid blend function\n");
276*61046927SAndroid Build Coastguard Worker       }
277*61046927SAndroid Build Coastguard Worker    }
278*61046927SAndroid Build Coastguard Worker }
279*61046927SAndroid Build Coastguard Worker 
280*61046927SAndroid Build Coastguard Worker bool
pan_blend_is_opaque(const struct pan_blend_equation equation)281*61046927SAndroid Build Coastguard Worker pan_blend_is_opaque(const struct pan_blend_equation equation)
282*61046927SAndroid Build Coastguard Worker {
283*61046927SAndroid Build Coastguard Worker    /* If a channel is masked out, we can't use opaque mode even if
284*61046927SAndroid Build Coastguard Worker     * blending is disabled, since we need a tilebuffer read in there */
285*61046927SAndroid Build Coastguard Worker    if (equation.color_mask != 0xF)
286*61046927SAndroid Build Coastguard Worker       return false;
287*61046927SAndroid Build Coastguard Worker 
288*61046927SAndroid Build Coastguard Worker    /* With nothing masked out, disabled bledning is opaque */
289*61046927SAndroid Build Coastguard Worker    if (!equation.blend_enable)
290*61046927SAndroid Build Coastguard Worker       return true;
291*61046927SAndroid Build Coastguard Worker 
292*61046927SAndroid Build Coastguard Worker    /* Also detect open-coded opaque blending */
293*61046927SAndroid Build Coastguard Worker    return equation.rgb_src_factor == PIPE_BLENDFACTOR_ONE &&
294*61046927SAndroid Build Coastguard Worker           equation.rgb_dst_factor == PIPE_BLENDFACTOR_ZERO &&
295*61046927SAndroid Build Coastguard Worker           (equation.rgb_func == PIPE_BLEND_ADD ||
296*61046927SAndroid Build Coastguard Worker            equation.rgb_func == PIPE_BLEND_SUBTRACT) &&
297*61046927SAndroid Build Coastguard Worker           equation.alpha_src_factor == PIPE_BLENDFACTOR_ONE &&
298*61046927SAndroid Build Coastguard Worker           equation.alpha_dst_factor == PIPE_BLENDFACTOR_ZERO &&
299*61046927SAndroid Build Coastguard Worker           (equation.alpha_func == PIPE_BLEND_ADD ||
300*61046927SAndroid Build Coastguard Worker            equation.alpha_func == PIPE_BLEND_SUBTRACT);
301*61046927SAndroid Build Coastguard Worker }
302*61046927SAndroid Build Coastguard Worker 
303*61046927SAndroid Build Coastguard Worker /* Check if a factor represents a constant value of val, assuming src_alpha is
304*61046927SAndroid Build Coastguard Worker  * the given constant.
305*61046927SAndroid Build Coastguard Worker  */
306*61046927SAndroid Build Coastguard Worker 
307*61046927SAndroid Build Coastguard Worker static inline bool
is_factor_01(enum pipe_blendfactor factor,unsigned val,unsigned srca)308*61046927SAndroid Build Coastguard Worker is_factor_01(enum pipe_blendfactor factor, unsigned val, unsigned srca)
309*61046927SAndroid Build Coastguard Worker {
310*61046927SAndroid Build Coastguard Worker    assert(val == 0 || val == 1);
311*61046927SAndroid Build Coastguard Worker    assert(srca == 0 || srca == 1);
312*61046927SAndroid Build Coastguard Worker 
313*61046927SAndroid Build Coastguard Worker    switch (factor) {
314*61046927SAndroid Build Coastguard Worker    case PIPE_BLENDFACTOR_ZERO:
315*61046927SAndroid Build Coastguard Worker       return (val == 0);
316*61046927SAndroid Build Coastguard Worker 
317*61046927SAndroid Build Coastguard Worker    case PIPE_BLENDFACTOR_ONE:
318*61046927SAndroid Build Coastguard Worker       return (val == 1);
319*61046927SAndroid Build Coastguard Worker 
320*61046927SAndroid Build Coastguard Worker    case PIPE_BLENDFACTOR_SRC_ALPHA:
321*61046927SAndroid Build Coastguard Worker       return (val == srca);
322*61046927SAndroid Build Coastguard Worker 
323*61046927SAndroid Build Coastguard Worker    case PIPE_BLENDFACTOR_INV_SRC_ALPHA:
324*61046927SAndroid Build Coastguard Worker       return (val == (1 - srca));
325*61046927SAndroid Build Coastguard Worker 
326*61046927SAndroid Build Coastguard Worker    default:
327*61046927SAndroid Build Coastguard Worker       return false;
328*61046927SAndroid Build Coastguard Worker    }
329*61046927SAndroid Build Coastguard Worker }
330*61046927SAndroid Build Coastguard Worker 
331*61046927SAndroid Build Coastguard Worker /* Returns if src alpha = 0 implies the blended colour equals the destination
332*61046927SAndroid Build Coastguard Worker  * colour. Suppose source alpha = 0 and consider cases.
333*61046927SAndroid Build Coastguard Worker  *
334*61046927SAndroid Build Coastguard Worker  * Additive blending: Equivalent to D = S * f_s + D * f_d for all D and all S
335*61046927SAndroid Build Coastguard Worker  * with S_a = 0, for each component. For the alpha component (if it unmasked),
336*61046927SAndroid Build Coastguard Worker  * we have S_a = 0 so this reduces to D = D * f_d <===> f_d = 1. For RGB
337*61046927SAndroid Build Coastguard Worker  * components (if unmasked), we need f_s = 0 and f_d = 1.
338*61046927SAndroid Build Coastguard Worker  *
339*61046927SAndroid Build Coastguard Worker  * Subtractive blending: Fails in general (D = S * f_S - D * f_D). We
340*61046927SAndroid Build Coastguard Worker  * would need f_S = 0 and f_D = -1, which is not valid in the APIs.
341*61046927SAndroid Build Coastguard Worker  *
342*61046927SAndroid Build Coastguard Worker  * Reverse subtractive blending (D = D * f_D - S * f_S), we need f_D = 1
343*61046927SAndroid Build Coastguard Worker  * and f_S = 0 up to masking. This is the same as additive blending.
344*61046927SAndroid Build Coastguard Worker  *
345*61046927SAndroid Build Coastguard Worker  * Min/max: Fails in general on the RGB components.
346*61046927SAndroid Build Coastguard Worker  */
347*61046927SAndroid Build Coastguard Worker 
348*61046927SAndroid Build Coastguard Worker bool
pan_blend_alpha_zero_nop(const struct pan_blend_equation eq)349*61046927SAndroid Build Coastguard Worker pan_blend_alpha_zero_nop(const struct pan_blend_equation eq)
350*61046927SAndroid Build Coastguard Worker {
351*61046927SAndroid Build Coastguard Worker    if (eq.rgb_func != PIPE_BLEND_ADD &&
352*61046927SAndroid Build Coastguard Worker        eq.rgb_func != PIPE_BLEND_REVERSE_SUBTRACT)
353*61046927SAndroid Build Coastguard Worker       return false;
354*61046927SAndroid Build Coastguard Worker 
355*61046927SAndroid Build Coastguard Worker    if (eq.color_mask & 0x8) {
356*61046927SAndroid Build Coastguard Worker       if (!is_factor_01(eq.alpha_dst_factor, 1, 0))
357*61046927SAndroid Build Coastguard Worker          return false;
358*61046927SAndroid Build Coastguard Worker    }
359*61046927SAndroid Build Coastguard Worker 
360*61046927SAndroid Build Coastguard Worker    if (eq.color_mask & 0x7) {
361*61046927SAndroid Build Coastguard Worker       if (!is_factor_01(eq.rgb_dst_factor, 1, 0))
362*61046927SAndroid Build Coastguard Worker          return false;
363*61046927SAndroid Build Coastguard Worker 
364*61046927SAndroid Build Coastguard Worker       if (!is_factor_01(eq.rgb_src_factor, 0, 0))
365*61046927SAndroid Build Coastguard Worker          return false;
366*61046927SAndroid Build Coastguard Worker    }
367*61046927SAndroid Build Coastguard Worker 
368*61046927SAndroid Build Coastguard Worker    return true;
369*61046927SAndroid Build Coastguard Worker }
370*61046927SAndroid Build Coastguard Worker 
371*61046927SAndroid Build Coastguard Worker /* Returns if src alpha = 1 implies the blended colour equals the source
372*61046927SAndroid Build Coastguard Worker  * colour. Suppose source alpha = 1 and consider cases.
373*61046927SAndroid Build Coastguard Worker  *
374*61046927SAndroid Build Coastguard Worker  * Additive blending: S = S * f_s + D * f_d. We need f_s = 1 and f_d = 0.
375*61046927SAndroid Build Coastguard Worker  *
376*61046927SAndroid Build Coastguard Worker  * Subtractive blending: S = S * f_s - D * f_d. Same as additive blending.
377*61046927SAndroid Build Coastguard Worker  *
378*61046927SAndroid Build Coastguard Worker  * Reverse subtractive blending: S = D * f_d - S * f_s. Fails in general since
379*61046927SAndroid Build Coastguard Worker  * it would require f_s = -1, which is not valid in the APIs.
380*61046927SAndroid Build Coastguard Worker  *
381*61046927SAndroid Build Coastguard Worker  * Min/max: Fails in general on the RGB components.
382*61046927SAndroid Build Coastguard Worker  *
383*61046927SAndroid Build Coastguard Worker  * Note if any component is masked, we can't use a store.
384*61046927SAndroid Build Coastguard Worker  */
385*61046927SAndroid Build Coastguard Worker 
386*61046927SAndroid Build Coastguard Worker bool
pan_blend_alpha_one_store(const struct pan_blend_equation eq)387*61046927SAndroid Build Coastguard Worker pan_blend_alpha_one_store(const struct pan_blend_equation eq)
388*61046927SAndroid Build Coastguard Worker {
389*61046927SAndroid Build Coastguard Worker    if (eq.rgb_func != PIPE_BLEND_ADD && eq.rgb_func != PIPE_BLEND_SUBTRACT)
390*61046927SAndroid Build Coastguard Worker       return false;
391*61046927SAndroid Build Coastguard Worker 
392*61046927SAndroid Build Coastguard Worker    if (eq.color_mask != 0xf)
393*61046927SAndroid Build Coastguard Worker       return false;
394*61046927SAndroid Build Coastguard Worker 
395*61046927SAndroid Build Coastguard Worker    return is_factor_01(eq.rgb_src_factor, 1, 1) &&
396*61046927SAndroid Build Coastguard Worker           is_factor_01(eq.alpha_src_factor, 1, 1) &&
397*61046927SAndroid Build Coastguard Worker           is_factor_01(eq.rgb_dst_factor, 0, 1) &&
398*61046927SAndroid Build Coastguard Worker           is_factor_01(eq.alpha_dst_factor, 0, 1);
399*61046927SAndroid Build Coastguard Worker }
400*61046927SAndroid Build Coastguard Worker 
401*61046927SAndroid Build Coastguard Worker static bool
is_dest_factor(enum pipe_blendfactor factor,bool alpha)402*61046927SAndroid Build Coastguard Worker is_dest_factor(enum pipe_blendfactor factor, bool alpha)
403*61046927SAndroid Build Coastguard Worker {
404*61046927SAndroid Build Coastguard Worker    factor = util_blendfactor_without_invert(factor);
405*61046927SAndroid Build Coastguard Worker 
406*61046927SAndroid Build Coastguard Worker    return factor == PIPE_BLENDFACTOR_DST_ALPHA ||
407*61046927SAndroid Build Coastguard Worker           factor == PIPE_BLENDFACTOR_DST_COLOR ||
408*61046927SAndroid Build Coastguard Worker           (factor == PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE && !alpha);
409*61046927SAndroid Build Coastguard Worker }
410*61046927SAndroid Build Coastguard Worker 
411*61046927SAndroid Build Coastguard Worker /* Determines if a blend equation reads back the destination. This can occur by
412*61046927SAndroid Build Coastguard Worker  * explicitly referencing the destination in the blend equation, or by using a
413*61046927SAndroid Build Coastguard Worker  * partial writemask. */
414*61046927SAndroid Build Coastguard Worker 
415*61046927SAndroid Build Coastguard Worker bool
pan_blend_reads_dest(const struct pan_blend_equation equation)416*61046927SAndroid Build Coastguard Worker pan_blend_reads_dest(const struct pan_blend_equation equation)
417*61046927SAndroid Build Coastguard Worker {
418*61046927SAndroid Build Coastguard Worker    if (equation.color_mask && equation.color_mask != 0xF)
419*61046927SAndroid Build Coastguard Worker       return true;
420*61046927SAndroid Build Coastguard Worker 
421*61046927SAndroid Build Coastguard Worker    if (!equation.blend_enable)
422*61046927SAndroid Build Coastguard Worker       return false;
423*61046927SAndroid Build Coastguard Worker 
424*61046927SAndroid Build Coastguard Worker    return is_dest_factor(equation.rgb_src_factor, false) ||
425*61046927SAndroid Build Coastguard Worker           is_dest_factor(equation.alpha_src_factor, true) ||
426*61046927SAndroid Build Coastguard Worker           equation.rgb_dst_factor != PIPE_BLENDFACTOR_ZERO ||
427*61046927SAndroid Build Coastguard Worker           equation.alpha_dst_factor != PIPE_BLENDFACTOR_ZERO;
428*61046927SAndroid Build Coastguard Worker }
429*61046927SAndroid Build Coastguard Worker 
430*61046927SAndroid Build Coastguard Worker /* Create the descriptor for a fixed blend mode given the corresponding API
431*61046927SAndroid Build Coastguard Worker  * state. Assumes the equation can be represented as fixed-function. */
432*61046927SAndroid Build Coastguard Worker 
433*61046927SAndroid Build Coastguard Worker void
pan_blend_to_fixed_function_equation(const struct pan_blend_equation equation,struct MALI_BLEND_EQUATION * out)434*61046927SAndroid Build Coastguard Worker pan_blend_to_fixed_function_equation(const struct pan_blend_equation equation,
435*61046927SAndroid Build Coastguard Worker                                      struct MALI_BLEND_EQUATION *out)
436*61046927SAndroid Build Coastguard Worker {
437*61046927SAndroid Build Coastguard Worker    /* If no blending is enabled, default back on `replace` mode */
438*61046927SAndroid Build Coastguard Worker    if (!equation.blend_enable) {
439*61046927SAndroid Build Coastguard Worker       out->color_mask = equation.color_mask;
440*61046927SAndroid Build Coastguard Worker       out->rgb.a = MALI_BLEND_OPERAND_A_SRC;
441*61046927SAndroid Build Coastguard Worker       out->rgb.b = MALI_BLEND_OPERAND_B_SRC;
442*61046927SAndroid Build Coastguard Worker       out->rgb.c = MALI_BLEND_OPERAND_C_ZERO;
443*61046927SAndroid Build Coastguard Worker       out->alpha.a = MALI_BLEND_OPERAND_A_SRC;
444*61046927SAndroid Build Coastguard Worker       out->alpha.b = MALI_BLEND_OPERAND_B_SRC;
445*61046927SAndroid Build Coastguard Worker       out->alpha.c = MALI_BLEND_OPERAND_C_ZERO;
446*61046927SAndroid Build Coastguard Worker       return;
447*61046927SAndroid Build Coastguard Worker    }
448*61046927SAndroid Build Coastguard Worker 
449*61046927SAndroid Build Coastguard Worker    /* Compile the fixed-function blend */
450*61046927SAndroid Build Coastguard Worker    to_panfrost_function(equation.rgb_func, equation.rgb_src_factor,
451*61046927SAndroid Build Coastguard Worker                         equation.rgb_dst_factor, false, &out->rgb);
452*61046927SAndroid Build Coastguard Worker    to_panfrost_function(equation.alpha_func, equation.alpha_src_factor,
453*61046927SAndroid Build Coastguard Worker                         equation.alpha_dst_factor, true, &out->alpha);
454*61046927SAndroid Build Coastguard Worker 
455*61046927SAndroid Build Coastguard Worker    out->color_mask = equation.color_mask;
456*61046927SAndroid Build Coastguard Worker }
457*61046927SAndroid Build Coastguard Worker 
458*61046927SAndroid Build Coastguard Worker uint32_t
pan_pack_blend(const struct pan_blend_equation equation)459*61046927SAndroid Build Coastguard Worker pan_pack_blend(const struct pan_blend_equation equation)
460*61046927SAndroid Build Coastguard Worker {
461*61046927SAndroid Build Coastguard Worker    STATIC_ASSERT(sizeof(uint32_t) == MALI_BLEND_EQUATION_LENGTH);
462*61046927SAndroid Build Coastguard Worker 
463*61046927SAndroid Build Coastguard Worker    uint32_t out = 0;
464*61046927SAndroid Build Coastguard Worker 
465*61046927SAndroid Build Coastguard Worker    pan_pack(&out, BLEND_EQUATION, cfg) {
466*61046927SAndroid Build Coastguard Worker       pan_blend_to_fixed_function_equation(equation, &cfg);
467*61046927SAndroid Build Coastguard Worker    }
468*61046927SAndroid Build Coastguard Worker 
469*61046927SAndroid Build Coastguard Worker    return out;
470*61046927SAndroid Build Coastguard Worker }
471*61046927SAndroid Build Coastguard Worker 
472*61046927SAndroid Build Coastguard Worker DERIVE_HASH_TABLE(pan_blend_shader_key);
473*61046927SAndroid Build Coastguard Worker 
474*61046927SAndroid Build Coastguard Worker void
pan_blend_shader_cache_init(struct pan_blend_shader_cache * cache,unsigned gpu_id)475*61046927SAndroid Build Coastguard Worker pan_blend_shader_cache_init(struct pan_blend_shader_cache *cache,
476*61046927SAndroid Build Coastguard Worker                             unsigned gpu_id)
477*61046927SAndroid Build Coastguard Worker {
478*61046927SAndroid Build Coastguard Worker    cache->gpu_id = gpu_id;
479*61046927SAndroid Build Coastguard Worker    cache->shaders = pan_blend_shader_key_table_create(NULL);
480*61046927SAndroid Build Coastguard Worker    pthread_mutex_init(&cache->lock, NULL);
481*61046927SAndroid Build Coastguard Worker }
482*61046927SAndroid Build Coastguard Worker 
483*61046927SAndroid Build Coastguard Worker void
pan_blend_shader_cache_cleanup(struct pan_blend_shader_cache * cache)484*61046927SAndroid Build Coastguard Worker pan_blend_shader_cache_cleanup(struct pan_blend_shader_cache *cache)
485*61046927SAndroid Build Coastguard Worker {
486*61046927SAndroid Build Coastguard Worker    _mesa_hash_table_destroy(cache->shaders, NULL);
487*61046927SAndroid Build Coastguard Worker    pthread_mutex_destroy(&cache->lock);
488*61046927SAndroid Build Coastguard Worker }
489*61046927SAndroid Build Coastguard Worker 
490*61046927SAndroid Build Coastguard Worker #else /* ifndef PAN_ARCH */
491*61046927SAndroid Build Coastguard Worker 
492*61046927SAndroid Build Coastguard Worker static const char *
logicop_str(enum pipe_logicop logicop)493*61046927SAndroid Build Coastguard Worker logicop_str(enum pipe_logicop logicop)
494*61046927SAndroid Build Coastguard Worker {
495*61046927SAndroid Build Coastguard Worker    switch (logicop) {
496*61046927SAndroid Build Coastguard Worker    case PIPE_LOGICOP_CLEAR:
497*61046927SAndroid Build Coastguard Worker       return "clear";
498*61046927SAndroid Build Coastguard Worker    case PIPE_LOGICOP_NOR:
499*61046927SAndroid Build Coastguard Worker       return "nor";
500*61046927SAndroid Build Coastguard Worker    case PIPE_LOGICOP_AND_INVERTED:
501*61046927SAndroid Build Coastguard Worker       return "and-inverted";
502*61046927SAndroid Build Coastguard Worker    case PIPE_LOGICOP_COPY_INVERTED:
503*61046927SAndroid Build Coastguard Worker       return "copy-inverted";
504*61046927SAndroid Build Coastguard Worker    case PIPE_LOGICOP_AND_REVERSE:
505*61046927SAndroid Build Coastguard Worker       return "and-reverse";
506*61046927SAndroid Build Coastguard Worker    case PIPE_LOGICOP_INVERT:
507*61046927SAndroid Build Coastguard Worker       return "invert";
508*61046927SAndroid Build Coastguard Worker    case PIPE_LOGICOP_XOR:
509*61046927SAndroid Build Coastguard Worker       return "xor";
510*61046927SAndroid Build Coastguard Worker    case PIPE_LOGICOP_NAND:
511*61046927SAndroid Build Coastguard Worker       return "nand";
512*61046927SAndroid Build Coastguard Worker    case PIPE_LOGICOP_AND:
513*61046927SAndroid Build Coastguard Worker       return "and";
514*61046927SAndroid Build Coastguard Worker    case PIPE_LOGICOP_EQUIV:
515*61046927SAndroid Build Coastguard Worker       return "equiv";
516*61046927SAndroid Build Coastguard Worker    case PIPE_LOGICOP_NOOP:
517*61046927SAndroid Build Coastguard Worker       return "noop";
518*61046927SAndroid Build Coastguard Worker    case PIPE_LOGICOP_OR_INVERTED:
519*61046927SAndroid Build Coastguard Worker       return "or-inverted";
520*61046927SAndroid Build Coastguard Worker    case PIPE_LOGICOP_COPY:
521*61046927SAndroid Build Coastguard Worker       return "copy";
522*61046927SAndroid Build Coastguard Worker    case PIPE_LOGICOP_OR_REVERSE:
523*61046927SAndroid Build Coastguard Worker       return "or-reverse";
524*61046927SAndroid Build Coastguard Worker    case PIPE_LOGICOP_OR:
525*61046927SAndroid Build Coastguard Worker       return "or";
526*61046927SAndroid Build Coastguard Worker    case PIPE_LOGICOP_SET:
527*61046927SAndroid Build Coastguard Worker       return "set";
528*61046927SAndroid Build Coastguard Worker    default:
529*61046927SAndroid Build Coastguard Worker       unreachable("Invalid logicop\n");
530*61046927SAndroid Build Coastguard Worker    }
531*61046927SAndroid Build Coastguard Worker }
532*61046927SAndroid Build Coastguard Worker 
533*61046927SAndroid Build Coastguard Worker static void
get_equation_str(const struct pan_blend_rt_state * rt_state,char * str,unsigned len)534*61046927SAndroid Build Coastguard Worker get_equation_str(const struct pan_blend_rt_state *rt_state, char *str,
535*61046927SAndroid Build Coastguard Worker                  unsigned len)
536*61046927SAndroid Build Coastguard Worker {
537*61046927SAndroid Build Coastguard Worker    const char *funcs[] = {
538*61046927SAndroid Build Coastguard Worker       "add", "sub", "reverse_sub", "min", "max",
539*61046927SAndroid Build Coastguard Worker    };
540*61046927SAndroid Build Coastguard Worker    const char *factors[] = {
541*61046927SAndroid Build Coastguard Worker       "",           "one",           "src_color",   "src_alpha",   "dst_alpha",
542*61046927SAndroid Build Coastguard Worker       "dst_color",  "src_alpha_sat", "const_color", "const_alpha", "src1_color",
543*61046927SAndroid Build Coastguard Worker       "src1_alpha",
544*61046927SAndroid Build Coastguard Worker    };
545*61046927SAndroid Build Coastguard Worker    int ret;
546*61046927SAndroid Build Coastguard Worker 
547*61046927SAndroid Build Coastguard Worker    if (!rt_state->equation.blend_enable) {
548*61046927SAndroid Build Coastguard Worker       ret = snprintf(str, len, "replace(%s%s%s%s)",
549*61046927SAndroid Build Coastguard Worker                      (rt_state->equation.color_mask & 1) ? "R" : "",
550*61046927SAndroid Build Coastguard Worker                      (rt_state->equation.color_mask & 2) ? "G" : "",
551*61046927SAndroid Build Coastguard Worker                      (rt_state->equation.color_mask & 4) ? "B" : "",
552*61046927SAndroid Build Coastguard Worker                      (rt_state->equation.color_mask & 8) ? "A" : "");
553*61046927SAndroid Build Coastguard Worker       assert(ret > 0);
554*61046927SAndroid Build Coastguard Worker       return;
555*61046927SAndroid Build Coastguard Worker    }
556*61046927SAndroid Build Coastguard Worker 
557*61046927SAndroid Build Coastguard Worker    if (rt_state->equation.color_mask & 7) {
558*61046927SAndroid Build Coastguard Worker       assert(rt_state->equation.rgb_func < ARRAY_SIZE(funcs));
559*61046927SAndroid Build Coastguard Worker       ret = snprintf(
560*61046927SAndroid Build Coastguard Worker          str, len, "%s%s%s(func=%s,src_factor=%s%s,dst_factor=%s%s)%s",
561*61046927SAndroid Build Coastguard Worker          (rt_state->equation.color_mask & 1) ? "R" : "",
562*61046927SAndroid Build Coastguard Worker          (rt_state->equation.color_mask & 2) ? "G" : "",
563*61046927SAndroid Build Coastguard Worker          (rt_state->equation.color_mask & 4) ? "B" : "",
564*61046927SAndroid Build Coastguard Worker          funcs[rt_state->equation.rgb_func],
565*61046927SAndroid Build Coastguard Worker          util_blendfactor_is_inverted(rt_state->equation.rgb_src_factor) ? "-"
566*61046927SAndroid Build Coastguard Worker                                                                          : "",
567*61046927SAndroid Build Coastguard Worker          factors[util_blendfactor_without_invert(
568*61046927SAndroid Build Coastguard Worker             rt_state->equation.rgb_src_factor)],
569*61046927SAndroid Build Coastguard Worker          util_blendfactor_is_inverted(rt_state->equation.rgb_dst_factor) ? "-"
570*61046927SAndroid Build Coastguard Worker                                                                          : "",
571*61046927SAndroid Build Coastguard Worker          factors[util_blendfactor_without_invert(
572*61046927SAndroid Build Coastguard Worker             rt_state->equation.rgb_dst_factor)],
573*61046927SAndroid Build Coastguard Worker          rt_state->equation.color_mask & 8 ? ";" : "");
574*61046927SAndroid Build Coastguard Worker       assert(ret > 0);
575*61046927SAndroid Build Coastguard Worker       str += ret;
576*61046927SAndroid Build Coastguard Worker       len -= ret;
577*61046927SAndroid Build Coastguard Worker    }
578*61046927SAndroid Build Coastguard Worker 
579*61046927SAndroid Build Coastguard Worker    if (rt_state->equation.color_mask & 8) {
580*61046927SAndroid Build Coastguard Worker       assert(rt_state->equation.alpha_func < ARRAY_SIZE(funcs));
581*61046927SAndroid Build Coastguard Worker       ret = snprintf(
582*61046927SAndroid Build Coastguard Worker          str, len, "A(func=%s,src_factor=%s%s,dst_factor=%s%s)",
583*61046927SAndroid Build Coastguard Worker          funcs[rt_state->equation.alpha_func],
584*61046927SAndroid Build Coastguard Worker          util_blendfactor_is_inverted(rt_state->equation.alpha_src_factor) ? "-"
585*61046927SAndroid Build Coastguard Worker                                                                            : "",
586*61046927SAndroid Build Coastguard Worker          factors[util_blendfactor_without_invert(
587*61046927SAndroid Build Coastguard Worker             rt_state->equation.alpha_src_factor)],
588*61046927SAndroid Build Coastguard Worker          util_blendfactor_is_inverted(rt_state->equation.alpha_dst_factor) ? "-"
589*61046927SAndroid Build Coastguard Worker                                                                            : "",
590*61046927SAndroid Build Coastguard Worker          factors[util_blendfactor_without_invert(
591*61046927SAndroid Build Coastguard Worker             rt_state->equation.alpha_dst_factor)]);
592*61046927SAndroid Build Coastguard Worker       assert(ret > 0);
593*61046927SAndroid Build Coastguard Worker       str += ret;
594*61046927SAndroid Build Coastguard Worker       len -= ret;
595*61046927SAndroid Build Coastguard Worker    }
596*61046927SAndroid Build Coastguard Worker }
597*61046927SAndroid Build Coastguard Worker 
598*61046927SAndroid Build Coastguard Worker static bool
pan_inline_blend_constants(nir_builder * b,nir_intrinsic_instr * intr,void * data)599*61046927SAndroid Build Coastguard Worker pan_inline_blend_constants(nir_builder *b, nir_intrinsic_instr *intr,
600*61046927SAndroid Build Coastguard Worker                            void *data)
601*61046927SAndroid Build Coastguard Worker {
602*61046927SAndroid Build Coastguard Worker    if (intr->intrinsic != nir_intrinsic_load_blend_const_color_rgba)
603*61046927SAndroid Build Coastguard Worker       return false;
604*61046927SAndroid Build Coastguard Worker 
605*61046927SAndroid Build Coastguard Worker    float *floats = data;
606*61046927SAndroid Build Coastguard Worker    const nir_const_value constants[4] = {
607*61046927SAndroid Build Coastguard Worker       nir_const_value_for_float(floats[0], 32),
608*61046927SAndroid Build Coastguard Worker       nir_const_value_for_float(floats[1], 32),
609*61046927SAndroid Build Coastguard Worker       nir_const_value_for_float(floats[2], 32),
610*61046927SAndroid Build Coastguard Worker       nir_const_value_for_float(floats[3], 32)};
611*61046927SAndroid Build Coastguard Worker 
612*61046927SAndroid Build Coastguard Worker    b->cursor = nir_after_instr(&intr->instr);
613*61046927SAndroid Build Coastguard Worker    nir_def *constant = nir_build_imm(b, 4, 32, constants);
614*61046927SAndroid Build Coastguard Worker    nir_def_replace(&intr->def, constant);
615*61046927SAndroid Build Coastguard Worker    return true;
616*61046927SAndroid Build Coastguard Worker }
617*61046927SAndroid Build Coastguard Worker 
618*61046927SAndroid Build Coastguard Worker nir_shader *
GENX(pan_blend_create_shader)619*61046927SAndroid Build Coastguard Worker GENX(pan_blend_create_shader)(const struct pan_blend_state *state,
620*61046927SAndroid Build Coastguard Worker                               nir_alu_type src0_type, nir_alu_type src1_type,
621*61046927SAndroid Build Coastguard Worker                               unsigned rt)
622*61046927SAndroid Build Coastguard Worker {
623*61046927SAndroid Build Coastguard Worker    const struct pan_blend_rt_state *rt_state = &state->rts[rt];
624*61046927SAndroid Build Coastguard Worker    char equation_str[128] = {0};
625*61046927SAndroid Build Coastguard Worker 
626*61046927SAndroid Build Coastguard Worker    get_equation_str(rt_state, equation_str, sizeof(equation_str));
627*61046927SAndroid Build Coastguard Worker 
628*61046927SAndroid Build Coastguard Worker    nir_builder b = nir_builder_init_simple_shader(
629*61046927SAndroid Build Coastguard Worker       MESA_SHADER_FRAGMENT, GENX(pan_shader_get_compiler_options)(),
630*61046927SAndroid Build Coastguard Worker       "pan_blend(rt=%d,fmt=%s,nr_samples=%d,%s=%s)", rt,
631*61046927SAndroid Build Coastguard Worker       util_format_name(rt_state->format), rt_state->nr_samples,
632*61046927SAndroid Build Coastguard Worker       state->logicop_enable ? "logicop" : "equation",
633*61046927SAndroid Build Coastguard Worker       state->logicop_enable ? logicop_str(state->logicop_func) : equation_str);
634*61046927SAndroid Build Coastguard Worker 
635*61046927SAndroid Build Coastguard Worker    const struct util_format_description *format_desc =
636*61046927SAndroid Build Coastguard Worker       util_format_description(rt_state->format);
637*61046927SAndroid Build Coastguard Worker    nir_alu_type nir_type = pan_unpacked_type_for_format(format_desc);
638*61046927SAndroid Build Coastguard Worker 
639*61046927SAndroid Build Coastguard Worker    /* Bifrost/Valhall support 16-bit and 32-bit register formats for
640*61046927SAndroid Build Coastguard Worker     * LD_TILE/ST_TILE/BLEND, but do not support 8-bit. Rather than making
641*61046927SAndroid Build Coastguard Worker     * the fragment output 8-bit and inserting extra conversions in the
642*61046927SAndroid Build Coastguard Worker     * compiler, promote the output to 16-bit. The larger size is still
643*61046927SAndroid Build Coastguard Worker     * compatible with correct conversion semantics.
644*61046927SAndroid Build Coastguard Worker     */
645*61046927SAndroid Build Coastguard Worker    if (PAN_ARCH >= 6 && nir_alu_type_get_type_size(nir_type) == 8)
646*61046927SAndroid Build Coastguard Worker       nir_type = nir_alu_type_get_base_type(nir_type) | 16;
647*61046927SAndroid Build Coastguard Worker 
648*61046927SAndroid Build Coastguard Worker    nir_lower_blend_options options = {
649*61046927SAndroid Build Coastguard Worker       .logicop_enable = state->logicop_enable,
650*61046927SAndroid Build Coastguard Worker       .logicop_func = state->logicop_func,
651*61046927SAndroid Build Coastguard Worker    };
652*61046927SAndroid Build Coastguard Worker 
653*61046927SAndroid Build Coastguard Worker    options.rt[rt].colormask = rt_state->equation.color_mask;
654*61046927SAndroid Build Coastguard Worker    options.format[rt] = rt_state->format;
655*61046927SAndroid Build Coastguard Worker 
656*61046927SAndroid Build Coastguard Worker    if (!rt_state->equation.blend_enable) {
657*61046927SAndroid Build Coastguard Worker       static const nir_lower_blend_channel replace = {
658*61046927SAndroid Build Coastguard Worker          .func = PIPE_BLEND_ADD,
659*61046927SAndroid Build Coastguard Worker          .src_factor = PIPE_BLENDFACTOR_ONE,
660*61046927SAndroid Build Coastguard Worker          .dst_factor = PIPE_BLENDFACTOR_ZERO,
661*61046927SAndroid Build Coastguard Worker       };
662*61046927SAndroid Build Coastguard Worker 
663*61046927SAndroid Build Coastguard Worker       options.rt[rt].rgb = replace;
664*61046927SAndroid Build Coastguard Worker       options.rt[rt].alpha = replace;
665*61046927SAndroid Build Coastguard Worker    } else {
666*61046927SAndroid Build Coastguard Worker       options.rt[rt].rgb.func = rt_state->equation.rgb_func;
667*61046927SAndroid Build Coastguard Worker       options.rt[rt].rgb.src_factor = rt_state->equation.rgb_src_factor;
668*61046927SAndroid Build Coastguard Worker       options.rt[rt].rgb.dst_factor = rt_state->equation.rgb_dst_factor;
669*61046927SAndroid Build Coastguard Worker       options.rt[rt].alpha.func = rt_state->equation.alpha_func;
670*61046927SAndroid Build Coastguard Worker       options.rt[rt].alpha.src_factor = rt_state->equation.alpha_src_factor;
671*61046927SAndroid Build Coastguard Worker       options.rt[rt].alpha.dst_factor = rt_state->equation.alpha_dst_factor;
672*61046927SAndroid Build Coastguard Worker    }
673*61046927SAndroid Build Coastguard Worker 
674*61046927SAndroid Build Coastguard Worker    nir_def *pixel = nir_load_barycentric_pixel(&b, 32, .interp_mode = 1);
675*61046927SAndroid Build Coastguard Worker    nir_def *zero = nir_imm_int(&b, 0);
676*61046927SAndroid Build Coastguard Worker 
677*61046927SAndroid Build Coastguard Worker    for (unsigned i = 0; i < 2; ++i) {
678*61046927SAndroid Build Coastguard Worker       nir_alu_type src_type =
679*61046927SAndroid Build Coastguard Worker          (i == 1 ? src1_type : src0_type) ?: nir_type_float32;
680*61046927SAndroid Build Coastguard Worker 
681*61046927SAndroid Build Coastguard Worker       /* HACK: workaround buggy TGSI shaders (u_blitter) */
682*61046927SAndroid Build Coastguard Worker       src_type = nir_alu_type_get_base_type(nir_type) |
683*61046927SAndroid Build Coastguard Worker                  nir_alu_type_get_type_size(src_type);
684*61046927SAndroid Build Coastguard Worker 
685*61046927SAndroid Build Coastguard Worker       nir_def *src = nir_load_interpolated_input(
686*61046927SAndroid Build Coastguard Worker          &b, 4, nir_alu_type_get_type_size(src_type), pixel, zero,
687*61046927SAndroid Build Coastguard Worker          .io_semantics.location = i ? VARYING_SLOT_VAR0 : VARYING_SLOT_COL0,
688*61046927SAndroid Build Coastguard Worker          .io_semantics.num_slots = 1, .base = i, .dest_type = src_type);
689*61046927SAndroid Build Coastguard Worker 
690*61046927SAndroid Build Coastguard Worker       /* On Midgard, the blend shader is responsible for format conversion.
691*61046927SAndroid Build Coastguard Worker        * As the OpenGL spec requires integer conversions to saturate, we must
692*61046927SAndroid Build Coastguard Worker        * saturate ourselves here. On Bifrost and later, the conversion
693*61046927SAndroid Build Coastguard Worker        * hardware handles this automatically.
694*61046927SAndroid Build Coastguard Worker        */
695*61046927SAndroid Build Coastguard Worker       nir_alu_type T = nir_alu_type_get_base_type(nir_type);
696*61046927SAndroid Build Coastguard Worker       bool should_saturate = (PAN_ARCH <= 5) && (T != nir_type_float);
697*61046927SAndroid Build Coastguard Worker       src = nir_convert_with_rounding(&b, src, T, nir_type,
698*61046927SAndroid Build Coastguard Worker                                       nir_rounding_mode_undef, should_saturate);
699*61046927SAndroid Build Coastguard Worker 
700*61046927SAndroid Build Coastguard Worker       nir_store_output(&b, src, zero, .write_mask = BITFIELD_MASK(4),
701*61046927SAndroid Build Coastguard Worker                        .src_type = nir_type,
702*61046927SAndroid Build Coastguard Worker                        .io_semantics.location = FRAG_RESULT_DATA0 + rt,
703*61046927SAndroid Build Coastguard Worker                        .io_semantics.num_slots = 1,
704*61046927SAndroid Build Coastguard Worker                        .io_semantics.dual_source_blend_index = i);
705*61046927SAndroid Build Coastguard Worker    }
706*61046927SAndroid Build Coastguard Worker 
707*61046927SAndroid Build Coastguard Worker    b.shader->info.io_lowered = true;
708*61046927SAndroid Build Coastguard Worker 
709*61046927SAndroid Build Coastguard Worker    NIR_PASS_V(b.shader, nir_lower_blend, &options);
710*61046927SAndroid Build Coastguard Worker 
711*61046927SAndroid Build Coastguard Worker    return b.shader;
712*61046927SAndroid Build Coastguard Worker }
713*61046927SAndroid Build Coastguard Worker 
714*61046927SAndroid Build Coastguard Worker #if PAN_ARCH >= 6
715*61046927SAndroid Build Coastguard Worker uint64_t
GENX(pan_blend_get_internal_desc)716*61046927SAndroid Build Coastguard Worker GENX(pan_blend_get_internal_desc)(enum pipe_format fmt, unsigned rt,
717*61046927SAndroid Build Coastguard Worker                                   unsigned force_size, bool dithered)
718*61046927SAndroid Build Coastguard Worker {
719*61046927SAndroid Build Coastguard Worker    const struct util_format_description *desc = util_format_description(fmt);
720*61046927SAndroid Build Coastguard Worker    uint64_t res;
721*61046927SAndroid Build Coastguard Worker 
722*61046927SAndroid Build Coastguard Worker    pan_pack(&res, INTERNAL_BLEND, cfg) {
723*61046927SAndroid Build Coastguard Worker       cfg.mode = MALI_BLEND_MODE_OPAQUE;
724*61046927SAndroid Build Coastguard Worker       cfg.fixed_function.num_comps = desc->nr_channels;
725*61046927SAndroid Build Coastguard Worker       cfg.fixed_function.rt = rt;
726*61046927SAndroid Build Coastguard Worker 
727*61046927SAndroid Build Coastguard Worker       nir_alu_type T = pan_unpacked_type_for_format(desc);
728*61046927SAndroid Build Coastguard Worker 
729*61046927SAndroid Build Coastguard Worker       if (force_size)
730*61046927SAndroid Build Coastguard Worker          T = nir_alu_type_get_base_type(T) | force_size;
731*61046927SAndroid Build Coastguard Worker 
732*61046927SAndroid Build Coastguard Worker       switch (T) {
733*61046927SAndroid Build Coastguard Worker       case nir_type_float16:
734*61046927SAndroid Build Coastguard Worker          cfg.fixed_function.conversion.register_format =
735*61046927SAndroid Build Coastguard Worker             MALI_REGISTER_FILE_FORMAT_F16;
736*61046927SAndroid Build Coastguard Worker          break;
737*61046927SAndroid Build Coastguard Worker       case nir_type_float32:
738*61046927SAndroid Build Coastguard Worker          cfg.fixed_function.conversion.register_format =
739*61046927SAndroid Build Coastguard Worker             MALI_REGISTER_FILE_FORMAT_F32;
740*61046927SAndroid Build Coastguard Worker          break;
741*61046927SAndroid Build Coastguard Worker       case nir_type_int8:
742*61046927SAndroid Build Coastguard Worker       case nir_type_int16:
743*61046927SAndroid Build Coastguard Worker          cfg.fixed_function.conversion.register_format =
744*61046927SAndroid Build Coastguard Worker             MALI_REGISTER_FILE_FORMAT_I16;
745*61046927SAndroid Build Coastguard Worker          break;
746*61046927SAndroid Build Coastguard Worker       case nir_type_int32:
747*61046927SAndroid Build Coastguard Worker          cfg.fixed_function.conversion.register_format =
748*61046927SAndroid Build Coastguard Worker             MALI_REGISTER_FILE_FORMAT_I32;
749*61046927SAndroid Build Coastguard Worker          break;
750*61046927SAndroid Build Coastguard Worker       case nir_type_uint8:
751*61046927SAndroid Build Coastguard Worker       case nir_type_uint16:
752*61046927SAndroid Build Coastguard Worker          cfg.fixed_function.conversion.register_format =
753*61046927SAndroid Build Coastguard Worker             MALI_REGISTER_FILE_FORMAT_U16;
754*61046927SAndroid Build Coastguard Worker          break;
755*61046927SAndroid Build Coastguard Worker       case nir_type_uint32:
756*61046927SAndroid Build Coastguard Worker          cfg.fixed_function.conversion.register_format =
757*61046927SAndroid Build Coastguard Worker             MALI_REGISTER_FILE_FORMAT_U32;
758*61046927SAndroid Build Coastguard Worker          break;
759*61046927SAndroid Build Coastguard Worker       default:
760*61046927SAndroid Build Coastguard Worker          unreachable("Invalid format");
761*61046927SAndroid Build Coastguard Worker       }
762*61046927SAndroid Build Coastguard Worker 
763*61046927SAndroid Build Coastguard Worker       cfg.fixed_function.conversion.memory_format =
764*61046927SAndroid Build Coastguard Worker          GENX(panfrost_dithered_format_from_pipe_format)(fmt, dithered);
765*61046927SAndroid Build Coastguard Worker    }
766*61046927SAndroid Build Coastguard Worker 
767*61046927SAndroid Build Coastguard Worker    return res;
768*61046927SAndroid Build Coastguard Worker }
769*61046927SAndroid Build Coastguard Worker 
770*61046927SAndroid Build Coastguard Worker static bool
inline_rt_conversion(nir_builder * b,nir_intrinsic_instr * intr,void * data)771*61046927SAndroid Build Coastguard Worker inline_rt_conversion(nir_builder *b, nir_intrinsic_instr *intr, void *data)
772*61046927SAndroid Build Coastguard Worker {
773*61046927SAndroid Build Coastguard Worker    if (intr->intrinsic != nir_intrinsic_load_rt_conversion_pan)
774*61046927SAndroid Build Coastguard Worker       return false;
775*61046927SAndroid Build Coastguard Worker 
776*61046927SAndroid Build Coastguard Worker    enum pipe_format *formats = data;
777*61046927SAndroid Build Coastguard Worker    unsigned rt = nir_intrinsic_base(intr);
778*61046927SAndroid Build Coastguard Worker    unsigned size = nir_alu_type_get_type_size(nir_intrinsic_src_type(intr));
779*61046927SAndroid Build Coastguard Worker    uint64_t conversion =
780*61046927SAndroid Build Coastguard Worker       GENX(pan_blend_get_internal_desc)(formats[rt], rt, size, false);
781*61046927SAndroid Build Coastguard Worker 
782*61046927SAndroid Build Coastguard Worker    b->cursor = nir_after_instr(&intr->instr);
783*61046927SAndroid Build Coastguard Worker    nir_def_rewrite_uses(&intr->def, nir_imm_int(b, conversion >> 32));
784*61046927SAndroid Build Coastguard Worker    return true;
785*61046927SAndroid Build Coastguard Worker }
786*61046927SAndroid Build Coastguard Worker 
787*61046927SAndroid Build Coastguard Worker bool
GENX(pan_inline_rt_conversion)788*61046927SAndroid Build Coastguard Worker GENX(pan_inline_rt_conversion)(nir_shader *s, enum pipe_format *formats)
789*61046927SAndroid Build Coastguard Worker {
790*61046927SAndroid Build Coastguard Worker    return nir_shader_intrinsics_pass(s, inline_rt_conversion,
791*61046927SAndroid Build Coastguard Worker                                      nir_metadata_control_flow, formats);
792*61046927SAndroid Build Coastguard Worker }
793*61046927SAndroid Build Coastguard Worker #endif
794*61046927SAndroid Build Coastguard Worker 
795*61046927SAndroid Build Coastguard Worker struct pan_blend_shader_variant *
GENX(pan_blend_get_shader_locked)796*61046927SAndroid Build Coastguard Worker GENX(pan_blend_get_shader_locked)(struct pan_blend_shader_cache *cache,
797*61046927SAndroid Build Coastguard Worker                                   const struct pan_blend_state *state,
798*61046927SAndroid Build Coastguard Worker                                   nir_alu_type src0_type,
799*61046927SAndroid Build Coastguard Worker                                   nir_alu_type src1_type, unsigned rt)
800*61046927SAndroid Build Coastguard Worker {
801*61046927SAndroid Build Coastguard Worker    struct pan_blend_shader_key key = {
802*61046927SAndroid Build Coastguard Worker       .format = state->rts[rt].format,
803*61046927SAndroid Build Coastguard Worker       .src0_type = src0_type,
804*61046927SAndroid Build Coastguard Worker       .src1_type = src1_type,
805*61046927SAndroid Build Coastguard Worker       .rt = rt,
806*61046927SAndroid Build Coastguard Worker       .has_constants = pan_blend_constant_mask(state->rts[rt].equation) != 0,
807*61046927SAndroid Build Coastguard Worker       .logicop_enable = state->logicop_enable,
808*61046927SAndroid Build Coastguard Worker       .logicop_func = state->logicop_func,
809*61046927SAndroid Build Coastguard Worker       .nr_samples = state->rts[rt].nr_samples,
810*61046927SAndroid Build Coastguard Worker       .equation = state->rts[rt].equation,
811*61046927SAndroid Build Coastguard Worker    };
812*61046927SAndroid Build Coastguard Worker 
813*61046927SAndroid Build Coastguard Worker    /* Blend shaders should only be used for blending on Bifrost onwards */
814*61046927SAndroid Build Coastguard Worker    assert(PAN_ARCH <= 5 || state->logicop_enable ||
815*61046927SAndroid Build Coastguard Worker           !pan_blend_is_opaque(state->rts[rt].equation));
816*61046927SAndroid Build Coastguard Worker    assert(state->rts[rt].equation.color_mask != 0);
817*61046927SAndroid Build Coastguard Worker 
818*61046927SAndroid Build Coastguard Worker    struct hash_entry *he =
819*61046927SAndroid Build Coastguard Worker       _mesa_hash_table_search(cache->shaders, &key);
820*61046927SAndroid Build Coastguard Worker    struct pan_blend_shader *shader = he ? he->data : NULL;
821*61046927SAndroid Build Coastguard Worker 
822*61046927SAndroid Build Coastguard Worker    if (!shader) {
823*61046927SAndroid Build Coastguard Worker       shader = rzalloc(cache->shaders, struct pan_blend_shader);
824*61046927SAndroid Build Coastguard Worker       shader->key = key;
825*61046927SAndroid Build Coastguard Worker       list_inithead(&shader->variants);
826*61046927SAndroid Build Coastguard Worker       _mesa_hash_table_insert(cache->shaders, &shader->key, shader);
827*61046927SAndroid Build Coastguard Worker    }
828*61046927SAndroid Build Coastguard Worker 
829*61046927SAndroid Build Coastguard Worker    list_for_each_entry(struct pan_blend_shader_variant, iter, &shader->variants,
830*61046927SAndroid Build Coastguard Worker                        node) {
831*61046927SAndroid Build Coastguard Worker       if (!key.has_constants ||
832*61046927SAndroid Build Coastguard Worker           !memcmp(iter->constants, state->constants, sizeof(iter->constants))) {
833*61046927SAndroid Build Coastguard Worker          return iter;
834*61046927SAndroid Build Coastguard Worker       }
835*61046927SAndroid Build Coastguard Worker    }
836*61046927SAndroid Build Coastguard Worker 
837*61046927SAndroid Build Coastguard Worker    struct pan_blend_shader_variant *variant = NULL;
838*61046927SAndroid Build Coastguard Worker 
839*61046927SAndroid Build Coastguard Worker    if (shader->nvariants < PAN_BLEND_SHADER_MAX_VARIANTS) {
840*61046927SAndroid Build Coastguard Worker       variant = rzalloc(shader, struct pan_blend_shader_variant);
841*61046927SAndroid Build Coastguard Worker       util_dynarray_init(&variant->binary, variant);
842*61046927SAndroid Build Coastguard Worker       list_add(&variant->node, &shader->variants);
843*61046927SAndroid Build Coastguard Worker       shader->nvariants++;
844*61046927SAndroid Build Coastguard Worker    } else {
845*61046927SAndroid Build Coastguard Worker       variant = list_last_entry(&shader->variants,
846*61046927SAndroid Build Coastguard Worker                                 struct pan_blend_shader_variant, node);
847*61046927SAndroid Build Coastguard Worker       list_del(&variant->node);
848*61046927SAndroid Build Coastguard Worker       list_add(&variant->node, &shader->variants);
849*61046927SAndroid Build Coastguard Worker       util_dynarray_clear(&variant->binary);
850*61046927SAndroid Build Coastguard Worker    }
851*61046927SAndroid Build Coastguard Worker 
852*61046927SAndroid Build Coastguard Worker    memcpy(variant->constants, state->constants, sizeof(variant->constants));
853*61046927SAndroid Build Coastguard Worker 
854*61046927SAndroid Build Coastguard Worker    nir_shader *nir =
855*61046927SAndroid Build Coastguard Worker       GENX(pan_blend_create_shader)(state, src0_type, src1_type, rt);
856*61046927SAndroid Build Coastguard Worker 
857*61046927SAndroid Build Coastguard Worker    nir_shader_intrinsics_pass(nir, pan_inline_blend_constants,
858*61046927SAndroid Build Coastguard Worker                               nir_metadata_control_flow,
859*61046927SAndroid Build Coastguard Worker                               (void *)state->constants);
860*61046927SAndroid Build Coastguard Worker 
861*61046927SAndroid Build Coastguard Worker    /* Compile the NIR shader */
862*61046927SAndroid Build Coastguard Worker    struct panfrost_compile_inputs inputs = {
863*61046927SAndroid Build Coastguard Worker       .gpu_id = cache->gpu_id,
864*61046927SAndroid Build Coastguard Worker       .is_blend = true,
865*61046927SAndroid Build Coastguard Worker       .blend.nr_samples = key.nr_samples,
866*61046927SAndroid Build Coastguard Worker    };
867*61046927SAndroid Build Coastguard Worker 
868*61046927SAndroid Build Coastguard Worker    enum pipe_format rt_formats[8] = {0};
869*61046927SAndroid Build Coastguard Worker    rt_formats[rt] = key.format;
870*61046927SAndroid Build Coastguard Worker 
871*61046927SAndroid Build Coastguard Worker #if PAN_ARCH >= 6
872*61046927SAndroid Build Coastguard Worker    inputs.blend.bifrost_blend_desc =
873*61046927SAndroid Build Coastguard Worker       GENX(pan_blend_get_internal_desc)(key.format, key.rt, 0, false);
874*61046927SAndroid Build Coastguard Worker #endif
875*61046927SAndroid Build Coastguard Worker 
876*61046927SAndroid Build Coastguard Worker    struct pan_shader_info info;
877*61046927SAndroid Build Coastguard Worker    pan_shader_preprocess(nir, inputs.gpu_id);
878*61046927SAndroid Build Coastguard Worker 
879*61046927SAndroid Build Coastguard Worker #if PAN_ARCH >= 6
880*61046927SAndroid Build Coastguard Worker    NIR_PASS_V(nir, GENX(pan_inline_rt_conversion), rt_formats);
881*61046927SAndroid Build Coastguard Worker #else
882*61046927SAndroid Build Coastguard Worker    NIR_PASS_V(nir, pan_lower_framebuffer, rt_formats,
883*61046927SAndroid Build Coastguard Worker               pan_raw_format_mask_midgard(rt_formats), MAX2(key.nr_samples, 1),
884*61046927SAndroid Build Coastguard Worker               cache->gpu_id < 0x700);
885*61046927SAndroid Build Coastguard Worker #endif
886*61046927SAndroid Build Coastguard Worker 
887*61046927SAndroid Build Coastguard Worker    GENX(pan_shader_compile)(nir, &inputs, &variant->binary, &info);
888*61046927SAndroid Build Coastguard Worker 
889*61046927SAndroid Build Coastguard Worker    variant->work_reg_count = info.work_reg_count;
890*61046927SAndroid Build Coastguard Worker 
891*61046927SAndroid Build Coastguard Worker #if PAN_ARCH <= 5
892*61046927SAndroid Build Coastguard Worker    variant->first_tag = info.midgard.first_tag;
893*61046927SAndroid Build Coastguard Worker #endif
894*61046927SAndroid Build Coastguard Worker 
895*61046927SAndroid Build Coastguard Worker    ralloc_free(nir);
896*61046927SAndroid Build Coastguard Worker 
897*61046927SAndroid Build Coastguard Worker    return variant;
898*61046927SAndroid Build Coastguard Worker }
899*61046927SAndroid Build Coastguard Worker #endif /* ifndef PAN_ARCH */
900