blob: 8564fa0eaf9aba8b6c188ce99692d4b5c2a958ea [file] [log] [blame]
Alyssa Rosenzweig7da251f2019-02-05 04:32:27 +00001/*
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_blend_shaders.h"
Tomeu Vizoso97f2d042019-03-08 15:24:57 +010027#include "pan_util.h"
Alyssa Rosenzweig7da251f2019-02-05 04:32:27 +000028#include "midgard/midgard_compile.h"
29#include "compiler/nir/nir_builder.h"
Alyssa Rosenzweigc2c89832019-07-10 09:51:32 -070030#include "nir/nir_lower_blend.h"
Alyssa Rosenzweig19b4e582020-05-13 15:04:47 -040031#include "panfrost/util/pan_lower_framebuffer.h"
Alyssa Rosenzweigd1a9b762019-05-06 02:13:55 +000032#include "gallium/auxiliary/util/u_blend.h"
Alyssa Rosenzweig46396af2019-07-05 15:40:08 -070033#include "util/u_memory.h"
Alyssa Rosenzweig7da251f2019-02-05 04:32:27 +000034
35/*
36 * Implements the command stream portion of programmatic blend shaders.
37 *
38 * On Midgard, common blending operations are accelerated by the fixed-function
39 * blending pipeline. Panfrost supports this fast path via the code in
40 * pan_blending.c. Nevertheless, uncommon blend modes (including some seemingly
41 * simple modes present in ES2) require "blend shaders", a special internal
42 * shader type used for programmable blending.
43 *
44 * Blend shaders operate during the normal blending time, but they bypass the
45 * fixed-function blending pipeline and instead go straight to the Midgard
46 * shader cores. The shaders themselves are essentially just fragment shaders,
47 * making heavy use of uint8 arithmetic to manipulate RGB values for the
48 * framebuffer.
49 *
50 * As is typical with Midgard, shader binaries must be accompanied by
51 * information about the first tag (ORed with the bottom nibble of address,
Alyssa Rosenzweig8bb51992020-05-12 15:39:38 -040052 * like usual) and work registers. Work register count is assumed to be less
53 * than or equal to the coresponding fragment shader's work count. This
54 * suggests that blend shader invocation is tied to fragment shader
Alyssa Rosenzweig7da251f2019-02-05 04:32:27 +000055 * execution.
56 *
Alyssa Rosenzweig8bb51992020-05-12 15:39:38 -040057 * The shaders themselves use the standard ISA. The source pixel colour,
58 * including alpha, is preloaded into r0 as a vec4 of float32. The destination
59 * pixel colour must be loaded explicitly via load/store ops, possibly
60 * performing conversions in software. The blended colour must be stored with a
61 * fragment writeout in the correct framebuffer format, either in software or
62 * via conversion opcodes on the load/store pipe.
Alyssa Rosenzweig7da251f2019-02-05 04:32:27 +000063 *
64 * Blend shaders hardcode constants. Naively, this requires recompilation each
65 * time the blend color changes, which is a performance risk. Accordingly, we
66 * 'cheat' a bit: instead of loading the constant, we compile a shader with a
67 * dummy constant, exporting the offset to the immediate in the shader binary,
68 * storing this generic binary and metadata in the CSO itself at CSO create
69 * time.
70 *
71 * We then hot patch in the color into this shader at attachment / color change
72 * time, allowing for CSO create to be the only expensive operation
73 * (compilation).
74 */
75
Alyssa Rosenzweigd1a9b762019-05-06 02:13:55 +000076static nir_lower_blend_options
Alyssa Rosenzweig8f4b1562019-12-30 12:13:45 -050077nir_make_options(const struct pipe_blend_state *blend, unsigned i)
Alyssa Rosenzweig7da251f2019-02-05 04:32:27 +000078{
Alyssa Rosenzweig8dc8b662020-05-13 16:27:25 -040079 nir_lower_blend_options options = { 0 };
Alyssa Rosenzweig7da251f2019-02-05 04:32:27 +000080
Icecream95068806c2020-02-20 17:59:16 +130081 if (blend->logicop_enable) {
82 options.logicop_enable = true;
83 options.logicop_func = blend->logicop_func;
84 return options;
85 }
86
87 options.logicop_enable = false;
88
Alyssa Rosenzweigf7cf5a32020-05-15 12:19:22 -040089 if (!blend->independent_blend_enable)
90 i = 0;
91
Alyssa Rosenzweig8f4b1562019-12-30 12:13:45 -050092 /* If blend is disabled, we just use replace mode */
Alyssa Rosenzweig5e825f52019-07-02 09:08:18 -070093
Alyssa Rosenzweig8f4b1562019-12-30 12:13:45 -050094 nir_lower_blend_channel rgb = {
95 .func = BLEND_FUNC_ADD,
96 .src_factor = BLEND_FACTOR_ZERO,
97 .invert_src_factor = true,
98 .dst_factor = BLEND_FACTOR_ZERO,
99 .invert_dst_factor = false
100 };
Alyssa Rosenzweigd1a9b762019-05-06 02:13:55 +0000101
Alyssa Rosenzweig8f4b1562019-12-30 12:13:45 -0500102 nir_lower_blend_channel alpha = rgb;
Alyssa Rosenzweig5e825f52019-07-02 09:08:18 -0700103
Alyssa Rosenzweig8f4b1562019-12-30 12:13:45 -0500104 if (blend->rt[i].blend_enable) {
105 rgb.func = util_blend_func_to_shader(blend->rt[i].rgb_func);
106 rgb.src_factor = util_blend_factor_to_shader(blend->rt[i].rgb_src_factor);
107 rgb.dst_factor = util_blend_factor_to_shader(blend->rt[i].rgb_dst_factor);
108 rgb.invert_src_factor = util_blend_factor_is_inverted(blend->rt[i].rgb_src_factor);
109 rgb.invert_dst_factor = util_blend_factor_is_inverted(blend->rt[i].rgb_dst_factor);
Alyssa Rosenzweig5e825f52019-07-02 09:08:18 -0700110
Alyssa Rosenzweig8f4b1562019-12-30 12:13:45 -0500111 alpha.func = util_blend_func_to_shader(blend->rt[i].alpha_func);
112 alpha.src_factor = util_blend_factor_to_shader(blend->rt[i].alpha_src_factor);
113 alpha.dst_factor = util_blend_factor_to_shader(blend->rt[i].alpha_dst_factor);
114 alpha.invert_src_factor = util_blend_factor_is_inverted(blend->rt[i].alpha_src_factor);
115 alpha.invert_dst_factor = util_blend_factor_is_inverted(blend->rt[i].alpha_dst_factor);
Alyssa Rosenzweigd1a9b762019-05-06 02:13:55 +0000116 }
117
Alyssa Rosenzweig8f4b1562019-12-30 12:13:45 -0500118 options.rgb = rgb;
119 options.alpha = alpha;
120
121 options.colormask = blend->rt[i].colormask;
122
Alyssa Rosenzweigd1a9b762019-05-06 02:13:55 +0000123 return options;
Alyssa Rosenzweig7da251f2019-02-05 04:32:27 +0000124}
125
Alyssa Rosenzweigb29027f2020-07-10 13:57:58 -0400126static nir_ssa_def *
127nir_iclamp(nir_builder *b, nir_ssa_def *v, int32_t lo, int32_t hi)
128{
129 return nir_imin(b, nir_imax(b, v, nir_imm_int(b, lo)), nir_imm_int(b, hi));
130}
131
Alyssa Rosenzweig46396af2019-07-05 15:40:08 -0700132struct panfrost_blend_shader
133panfrost_compile_blend_shader(
Alyssa Rosenzweiga2d0ea92019-07-10 10:10:31 -0700134 struct panfrost_context *ctx,
135 struct pipe_blend_state *cso,
Alyssa Rosenzweiga2d55032019-11-23 21:44:16 -0500136 enum pipe_format format,
137 unsigned rt)
Alyssa Rosenzweig7da251f2019-02-05 04:32:27 +0000138{
Alyssa Rosenzweigca8c6252020-03-23 18:44:21 -0400139 struct panfrost_device *dev = pan_device(ctx->base.screen);
Alyssa Rosenzweig46396af2019-07-05 15:40:08 -0700140 struct panfrost_blend_shader res;
141
Tomeu Vizoso950b5fc52019-08-01 16:45:50 +0200142 res.ctx = ctx;
143
Alyssa Rosenzweig7da251f2019-02-05 04:32:27 +0000144 /* Build the shader */
145
146 nir_shader *shader = nir_shader_create(NULL, MESA_SHADER_FRAGMENT, &midgard_nir_options, NULL);
147 nir_function *fn = nir_function_create(shader, "main");
148 nir_function_impl *impl = nir_function_impl_create(fn);
149
Alyssa Rosenzweig8dc8b662020-05-13 16:27:25 -0400150 const struct util_format_description *format_desc =
151 util_format_description(format);
152
153 nir_alu_type T = pan_unpacked_type_for_format(format_desc);
154 enum glsl_base_type g =
155 (T == nir_type_float16) ? GLSL_TYPE_FLOAT16 :
156 (T == nir_type_float32) ? GLSL_TYPE_FLOAT :
157 (T == nir_type_int8) ? GLSL_TYPE_INT8 :
158 (T == nir_type_int16) ? GLSL_TYPE_INT16 :
159 (T == nir_type_int32) ? GLSL_TYPE_INT :
160 (T == nir_type_uint8) ? GLSL_TYPE_UINT8 :
161 (T == nir_type_uint16) ? GLSL_TYPE_UINT16 :
162 (T == nir_type_uint32) ? GLSL_TYPE_UINT :
163 GLSL_TYPE_FLOAT;
164
Alyssa Rosenzweig7da251f2019-02-05 04:32:27 +0000165 /* Create the blend variables */
166
167 nir_variable *c_src = nir_variable_create(shader, nir_var_shader_in, glsl_vector_type(GLSL_TYPE_FLOAT, 4), "gl_Color");
Icecream95787c1ed2020-06-25 22:56:14 +1200168 nir_variable *c_src1 = nir_variable_create(shader, nir_var_shader_in, glsl_vector_type(GLSL_TYPE_FLOAT, 4), "gl_Color1");
Alyssa Rosenzweig8dc8b662020-05-13 16:27:25 -0400169 nir_variable *c_out = nir_variable_create(shader, nir_var_shader_out, glsl_vector_type(g, 4), "gl_FragColor");
Alyssa Rosenzweig7da251f2019-02-05 04:32:27 +0000170
171 c_src->data.location = VARYING_SLOT_COL0;
Icecream95787c1ed2020-06-25 22:56:14 +1200172 c_src1->data.location = VARYING_SLOT_VAR0;
Alyssa Rosenzweig7da251f2019-02-05 04:32:27 +0000173 c_out->data.location = FRAG_RESULT_COLOR;
174
Icecream95787c1ed2020-06-25 22:56:14 +1200175 c_src1->data.driver_location = 1;
176
Alyssa Rosenzweig7da251f2019-02-05 04:32:27 +0000177 /* Setup nir_builder */
178
179 nir_builder _b;
180 nir_builder *b = &_b;
181 nir_builder_init(b, impl);
182 b->cursor = nir_before_block(nir_start_block(impl));
183
184 /* Setup inputs */
185
Icecream95787c1ed2020-06-25 22:56:14 +1200186 nir_ssa_def *s_src[] = {nir_load_var(b, c_src), nir_load_var(b, c_src1)};
Alyssa Rosenzweig7da251f2019-02-05 04:32:27 +0000187
Icecream95787c1ed2020-06-25 22:56:14 +1200188 for (int i = 0; i < ARRAY_SIZE(s_src); ++i) {
189 if (T == nir_type_float16)
190 s_src[i] = nir_f2f16(b, s_src[i]);
191 else if (T == nir_type_int16)
192 s_src[i] = nir_i2i16(b, nir_iclamp(b, s_src[i], -32768, 32767));
193 else if (T == nir_type_uint16)
194 s_src[i] = nir_u2u16(b, nir_umin(b, s_src[i], nir_imm_int(b, 65535)));
195 else if (T == nir_type_int8)
196 s_src[i] = nir_i2i8(b, nir_iclamp(b, s_src[i], -128, 127));
197 else if (T == nir_type_uint8)
198 s_src[i] = nir_u2u8(b, nir_umin(b, s_src[i], nir_imm_int(b, 255)));
199 }
Alyssa Rosenzweig8dc8b662020-05-13 16:27:25 -0400200
Alyssa Rosenzweig7da251f2019-02-05 04:32:27 +0000201 /* Build a trivial blend shader */
Icecream95787c1ed2020-06-25 22:56:14 +1200202 nir_store_var(b, c_out, s_src[0], 0xFF);
Alyssa Rosenzweigd1a9b762019-05-06 02:13:55 +0000203
204 nir_lower_blend_options options =
Alyssa Rosenzweig8f4b1562019-12-30 12:13:45 -0500205 nir_make_options(cso, rt);
Icecream95339f1272020-02-26 22:03:13 +1300206 options.format = format;
Icecream95787c1ed2020-06-25 22:56:14 +1200207 options.src1 = s_src[1];
Icecream95339f1272020-02-26 22:03:13 +1300208
Alyssa Rosenzweig8dc8b662020-05-13 16:27:25 -0400209 if (T == nir_type_float16)
210 options.half = true;
211
Alyssa Rosenzweigd1a9b762019-05-06 02:13:55 +0000212 NIR_PASS_V(shader, nir_lower_blend, options);
Alyssa Rosenzweigd1513192019-07-01 13:26:07 -0700213
Alyssa Rosenzweig7da251f2019-02-05 04:32:27 +0000214 /* Compile the built shader */
215
Boris Brezillon0a74a042020-10-08 10:09:56 +0200216 panfrost_program program;
217
218 struct panfrost_compile_inputs inputs = {
219 .gpu_id = dev->gpu_id,
220 .is_blend = true,
221 .blend.rt = rt,
222 .rt_formats = {format},
Icecream951e1eee92020-07-06 19:30:37 +1200223 };
224
Boris Brezillon0a74a042020-10-08 10:09:56 +0200225 midgard_compile_shader_nir(shader, &program, &inputs);
Alyssa Rosenzweig7da251f2019-02-05 04:32:27 +0000226
Alyssa Rosenzweig46396af2019-07-05 15:40:08 -0700227 /* Allow us to patch later */
228 res.patch_index = program.blend_patch_offset;
229 res.first_tag = program.first_tag;
Tomeu Vizoso950b5fc52019-08-01 16:45:50 +0200230 res.size = program.compiled.size;
231 res.buffer = program.compiled.data;
Alyssa Rosenzweigb3fdd772020-07-08 17:17:14 -0400232 res.work_count = program.work_register_count;
Alyssa Rosenzweig46396af2019-07-05 15:40:08 -0700233
234 return res;
Alyssa Rosenzweig7da251f2019-02-05 04:32:27 +0000235}