From 93824b6451a4cc3eece1d7afa77e9a440ee41ee3 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Wed, 10 Feb 2021 08:47:39 +0100 Subject: [PATCH] panfrost: Move the blend logic out of the gallium driver Most of it is API-independent, so let's move it out of the gallium driver so it can be shared with the Vulkan driver. Signed-off-by: Boris Brezillon Acked-by: Alyssa Rosenzweig Part-of: --- src/gallium/drivers/panfrost/Makefile.sources | 2 - src/gallium/drivers/panfrost/meson.build | 1 - src/gallium/drivers/panfrost/pan_blend_cso.c | 133 ++---- src/gallium/drivers/panfrost/pan_blend_cso.h | 18 +- src/gallium/drivers/panfrost/pan_blend_shaders.c | 130 +----- src/gallium/drivers/panfrost/pan_blending.c | 303 ------------ src/gallium/drivers/panfrost/pan_blending.h | 45 -- src/gallium/drivers/panfrost/pan_context.c | 1 - src/gallium/drivers/panfrost/pan_job.c | 4 +- src/panfrost/Makefile.sources | 2 + src/panfrost/lib/meson.build | 1 + src/panfrost/lib/pan_blend.c | 565 +++++++++++++++++++++++ src/panfrost/lib/pan_blend.h | 104 +++++ 13 files changed, 725 insertions(+), 584 deletions(-) delete mode 100644 src/gallium/drivers/panfrost/pan_blending.c delete mode 100644 src/gallium/drivers/panfrost/pan_blending.h create mode 100644 src/panfrost/lib/pan_blend.c create mode 100644 src/panfrost/lib/pan_blend.h diff --git a/src/gallium/drivers/panfrost/Makefile.sources b/src/gallium/drivers/panfrost/Makefile.sources index d858d47..81e9884 100644 --- a/src/gallium/drivers/panfrost/Makefile.sources +++ b/src/gallium/drivers/panfrost/Makefile.sources @@ -2,8 +2,6 @@ C_SOURCES := \ pan_assemble.c \ pan_blend_cso.c \ pan_blend_cso.h \ - pan_blending.c \ - pan_blending.h \ pan_blend_shaders.c \ pan_blend_shaders.h \ pan_blit.c \ diff --git a/src/gallium/drivers/panfrost/meson.build b/src/gallium/drivers/panfrost/meson.build index 66647c9..0e4a70b 100644 --- a/src/gallium/drivers/panfrost/meson.build +++ b/src/gallium/drivers/panfrost/meson.build @@ -29,7 +29,6 @@ files_panfrost = files( 'pan_blit.c', 'pan_job.c', 'pan_assemble.c', - 'pan_blending.c', 'pan_blend_shaders.c', 'pan_blend_cso.c', 'pan_cmdstream.c', diff --git a/src/gallium/drivers/panfrost/pan_blend_cso.c b/src/gallium/drivers/panfrost/pan_blend_cso.c index 553df21..32ccab4 100644 --- a/src/gallium/drivers/panfrost/pan_blend_cso.c +++ b/src/gallium/drivers/panfrost/pan_blend_cso.c @@ -29,7 +29,6 @@ #include "util/u_memory.h" #include "gallium/auxiliary/util/u_blend.h" #include "pan_blend_shaders.h" -#include "pan_blending.h" #include "pan_bo.h" #include "panfrost-quirks.h" @@ -115,50 +114,38 @@ static void * panfrost_create_blend_state(struct pipe_context *pipe, const struct pipe_blend_state *blend) { - struct panfrost_device *dev = pan_device(pipe->screen); struct panfrost_context *ctx = pan_context(pipe); struct panfrost_blend_state *so = rzalloc(ctx, struct panfrost_blend_state); so->base = *blend; + so->pan.dither = blend->dither; + so->pan.logicop_enable = blend->logicop_enable; + so->pan.logicop_func = blend->logicop_func; + so->pan.rt_count = blend->max_rt + 1; + /* TODO: The following features are not yet implemented */ assert(!blend->alpha_to_one); - for (unsigned c = 0; c < PIPE_MAX_COLOR_BUFS; ++c) { + for (unsigned c = 0; c < so->pan.rt_count; ++c) { unsigned g = blend->independent_blend_enable ? c : 0; - struct pipe_rt_blend_state pipe = blend->rt[g]; - - struct panfrost_blend_rt *rt = &so->rt[c]; + const struct pipe_rt_blend_state *pipe = &blend->rt[g]; + struct pan_blend_equation *equation = &so->pan.rts[c].equation; - /* Logic ops are always shader */ - if (blend->logicop_enable) { - rt->load_dest = true; + equation->color_mask = pipe->colormask; + equation->blend_enable = pipe->blend_enable; + if (!equation->blend_enable) continue; - } - - rt->constant_mask = panfrost_blend_constant_mask(&pipe); - rt->has_fixed_function = - panfrost_make_fixed_blend_mode(pipe, &rt->equation); - - /* v6 doesn't support blend constants in FF blend equations. */ - if (rt->has_fixed_function && dev->arch == 6 && rt->constant_mask) - rt->has_fixed_function = false; - - if (rt->has_fixed_function) { - rt->opaque = pipe.rgb_src_factor == PIPE_BLENDFACTOR_ONE && - pipe.rgb_dst_factor == PIPE_BLENDFACTOR_ZERO && - (pipe.rgb_func == PIPE_BLEND_ADD || - pipe.rgb_func == PIPE_BLEND_SUBTRACT) && - pipe.alpha_src_factor == PIPE_BLENDFACTOR_ONE && - pipe.alpha_dst_factor == PIPE_BLENDFACTOR_ZERO && - (pipe.alpha_func == PIPE_BLEND_ADD || - pipe.alpha_func == PIPE_BLEND_SUBTRACT) && - pipe.colormask == 0xf; - } - - rt->load_dest = util_blend_uses_dest(pipe) - || pipe.colormask != 0xF; - - rt->no_colour = pipe.colormask == 0x0; + + equation->rgb_func = util_blend_func_to_shader(pipe->rgb_func); + equation->rgb_src_factor = util_blend_factor_to_shader(pipe->rgb_src_factor); + equation->rgb_invert_src_factor = util_blend_factor_is_inverted(pipe->rgb_src_factor); + equation->rgb_dst_factor = util_blend_factor_to_shader(pipe->rgb_dst_factor); + equation->rgb_invert_dst_factor = util_blend_factor_is_inverted(pipe->rgb_dst_factor); + equation->alpha_func = util_blend_func_to_shader(pipe->alpha_func); + equation->alpha_src_factor = util_blend_factor_to_shader(pipe->alpha_src_factor); + equation->alpha_invert_src_factor = util_blend_factor_is_inverted(pipe->alpha_src_factor); + equation->alpha_dst_factor = util_blend_factor_to_shader(pipe->alpha_dst_factor); + equation->alpha_invert_dst_factor = util_blend_factor_is_inverted(pipe->alpha_dst_factor); } return so; @@ -190,77 +177,47 @@ panfrost_set_blend_color(struct pipe_context *pipe, ctx->blend_color = *blend_color; } -/* Given a vec4 of constants, reduce it to just a single constant according to - * the mask (if we can) */ - -static bool -panfrost_blend_constant(float *out, float *in, unsigned mask) -{ - /* If there is no components used, it automatically works */ - - if (!mask) - return true; - - /* Find some starter mask */ - unsigned first = ffs(mask) - 1; - float cons = in[first]; - mask ^= (1 << first); - - /* Ensure the rest are equal */ - while (mask) { - unsigned i = u_bit_scan(&mask); - - if (in[i] != cons) - return false; - } - - /* Otherwise, we're good to go */ - *out = cons; - return true; -} - /* Create a final blend given the context */ struct panfrost_blend_final panfrost_get_blend_for_context(struct panfrost_context *ctx, unsigned rti, struct panfrost_bo **bo, unsigned *shader_offset) { + struct panfrost_device *dev = pan_device(ctx->base.screen); struct panfrost_batch *batch = panfrost_get_batch_for_fbo(ctx); struct pipe_framebuffer_state *fb = &ctx->pipe_framebuffer; enum pipe_format fmt = fb->cbufs[rti]->format; + unsigned nr_samples = fb->cbufs[rti]->nr_samples ? : + fb->cbufs[rti]->texture->nr_samples; /* Grab the blend state */ struct panfrost_blend_state *blend = ctx->blend; - struct panfrost_blend_rt *rt = &blend->rt[rti]; + struct pan_blend_state pan_blend = blend->pan; + + pan_blend.rts[rti].format = fmt; + pan_blend.rts[rti].nr_samples = nr_samples; + memcpy(pan_blend.constants, ctx->blend_color.color, + sizeof(pan_blend.constants)); /* First, we'll try fixed function, matching equation and constant */ - if (rt->has_fixed_function && panfrost_can_fixed_blend(fmt)) { - float constant = 0.0; - - if (panfrost_blend_constant( - &constant, - ctx->blend_color.color, - rt->constant_mask)) { - struct panfrost_blend_final final = { - .equation = { - .equation = rt->equation, - .constant = constant - }, - .load_dest = rt->load_dest, - .opaque = rt->opaque, - .no_colour = rt->no_colour - }; - - return final; - } + if (pan_blend_can_fixed_function(dev, &pan_blend, rti)) { + struct panfrost_blend_final final = { + .load_dest = pan_blend_reads_dest(&pan_blend, rti), + .equation.constant = pan_blend_get_constant(dev, &pan_blend, rti), + .opaque = pan_blend_is_opaque(&pan_blend, rti), + .no_colour = pan_blend.rts[rti].equation.color_mask == 0, + }; + + pan_blend_to_fixed_function_equation(dev, &pan_blend, rti, + &final.equation.equation); + return final; } - unsigned nr_samples = fb->cbufs[rti]->nr_samples ? : - fb->cbufs[rti]->texture->nr_samples; /* Otherwise, we need to grab a shader */ + unsigned constant_mask = pan_blend_constant_mask(&pan_blend, rti); struct panfrost_blend_shader *shader = panfrost_get_blend_shader(ctx, blend, fmt, nr_samples, rti, - rt->constant_mask ? + constant_mask ? ctx->blend_color.color : NULL); /* Upload the shader, sharing a BO */ @@ -284,7 +241,7 @@ panfrost_get_blend_for_context(struct panfrost_context *ctx, unsigned rti, struc .first_tag = shader->first_tag, .gpu = (*bo)->ptr.gpu + *shader_offset, }, - .load_dest = rt->load_dest, + .load_dest = pan_blend_reads_dest(&pan_blend, rti), }; *shader_offset += shader->size; diff --git a/src/gallium/drivers/panfrost/pan_blend_cso.h b/src/gallium/drivers/panfrost/pan_blend_cso.h index 433f94a..71b4001 100644 --- a/src/gallium/drivers/panfrost/pan_blend_cso.h +++ b/src/gallium/drivers/panfrost/pan_blend_cso.h @@ -28,6 +28,7 @@ #ifndef __PAN_BLEND_CSO_H #define __PAN_BLEND_CSO_H +#include "pan_blend.h" #include "util/hash_table.h" #include "nir.h" @@ -95,24 +96,9 @@ struct panfrost_blend_equation_final { float constant; }; -struct panfrost_blend_rt { - /* If has_fixed_function is set, equation is the - * fixed-function configuration for this blend state */ - - bool has_fixed_function; - struct MALI_BLEND_EQUATION equation; - - /* Mask of blend color components read */ - unsigned constant_mask; - - /* Properties of the blend mode */ - bool opaque, load_dest, no_colour; -}; - struct panfrost_blend_state { struct pipe_blend_state base; - - struct panfrost_blend_rt rt[PIPE_MAX_COLOR_BUFS]; + struct pan_blend_state pan; }; /* Container for a final blend state, specialized to constants and a diff --git a/src/gallium/drivers/panfrost/pan_blend_shaders.c b/src/gallium/drivers/panfrost/pan_blend_shaders.c index 4d0166e..f2ad5c3 100644 --- a/src/gallium/drivers/panfrost/pan_blend_shaders.c +++ b/src/gallium/drivers/panfrost/pan_blend_shaders.c @@ -75,62 +75,6 @@ * (compilation). */ -static nir_lower_blend_options -nir_make_options(const struct pipe_blend_state *blend, unsigned i) -{ - nir_lower_blend_options options = { 0 }; - - if (blend->logicop_enable) { - options.logicop_enable = true; - options.logicop_func = blend->logicop_func; - return options; - } - - options.logicop_enable = false; - - if (!blend->independent_blend_enable) - i = 0; - - /* If blend is disabled, we just use replace mode */ - - nir_lower_blend_channel rgb = { - .func = BLEND_FUNC_ADD, - .src_factor = BLEND_FACTOR_ZERO, - .invert_src_factor = true, - .dst_factor = BLEND_FACTOR_ZERO, - .invert_dst_factor = false - }; - - nir_lower_blend_channel alpha = rgb; - - if (blend->rt[i].blend_enable) { - rgb.func = util_blend_func_to_shader(blend->rt[i].rgb_func); - rgb.src_factor = util_blend_factor_to_shader(blend->rt[i].rgb_src_factor); - rgb.dst_factor = util_blend_factor_to_shader(blend->rt[i].rgb_dst_factor); - rgb.invert_src_factor = util_blend_factor_is_inverted(blend->rt[i].rgb_src_factor); - rgb.invert_dst_factor = util_blend_factor_is_inverted(blend->rt[i].rgb_dst_factor); - - alpha.func = util_blend_func_to_shader(blend->rt[i].alpha_func); - alpha.src_factor = util_blend_factor_to_shader(blend->rt[i].alpha_src_factor); - alpha.dst_factor = util_blend_factor_to_shader(blend->rt[i].alpha_dst_factor); - alpha.invert_src_factor = util_blend_factor_is_inverted(blend->rt[i].alpha_src_factor); - alpha.invert_dst_factor = util_blend_factor_is_inverted(blend->rt[i].alpha_dst_factor); - } - - options.rgb = rgb; - options.alpha = alpha; - - options.colormask = blend->rt[i].colormask; - - return options; -} - -static nir_ssa_def * -nir_iclamp(nir_builder *b, nir_ssa_def *v, int32_t lo, int32_t hi) -{ - return nir_imin(b, nir_imax(b, v, nir_imm_int(b, lo)), nir_imm_int(b, hi)); -} - struct panfrost_blend_shader * panfrost_create_blend_shader(struct panfrost_context *ctx, struct panfrost_blend_state *state, @@ -138,82 +82,16 @@ panfrost_create_blend_shader(struct panfrost_context *ctx, { struct panfrost_device *dev = pan_device(ctx->base.screen); struct panfrost_blend_shader *res = rzalloc(ctx, struct panfrost_blend_shader); + struct pan_blend_state pan_blend = state->pan; res->ctx = ctx; res->key = *key; /* Build the shader */ + pan_blend.rts[key->rt].format = key->format; + pan_blend.rts[key->rt].nr_samples = key->nr_samples; + res->nir = pan_blend_create_shader(dev, &pan_blend, key->rt); - nir_shader *shader = nir_shader_create(ctx, MESA_SHADER_FRAGMENT, &midgard_nir_options, NULL); - nir_function *fn = nir_function_create(shader, "main"); - fn->is_entrypoint = true; - nir_function_impl *impl = nir_function_impl_create(fn); - - const struct util_format_description *format_desc = - util_format_description(key->format); - - nir_alu_type T = pan_unpacked_type_for_format(format_desc); - enum glsl_base_type g = - (T == nir_type_float16) ? GLSL_TYPE_FLOAT16 : - (T == nir_type_float32) ? GLSL_TYPE_FLOAT : - (T == nir_type_int8) ? GLSL_TYPE_INT8 : - (T == nir_type_int16) ? GLSL_TYPE_INT16 : - (T == nir_type_int32) ? GLSL_TYPE_INT : - (T == nir_type_uint8) ? GLSL_TYPE_UINT8 : - (T == nir_type_uint16) ? GLSL_TYPE_UINT16 : - (T == nir_type_uint32) ? GLSL_TYPE_UINT : - GLSL_TYPE_FLOAT; - - /* Create the blend variables */ - - nir_variable *c_src = nir_variable_create(shader, nir_var_shader_in, glsl_vector_type(GLSL_TYPE_FLOAT, 4), "gl_Color"); - nir_variable *c_src1 = nir_variable_create(shader, nir_var_shader_in, glsl_vector_type(GLSL_TYPE_FLOAT, 4), "gl_Color1"); - nir_variable *c_out = nir_variable_create(shader, nir_var_shader_out, glsl_vector_type(g, 4), "gl_FragColor"); - - c_src->data.location = VARYING_SLOT_COL0; - c_src1->data.location = VARYING_SLOT_VAR0; - c_out->data.location = FRAG_RESULT_COLOR; - - c_src1->data.driver_location = 1; - - /* Setup nir_builder */ - - nir_builder _b; - nir_builder *b = &_b; - nir_builder_init(b, impl); - b->cursor = nir_before_block(nir_start_block(impl)); - - /* Setup inputs */ - - nir_ssa_def *s_src[] = {nir_load_var(b, c_src), nir_load_var(b, c_src1)}; - - for (int i = 0; i < ARRAY_SIZE(s_src); ++i) { - if (T == nir_type_float16) - s_src[i] = nir_f2f16(b, s_src[i]); - else if (T == nir_type_int16) - s_src[i] = nir_i2i16(b, nir_iclamp(b, s_src[i], -32768, 32767)); - else if (T == nir_type_uint16) - s_src[i] = nir_u2u16(b, nir_umin(b, s_src[i], nir_imm_int(b, 65535))); - else if (T == nir_type_int8) - s_src[i] = nir_i2i8(b, nir_iclamp(b, s_src[i], -128, 127)); - else if (T == nir_type_uint8) - s_src[i] = nir_u2u8(b, nir_umin(b, s_src[i], nir_imm_int(b, 255))); - } - - /* Build a trivial blend shader */ - nir_store_var(b, c_out, s_src[0], 0xFF); - - nir_lower_blend_options options = nir_make_options(&state->base, key->rt); - options.format = key->format; - options.is_bifrost = pan_is_bifrost(dev); - options.src1 = s_src[1]; - - if (T == nir_type_float16) - options.half = true; - - NIR_PASS_V(shader, nir_lower_blend, options); - - res->nir = shader; return res; } diff --git a/src/gallium/drivers/panfrost/pan_blending.c b/src/gallium/drivers/panfrost/pan_blending.c deleted file mode 100644 index bc76fac..0000000 --- a/src/gallium/drivers/panfrost/pan_blending.c +++ /dev/null @@ -1,303 +0,0 @@ -/* - * © Copyright 2018 Alyssa Rosenzweig - * Copyright (C) 2019-2020 Collabora, Ltd. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - */ - -#include -#include "pan_blending.h" -#include "pan_context.h" -#include "gallium/auxiliary/util/u_blend.h" -#include "util/format/u_format.h" - -/* Implements fixed-function blending on Midgard. */ - -/* Not all formats can be blended by fixed-function hardware */ - -bool -panfrost_can_fixed_blend(enum pipe_format format) -{ - return panfrost_blend_format(format).internal != 0; -} - -/* Helper to find the uncomplemented Gallium blend factor corresponding to a - * complemented Gallium blend factor */ - -static int -complement_factor(int factor) -{ - switch (factor) { - case PIPE_BLENDFACTOR_INV_SRC_COLOR: - return PIPE_BLENDFACTOR_SRC_COLOR; - - case PIPE_BLENDFACTOR_INV_SRC_ALPHA: - return PIPE_BLENDFACTOR_SRC_ALPHA; - - case PIPE_BLENDFACTOR_INV_DST_ALPHA: - return PIPE_BLENDFACTOR_DST_ALPHA; - - case PIPE_BLENDFACTOR_INV_DST_COLOR: - return PIPE_BLENDFACTOR_DST_COLOR; - - case PIPE_BLENDFACTOR_INV_CONST_COLOR: - return PIPE_BLENDFACTOR_CONST_COLOR; - - case PIPE_BLENDFACTOR_INV_CONST_ALPHA: - return PIPE_BLENDFACTOR_CONST_ALPHA; - - default: - return -1; - } -} - -/* Helper to strip the complement from any Gallium blend factor */ - -static int -uncomplement_factor(int factor) -{ - int complement = complement_factor(factor); - return (complement == -1) ? factor : complement; -} - -/* Check if this is a special edge case blend factor, which may require the use - * of clip modifiers */ - -static bool -is_edge_blendfactor(unsigned factor) -{ - return factor == PIPE_BLENDFACTOR_ONE || factor == PIPE_BLENDFACTOR_ZERO; -} - -static bool -factor_is_supported(unsigned factor) -{ - return factor != PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE && - factor != PIPE_BLENDFACTOR_SRC1_COLOR && - factor != PIPE_BLENDFACTOR_SRC1_ALPHA && - factor != PIPE_BLENDFACTOR_INV_SRC1_COLOR && - factor != PIPE_BLENDFACTOR_INV_SRC1_ALPHA; -} - -static bool -can_use_fixed_function_blend(unsigned blend_func, - unsigned src_factor, - unsigned dest_factor) -{ - if (blend_func != PIPE_BLEND_ADD && - blend_func != PIPE_BLEND_SUBTRACT && - blend_func != PIPE_BLEND_REVERSE_SUBTRACT) - return false; - - if (!factor_is_supported(src_factor) || - !factor_is_supported(dest_factor)) - return false; - - if (src_factor != dest_factor && - src_factor != complement_factor(dest_factor) && - complement_factor(src_factor) != dest_factor && - !is_edge_blendfactor(src_factor) && - !is_edge_blendfactor(dest_factor)) - return false; - - return true; -} - -static void to_c_factor(unsigned factor, struct MALI_BLEND_FUNCTION *function) -{ - if (complement_factor(factor) >= 0) - function->invert_c = true; - - switch (uncomplement_factor(factor)) { - case PIPE_BLENDFACTOR_ONE: - case PIPE_BLENDFACTOR_ZERO: - function->invert_c = factor == PIPE_BLENDFACTOR_ONE; - function->c = MALI_BLEND_OPERAND_C_ZERO; - break; - - case PIPE_BLENDFACTOR_SRC_ALPHA: - function->c = MALI_BLEND_OPERAND_C_SRC_ALPHA; - break; - - case PIPE_BLENDFACTOR_DST_ALPHA: - function->c = MALI_BLEND_OPERAND_C_DEST_ALPHA; - break; - - case PIPE_BLENDFACTOR_SRC_COLOR: - function->c = MALI_BLEND_OPERAND_C_SRC; - break; - - case PIPE_BLENDFACTOR_DST_COLOR: - function->c = MALI_BLEND_OPERAND_C_DEST; - break; - - case PIPE_BLENDFACTOR_CONST_COLOR: - case PIPE_BLENDFACTOR_CONST_ALPHA: - function->c = MALI_BLEND_OPERAND_C_CONSTANT; - break; - default: - unreachable("Invalid blend factor"); - } - -} - -static bool -to_panfrost_function(unsigned blend_func, - unsigned src_factor, - unsigned dest_factor, - struct MALI_BLEND_FUNCTION *function) -{ - if (!can_use_fixed_function_blend(blend_func, src_factor, dest_factor)) - return false; - - if (src_factor == PIPE_BLENDFACTOR_ZERO) { - function->a = MALI_BLEND_OPERAND_A_ZERO; - function->b = MALI_BLEND_OPERAND_B_DEST; - if (blend_func == PIPE_BLEND_SUBTRACT) - function->negate_b = true; - to_c_factor(dest_factor, function); - } else if (src_factor == PIPE_BLENDFACTOR_ONE) { - function->a = MALI_BLEND_OPERAND_A_SRC; - function->b = MALI_BLEND_OPERAND_B_DEST; - if (blend_func == PIPE_BLEND_SUBTRACT) - function->negate_b = true; - else if (blend_func == PIPE_BLEND_REVERSE_SUBTRACT) - function->negate_a = true; - to_c_factor(dest_factor, function); - } else if (dest_factor == PIPE_BLENDFACTOR_ZERO) { - function->a = MALI_BLEND_OPERAND_A_ZERO; - function->b = MALI_BLEND_OPERAND_B_SRC; - if (blend_func == PIPE_BLEND_REVERSE_SUBTRACT) - function->negate_b = true; - to_c_factor(src_factor, function); - } else if (dest_factor == PIPE_BLENDFACTOR_ONE) { - function->a = MALI_BLEND_OPERAND_A_DEST; - function->b = MALI_BLEND_OPERAND_B_SRC; - if (blend_func == PIPE_BLEND_SUBTRACT) - function->negate_a = true; - else if (blend_func == PIPE_BLEND_REVERSE_SUBTRACT) - function->negate_b = true; - to_c_factor(src_factor, function); - } else if (src_factor == dest_factor) { - function->a = MALI_BLEND_OPERAND_A_ZERO; - to_c_factor(src_factor, function); - - switch (blend_func) { - case PIPE_BLEND_ADD: - function->b = MALI_BLEND_OPERAND_B_SRC_PLUS_DEST; - break; - case PIPE_BLEND_REVERSE_SUBTRACT: - function->negate_b = true; - /* fall-through */ - case PIPE_BLEND_SUBTRACT: - function->b = MALI_BLEND_OPERAND_B_SRC_MINUS_DEST; - break; - default: - unreachable("Invalid blend function"); - } - } else { - assert(src_factor == complement_factor(dest_factor) || - complement_factor(src_factor) == dest_factor); - - function->a = MALI_BLEND_OPERAND_A_DEST; - to_c_factor(src_factor, function); - - switch (blend_func) { - case PIPE_BLEND_ADD: - function->b = MALI_BLEND_OPERAND_B_SRC_MINUS_DEST; - break; - case PIPE_BLEND_REVERSE_SUBTRACT: - function->b = MALI_BLEND_OPERAND_B_SRC_PLUS_DEST; - function->negate_b = true; - break; - case PIPE_BLEND_SUBTRACT: - function->b = MALI_BLEND_OPERAND_B_SRC_PLUS_DEST; - function->negate_a = true; - break; - } - } - - return true; -} - -/* We can upload a single constant for all of the factors. So, scan - * the factors for constants used to create a mask to check later. */ - -static unsigned -panfrost_blend_factor_constant_mask(enum pipe_blendfactor factor) -{ - unsigned mask = 0; - - factor = uncomplement_factor(factor); - if (factor == PIPE_BLENDFACTOR_CONST_COLOR) - mask |= 0b0111; /* RGB */ - else if (factor == PIPE_BLENDFACTOR_CONST_ALPHA) - mask |= 0b1000; /* A */ - - return mask; -} - -unsigned -panfrost_blend_constant_mask(const struct pipe_rt_blend_state *blend) -{ - return panfrost_blend_factor_constant_mask(blend->rgb_src_factor) | - panfrost_blend_factor_constant_mask(blend->rgb_dst_factor) | - panfrost_blend_factor_constant_mask(blend->alpha_src_factor) | - panfrost_blend_factor_constant_mask(blend->alpha_dst_factor); -} - -/* Create the descriptor for a fixed blend mode given the corresponding Gallium - * state, if possible. Return true and write out the blend descriptor into - * blend_equation. If it is not possible with the fixed function - * representation, return false to handle degenerate cases with a blend shader - */ - -bool -panfrost_make_fixed_blend_mode(const struct pipe_rt_blend_state blend, - struct MALI_BLEND_EQUATION *equation) -{ - /* If no blending is enabled, default back on `replace` mode */ - - if (!blend.blend_enable) { - equation->color_mask = blend.colormask; - equation->rgb.a = MALI_BLEND_OPERAND_A_SRC; - equation->rgb.b = MALI_BLEND_OPERAND_B_SRC; - equation->rgb.c = MALI_BLEND_OPERAND_C_ZERO; - equation->alpha.a = MALI_BLEND_OPERAND_A_SRC; - equation->alpha.b = MALI_BLEND_OPERAND_B_SRC; - equation->alpha.c = MALI_BLEND_OPERAND_C_ZERO; - return true; - } - - /* Try to compile the actual fixed-function blend */ - if (!to_panfrost_function(blend.rgb_func, blend.rgb_src_factor, - blend.rgb_dst_factor, - &equation->rgb)) - return false; - - if (!to_panfrost_function(blend.alpha_func, blend.alpha_src_factor, - blend.alpha_dst_factor, - &equation->alpha)) - return false; - - equation->color_mask = blend.colormask; - return true; -} diff --git a/src/gallium/drivers/panfrost/pan_blending.h b/src/gallium/drivers/panfrost/pan_blending.h deleted file mode 100644 index ccc4025..0000000 --- a/src/gallium/drivers/panfrost/pan_blending.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * © Copyright 2018 Alyssa Rosenzweig - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - */ - -#ifndef __PAN_BLENDING_H__ -#define __PAN_BLENDING_H__ - -#include "pipe/p_state.h" -#include "pipe/p_defines.h" -#include -#include "pan_blend_cso.h" - -struct panfrost_blend_state; - -unsigned -panfrost_blend_constant_mask(const struct pipe_rt_blend_state *blend); - -bool -panfrost_make_fixed_blend_mode(const struct pipe_rt_blend_state blend, - struct MALI_BLEND_EQUATION *equation); - -bool -panfrost_can_fixed_blend(enum pipe_format format); - -#endif diff --git a/src/gallium/drivers/panfrost/pan_context.c b/src/gallium/drivers/panfrost/pan_context.c index d324dd7..7fb9f0f 100644 --- a/src/gallium/drivers/panfrost/pan_context.c +++ b/src/gallium/drivers/panfrost/pan_context.c @@ -51,7 +51,6 @@ #include "midgard_pack.h" #include "pan_screen.h" -#include "pan_blending.h" #include "pan_blend_shaders.h" #include "pan_cmdstream.h" #include "pan_util.h" diff --git a/src/gallium/drivers/panfrost/pan_job.c b/src/gallium/drivers/panfrost/pan_job.c index 25f664a..f469c38 100644 --- a/src/gallium/drivers/panfrost/pan_job.c +++ b/src/gallium/drivers/panfrost/pan_job.c @@ -37,7 +37,6 @@ #include "util/rounding.h" #include "util/u_framebuffer.h" #include "pan_util.h" -#include "pan_blending.h" #include "pan_cmdstream.h" #include "decode.h" #include "panfrost-quirks.h" @@ -829,7 +828,8 @@ panfrost_load_surface(struct panfrost_batch *batch, struct pipe_surface *surf, u mali_ptr blend_shader = 0; - if (loc >= FRAG_RESULT_DATA0 && !panfrost_can_fixed_blend(rsrc->base.format)) { + if (loc >= FRAG_RESULT_DATA0 && + !panfrost_blend_format(rsrc->base.format).internal) { struct panfrost_blend_shader *b = panfrost_get_blend_shader(batch->ctx, batch->ctx->blit_blend, rsrc->base.format, diff --git a/src/panfrost/Makefile.sources b/src/panfrost/Makefile.sources index fcf9682..2793c19 100644 --- a/src/panfrost/Makefile.sources +++ b/src/panfrost/Makefile.sources @@ -31,6 +31,8 @@ lib_FILES := \ lib/pan_attributes.c \ lib/pan_bo.c \ lib/pan_bo.h \ + lib/pan_blend.c \ + lib/pan_blend.h \ lib/pan_blit.c \ lib/pan_device.h \ lib/pan_encoder.h \ diff --git a/src/panfrost/lib/meson.build b/src/panfrost/lib/meson.build index a32b7de..1c3f435 100644 --- a/src/panfrost/lib/meson.build +++ b/src/panfrost/lib/meson.build @@ -25,6 +25,7 @@ libpanfrost_lib_files = files( 'pan_afbc.c', 'pan_attributes.c', 'pan_bo.c', + 'pan_blend.c', 'pan_blit.c', 'pan_format.c', 'pan_invocation.c', diff --git a/src/panfrost/lib/pan_blend.c b/src/panfrost/lib/pan_blend.c new file mode 100644 index 0000000..3f955b0 --- /dev/null +++ b/src/panfrost/lib/pan_blend.c @@ -0,0 +1,565 @@ +/* + * Copyright (C) 2018 Alyssa Rosenzweig + * Copyright (C) 2019-2021 Collabora, Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "pan_blend.h" +#include "pan_shader.h" +#include "pan_texture.h" +#include "panfrost/util/pan_lower_framebuffer.h" +#include "panfrost/util/nir_lower_blend.h" +#include "util/format/u_format.h" +#include "compiler/nir/nir.h" +#include "compiler/nir/nir_builder.h" + +/* Implements fixed-function blending on Midgard. */ + +/* Check if this is a special edge case blend factor, which may require the use + * of clip modifiers */ + +static bool +factor_is_supported(enum blend_factor factor) +{ + return factor != BLEND_FACTOR_SRC_ALPHA_SATURATE && + factor != BLEND_FACTOR_SRC1_COLOR && + factor != BLEND_FACTOR_SRC1_ALPHA; +} + +static bool +can_fixed_function_equation(enum blend_func blend_func, + enum blend_factor src_factor, + enum blend_factor dest_factor) +{ + if (blend_func != BLEND_FUNC_ADD && + blend_func != BLEND_FUNC_SUBTRACT && + blend_func != BLEND_FUNC_REVERSE_SUBTRACT) + return false; + + if (!factor_is_supported(src_factor) || + !factor_is_supported(dest_factor)) + return false; + + if (src_factor != dest_factor && + src_factor != BLEND_FACTOR_ZERO && + dest_factor != BLEND_FACTOR_ZERO) + return false; + + return true; +} + +static unsigned +blend_factor_constant_mask(enum blend_factor factor) +{ + unsigned mask = 0; + + if (factor == BLEND_FACTOR_CONSTANT_COLOR) + mask |= 0b0111; /* RGB */ + else if (factor == BLEND_FACTOR_CONSTANT_ALPHA) + mask |= 0b1000; /* A */ + + return mask; +} + +unsigned +pan_blend_constant_mask(const struct pan_blend_state *state, + unsigned rt) +{ + const struct pan_blend_equation *e = &state->rts[rt].equation; + + return blend_factor_constant_mask(e->rgb_src_factor) | + blend_factor_constant_mask(e->rgb_dst_factor) | + blend_factor_constant_mask(e->alpha_src_factor) | + blend_factor_constant_mask(e->alpha_dst_factor); +} + +static bool +can_blend_constant(const struct panfrost_device *dev, + const struct pan_blend_state *state, + unsigned rt) +{ + unsigned constant_mask = pan_blend_constant_mask(state, rt); + if (!constant_mask) + return true; + + /* v6 doesn't support blend constants in FF blend equations. */ + if (dev->arch == 6) + return false; + + unsigned first_constant = ffs(constant_mask) - 1; + float constant = state->constants[first_constant]; + + for (unsigned i = first_constant + 1; i < ARRAY_SIZE(state->constants); i++) { + if (((1 << i) & constant_mask) && + state->constants[i] != constant) + return false; + } + + return true; +} + +float +pan_blend_get_constant(ASSERTED const struct panfrost_device *dev, + const struct pan_blend_state *state, + unsigned rt) +{ + assert(can_blend_constant(dev, state, rt)); + + unsigned constant_mask = pan_blend_constant_mask(state, rt); + + if (!constant_mask) + return 0.0f; + + return state->constants[ffs(constant_mask) - 1]; +} + +bool +pan_blend_can_fixed_function(const struct panfrost_device *dev, + const struct pan_blend_state *state, + unsigned rt) +{ + const struct pan_blend_rt_state *rt_state = &state->rts[rt]; + + /* LogicOp requires a blend shader */ + if (state->logicop_enable) + return false; + + /* Not all formats can be blended by fixed-function hardware */ + if (!panfrost_blend_format(rt_state->format).internal) + return false; + + if (!rt_state->equation.blend_enable) + return true; + + if (!can_blend_constant(dev, state, rt)) + return false; + + return can_fixed_function_equation(rt_state->equation.rgb_func, + rt_state->equation.rgb_src_factor, + rt_state->equation.rgb_dst_factor) && + can_fixed_function_equation(rt_state->equation.alpha_func, + rt_state->equation.alpha_src_factor, + rt_state->equation.alpha_dst_factor); +} + +static void +to_c_factor(enum blend_factor factor, bool invert_factor, + struct MALI_BLEND_FUNCTION *function) +{ + function->invert_c = invert_factor; + + switch (factor) { + case BLEND_FACTOR_ZERO: + function->c = MALI_BLEND_OPERAND_C_ZERO; + break; + + case BLEND_FACTOR_SRC_ALPHA: + function->c = MALI_BLEND_OPERAND_C_SRC_ALPHA; + break; + + case BLEND_FACTOR_DST_ALPHA: + function->c = MALI_BLEND_OPERAND_C_DEST_ALPHA; + break; + + case BLEND_FACTOR_SRC_COLOR: + function->c = MALI_BLEND_OPERAND_C_SRC; + break; + + case BLEND_FACTOR_DST_COLOR: + function->c = MALI_BLEND_OPERAND_C_DEST; + break; + + case BLEND_FACTOR_CONSTANT_COLOR: + case BLEND_FACTOR_CONSTANT_ALPHA: + function->c = MALI_BLEND_OPERAND_C_CONSTANT; + break; + default: + unreachable("Invalid blend factor"); + } + +} + +static void +to_panfrost_function(enum blend_func blend_func, + enum blend_factor src_factor, + bool invert_src, + enum blend_factor dest_factor, + bool invert_dest, + struct MALI_BLEND_FUNCTION *function) +{ + assert(can_fixed_function_equation(blend_func, src_factor, dest_factor)); + + if (src_factor == BLEND_FACTOR_ZERO && !invert_src) { + function->a = MALI_BLEND_OPERAND_A_ZERO; + function->b = MALI_BLEND_OPERAND_B_DEST; + if (blend_func == BLEND_FUNC_SUBTRACT) + function->negate_b = true; + to_c_factor(dest_factor, invert_dest, function); + } else if (src_factor == BLEND_FACTOR_ZERO && invert_src) { + function->a = MALI_BLEND_OPERAND_A_SRC; + function->b = MALI_BLEND_OPERAND_B_DEST; + if (blend_func == BLEND_FUNC_SUBTRACT) + function->negate_b = true; + else if (blend_func == BLEND_FUNC_REVERSE_SUBTRACT) + function->negate_a = true; + to_c_factor(dest_factor, invert_dest, function); + } else if (dest_factor == BLEND_FACTOR_ZERO && !invert_dest) { + function->a = MALI_BLEND_OPERAND_A_ZERO; + function->b = MALI_BLEND_OPERAND_B_SRC; + if (blend_func == BLEND_FUNC_REVERSE_SUBTRACT) + function->negate_b = true; + to_c_factor(src_factor, invert_src, function); + } else if (dest_factor == BLEND_FACTOR_ZERO && invert_dest) { + function->a = MALI_BLEND_OPERAND_A_DEST; + function->b = MALI_BLEND_OPERAND_B_SRC; + if (blend_func == BLEND_FUNC_SUBTRACT) + function->negate_a = true; + else if (blend_func == BLEND_FUNC_REVERSE_SUBTRACT) + function->negate_b = true; + to_c_factor(src_factor, invert_src, function); + } else if (src_factor == dest_factor && invert_src == invert_dest) { + function->a = MALI_BLEND_OPERAND_A_ZERO; + to_c_factor(src_factor, invert_src, function); + + switch (blend_func) { + case BLEND_FUNC_ADD: + function->b = MALI_BLEND_OPERAND_B_SRC_PLUS_DEST; + break; + case BLEND_FUNC_REVERSE_SUBTRACT: + function->negate_b = true; + /* fall-through */ + case BLEND_FUNC_SUBTRACT: + function->b = MALI_BLEND_OPERAND_B_SRC_MINUS_DEST; + break; + default: + unreachable("Invalid blend function"); + } + } else { + assert(src_factor == dest_factor && invert_src != invert_dest); + + function->a = MALI_BLEND_OPERAND_A_DEST; + to_c_factor(src_factor, invert_src, function); + + switch (blend_func) { + case BLEND_FUNC_ADD: + function->b = MALI_BLEND_OPERAND_B_SRC_MINUS_DEST; + break; + case BLEND_FUNC_REVERSE_SUBTRACT: + function->b = MALI_BLEND_OPERAND_B_SRC_PLUS_DEST; + function->negate_b = true; + break; + case BLEND_FUNC_SUBTRACT: + function->b = MALI_BLEND_OPERAND_B_SRC_PLUS_DEST; + function->negate_a = true; + break; + default: + unreachable("Invalid blend function\n"); + } + } +} + +bool +pan_blend_is_opaque(const struct pan_blend_state *state, unsigned rt) +{ + const struct pan_blend_equation *equation = &state->rts[rt].equation; + + return equation->rgb_src_factor == BLEND_FACTOR_ZERO && + equation->rgb_invert_src_factor && + equation->rgb_dst_factor == BLEND_FACTOR_ZERO && + !equation->rgb_invert_dst_factor && + (equation->rgb_func == BLEND_FUNC_ADD || + equation->rgb_func == BLEND_FUNC_SUBTRACT) && + equation->alpha_src_factor == BLEND_FACTOR_ZERO && + equation->alpha_invert_src_factor && + equation->alpha_dst_factor == BLEND_FACTOR_ZERO && + !equation->alpha_invert_dst_factor && + (equation->alpha_func == BLEND_FUNC_ADD || + equation->alpha_func == BLEND_FUNC_SUBTRACT) && + equation->color_mask == 0xf; +} + +static bool +is_dest_factor(enum blend_factor factor, bool alpha) +{ + return factor == BLEND_FACTOR_DST_ALPHA || + factor == BLEND_FACTOR_DST_COLOR || + (factor == BLEND_FACTOR_SRC_ALPHA_SATURATE && !alpha); +} + +bool +pan_blend_reads_dest(const struct pan_blend_state *state, unsigned rt) +{ + const struct pan_blend_rt_state *rt_state = &state->rts[rt]; + + if (state->logicop_enable || + (rt_state->equation.color_mask && + rt_state->equation.color_mask != 0xF)) + return true; + + if (is_dest_factor(rt_state->equation.rgb_src_factor, false) || + is_dest_factor(rt_state->equation.alpha_src_factor, true) || + rt_state->equation.rgb_dst_factor != BLEND_FACTOR_ZERO || + rt_state->equation.rgb_invert_dst_factor || + rt_state->equation.alpha_dst_factor != BLEND_FACTOR_ZERO || + rt_state->equation.alpha_invert_dst_factor) + return true; + + return false; +} + +/* Create the descriptor for a fixed blend mode given the corresponding Gallium + * state, if possible. Return true and write out the blend descriptor into + * blend_equation. If it is not possible with the fixed function + * representation, return false to handle degenerate cases with a blend shader + */ + +void +pan_blend_to_fixed_function_equation(ASSERTED const struct panfrost_device *dev, + const struct pan_blend_state *state, + unsigned rt, + struct MALI_BLEND_EQUATION *equation) +{ + const struct pan_blend_rt_state *rt_state = &state->rts[rt]; + + assert(pan_blend_can_fixed_function(dev, state, rt)); + + /* If no blending is enabled, default back on `replace` mode */ + if (!rt_state->equation.blend_enable) { + equation->color_mask = rt_state->equation.color_mask; + equation->rgb.a = MALI_BLEND_OPERAND_A_SRC; + equation->rgb.b = MALI_BLEND_OPERAND_B_SRC; + equation->rgb.c = MALI_BLEND_OPERAND_C_ZERO; + equation->alpha.a = MALI_BLEND_OPERAND_A_SRC; + equation->alpha.b = MALI_BLEND_OPERAND_B_SRC; + equation->alpha.c = MALI_BLEND_OPERAND_C_ZERO; + return; + } + + /* Try to compile the actual fixed-function blend */ + to_panfrost_function(rt_state->equation.rgb_func, + rt_state->equation.rgb_src_factor, + rt_state->equation.rgb_invert_src_factor, + rt_state->equation.rgb_dst_factor, + rt_state->equation.rgb_invert_dst_factor, + &equation->rgb); + + to_panfrost_function(rt_state->equation.alpha_func, + rt_state->equation.alpha_src_factor, + rt_state->equation.alpha_invert_src_factor, + rt_state->equation.alpha_dst_factor, + rt_state->equation.alpha_invert_dst_factor, + &equation->alpha); + equation->color_mask = rt_state->equation.color_mask; +} + +static const char * +logicop_str(enum pipe_logicop logicop) +{ + switch (logicop) { + case PIPE_LOGICOP_CLEAR: return "clear"; + case PIPE_LOGICOP_NOR: return "nor"; + case PIPE_LOGICOP_AND_INVERTED: return "and-inverted"; + case PIPE_LOGICOP_COPY_INVERTED: return "copy-inverted"; + case PIPE_LOGICOP_AND_REVERSE: return "and-reverse"; + case PIPE_LOGICOP_INVERT: return "invert"; + case PIPE_LOGICOP_XOR: return "xor"; + case PIPE_LOGICOP_NAND: return "nand"; + case PIPE_LOGICOP_AND: return "and"; + case PIPE_LOGICOP_EQUIV: return "equiv"; + case PIPE_LOGICOP_NOOP: return "noop"; + case PIPE_LOGICOP_OR_INVERTED: return "or-inverted"; + case PIPE_LOGICOP_COPY: return "copy"; + case PIPE_LOGICOP_OR_REVERSE: return "or-reverse"; + case PIPE_LOGICOP_OR: return "or"; + case PIPE_LOGICOP_SET: return "set"; + default: unreachable("Invalid logicop\n"); + } +} + +static void +get_equation_str(const struct pan_blend_rt_state *rt_state, + char *str, unsigned len) +{ + const char *funcs[] = { + "add", "sub", "reverse_sub", "min", "max", + }; + const char *factors[] = { + "zero", "src_color", "src1_color", "dst_color", + "src_alpha", "src1_alpha", "dst_alpha", + "const_color", "const_alpha", "src_alpha_sat", + }; + int ret; + + if (!rt_state->equation.blend_enable) { + ret = snprintf(str, len, "replace"); + assert(ret > 0); + return; + } + + if (rt_state->equation.color_mask & 7) { + assert(rt_state->equation.rgb_func < ARRAY_SIZE(funcs)); + assert(rt_state->equation.rgb_src_factor < ARRAY_SIZE(factors)); + assert(rt_state->equation.rgb_dst_factor < ARRAY_SIZE(factors)); + ret = snprintf(str, len, "%s%s%s(func=%s,src_factor=%s%s,dst_factor=%s%s)%s", + (rt_state->equation.color_mask & 1) ? "R" : "", + (rt_state->equation.color_mask & 2) ? "G" : "", + (rt_state->equation.color_mask & 4) ? "B" : "", + funcs[rt_state->equation.rgb_func], + rt_state->equation.rgb_invert_src_factor ? "-" : "", + factors[rt_state->equation.rgb_src_factor], + rt_state->equation.rgb_invert_dst_factor ? "-" : "", + factors[rt_state->equation.rgb_dst_factor], + rt_state->equation.color_mask & 8 ? ";" : ""); + assert(ret > 0); + str += ret; + len -= ret; + } + + if (rt_state->equation.color_mask & 8) { + assert(rt_state->equation.alpha_func < ARRAY_SIZE(funcs)); + assert(rt_state->equation.alpha_src_factor < ARRAY_SIZE(factors)); + assert(rt_state->equation.alpha_dst_factor < ARRAY_SIZE(factors)); + ret = snprintf(str, len, "A(func=%s,src_factor=%s%s,dst_factor=%s%s)", + funcs[rt_state->equation.alpha_func], + rt_state->equation.alpha_invert_src_factor ? "-" : "", + factors[rt_state->equation.alpha_src_factor], + rt_state->equation.alpha_invert_dst_factor ? "-" : "", + factors[rt_state->equation.alpha_dst_factor]); + assert(ret > 0); + str += ret; + len -= ret; + } +} + +static nir_ssa_def * +nir_iclamp(nir_builder *b, nir_ssa_def *v, int32_t lo, int32_t hi) +{ + return nir_imin(b, nir_imax(b, v, nir_imm_int(b, lo)), nir_imm_int(b, hi)); +} + +nir_shader * +pan_blend_create_shader(const struct panfrost_device *dev, + const struct pan_blend_state *state, + unsigned rt) +{ + const struct pan_blend_rt_state *rt_state = &state->rts[rt]; + char equation_str[128] = { 0 }; + + get_equation_str(rt_state, equation_str, sizeof(equation_str)); + + nir_builder b = + nir_builder_init_simple_shader(MESA_SHADER_FRAGMENT, + pan_shader_get_compiler_options(dev), + "pan_blend(rt=%d,fmt=%s,nr_samples=%d,%s=%s)", + rt, util_format_name(rt_state->format), + rt_state->nr_samples, + state->logicop_enable ? "logicop" : "equation", + state->logicop_enable ? + logicop_str(state->logicop_func) : equation_str); + + const struct util_format_description *format_desc = + util_format_description(rt_state->format); + nir_alu_type nir_type = pan_unpacked_type_for_format(format_desc); + enum glsl_base_type glsl_type = nir_get_glsl_base_type_for_nir_type(nir_type); + + nir_lower_blend_options options = { + .logicop_enable = state->logicop_enable, + .logicop_func = state->logicop_func, + .colormask = rt_state->equation.color_mask, + .half = nir_type == nir_type_float16, + .format = rt_state->format, + .is_bifrost = pan_is_bifrost(dev), + }; + + if (!rt_state->equation.blend_enable) { + static const nir_lower_blend_channel replace = { + .func = BLEND_FUNC_ADD, + .src_factor = BLEND_FACTOR_ZERO, + .invert_src_factor = true, + .dst_factor = BLEND_FACTOR_ZERO, + .invert_dst_factor = false, + }; + + options.rgb = replace; + options.alpha = replace; + } else { + options.rgb.func = rt_state->equation.rgb_func; + options.rgb.src_factor = rt_state->equation.rgb_src_factor; + options.rgb.invert_src_factor = rt_state->equation.rgb_invert_src_factor; + options.rgb.dst_factor = rt_state->equation.rgb_dst_factor; + options.rgb.invert_dst_factor = rt_state->equation.rgb_invert_dst_factor; + options.alpha.func = rt_state->equation.alpha_func; + options.alpha.src_factor = rt_state->equation.alpha_src_factor; + options.alpha.invert_src_factor = rt_state->equation.alpha_invert_src_factor; + options.alpha.dst_factor = rt_state->equation.alpha_dst_factor; + options.alpha.invert_dst_factor = rt_state->equation.alpha_invert_dst_factor; + } + + nir_variable *c_src = + nir_variable_create(b.shader, nir_var_shader_in, + glsl_vector_type(GLSL_TYPE_FLOAT, 4), + "gl_Color"); + c_src->data.location = VARYING_SLOT_COL0; + nir_variable *c_src1 = + nir_variable_create(b.shader, nir_var_shader_in, + glsl_vector_type(GLSL_TYPE_FLOAT, 4), + "gl_Color1"); + c_src1->data.location = VARYING_SLOT_VAR0; + c_src1->data.driver_location = 1; + nir_variable *c_out = + nir_variable_create(b.shader, nir_var_shader_out, + glsl_vector_type(glsl_type, 4), + "gl_FragColor"); + c_out->data.location = FRAG_RESULT_COLOR; + + nir_ssa_def *s_src[] = {nir_load_var(&b, c_src), nir_load_var(&b, c_src1)}; + + for (int i = 0; i < ARRAY_SIZE(s_src); ++i) { + switch (nir_type) { + case nir_type_float16: + s_src[i] = nir_f2f16(&b, s_src[i]); + break; + case nir_type_int16: + s_src[i] = nir_i2i16(&b, nir_iclamp(&b, s_src[i], -32768, 32767)); + break; + case nir_type_uint16: + s_src[i] = nir_u2u16(&b, nir_umin(&b, s_src[i], nir_imm_int(&b, 65535))); + break; + case nir_type_int8: + s_src[i] = nir_i2i8(&b, nir_iclamp(&b, s_src[i], -128, 127)); + break; + case nir_type_uint8: + s_src[i] = nir_u2u8(&b, nir_umin(&b, s_src[i], nir_imm_int(&b, 255))); + break; + default: + break; + } + } + + /* Build a trivial blend shader */ + nir_store_var(&b, c_out, s_src[0], 0xFF); + + options.src1 = s_src[1]; + + NIR_PASS_V(b.shader, nir_lower_blend, options); + + return b.shader; +} diff --git a/src/panfrost/lib/pan_blend.h b/src/panfrost/lib/pan_blend.h new file mode 100644 index 0000000..d460c1e --- /dev/null +++ b/src/panfrost/lib/pan_blend.h @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2018 Alyssa Rosenzweig + * Copyright (C) 2019-2021 Collabora, Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef __PAN_BLEND_H__ +#define __PAN_BLEND_H__ + +#include "util/u_dynarray.h" +#include "util/format/u_format.h" +#include "compiler/shader_enums.h" +#include "compiler/nir/nir.h" + +#include "panfrost/util/pan_ir.h" + +struct MALI_BLEND_EQUATION; +struct panfrost_device; + +struct pan_blend_equation { + unsigned blend_enable : 1; + enum blend_func rgb_func : 3; + unsigned rgb_invert_src_factor : 1; + enum blend_factor rgb_src_factor : 4; + unsigned rgb_invert_dst_factor : 1; + enum blend_factor rgb_dst_factor : 4; + enum blend_func alpha_func : 3; + unsigned alpha_invert_src_factor : 1; + enum blend_factor alpha_src_factor : 4; + unsigned alpha_invert_dst_factor : 1; + enum blend_factor alpha_dst_factor : 4; + unsigned color_mask : 4; +}; + +struct pan_blend_rt_state { + /* RT format */ + enum pipe_format format; + + /* Number of samples */ + unsigned nr_samples; + + struct pan_blend_equation equation; +}; + +struct pan_blend_state { + bool dither; + bool logicop_enable; + enum pipe_logicop logicop_func; + float constants[4]; + unsigned rt_count; + struct pan_blend_rt_state rts[8]; +}; + +bool +pan_blend_reads_dest(const struct pan_blend_state *state, unsigned rt); + +bool +pan_blend_can_fixed_function(const struct panfrost_device *dev, + const struct pan_blend_state *state, + unsigned rt); + +bool +pan_blend_is_opaque(const struct pan_blend_state *state, + unsigned rt); + +unsigned +pan_blend_constant_mask(const struct pan_blend_state *state, + unsigned rt); + +float +pan_blend_get_constant(const struct panfrost_device *dev, + const struct pan_blend_state *state, + unsigned rt); + +void +pan_blend_to_fixed_function_equation(const struct panfrost_device *dev, + const struct pan_blend_state *state, + unsigned rt, + struct MALI_BLEND_EQUATION *equation); + +nir_shader * +pan_blend_create_shader(const struct panfrost_device *dev, + const struct pan_blend_state *state, + unsigned rt); + +#endif -- 2.7.4