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 \
'pan_blit.c',
'pan_job.c',
'pan_assemble.c',
- 'pan_blending.c',
'pan_blend_shaders.c',
'pan_blend_cso.c',
'pan_cmdstream.c',
#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"
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;
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 */
.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;
#ifndef __PAN_BLEND_CSO_H
#define __PAN_BLEND_CSO_H
+#include "pan_blend.h"
#include "util/hash_table.h"
#include "nir.h"
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
* (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,
{
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;
}
+++ /dev/null
-/*
- * © 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 <stdio.h>
-#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;
-}
+++ /dev/null
-/*
- * © 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 <midgard_pack.h>
-#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
#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"
#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"
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,
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 \
'pan_afbc.c',
'pan_attributes.c',
'pan_bo.c',
+ 'pan_blend.c',
'pan_blit.c',
'pan_format.c',
'pan_invocation.c',
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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