Alyssa Rosenzweig | 7da251f | 2019-02-05 04:32:27 +0000 | [diff] [blame] | 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_blend_shaders.h" |
Tomeu Vizoso | 97f2d04 | 2019-03-08 15:24:57 +0100 | [diff] [blame] | 27 | #include "pan_util.h" |
Alyssa Rosenzweig | 7da251f | 2019-02-05 04:32:27 +0000 | [diff] [blame] | 28 | #include "midgard/midgard_compile.h" |
| 29 | #include "compiler/nir/nir_builder.h" |
Alyssa Rosenzweig | c2c8983 | 2019-07-10 09:51:32 -0700 | [diff] [blame] | 30 | #include "nir/nir_lower_blend.h" |
Alyssa Rosenzweig | 19b4e58 | 2020-05-13 15:04:47 -0400 | [diff] [blame] | 31 | #include "panfrost/util/pan_lower_framebuffer.h" |
Alyssa Rosenzweig | d1a9b76 | 2019-05-06 02:13:55 +0000 | [diff] [blame] | 32 | #include "gallium/auxiliary/util/u_blend.h" |
Alyssa Rosenzweig | 46396af | 2019-07-05 15:40:08 -0700 | [diff] [blame] | 33 | #include "util/u_memory.h" |
Alyssa Rosenzweig | 7da251f | 2019-02-05 04:32:27 +0000 | [diff] [blame] | 34 | |
| 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 Rosenzweig | 8bb5199 | 2020-05-12 15:39:38 -0400 | [diff] [blame] | 52 | * 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 Rosenzweig | 7da251f | 2019-02-05 04:32:27 +0000 | [diff] [blame] | 55 | * execution. |
| 56 | * |
Alyssa Rosenzweig | 8bb5199 | 2020-05-12 15:39:38 -0400 | [diff] [blame] | 57 | * 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 Rosenzweig | 7da251f | 2019-02-05 04:32:27 +0000 | [diff] [blame] | 63 | * |
| 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 Rosenzweig | d1a9b76 | 2019-05-06 02:13:55 +0000 | [diff] [blame] | 76 | static nir_lower_blend_options |
Alyssa Rosenzweig | 8f4b156 | 2019-12-30 12:13:45 -0500 | [diff] [blame] | 77 | nir_make_options(const struct pipe_blend_state *blend, unsigned i) |
Alyssa Rosenzweig | 7da251f | 2019-02-05 04:32:27 +0000 | [diff] [blame] | 78 | { |
Alyssa Rosenzweig | 8dc8b66 | 2020-05-13 16:27:25 -0400 | [diff] [blame] | 79 | nir_lower_blend_options options = { 0 }; |
Alyssa Rosenzweig | 7da251f | 2019-02-05 04:32:27 +0000 | [diff] [blame] | 80 | |
Icecream95 | 068806c | 2020-02-20 17:59:16 +1300 | [diff] [blame] | 81 | 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 Rosenzweig | f7cf5a3 | 2020-05-15 12:19:22 -0400 | [diff] [blame] | 89 | if (!blend->independent_blend_enable) |
| 90 | i = 0; |
| 91 | |
Alyssa Rosenzweig | 8f4b156 | 2019-12-30 12:13:45 -0500 | [diff] [blame] | 92 | /* If blend is disabled, we just use replace mode */ |
Alyssa Rosenzweig | 5e825f5 | 2019-07-02 09:08:18 -0700 | [diff] [blame] | 93 | |
Alyssa Rosenzweig | 8f4b156 | 2019-12-30 12:13:45 -0500 | [diff] [blame] | 94 | 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 Rosenzweig | d1a9b76 | 2019-05-06 02:13:55 +0000 | [diff] [blame] | 101 | |
Alyssa Rosenzweig | 8f4b156 | 2019-12-30 12:13:45 -0500 | [diff] [blame] | 102 | nir_lower_blend_channel alpha = rgb; |
Alyssa Rosenzweig | 5e825f5 | 2019-07-02 09:08:18 -0700 | [diff] [blame] | 103 | |
Alyssa Rosenzweig | 8f4b156 | 2019-12-30 12:13:45 -0500 | [diff] [blame] | 104 | 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 Rosenzweig | 5e825f5 | 2019-07-02 09:08:18 -0700 | [diff] [blame] | 110 | |
Alyssa Rosenzweig | 8f4b156 | 2019-12-30 12:13:45 -0500 | [diff] [blame] | 111 | 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 Rosenzweig | d1a9b76 | 2019-05-06 02:13:55 +0000 | [diff] [blame] | 116 | } |
| 117 | |
Alyssa Rosenzweig | 8f4b156 | 2019-12-30 12:13:45 -0500 | [diff] [blame] | 118 | options.rgb = rgb; |
| 119 | options.alpha = alpha; |
| 120 | |
| 121 | options.colormask = blend->rt[i].colormask; |
| 122 | |
Alyssa Rosenzweig | d1a9b76 | 2019-05-06 02:13:55 +0000 | [diff] [blame] | 123 | return options; |
Alyssa Rosenzweig | 7da251f | 2019-02-05 04:32:27 +0000 | [diff] [blame] | 124 | } |
| 125 | |
Alyssa Rosenzweig | b29027f | 2020-07-10 13:57:58 -0400 | [diff] [blame] | 126 | static nir_ssa_def * |
| 127 | nir_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 Rosenzweig | 46396af | 2019-07-05 15:40:08 -0700 | [diff] [blame] | 132 | struct panfrost_blend_shader |
| 133 | panfrost_compile_blend_shader( |
Alyssa Rosenzweig | a2d0ea9 | 2019-07-10 10:10:31 -0700 | [diff] [blame] | 134 | struct panfrost_context *ctx, |
| 135 | struct pipe_blend_state *cso, |
Alyssa Rosenzweig | a2d5503 | 2019-11-23 21:44:16 -0500 | [diff] [blame] | 136 | enum pipe_format format, |
| 137 | unsigned rt) |
Alyssa Rosenzweig | 7da251f | 2019-02-05 04:32:27 +0000 | [diff] [blame] | 138 | { |
Alyssa Rosenzweig | ca8c625 | 2020-03-23 18:44:21 -0400 | [diff] [blame] | 139 | struct panfrost_device *dev = pan_device(ctx->base.screen); |
Alyssa Rosenzweig | 46396af | 2019-07-05 15:40:08 -0700 | [diff] [blame] | 140 | struct panfrost_blend_shader res; |
| 141 | |
Tomeu Vizoso | 950b5fc5 | 2019-08-01 16:45:50 +0200 | [diff] [blame] | 142 | res.ctx = ctx; |
| 143 | |
Alyssa Rosenzweig | 7da251f | 2019-02-05 04:32:27 +0000 | [diff] [blame] | 144 | /* 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 Rosenzweig | 8dc8b66 | 2020-05-13 16:27:25 -0400 | [diff] [blame] | 150 | 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 Rosenzweig | 7da251f | 2019-02-05 04:32:27 +0000 | [diff] [blame] | 165 | /* 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"); |
Icecream95 | 787c1ed | 2020-06-25 22:56:14 +1200 | [diff] [blame] | 168 | nir_variable *c_src1 = nir_variable_create(shader, nir_var_shader_in, glsl_vector_type(GLSL_TYPE_FLOAT, 4), "gl_Color1"); |
Alyssa Rosenzweig | 8dc8b66 | 2020-05-13 16:27:25 -0400 | [diff] [blame] | 169 | nir_variable *c_out = nir_variable_create(shader, nir_var_shader_out, glsl_vector_type(g, 4), "gl_FragColor"); |
Alyssa Rosenzweig | 7da251f | 2019-02-05 04:32:27 +0000 | [diff] [blame] | 170 | |
| 171 | c_src->data.location = VARYING_SLOT_COL0; |
Icecream95 | 787c1ed | 2020-06-25 22:56:14 +1200 | [diff] [blame] | 172 | c_src1->data.location = VARYING_SLOT_VAR0; |
Alyssa Rosenzweig | 7da251f | 2019-02-05 04:32:27 +0000 | [diff] [blame] | 173 | c_out->data.location = FRAG_RESULT_COLOR; |
| 174 | |
Icecream95 | 787c1ed | 2020-06-25 22:56:14 +1200 | [diff] [blame] | 175 | c_src1->data.driver_location = 1; |
| 176 | |
Alyssa Rosenzweig | 7da251f | 2019-02-05 04:32:27 +0000 | [diff] [blame] | 177 | /* 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 | |
Icecream95 | 787c1ed | 2020-06-25 22:56:14 +1200 | [diff] [blame] | 186 | nir_ssa_def *s_src[] = {nir_load_var(b, c_src), nir_load_var(b, c_src1)}; |
Alyssa Rosenzweig | 7da251f | 2019-02-05 04:32:27 +0000 | [diff] [blame] | 187 | |
Icecream95 | 787c1ed | 2020-06-25 22:56:14 +1200 | [diff] [blame] | 188 | 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 Rosenzweig | 8dc8b66 | 2020-05-13 16:27:25 -0400 | [diff] [blame] | 200 | |
Alyssa Rosenzweig | 7da251f | 2019-02-05 04:32:27 +0000 | [diff] [blame] | 201 | /* Build a trivial blend shader */ |
Icecream95 | 787c1ed | 2020-06-25 22:56:14 +1200 | [diff] [blame] | 202 | nir_store_var(b, c_out, s_src[0], 0xFF); |
Alyssa Rosenzweig | d1a9b76 | 2019-05-06 02:13:55 +0000 | [diff] [blame] | 203 | |
| 204 | nir_lower_blend_options options = |
Alyssa Rosenzweig | 8f4b156 | 2019-12-30 12:13:45 -0500 | [diff] [blame] | 205 | nir_make_options(cso, rt); |
Icecream95 | 339f127 | 2020-02-26 22:03:13 +1300 | [diff] [blame] | 206 | options.format = format; |
Icecream95 | 787c1ed | 2020-06-25 22:56:14 +1200 | [diff] [blame] | 207 | options.src1 = s_src[1]; |
Icecream95 | 339f127 | 2020-02-26 22:03:13 +1300 | [diff] [blame] | 208 | |
Alyssa Rosenzweig | 8dc8b66 | 2020-05-13 16:27:25 -0400 | [diff] [blame] | 209 | if (T == nir_type_float16) |
| 210 | options.half = true; |
| 211 | |
Alyssa Rosenzweig | d1a9b76 | 2019-05-06 02:13:55 +0000 | [diff] [blame] | 212 | NIR_PASS_V(shader, nir_lower_blend, options); |
Alyssa Rosenzweig | d151319 | 2019-07-01 13:26:07 -0700 | [diff] [blame] | 213 | |
Alyssa Rosenzweig | 7da251f | 2019-02-05 04:32:27 +0000 | [diff] [blame] | 214 | /* Compile the built shader */ |
| 215 | |
Boris Brezillon | 0a74a04 | 2020-10-08 10:09:56 +0200 | [diff] [blame^] | 216 | 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}, |
Icecream95 | 1e1eee9 | 2020-07-06 19:30:37 +1200 | [diff] [blame] | 223 | }; |
| 224 | |
Boris Brezillon | 0a74a04 | 2020-10-08 10:09:56 +0200 | [diff] [blame^] | 225 | midgard_compile_shader_nir(shader, &program, &inputs); |
Alyssa Rosenzweig | 7da251f | 2019-02-05 04:32:27 +0000 | [diff] [blame] | 226 | |
Alyssa Rosenzweig | 46396af | 2019-07-05 15:40:08 -0700 | [diff] [blame] | 227 | /* Allow us to patch later */ |
| 228 | res.patch_index = program.blend_patch_offset; |
| 229 | res.first_tag = program.first_tag; |
Tomeu Vizoso | 950b5fc5 | 2019-08-01 16:45:50 +0200 | [diff] [blame] | 230 | res.size = program.compiled.size; |
| 231 | res.buffer = program.compiled.data; |
Alyssa Rosenzweig | b3fdd77 | 2020-07-08 17:17:14 -0400 | [diff] [blame] | 232 | res.work_count = program.work_register_count; |
Alyssa Rosenzweig | 46396af | 2019-07-05 15:40:08 -0700 | [diff] [blame] | 233 | |
| 234 | return res; |
Alyssa Rosenzweig | 7da251f | 2019-02-05 04:32:27 +0000 | [diff] [blame] | 235 | } |