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 <boris.brezillon@collabora.com> Acked-by: Alyssa Rosenzweig <alyssa.rosenzweig@collabora.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/8963>
This commit is contained in:
parent
37974bcd26
commit
93824b6451
|
@ -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 \
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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];
|
||||
const struct pipe_rt_blend_state *pipe = &blend->rt[g];
|
||||
struct pan_blend_equation *equation = &so->pan.rts[c].equation;
|
||||
|
||||
struct panfrost_blend_rt *rt = &so->rt[c];
|
||||
|
||||
/* 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;
|
||||
|
||||
/* Grab the blend state */
|
||||
struct panfrost_blend_state *blend = ctx->blend;
|
||||
struct panfrost_blend_rt *rt = &blend->rt[rti];
|
||||
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
|
||||
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 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 (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;
|
||||
}
|
||||
|
||||
|
||||
/* 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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 <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;
|
||||
}
|
|
@ -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 <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
|
|
@ -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"
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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
|
Loading…
Reference in New Issue