Home | History | Annotate | Line # | Download | only in panfrost
      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