panfrost: Cleanup default blend mode
[mesa.git] / src / gallium / drivers / panfrost / pan_blending.c
1 /*
2 * © Copyright 2018 Alyssa Rosenzweig
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 *
23 */
24
25 #include <stdio.h>
26 #include "pan_blending.h"
27 #include "pan_context.h"
28 #include "gallium/auxiliary/util/u_blend.h"
29
30 /*
31 * Implements fixed-function blending on Midgard.
32 *
33 * Midgard splits blending into a fixed-function fast path and a programmable
34 * slow path. The fixed function blending architecture is based on "dominant"
35 * blend factors. Blending is encoded separately (but identically) between RGB
36 * and alpha functions.
37 *
38 * Essentially, for a given blending operation, there is a single dominant
39 * factor. The following dominant factors are possible:
40 *
41 * - zero
42 * - source color
43 * - destination color
44 * - source alpha
45 * - destination alpha
46 * - constant float
47 *
48 * Further, a dominant factor's arithmetic compliment could be used. For
49 * instance, to encode GL_ONE_MINUS_SOURCE_ALPHA, the dominant factor would be
50 * MALI_DOMINANT_SRC_ALPHA with the complement_dominant bit set.
51 *
52 * A single constant float can be passed to the fixed-function hardware,
53 * allowing CONSTANT_ALPHA support. Further, if all components of the constant
54 * glBlendColor are identical, CONSTANT_COLOR can be implemented with the
55 * constant float mode. If the components differ, programmable blending is
56 * required.
57 *
58 * The nondominant factor can be either:
59 *
60 * - the same as the dominant factor (MALI_BLEND_NON_MIRROR)
61 * - zero (MALI_BLEND_NON_ZERO)
62 *
63 * Exactly one of the blend operation's source or destination can be used as
64 * the dominant factor; this is selected by the
65 * MALI_BLEND_DOM_SOURCE/DESTINATION flag.
66 *
67 * By default, all blending follows the standard OpenGL addition equation:
68 *
69 * out = source_value * source_factor + destination_value * destination_factor
70 *
71 * By setting the negate_source or negate_dest bits, other blend functions can
72 * be created. For instance, for SUBTRACT mode, set the "negate destination"
73 * flag, and similarly for REVERSE_SUBTRACT with "negate source".
74 *
75 * Finally, there is a "clip modifier" controlling the final blending
76 * behaviour, allowing for the following modes:
77 *
78 * - normal
79 * - force source factor to one (MALI_BLEND_MODE_SOURCE_ONE)
80 * - force destination factor to one (MALI_BLEND_MODE_DEST_ONE)
81 *
82 * The clipping flags can be used to encode blend modes where the nondominant
83 * factor is ONE.
84 *
85 * As an example putting it all together, to encode the following blend state:
86 *
87 * glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
88 * glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_ONE);
89 *
90 * We need the following configuration:
91 *
92 * - negate source (for REVERSE_SUBTRACT)
93 * - dominant factor "source alpha"
94 * - complement dominant
95 * - source dominant
96 * - force destination to ONE
97 *
98 * The following routines implement this fixed function blending encoding
99 */
100
101 /* Helper to find the uncomplemented Gallium blend factor corresponding to a
102 * complemented Gallium blend factor */
103
104 static int
105 complement_factor(int factor)
106 {
107 switch (factor) {
108 case PIPE_BLENDFACTOR_INV_SRC_COLOR:
109 return PIPE_BLENDFACTOR_SRC_COLOR;
110
111 case PIPE_BLENDFACTOR_INV_SRC_ALPHA:
112 return PIPE_BLENDFACTOR_SRC_ALPHA;
113
114 case PIPE_BLENDFACTOR_INV_DST_ALPHA:
115 return PIPE_BLENDFACTOR_DST_ALPHA;
116
117 case PIPE_BLENDFACTOR_INV_DST_COLOR:
118 return PIPE_BLENDFACTOR_DST_COLOR;
119
120 case PIPE_BLENDFACTOR_INV_CONST_COLOR:
121 return PIPE_BLENDFACTOR_CONST_COLOR;
122
123 case PIPE_BLENDFACTOR_INV_CONST_ALPHA:
124 return PIPE_BLENDFACTOR_CONST_ALPHA;
125
126 default:
127 return -1;
128 }
129 }
130
131 /* Helper to strip the complement from any Gallium blend factor */
132
133 static int
134 uncomplement_factor(int factor)
135 {
136 int complement = complement_factor(factor);
137 return (complement == -1) ? factor : complement;
138 }
139
140
141 /* Attempt to find the dominant factor given a particular factor, complementing
142 * as necessary */
143
144 static bool
145 panfrost_make_dominant_factor(unsigned src_factor, enum mali_dominant_factor *factor)
146 {
147 switch (src_factor) {
148 case PIPE_BLENDFACTOR_SRC_COLOR:
149 case PIPE_BLENDFACTOR_INV_SRC_COLOR:
150 *factor = MALI_DOMINANT_SRC_COLOR;
151 break;
152
153 case PIPE_BLENDFACTOR_SRC_ALPHA:
154 case PIPE_BLENDFACTOR_INV_SRC_ALPHA:
155 *factor = MALI_DOMINANT_SRC_ALPHA;
156 break;
157
158 case PIPE_BLENDFACTOR_DST_COLOR:
159 case PIPE_BLENDFACTOR_INV_DST_COLOR:
160 *factor = MALI_DOMINANT_DST_COLOR;
161 break;
162
163 case PIPE_BLENDFACTOR_DST_ALPHA:
164 case PIPE_BLENDFACTOR_INV_DST_ALPHA:
165 *factor = MALI_DOMINANT_DST_ALPHA;
166 break;
167
168 case PIPE_BLENDFACTOR_ONE:
169 case PIPE_BLENDFACTOR_ZERO:
170 *factor = MALI_DOMINANT_ZERO;
171 break;
172
173 case PIPE_BLENDFACTOR_CONST_ALPHA:
174 case PIPE_BLENDFACTOR_INV_CONST_ALPHA:
175 case PIPE_BLENDFACTOR_CONST_COLOR:
176 case PIPE_BLENDFACTOR_INV_CONST_COLOR:
177 *factor = MALI_DOMINANT_CONSTANT;
178 break;
179
180 default:
181 /* Fancy blend modes not supported */
182 return false;
183 }
184
185 return true;
186 }
187
188 /* Check if this is a special edge case blend factor, which may require the use
189 * of clip modifiers */
190
191 static bool
192 is_edge_blendfactor(unsigned factor)
193 {
194 return factor == PIPE_BLENDFACTOR_ONE || factor == PIPE_BLENDFACTOR_ZERO;
195 }
196
197 /* Perform the actual fixed function encoding. Encode the function with negate
198 * bits. Check for various cases to work out the dominant/nondominant split and
199 * accompanying flags. */
200
201 static bool
202 panfrost_make_fixed_blend_part(unsigned func, unsigned src_factor, unsigned dst_factor, unsigned *out)
203 {
204 struct mali_blend_mode part = { 0 };
205
206 /* Make sure that the blend function is representible */
207
208 switch (func) {
209 case PIPE_BLEND_ADD:
210 break;
211
212 /* TODO: Reenable subtraction modes when those fixed */
213 case PIPE_BLEND_SUBTRACT:
214 case PIPE_BLEND_REVERSE_SUBTRACT:
215 default:
216 return false;
217 }
218
219 part.clip_modifier = MALI_BLEND_MOD_NORMAL;
220
221 /* Decide which is dominant, source or destination. If one is an edge
222 * case, use the other as a factor. If they're the same, it doesn't
223 * matter; we just mirror. If they're different non-edge-cases, you
224 * need a blend shader (don't do that). */
225
226 if (is_edge_blendfactor(dst_factor)) {
227 part.dominant = MALI_BLEND_DOM_SOURCE;
228 part.nondominant_mode = MALI_BLEND_NON_ZERO;
229
230 if (dst_factor == PIPE_BLENDFACTOR_ONE)
231 part.clip_modifier = MALI_BLEND_MOD_DEST_ONE;
232 } else if (is_edge_blendfactor(src_factor)) {
233 part.dominant = MALI_BLEND_DOM_DESTINATION;
234 part.nondominant_mode = MALI_BLEND_NON_ZERO;
235
236 if (src_factor == PIPE_BLENDFACTOR_ONE)
237 part.clip_modifier = MALI_BLEND_MOD_SOURCE_ONE;
238 } else if (src_factor == dst_factor) {
239 /* XXX: Why? */
240 part.dominant = func == PIPE_BLEND_ADD ?
241 MALI_BLEND_DOM_DESTINATION : MALI_BLEND_DOM_SOURCE;
242
243 part.nondominant_mode = MALI_BLEND_NON_MIRROR;
244 } else if (src_factor == complement_factor(dst_factor)) {
245 /* TODO: How does this work exactly? */
246 part.dominant = MALI_BLEND_DOM_SOURCE;
247 part.nondominant_mode = MALI_BLEND_NON_MIRROR;
248 part.clip_modifier = MALI_BLEND_MOD_DEST_ONE;
249
250 /* The complement is handled by the clip modifier, don't set a
251 * complement flag */
252
253 dst_factor = src_factor;
254 } else if (dst_factor == complement_factor(src_factor)) {
255 part.dominant = MALI_BLEND_DOM_SOURCE;
256 part.nondominant_mode = MALI_BLEND_NON_MIRROR;
257 part.clip_modifier = MALI_BLEND_MOD_SOURCE_ONE;
258
259 src_factor = dst_factor;
260 } else {
261 return false;
262 }
263
264 unsigned in_dominant_factor =
265 part.dominant == MALI_BLEND_DOM_SOURCE ? src_factor : dst_factor;
266
267 if (part.clip_modifier == MALI_BLEND_MOD_NORMAL && in_dominant_factor == PIPE_BLENDFACTOR_ONE) {
268 part.clip_modifier = part.dominant == MALI_BLEND_DOM_SOURCE ? MALI_BLEND_MOD_SOURCE_ONE : MALI_BLEND_MOD_DEST_ONE;
269 in_dominant_factor = PIPE_BLENDFACTOR_ZERO;
270 }
271
272 enum mali_dominant_factor dominant_factor;
273
274 if (!panfrost_make_dominant_factor(in_dominant_factor, &dominant_factor))
275 return false;
276
277 part.dominant_factor = dominant_factor;
278 part.complement_dominant = util_blend_factor_is_inverted(in_dominant_factor);
279
280 /* It's not clear what this does, but fixes some ADD blending tests.
281 * More research is needed XXX */
282
283 if ((part.clip_modifier == MALI_BLEND_MOD_SOURCE_ONE) && (part.dominant == MALI_BLEND_DOM_SOURCE))
284 part.negate_dest = true;
285
286 /* Write out mode */
287 memcpy(out, &part, sizeof(part));
288
289 return true;
290 }
291
292 /* We can upload a single constant for all of the factors. So, scan the factors
293 * for constants used, and scan the constants for the constants used. If there
294 * is a single unique constant, output that. If there are multiple,
295 * fixed-function operation breaks down. */
296
297 static bool
298 panfrost_make_constant(unsigned *factors, unsigned num_factors, const struct pipe_blend_color *blend_color, void *out)
299 {
300 /* Color components used */
301 bool cc[4] = { false };
302
303 for (unsigned i = 0; i < num_factors; ++i) {
304 unsigned factor = uncomplement_factor(factors[i]);
305
306 if (factor == PIPE_BLENDFACTOR_CONST_COLOR)
307 cc[0] = cc[1] = cc[2] = true;
308 else if (factor == PIPE_BLENDFACTOR_CONST_ALPHA)
309 cc[3] = true;
310 }
311
312 /* Find the actual constant associated with the components used*/
313
314 float constant = 0.0;
315 bool has_constant = false;
316
317 for (unsigned i = 0; i < 4; ++i) {
318 /* If the component is unused, nothing to do */
319 if (!cc[i]) continue;
320
321 float value = blend_color->color[i];
322
323 /* Either there's a second constant, in which case we fail, or
324 * there's no constant / a first constant, in which case we use
325 * that constant */
326
327 if (has_constant && constant != value) {
328 return false;
329 } else {
330 has_constant = true;
331 constant = value;
332 }
333 }
334
335 /* We have the constant -- success! */
336
337 memcpy(out, &constant, sizeof(float));
338 return true;
339 }
340
341 /* Create the descriptor for a fixed blend mode given the corresponding Gallium
342 * state, if possible. Return true and write out the blend descriptor into
343 * blend_equation. If it is not possible with the fixed function
344 * representating, return false to handle degenerate cases with a blend shader
345 */
346
347 bool
348 panfrost_make_fixed_blend_mode(const struct pipe_rt_blend_state *blend, struct panfrost_blend_state *so, unsigned colormask, const struct pipe_blend_color *blend_color)
349 {
350 struct mali_blend_equation *out = &so->equation;
351
352 /* Gallium and Mali represent colour masks identically. XXX: Static assert for future proof */
353 out->color_mask = colormask;
354
355 /* If no blending is enabled, default back on `replace` mode */
356
357 if (!blend->blend_enable) {
358 out->rgb_mode = 0x122;
359 out->alpha_mode = 0x122;
360 return true;
361 }
362
363 /* We have room only for a single float32 constant between the four
364 * components. If we need more, spill to the programmable pipeline. */
365
366 unsigned factors[] = {
367 blend->rgb_src_factor, blend->rgb_dst_factor,
368 blend->alpha_src_factor, blend->alpha_dst_factor,
369 };
370
371 if (!panfrost_make_constant(factors, ARRAY_SIZE(factors), blend_color, &so->constant))
372 return false;
373
374 unsigned rgb_mode = 0;
375 unsigned alpha_mode = 0;
376
377 if (!panfrost_make_fixed_blend_part(
378 blend->rgb_func, blend->rgb_src_factor, blend->rgb_dst_factor,
379 &rgb_mode))
380 return false;
381
382 if (!panfrost_make_fixed_blend_part(
383 blend->alpha_func, blend->alpha_src_factor, blend->alpha_dst_factor,
384 &alpha_mode))
385 return false;
386
387 out->rgb_mode = rgb_mode;
388 out->alpha_mode = alpha_mode;
389
390 return true;
391 }