"Fossies" - the Fresh Open Source Software Archive

Member "mesa-20.1.8/src/gallium/drivers/panfrost/pan_blend_cso.c" (16 Sep 2020, 11196 Bytes) of package /linux/misc/mesa-20.1.8.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "pan_blend_cso.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 20.2.0-rc2_vs_20.2.0-rc3.

    1 /*
    2  * Copyright (C) 2019 Collabora, Ltd.
    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  * Authors (Collabora):
   24  *   Alyssa Rosenzweig <alyssa.rosenzweig@collabora.com>
   25  *
   26  */
   27 
   28 #include <stdio.h>
   29 #include "util/u_memory.h"
   30 #include "pan_blend_shaders.h"
   31 #include "pan_blending.h"
   32 #include "pan_bo.h"
   33 #include "panfrost-quirks.h"
   34 
   35 /* A given Gallium blend state can be encoded to the hardware in numerous,
   36  * dramatically divergent ways due to the interactions of blending with
   37  * framebuffer formats. Conceptually, there are two modes:
   38  *
   39  * - Fixed-function blending (for suitable framebuffer formats, suitable blend
   40  *   state, and suitable blend constant)
   41  *
   42  * - Blend shaders (for everything else)
   43  *
   44  * A given Gallium blend configuration will compile to exactly one
   45  * fixed-function blend state, if it compiles to any, although the constant
   46  * will vary across runs as that is tracked outside of the Gallium CSO.
   47  *
   48  * However, that same blend configuration will compile to many different blend
   49  * shaders, depending on the framebuffer formats active. The rationale is that
   50  * blend shaders override not just fixed-function blending but also
   51  * fixed-function format conversion. As such, each blend shader must be
   52  * hardcoded to a particular framebuffer format to correctly pack/unpack it. As
   53  * a concrete example, to the hardware there is no difference (!) between RG16F
   54  * and RG16UI -- both are simply 4-byte-per-pixel chunks. Thus both formats
   55  * require a blend shader (even with blending is totally disabled!), required
   56  * to do conversion as necessary (if necessary).
   57  *
   58  * All of this state is encapsulated in the panfrost_blend_state struct
   59  * (our subclass of pipe_blend_state).
   60  */
   61 
   62 /* Given an initialized CSO and a particular framebuffer format, grab a
   63  * blend shader, generating and compiling it if it doesn't exist
   64  * (lazy-loading in a way). This routine, when the cache hits, should
   65  * befast, suitable for calling every draw to avoid wacky dirty
   66  * tracking paths. If the cache hits, boom, done. */
   67 
   68 static struct panfrost_blend_shader *
   69 panfrost_get_blend_shader(
   70         struct panfrost_context *ctx,
   71         struct panfrost_blend_state *blend,
   72         enum pipe_format fmt,
   73         unsigned rt)
   74 {
   75         /* Prevent NULL collision issues.. */
   76         assert(fmt != 0);
   77 
   78         /* Check the cache. Key by the RT and format */
   79         struct hash_table_u64 *shaders = blend->rt[rt].shaders;
   80         unsigned key = (fmt << 3) | rt;
   81 
   82         struct panfrost_blend_shader *shader =
   83                 _mesa_hash_table_u64_search(shaders, key);
   84 
   85         if (shader)
   86                 return shader;
   87 
   88         /* Cache miss. Build one instead, cache it, and go */
   89 
   90         struct panfrost_blend_shader generated =
   91                 panfrost_compile_blend_shader(ctx, &blend->base, fmt, rt);
   92 
   93         shader = mem_dup(&generated, sizeof(generated));
   94         _mesa_hash_table_u64_insert(shaders, key, shader);
   95         return  shader;
   96 }
   97 
   98 /* Create a blend CSO. Essentially, try to compile a fixed-function
   99  * expression and initialize blend shaders */
  100 
  101 static void *
  102 panfrost_create_blend_state(struct pipe_context *pipe,
  103                             const struct pipe_blend_state *blend)
  104 {
  105         struct panfrost_context *ctx = pan_context(pipe);
  106         struct panfrost_blend_state *so = rzalloc(ctx, struct panfrost_blend_state);
  107         so->base = *blend;
  108 
  109         /* TODO: The following features are not yet implemented */
  110         assert(!blend->alpha_to_coverage);
  111         assert(!blend->alpha_to_one);
  112 
  113         for (unsigned c = 0; c < PIPE_MAX_COLOR_BUFS; ++c) {
  114                 struct panfrost_blend_rt *rt = &so->rt[c];
  115 
  116                 /* There are two paths. First, we would like to try a
  117                  * fixed-function if we can */
  118 
  119                 /* Without indep blending, the first RT settings replicate */
  120 
  121                 if (!blend->logicop_enable) {
  122                         unsigned g =
  123                                 blend->independent_blend_enable ? c : 0;
  124 
  125                         rt->has_fixed_function =
  126                                 panfrost_make_fixed_blend_mode(
  127                                         &blend->rt[g],
  128                                         &rt->equation,
  129                                         &rt->constant_mask,
  130                                         blend->rt[g].colormask);
  131                 }
  132 
  133                 /* Regardless if that works, we also need to initialize
  134                  * the blend shaders */
  135 
  136                 rt->shaders = _mesa_hash_table_u64_create(so);
  137         }
  138 
  139         return so;
  140 }
  141 
  142 static void
  143 panfrost_bind_blend_state(struct pipe_context *pipe,
  144                           void *cso)
  145 {
  146         struct panfrost_context *ctx = pan_context(pipe);
  147         struct pipe_blend_state *blend = (struct pipe_blend_state *) cso;
  148         struct panfrost_blend_state *pblend = (struct panfrost_blend_state *) cso;
  149         ctx->blend = pblend;
  150 
  151         if (!blend)
  152                 return;
  153 }
  154 
  155 static void
  156 panfrost_delete_blend_shader(struct hash_entry *entry)
  157 {
  158         struct panfrost_blend_shader *shader = (struct panfrost_blend_shader *)entry->data;
  159         free(shader->buffer);
  160         free(shader);
  161 }
  162 
  163 static void
  164 panfrost_delete_blend_state(struct pipe_context *pipe,
  165                             void *cso)
  166 {
  167         struct panfrost_blend_state *blend = (struct panfrost_blend_state *) cso;
  168 
  169         for (unsigned c = 0; c < PIPE_MAX_COLOR_BUFS; ++c) {
  170                 struct panfrost_blend_rt *rt = &blend->rt[c];
  171                 _mesa_hash_table_u64_clear(rt->shaders, panfrost_delete_blend_shader);
  172         }
  173         ralloc_free(blend);
  174 }
  175 
  176 static void
  177 panfrost_set_blend_color(struct pipe_context *pipe,
  178                          const struct pipe_blend_color *blend_color)
  179 {
  180         struct panfrost_context *ctx = pan_context(pipe);
  181 
  182         if (blend_color)
  183                 ctx->blend_color = *blend_color;
  184 }
  185 
  186 /* Given a vec4 of constants, reduce it to just a single constant according to
  187  * the mask (if we can) */
  188 
  189 static bool
  190 panfrost_blend_constant(float *out, float *in, unsigned mask)
  191 {
  192         /* If there is no components used, it automatically works. Do set a
  193          * dummy constant just to avoid reading uninitialized memory. */
  194 
  195         if (!mask) {
  196                 *out = 0.0;
  197                 return true;
  198         }
  199 
  200         /* Find some starter mask */
  201         unsigned first = ffs(mask) - 1;
  202         float cons = in[first];
  203         mask ^= (1 << first);
  204 
  205         /* Ensure the rest are equal */
  206         while (mask) {
  207                 unsigned i = u_bit_scan(&mask);
  208 
  209                 if (in[i] != cons) {
  210                         *out = 0.0;
  211                         return false;
  212                 }
  213         }
  214 
  215         /* Otherwise, we're good to go */
  216         *out = cons;
  217         return true;
  218 }
  219 
  220 /* Create a final blend given the context */
  221 
  222 struct panfrost_blend_final
  223 panfrost_get_blend_for_context(struct panfrost_context *ctx, unsigned rti, struct panfrost_bo **bo, unsigned *shader_offset)
  224 {
  225         struct panfrost_batch *batch = panfrost_get_batch_for_fbo(ctx);
  226 
  227         /* Grab the format, falling back gracefully if called invalidly (which
  228          * has to happen for no-color-attachment FBOs, for instance)  */
  229         struct pipe_framebuffer_state *fb = &ctx->pipe_framebuffer;
  230         enum pipe_format fmt = PIPE_FORMAT_R8G8B8A8_UNORM;
  231 
  232         if ((fb->nr_cbufs > rti) && fb->cbufs[rti])
  233                 fmt = fb->cbufs[rti]->format;
  234 
  235         /* Grab the blend state */
  236         struct panfrost_blend_state *blend = ctx->blend;
  237         assert(blend);
  238 
  239         struct panfrost_blend_rt *rt = &blend->rt[rti];
  240 
  241         struct panfrost_blend_final final;
  242 
  243         /* First, we'll try a fixed function path */
  244         if (rt->has_fixed_function && panfrost_can_fixed_blend(fmt)) {
  245                 if (panfrost_blend_constant(
  246                             &final.equation.constant,
  247                             ctx->blend_color.color,
  248                             rt->constant_mask)) {
  249                         /* There's an equation and suitable constant, so we're good to go */
  250                         final.is_shader = false;
  251                         final.equation.equation = &rt->equation;
  252 
  253                         final.no_blending =
  254                                 (rt->equation.rgb_mode == 0x122) &&
  255                                 (rt->equation.alpha_mode == 0x122) &&
  256                                 (rt->equation.color_mask == 0xf);
  257 
  258                         return final;
  259                 }
  260         }
  261 
  262         /* Otherwise, we need to grab a shader */
  263         struct panfrost_blend_shader *shader = panfrost_get_blend_shader(ctx, blend, fmt, rti);
  264         final.is_shader = true;
  265         final.no_blending = false;
  266         final.shader.work_count = shader->work_count;
  267         final.shader.first_tag = shader->first_tag;
  268 
  269         /* Upload the shader, sharing a BO */
  270         if (!(*bo)) {
  271                 *bo = panfrost_batch_create_bo(batch, 4096,
  272                    PAN_BO_EXECUTE,
  273                    PAN_BO_ACCESS_PRIVATE |
  274                    PAN_BO_ACCESS_READ |
  275                    PAN_BO_ACCESS_VERTEX_TILER |
  276                    PAN_BO_ACCESS_FRAGMENT);
  277         }
  278 
  279         /* Size check */
  280         assert((*shader_offset + shader->size) < 4096);
  281 
  282         memcpy((*bo)->cpu + *shader_offset, shader->buffer, shader->size);
  283         final.shader.gpu = (*bo)->gpu + *shader_offset;
  284 
  285         if (shader->patch_index) {
  286                 /* We have to specialize the blend shader to use constants, so
  287                  * patch in the current constants */
  288 
  289                 float *patch = (float *) ((*bo)->cpu + *shader_offset + shader->patch_index);
  290                 memcpy(patch, ctx->blend_color.color, sizeof(float) * 4);
  291         }
  292 
  293         *shader_offset += shader->size;
  294 
  295         return final;
  296 }
  297 
  298 void
  299 panfrost_blend_context_init(struct pipe_context *pipe)
  300 {
  301         pipe->create_blend_state = panfrost_create_blend_state;
  302         pipe->bind_blend_state   = panfrost_bind_blend_state;
  303         pipe->delete_blend_state = panfrost_delete_blend_state;
  304 
  305         pipe->set_blend_color = panfrost_set_blend_color;
  306 }