From 46396af1ec4b69ca4a38b501fa2cf37386947840 Mon Sep 17 00:00:00 2001 From: Alyssa Rosenzweig Date: Fri, 5 Jul 2019 15:40:08 -0700 Subject: panfrost: Refactor blend infrastructure We would like to permit keying blend shaders against the framebuffer format, which requires some new blending abstractions. Signed-off-by: Alyssa Rosenzweig --- src/gallium/drivers/panfrost/meson.build | 1 + src/gallium/drivers/panfrost/pan_blend.h | 109 +++++++++ src/gallium/drivers/panfrost/pan_blend_cso.c | 268 +++++++++++++++++++++++ src/gallium/drivers/panfrost/pan_blend_shaders.c | 34 ++- src/gallium/drivers/panfrost/pan_blend_shaders.h | 8 +- src/gallium/drivers/panfrost/pan_blending.c | 75 ++----- src/gallium/drivers/panfrost/pan_blending.h | 13 +- src/gallium/drivers/panfrost/pan_context.c | 133 +++-------- src/gallium/drivers/panfrost/pan_context.h | 16 +- 9 files changed, 455 insertions(+), 202 deletions(-) create mode 100644 src/gallium/drivers/panfrost/pan_blend.h create mode 100644 src/gallium/drivers/panfrost/pan_blend_cso.c diff --git a/src/gallium/drivers/panfrost/meson.build b/src/gallium/drivers/panfrost/meson.build index cc49903aaac..6b907f155ae 100644 --- a/src/gallium/drivers/panfrost/meson.build +++ b/src/gallium/drivers/panfrost/meson.build @@ -56,6 +56,7 @@ files_panfrost = files( 'pan_format.c', 'pan_blending.c', 'pan_blend_shaders.c', + 'pan_blend_cso.c', 'pan_pretty_print.c', 'pan_fragment.c', 'pan_invocation.c', diff --git a/src/gallium/drivers/panfrost/pan_blend.h b/src/gallium/drivers/panfrost/pan_blend.h new file mode 100644 index 00000000000..486ed4dc034 --- /dev/null +++ b/src/gallium/drivers/panfrost/pan_blend.h @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2019 Collabora + * + * 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. + * + * Authors (Collabora): + * Alyssa Rosenzweig + * + */ + +#ifndef __PAN_BLEND_H +#define __PAN_BLEND_H + +#include "util/hash_table.h" + +/* An internal blend shader descriptor, from the compiler */ + +struct panfrost_blend_shader { + /* The compiled shader in GPU memory */ + struct panfrost_transfer shader; + + /* Byte count of the shader */ + unsigned size; + + /* Number of 128-bit work registers required by the shader */ + unsigned work_count; + + /* Offset into the shader to patch constants. Zero to disable patching + * (it is illogical to have constants at offset 0). */ + unsigned patch_index; + + /* First instruction tag (for tagging the pointer) */ + unsigned first_tag; +}; + +/* A blend shader descriptor ready for actual use */ + +struct panfrost_blend_shader_final { + /* The upload, possibly to transient memory */ + mali_ptr gpu; + + /* Same meaning as panfrost_blend_shader */ + unsigned work_count; +}; + +struct panfrost_blend_equation_final { + struct mali_blend_equation *equation; + 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; + + /* Regardless of fixed-function blending, this is a map of pipe_format + * to panfrost_blend_shader */ + + struct hash_table_u64 *shaders; +}; + +struct panfrost_blend_state { + struct pipe_blend_state base; + + struct panfrost_blend_rt rt[PIPE_MAX_COLOR_BUFS]; +}; + +/* Container for a final blend state, specialized to constants and a + * framebuffer formats. */ + +struct panfrost_blend_final { + /* Set for a shader, clear for an equation */ + bool is_shader; + + union { + struct panfrost_blend_shader_final shader; + struct panfrost_blend_equation_final equation; + }; +}; + +void +panfrost_blend_context_init(struct pipe_context *pipe); + +struct panfrost_blend_final +panfrost_get_blend_for_context(struct panfrost_context *ctx, unsigned rt); + +#endif diff --git a/src/gallium/drivers/panfrost/pan_blend_cso.c b/src/gallium/drivers/panfrost/pan_blend_cso.c new file mode 100644 index 00000000000..a1b8111190f --- /dev/null +++ b/src/gallium/drivers/panfrost/pan_blend_cso.c @@ -0,0 +1,268 @@ +/* + * Copyright (C) 2019 Collabora + * + * 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. + * + * Authors (Collabora): + * Alyssa Rosenzweig + * + */ + +#include +#include "util/u_memory.h" +#include "pan_blend_shaders.h" +#include "pan_blending.h" + +/* A given Gallium blend state can be encoded to the hardware in numerous, + * dramatically divergent ways due to the interactions of blending with + * framebuffer formats. Conceptually, there are two modes: + * + * - Fixed-function blending (for suitable framebuffer formats, suitable blend + * state, and suitable blend constant) + * + * - Blend shaders (for everything else) + * + * A given Gallium blend configuration will compile to exactly one + * fixed-function blend state, if it compiles to any, although the constant + * will vary across runs as that is tracked outside of the Gallium CSO. + * + * However, that same blend configuration will compile to many different blend + * shaders, depending on the framebuffer formats active. The rationale is that + * blend shaders override not just fixed-function blending but also + * fixed-function format conversion. As such, each blend shader must be + * hardcoded to a particular framebuffer format to correctly pack/unpack it. As + * a concrete example, to the hardware there is no difference (!) between RG16F + * and RG16UI -- both are simply 4-byte-per-pixel chunks. Thus both formats + * require a blend shader (even with blending is totally disabled!), required + * to do conversion as necessary (if necessary). + * + * All of this state is encapsulated in the panfrost_blend_state struct + * (our subclass of pipe_blend_state). + */ + +/* Given an initialized CSO and a particular framebuffer format, grab a + * blend shader, generating and compiling it if it doesn't exist + * (lazy-loading in a way). This routine, when the cache hits, should + * befast, suitable for calling every draw to avoid wacky dirty + * tracking paths. If the cache hits, boom, done. */ + +static struct panfrost_blend_shader * +panfrost_get_blend_shader( + struct panfrost_context *ctx, + struct panfrost_blend_state *blend, + enum pipe_format fmt, + unsigned rt) +{ + /* Prevent NULL collision issues.. */ + assert(fmt != 0); + + /* Check the cache */ + struct hash_table_u64 *shaders = blend->rt[rt].shaders; + + struct panfrost_blend_shader *shader = + _mesa_hash_table_u64_search(shaders, fmt); + + if (shader) + return shader; + + /* Cache miss. Build one instead, cache it, and go */ + + struct panfrost_blend_shader generated = + panfrost_compile_blend_shader(ctx, &blend->base, fmt); + + shader = mem_dup(&generated, sizeof(generated)); + _mesa_hash_table_u64_insert(shaders, fmt, shader); + return shader; +} + +/* Create a blend CSO. Essentially, try to compile a fixed-function + * expression and initialize blend shaders */ + +static void * +panfrost_create_blend_state(struct pipe_context *pipe, + const struct pipe_blend_state *blend) +{ + struct panfrost_context *ctx = pan_context(pipe); + struct panfrost_blend_state *so = rzalloc(ctx, struct panfrost_blend_state); + 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); + + for (unsigned c = 0; c < 4; ++c) { + struct panfrost_blend_rt *rt = &so->rt[c]; + + /* There are two paths. First, we would like to try a + * fixed-function if we can */ + + rt->has_fixed_function = + panfrost_make_fixed_blend_mode( + &blend->rt[c], + &rt->equation, + &rt->constant_mask, + blend->rt[c].colormask); + + /* Regardless if that works, we also need to initialize + * the blend shaders */ + + rt->shaders = _mesa_hash_table_u64_create(NULL); + } + + return so; +} + +static void +panfrost_bind_blend_state(struct pipe_context *pipe, + void *cso) +{ + struct panfrost_context *ctx = pan_context(pipe); + struct pipe_blend_state *blend = (struct pipe_blend_state *) cso; + struct panfrost_blend_state *pblend = (struct panfrost_blend_state *) cso; + ctx->blend = pblend; + + if (!blend) + return; + + SET_BIT(ctx->fragment_shader_core.unknown2_4, MALI_NO_DITHER, !blend->dither); + + /* Shader itself is not dirty, but the shader core is */ + ctx->dirty |= PAN_DIRTY_FS; +} + +static void +panfrost_delete_blend_state(struct pipe_context *pipe, + void *blend) +{ + /* TODO: leaks internally? */ + + ralloc_free(blend); +} + +static void +panfrost_set_blend_color(struct pipe_context *pipe, + const struct pipe_blend_color *blend_color) +{ + struct panfrost_context *ctx = pan_context(pipe); + + if (blend_color) + 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. Do set a + * dummy constant just to avoid reading uninitialized memory. */ + + if (!mask) { + *out = 0.0; + 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) { + *out = 0.0; + 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) +{ + /* Grab the format */ + struct pipe_framebuffer_state *fb = &ctx->pipe_framebuffer; + assert(fb->nr_cbufs > rti); + enum pipe_format fmt = fb->cbufs[rti]->format; + + /* Grab the blend state */ + struct panfrost_blend_state *blend = ctx->blend; + assert(blend); + + struct panfrost_blend_rt *rt = &blend->rt[rti]; + + struct panfrost_blend_final final; + + /* First, we'll try a fixed function path */ + if (rt->has_fixed_function && panfrost_can_fixed_blend(fmt)) { + if (panfrost_blend_constant( + &final.equation.constant, + ctx->blend_color.color, + rt->constant_mask)) + { + /* There's an equation and suitable constant, so we're good to go */ + final.is_shader = false; + final.equation.equation = &rt->equation; + return final; + } + } + + /* Otherwise, we need to grab a shader */ + struct panfrost_blend_shader *shader = panfrost_get_blend_shader(ctx, blend, fmt, rti); + final.is_shader = true; + final.shader.work_count = shader->work_count; + + if (shader->patch_index) { + /* We have to specialize the blend shader to use constants, so + * patch in the current constants and upload to transient + * memory */ + + float *patch = (float *) (shader->shader.cpu + shader->patch_index); + memcpy(patch, ctx->blend_color.color, sizeof(float) * 4); + + final.shader.gpu = panfrost_upload_transient( + ctx, shader->shader.cpu, shader->size); + } else { + /* No need to specialize further, use the preuploaded */ + final.shader.gpu = shader->shader.gpu; + } + + final.shader.gpu |= shader->first_tag; + return final; +} + +void +panfrost_blend_context_init(struct pipe_context *pipe) +{ + pipe->create_blend_state = panfrost_create_blend_state; + pipe->bind_blend_state = panfrost_bind_blend_state; + pipe->delete_blend_state = panfrost_delete_blend_state; + + pipe->set_blend_color = panfrost_set_blend_color; +} diff --git a/src/gallium/drivers/panfrost/pan_blend_shaders.c b/src/gallium/drivers/panfrost/pan_blend_shaders.c index 2b6206545b3..993b612ee50 100644 --- a/src/gallium/drivers/panfrost/pan_blend_shaders.c +++ b/src/gallium/drivers/panfrost/pan_blend_shaders.c @@ -29,6 +29,7 @@ #include "compiler/nir/nir_builder.h" #include "midgard/nir_lower_blend.h" #include "gallium/auxiliary/util/u_blend.h" +#include "util/u_memory.h" /* * Implements the command stream portion of programmatic blend shaders. @@ -124,13 +125,14 @@ nir_make_options(const struct pipe_blend_state *blend, unsigned nr_cbufs) return options; } -void -panfrost_make_blend_shader( +struct panfrost_blend_shader +panfrost_compile_blend_shader( struct panfrost_context *ctx, - struct panfrost_blend_state *cso, - const struct pipe_blend_color *blend_color, + struct pipe_blend_state *cso, enum pipe_format format) { + struct panfrost_blend_shader res; + /* Build the shader */ nir_shader *shader = nir_shader_create(NULL, MESA_SHADER_FRAGMENT, &midgard_nir_options, NULL); @@ -160,7 +162,7 @@ panfrost_make_blend_shader( nir_store_var(b, c_out, s_src, 0xFF); nir_lower_blend_options options = - nir_make_options(&cso->base, 1); + nir_make_options(cso, 1); NIR_PASS_V(shader, nir_lower_blend, options); NIR_PASS_V(shader, nir_lower_framebuffer, format); @@ -175,20 +177,16 @@ panfrost_make_blend_shader( int size = program.compiled.size; uint8_t *dst = program.compiled.data; - /* Hot patch in constant color */ - - if (program.blend_patch_offset >= 0) { - float *hot_color = (float *) (dst + program.blend_patch_offset); - - for (int c = 0; c < 4; ++c) - hot_color[c] = blend_color->color[c]; - } + res.shader.cpu = mem_dup(dst, size); + res.shader.gpu = panfrost_upload(&ctx->shaders, dst, size, true); - cso->blend_shader = panfrost_upload(&ctx->shaders, dst, size, true) | program.first_tag; + /* At least two work registers are needed due to an encoding quirk */ + res.work_count = MAX2(program.work_register_count, 2); - /* We need to switch to shader mode */ - cso->has_blend_shader = true; + /* Allow us to patch later */ + res.patch_index = program.blend_patch_offset; + res.first_tag = program.first_tag; + res.size = size; - /* At least two work registers are needed due to an encoding quirk */ - cso->blend_work_count = MAX2(program.work_register_count, 2); + return res; } diff --git a/src/gallium/drivers/panfrost/pan_blend_shaders.h b/src/gallium/drivers/panfrost/pan_blend_shaders.h index 23acd39581a..1d2f090c4cc 100644 --- a/src/gallium/drivers/panfrost/pan_blend_shaders.h +++ b/src/gallium/drivers/panfrost/pan_blend_shaders.h @@ -29,12 +29,12 @@ #include "pipe/p_defines.h" #include #include "pan_context.h" +#include "pan_blend.h" -void -panfrost_make_blend_shader( +struct panfrost_blend_shader +panfrost_compile_blend_shader( struct panfrost_context *ctx, - struct panfrost_blend_state *cso, - const struct pipe_blend_color *blend_color, + struct pipe_blend_state *cso, enum pipe_format format); #endif diff --git a/src/gallium/drivers/panfrost/pan_blending.c b/src/gallium/drivers/panfrost/pan_blending.c index 6bdc8395d18..72eeb59280c 100644 --- a/src/gallium/drivers/panfrost/pan_blending.c +++ b/src/gallium/drivers/panfrost/pan_blending.c @@ -101,8 +101,8 @@ /* Not all formats can be blended by fixed-function hardware */ -static bool -panfrost_can_blend(enum pipe_format format) +bool +panfrost_can_fixed_blend(enum pipe_format format) { /* Fixed-function can handle sRGB */ format = util_format_linear(format); @@ -318,53 +318,24 @@ panfrost_make_fixed_blend_part(unsigned func, unsigned src_factor, unsigned dst_ return true; } -/* We can upload a single constant for all of the factors. So, scan the factors - * for constants used, and scan the constants for the constants used. If there - * is a single unique constant, output that. If there are multiple, - * fixed-function operation breaks down. */ +/* 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 bool -panfrost_make_constant(unsigned *factors, unsigned num_factors, const struct pipe_blend_color *blend_color, void *out) +static unsigned +panfrost_constant_mask(unsigned *factors, unsigned num_factors) { - /* Color components used */ - bool cc[4] = { false }; + unsigned mask = 0; for (unsigned i = 0; i < num_factors; ++i) { unsigned factor = uncomplement_factor(factors[i]); if (factor == PIPE_BLENDFACTOR_CONST_COLOR) - cc[0] = cc[1] = cc[2] = true; + mask |= 0b0111; /* RGB */ else if (factor == PIPE_BLENDFACTOR_CONST_ALPHA) - cc[3] = true; - } - - /* Find the actual constant associated with the components used*/ - - float constant = 0.0; - bool has_constant = false; - - for (unsigned i = 0; i < 4; ++i) { - /* If the component is unused, nothing to do */ - if (!cc[i]) continue; - - float value = blend_color->color[i]; - - /* Either there's a second constant, in which case we fail, or - * there's no constant / a first constant, in which case we use - * that constant */ - - if (has_constant && constant != value) { - return false; - } else { - has_constant = true; - constant = value; - } + mask |= 0b1000; /* A */ } - /* We have the constant -- success! */ - - memcpy(out, &constant, sizeof(float)); - return true; + return mask; } /* Create the descriptor for a fixed blend mode given the corresponding Gallium @@ -376,19 +347,13 @@ panfrost_make_constant(unsigned *factors, unsigned num_factors, const struct pip bool panfrost_make_fixed_blend_mode( const struct pipe_rt_blend_state *blend, - struct panfrost_blend_state *so, - unsigned colormask, - const struct pipe_blend_color *blend_color, - enum pipe_format format) + struct mali_blend_equation *out, + unsigned *constant_mask, + unsigned colormask) { - struct mali_blend_equation *out = &so->equation; - - /* Check if the format supports fixed-function blending at all */ + /* Gallium and Mali represent colour masks identically. XXX: Static + * assert for future proof */ - if (!panfrost_can_blend(format)) - return false; - - /* Gallium and Mali represent colour masks identically. XXX: Static assert for future proof */ out->color_mask = colormask; /* If no blending is enabled, default back on `replace` mode */ @@ -399,16 +364,18 @@ panfrost_make_fixed_blend_mode( return true; } - /* We have room only for a single float32 constant between the four - * components. If we need more, spill to the programmable pipeline. */ + /* At draw-time, we'll need to analyze the blend constant, so + * precompute a mask for it -- even if we don't end up able to use + * fixed-function blending */ unsigned factors[] = { blend->rgb_src_factor, blend->rgb_dst_factor, blend->alpha_src_factor, blend->alpha_dst_factor, }; - if (!panfrost_make_constant(factors, ARRAY_SIZE(factors), blend_color, &so->constant)) - return false; + *constant_mask = panfrost_constant_mask(factors, ARRAY_SIZE(factors)); + + /* Try to compile the actual fixed-function blend */ unsigned rgb_mode = 0; unsigned alpha_mode = 0; diff --git a/src/gallium/drivers/panfrost/pan_blending.h b/src/gallium/drivers/panfrost/pan_blending.h index 4be0c4d4385..163237eed5e 100644 --- a/src/gallium/drivers/panfrost/pan_blending.h +++ b/src/gallium/drivers/panfrost/pan_blending.h @@ -31,11 +31,14 @@ struct panfrost_blend_state; -bool panfrost_make_fixed_blend_mode( +bool +panfrost_make_fixed_blend_mode( const struct pipe_rt_blend_state *blend, - struct panfrost_blend_state *so, - unsigned colormask, - const struct pipe_blend_color *blend_color, - enum pipe_format format); + struct mali_blend_equation *out, + unsigned *constant_mask, + unsigned colormask); + +bool +panfrost_can_fixed_blend(enum pipe_format format); #endif diff --git a/src/gallium/drivers/panfrost/pan_context.c b/src/gallium/drivers/panfrost/pan_context.c index c26a6dbaabb..69d877277be 100644 --- a/src/gallium/drivers/panfrost/pan_context.c +++ b/src/gallium/drivers/panfrost/pan_context.c @@ -1071,9 +1071,14 @@ panfrost_emit_for_draw(struct panfrost_context *ctx, bool with_vertex_data) COPY(midgard1.unknown2); #undef COPY + + /* Get blending setup */ + struct panfrost_blend_final blend = + panfrost_get_blend_for_context(ctx, 0); + /* If there is a blend shader, work registers are shared */ - if (ctx->blend->has_blend_shader) + if (blend.is_shader) ctx->fragment_shader_core.midgard1.work_count = /*MAX2(ctx->fragment_shader_core.midgard1.work_count, ctx->blend->blend_work_count)*/16; /* Set late due to depending on render state */ @@ -1112,18 +1117,19 @@ panfrost_emit_for_draw(struct panfrost_context *ctx, bool with_vertex_data) /* Check if we're using the default blend descriptor (fast path) */ bool no_blending = - !ctx->blend->has_blend_shader && - (ctx->blend->equation.rgb_mode == 0x122) && - (ctx->blend->equation.alpha_mode == 0x122) && - (ctx->blend->equation.color_mask == 0xf); + !blend.is_shader && + (blend.equation.equation->rgb_mode == 0x122) && + (blend.equation.equation->alpha_mode == 0x122) && + (blend.equation.equation->color_mask == 0xf); /* Even on MFBD, the shader descriptor gets blend shaders. It's * *also* copied to the blend_meta appended (by convention), * but this is the field actually read by the hardware. (Or * maybe both are read...?) */ - if (ctx->blend->has_blend_shader) { - ctx->fragment_shader_core.blend.shader = ctx->blend->blend_shader; + if (blend.is_shader) { + ctx->fragment_shader_core.blend.shader = + blend.shader.gpu; } else { ctx->fragment_shader_core.blend.shader = 0; } @@ -1134,9 +1140,11 @@ panfrost_emit_for_draw(struct panfrost_context *ctx, bool with_vertex_data) * additionally need to signal CAN_DISCARD for nontrivial blend * modes (so we're able to read back the destination buffer) */ - if (!ctx->blend->has_blend_shader) { - ctx->fragment_shader_core.blend.equation = ctx->blend->equation; - ctx->fragment_shader_core.blend.constant = ctx->blend->constant; + if (!blend.is_shader) { + ctx->fragment_shader_core.blend.equation = + *blend.equation.equation; + ctx->fragment_shader_core.blend.constant = + blend.equation.constant; } if (!no_blending) { @@ -1155,13 +1163,13 @@ panfrost_emit_for_draw(struct panfrost_context *ctx, bool with_vertex_data) unsigned blend_count = 0x200; - if (ctx->blend->has_blend_shader) { + if (blend.is_shader) { /* For a blend shader, the bottom nibble corresponds to * the number of work registers used, which signals the * -existence- of a blend shader */ - assert(ctx->blend->blend_work_count >= 2); - blend_count |= MIN2(ctx->blend->blend_work_count, 3); + assert(blend.shader.work_count >= 2); + blend_count |= MIN2(blend.shader.work_count, 3); } else { /* Otherwise, the bottom bit simply specifies if * blending (anything other than REPLACE) is enabled */ @@ -1191,13 +1199,13 @@ panfrost_emit_for_draw(struct panfrost_context *ctx, bool with_vertex_data) * native Midgard ops for helping here, but * they're not well-understood yet. */ - assert(!(is_srgb && ctx->blend->has_blend_shader)); + assert(!(is_srgb && blend.is_shader)); - if (ctx->blend->has_blend_shader) { - rts[i].blend.shader = ctx->blend->blend_shader; + if (blend.is_shader) { + rts[i].blend.shader = blend.shader.gpu; } else { - rts[i].blend.equation = ctx->blend->equation; - rts[i].blend.constant = ctx->blend->constant; + rts[i].blend.equation = *blend.equation.equation; + rts[i].blend.constant = blend.equation.constant; } } @@ -2363,88 +2371,6 @@ panfrost_set_framebuffer_state(struct pipe_context *pctx, } } -static void * -panfrost_create_blend_state(struct pipe_context *pipe, - const struct pipe_blend_state *blend) -{ - struct panfrost_context *ctx = pan_context(pipe); - struct panfrost_blend_state *so = rzalloc(ctx, struct panfrost_blend_state); - 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); - - /* Compile the blend state, first as fixed-function if we can */ - - /* TODO: Key by format */ - enum pipe_format format = ctx->pipe_framebuffer.nr_cbufs ? - ctx->pipe_framebuffer.cbufs[0]->format : - PIPE_FORMAT_R8G8B8A8_UNORM; - - if (panfrost_make_fixed_blend_mode(&blend->rt[0], so, blend->rt[0].colormask, &ctx->blend_color, format)) - return so; - - /* If we can't, compile a blend shader instead */ - - panfrost_make_blend_shader(ctx, so, &ctx->blend_color, format); - - return so; -} - -static void -panfrost_bind_blend_state(struct pipe_context *pipe, - void *cso) -{ - struct panfrost_context *ctx = pan_context(pipe); - struct pipe_blend_state *blend = (struct pipe_blend_state *) cso; - struct panfrost_blend_state *pblend = (struct panfrost_blend_state *) cso; - ctx->blend = pblend; - - if (!blend) - return; - - SET_BIT(ctx->fragment_shader_core.unknown2_4, MALI_NO_DITHER, !blend->dither); - - /* TODO: Attach color */ - - /* Shader itself is not dirty, but the shader core is */ - ctx->dirty |= PAN_DIRTY_FS; -} - -static void -panfrost_delete_blend_state(struct pipe_context *pipe, - void *blend) -{ - struct panfrost_blend_state *so = (struct panfrost_blend_state *) blend; - - if (so->has_blend_shader) { - DBG("Deleting blend state leak blend shaders bytecode\n"); - } - - ralloc_free(blend); -} - -static void -panfrost_set_blend_color(struct pipe_context *pipe, - const struct pipe_blend_color *blend_color) -{ - struct panfrost_context *ctx = pan_context(pipe); - - /* If blend_color is we're unbinding, so ctx->blend_color is now undefined -> nothing to do */ - - if (blend_color) { - ctx->blend_color = *blend_color; - - /* The blend mode depends on the blend constant color, due to the - * fixed/programmable split. So, we're forced to regenerate the blend - * equation */ - - /* TODO: Attach color */ - } -} - static void * panfrost_create_depth_stencil_state(struct pipe_context *pipe, const struct pipe_depth_stencil_alpha_state *depth_stencil) @@ -2795,12 +2721,6 @@ panfrost_create_context(struct pipe_screen *screen, void *priv, unsigned flags) gallium->delete_sampler_state = panfrost_generic_cso_delete; gallium->bind_sampler_states = panfrost_bind_sampler_states; - gallium->create_blend_state = panfrost_create_blend_state; - gallium->bind_blend_state = panfrost_bind_blend_state; - gallium->delete_blend_state = panfrost_delete_blend_state; - - gallium->set_blend_color = panfrost_set_blend_color; - gallium->create_depth_stencil_alpha_state = panfrost_create_depth_stencil_state; gallium->bind_depth_stencil_alpha_state = panfrost_bind_depth_stencil_state; gallium->delete_depth_stencil_alpha_state = panfrost_delete_depth_stencil_state; @@ -2824,6 +2744,7 @@ panfrost_create_context(struct pipe_screen *screen, void *priv, unsigned flags) gallium->set_stream_output_targets = panfrost_set_stream_output_targets; panfrost_resource_context_init(gallium); + panfrost_blend_context_init(gallium); panfrost_drm_init_context(ctx); diff --git a/src/gallium/drivers/panfrost/pan_context.h b/src/gallium/drivers/panfrost/pan_context.h index a913c8581ef..9b977ed59ec 100644 --- a/src/gallium/drivers/panfrost/pan_context.h +++ b/src/gallium/drivers/panfrost/pan_context.h @@ -31,6 +31,7 @@ #include #include "pan_resource.h" #include "pan_job.h" +#include "pan_blend.h" #include "pipe/p_compiler.h" #include "pipe/p_config.h" @@ -228,21 +229,6 @@ struct panfrost_rasterizer { unsigned tiler_gl_enables; }; -struct panfrost_blend_state { - struct pipe_blend_state base; - - /* Whether a blend shader is in use */ - bool has_blend_shader; - - /* Compiled fixed function command */ - struct mali_blend_equation equation; - float constant; - - /* Compiled blend shader */ - mali_ptr blend_shader; - int blend_work_count; -}; - /* Variants bundle together to form the backing CSO, bundling multiple * shaders with varying emulated features baked in (alpha test * parameters, etc) */ -- cgit v1.2.3