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" 27 #include "pan_util.h" 28 #include "midgard/midgard_compile.h" 29 #include "compiler/nir/nir_builder.h" 30 //#include "gallium/auxiliary/nir/nir_lower_blend.h" 31 32 /* 33 * Implements the command stream portion of programmatic blend shaders. 34 * 35 * On Midgard, common blending operations are accelerated by the fixed-function 36 * blending pipeline. Panfrost supports this fast path via the code in 37 * pan_blending.c. Nevertheless, uncommon blend modes (including some seemingly 38 * simple modes present in ES2) require "blend shaders", a special internal 39 * shader type used for programmable blending. 40 * 41 * Blend shaders operate during the normal blending time, but they bypass the 42 * fixed-function blending pipeline and instead go straight to the Midgard 43 * shader cores. The shaders themselves are essentially just fragment shaders, 44 * making heavy use of uint8 arithmetic to manipulate RGB values for the 45 * framebuffer. 46 * 47 * As is typical with Midgard, shader binaries must be accompanied by 48 * information about the first tag (ORed with the bottom nibble of address, 49 * like usual) and work registers. Work register count is specified in the 50 * blend descriptor, as well as in the coresponding fragment shader's work 51 * count. This suggests that blend shader invocation is tied to fragment shader 52 * execution. 53 * 54 * --- 55 * 56 * As for blend shaders, they use the standard ISA. 57 * 58 * The source pixel colour, including alpha, is preloaded into r0 as a vec4 of 59 * float32. 60 * 61 * The destination pixel colour must be loaded explicitly via load/store ops. 62 * TODO: Investigate. 63 * 64 * They use fragment shader writeout; however, instead of writing a vec4 of 65 * float32 for RGBA encoding, we writeout a vec4 of uint8, using 8-bit imov 66 * instead of 32-bit fmov. The net result is that r0 encodes a single uint32 67 * containing all four channels of the color. Accordingly, the blend shader 68 * epilogue has to scale all four channels by 255 and then type convert to a 69 * uint8. 70 * 71 * --- 72 * 73 * Blend shaders hardcode constants. Naively, this requires recompilation each 74 * time the blend color changes, which is a performance risk. Accordingly, we 75 * 'cheat' a bit: instead of loading the constant, we compile a shader with a 76 * dummy constant, exporting the offset to the immediate in the shader binary, 77 * storing this generic binary and metadata in the CSO itself at CSO create 78 * time. 79 * 80 * We then hot patch in the color into this shader at attachment / color change 81 * time, allowing for CSO create to be the only expensive operation 82 * (compilation). 83 */ 84 85 static nir_ssa_def * 86 nir_blending_f(const struct pipe_rt_blend_state *blend, nir_builder *b, 87 nir_ssa_def *s_src, nir_ssa_def *s_dst, nir_ssa_def *s_con) 88 { 89 /* Stub, to be replaced by the real implementation when that is 90 * upstream (pending on a rewrite to be Gallium agnostic) */ 91 92 return s_src; 93 } 94 95 void 96 panfrost_make_blend_shader(struct panfrost_context *ctx, struct panfrost_blend_state *cso, const struct pipe_blend_color *blend_color) 97 { 98 const struct pipe_rt_blend_state *blend = &cso->base.rt[0]; 99 100 /* Build the shader */ 101 102 nir_shader *shader = nir_shader_create(NULL, MESA_SHADER_FRAGMENT, &midgard_nir_options, NULL); 103 nir_function *fn = nir_function_create(shader, "main"); 104 nir_function_impl *impl = nir_function_impl_create(fn); 105 106 /* Create the blend variables */ 107 108 nir_variable *c_src = nir_variable_create(shader, nir_var_shader_in, glsl_vector_type(GLSL_TYPE_FLOAT, 4), "gl_Color"); 109 nir_variable *c_dst = nir_variable_create(shader, nir_var_shader_in, glsl_vector_type(GLSL_TYPE_FLOAT, 4), "gl_SecondaryColor"); 110 nir_variable *c_out = nir_variable_create(shader, nir_var_shader_out, glsl_vector_type(GLSL_TYPE_FLOAT, 4), "gl_FragColor"); 111 nir_variable *c_con = nir_variable_create(shader, nir_var_uniform, glsl_vector_type(GLSL_TYPE_FLOAT, 4), "constant"); 112 113 c_src->data.location = VARYING_SLOT_COL0; 114 c_dst->data.location = VARYING_SLOT_COL1; 115 c_out->data.location = FRAG_RESULT_COLOR; 116 117 /* Setup nir_builder */ 118 119 nir_builder _b; 120 nir_builder *b = &_b; 121 nir_builder_init(b, impl); 122 b->cursor = nir_before_block(nir_start_block(impl)); 123 124 /* Setup inputs */ 125 126 nir_ssa_def *s_src = nir_load_var(b, c_src); 127 nir_ssa_def *s_dst = nir_load_var(b, c_dst); 128 nir_ssa_def *s_con = nir_load_var(b, c_con); 129 130 /* Build a trivial blend shader */ 131 nir_store_var(b, c_out, nir_blending_f(blend, b, s_src, s_dst, s_con), 0xFF); 132 133 /* Compile the built shader */ 134 135 midgard_program program; 136 midgard_compile_shader_nir(shader, &program, true); 137 138 /* Upload the shader */ 139 140 int size = program.compiled.size; 141 uint8_t *dst = program.compiled.data; 142 143 /* Hot patch in constant color */ 144 145 if (program.blend_patch_offset >= 0) { 146 float *hot_color = (float *) (dst + program.blend_patch_offset); 147 148 for (int c = 0; c < 4; ++c) 149 hot_color[c] = blend_color->color[c]; 150 } 151 152 cso->blend_shader = panfrost_upload(&ctx->shaders, dst, size, true) | program.first_tag; 153 154 /* We need to switch to shader mode */ 155 cso->has_blend_shader = true; 156 157 /* At least two work registers are needed due to an encoding quirk */ 158 cso->blend_work_count = MAX2(program.work_register_count, 2); 159 } 160