From 068806c9f6be9bab84ed0d4868f16705cf4c7e6d Mon Sep 17 00:00:00 2001 From: Icecream95 Date: Thu, 20 Feb 2020 17:59:16 +1300 Subject: panfrost: LogicOp support The generated shaders are definitely not optimal, but for a feature hardly anyone uses, it's probably good enough. The XScreensaver demos quasicrystal, blitspin, bouboule, crystal and munch now seem to work, with no obvious problems. Currently this only works for 8-bit textures. Reviewed-by: Alyssa Rosenzweig Tested-by: Marge Bot Part-of: --- src/gallium/drivers/panfrost/nir/nir_lower_blend.c | 67 ++++++++++++++++++++++ src/gallium/drivers/panfrost/nir/nir_lower_blend.h | 3 + src/gallium/drivers/panfrost/pan_blend_cso.c | 19 +++--- src/gallium/drivers/panfrost/pan_blend_shaders.c | 8 +++ 4 files changed, 88 insertions(+), 9 deletions(-) diff --git a/src/gallium/drivers/panfrost/nir/nir_lower_blend.c b/src/gallium/drivers/panfrost/nir/nir_lower_blend.c index 4f3a91945e5..a2ff37922d9 100644 --- a/src/gallium/drivers/panfrost/nir/nir_lower_blend.c +++ b/src/gallium/drivers/panfrost/nir/nir_lower_blend.c @@ -156,6 +156,70 @@ nir_color_mask( return nir_vec(b, masked, 4); } +static nir_ssa_def * +nir_logicop_func( + nir_builder *b, + unsigned func, + nir_ssa_def *src, nir_ssa_def *dst) +{ + switch (func) { + case PIPE_LOGICOP_CLEAR: + return nir_imm_ivec4(b, 0, 0, 0, 0); + case PIPE_LOGICOP_NOR: + return nir_inot(b, nir_ior(b, src, dst)); + case PIPE_LOGICOP_AND_INVERTED: + return nir_iand(b, nir_inot(b, src), dst); + case PIPE_LOGICOP_COPY_INVERTED: + return nir_inot(b, src); + case PIPE_LOGICOP_AND_REVERSE: + return nir_iand(b, src, nir_inot(b, dst)); + case PIPE_LOGICOP_INVERT: + return nir_inot(b, dst); + case PIPE_LOGICOP_XOR: + return nir_ixor(b, src, dst); + case PIPE_LOGICOP_NAND: + return nir_inot(b, nir_iand(b, src, dst)); + case PIPE_LOGICOP_AND: + return nir_iand(b, src, dst); + case PIPE_LOGICOP_EQUIV: + return nir_inot(b, nir_ixor(b, src, dst)); + case PIPE_LOGICOP_NOOP: + return dst; + case PIPE_LOGICOP_OR_INVERTED: + return nir_ior(b, nir_inot(b, src), dst); + case PIPE_LOGICOP_COPY: + return src; + case PIPE_LOGICOP_OR_REVERSE: + return nir_ior(b, src, nir_inot(b, dst)); + case PIPE_LOGICOP_OR: + return nir_ior(b, src, dst); + case PIPE_LOGICOP_SET: + return nir_imm_ivec4(b, ~0, ~0, ~0, ~0); + } + + unreachable("Invalid logciop function"); +} + +static nir_ssa_def * +nir_blend_logicop( + nir_builder *b, + nir_lower_blend_options options, + nir_ssa_def *src, nir_ssa_def *dst) +{ + /* TODO: Support other sizes */ + nir_ssa_def *factor = nir_imm_float(b, 255); + + src = nir_fmin(b, nir_fmax(b, src, nir_imm_float(b, -1)), nir_imm_float(b, 1)); + src = nir_f2u32(b, nir_fround_even(b, nir_fmul(b, src, factor))); + + dst = nir_fmin(b, nir_fmax(b, dst, nir_imm_float(b, -1)), nir_imm_float(b, 1)); + dst = nir_f2u32(b, nir_fround_even(b, nir_fmul(b, dst, factor))); + + nir_ssa_def *out = nir_logicop_func(b, options.logicop_func, src, dst); + + return nir_fdiv(b, nir_u2f32(b, out), factor); +} + /* Given a blend state, the source color, and the destination color, * return the blended color */ @@ -166,6 +230,9 @@ nir_blend( nir_lower_blend_options options, nir_ssa_def *src, nir_ssa_def *dst) { + if (options.logicop_enable) + return nir_blend_logicop(b, options, src, dst); + /* Grab the blend constant ahead of time */ nir_ssa_def *bconst = nir_load_blend_const_color_rgba(b); diff --git a/src/gallium/drivers/panfrost/nir/nir_lower_blend.h b/src/gallium/drivers/panfrost/nir/nir_lower_blend.h index d150e99c72f..99530c3e973 100644 --- a/src/gallium/drivers/panfrost/nir/nir_lower_blend.h +++ b/src/gallium/drivers/panfrost/nir/nir_lower_blend.h @@ -48,6 +48,9 @@ typedef struct { /* 4-bit colormask. 0x0 for none, 0xF for RGBA, 0x1 for R */ unsigned colormask; + + bool logicop_enable; + unsigned logicop_func; } nir_lower_blend_options; void nir_lower_blend(nir_shader *shader, nir_lower_blend_options options); diff --git a/src/gallium/drivers/panfrost/pan_blend_cso.c b/src/gallium/drivers/panfrost/pan_blend_cso.c index 94f229b620d..8b4635ca286 100644 --- a/src/gallium/drivers/panfrost/pan_blend_cso.c +++ b/src/gallium/drivers/panfrost/pan_blend_cso.c @@ -107,7 +107,6 @@ panfrost_create_blend_state(struct pipe_context *pipe, so->base = *blend; /* TODO: The following features are not yet implemented */ - assert(!blend->logicop_enable); assert(!blend->alpha_to_coverage); assert(!blend->alpha_to_one); @@ -119,15 +118,17 @@ panfrost_create_blend_state(struct pipe_context *pipe, /* Without indep blending, the first RT settings replicate */ - unsigned g = - blend->independent_blend_enable ? c : 0; + if (!blend->logicop_enable) { + unsigned g = + blend->independent_blend_enable ? c : 0; - rt->has_fixed_function = - panfrost_make_fixed_blend_mode( - &blend->rt[g], - &rt->equation, - &rt->constant_mask, - blend->rt[g].colormask); + rt->has_fixed_function = + panfrost_make_fixed_blend_mode( + &blend->rt[g], + &rt->equation, + &rt->constant_mask, + blend->rt[g].colormask); + } /* Regardless if that works, we also need to initialize * the blend shaders */ diff --git a/src/gallium/drivers/panfrost/pan_blend_shaders.c b/src/gallium/drivers/panfrost/pan_blend_shaders.c index cca2eb567b5..0f0e1b5ffd9 100644 --- a/src/gallium/drivers/panfrost/pan_blend_shaders.c +++ b/src/gallium/drivers/panfrost/pan_blend_shaders.c @@ -89,6 +89,14 @@ nir_make_options(const struct pipe_blend_state *blend, unsigned i) { nir_lower_blend_options options; + if (blend->logicop_enable) { + options.logicop_enable = true; + options.logicop_func = blend->logicop_func; + return options; + } + + options.logicop_enable = false; + /* If blend is disabled, we just use replace mode */ nir_lower_blend_channel rgb = { -- cgit v1.2.1