From 25a879e5f99b2d9ca7390982a6427d17d793b59f Mon Sep 17 00:00:00 2001 From: Alyssa Rosenzweig Date: Tue, 6 Jul 2021 17:53:15 -0400 Subject: [PATCH] panfrost: Move blend CSO to cmdstream/context Create is hardware specifc, bind/delete/set_colour is not. Signed-off-by: Alyssa Rosenzweig Acked-by: Boris Brezillon Part-of: --- src/gallium/drivers/panfrost/meson.build | 1 - src/gallium/drivers/panfrost/pan_blend_cso.c | 229 ------------------- src/gallium/drivers/panfrost/pan_blend_cso.h | 3 - src/gallium/drivers/panfrost/pan_cmdstream.c | 100 ++++++++ src/gallium/drivers/panfrost/pan_context.c | 93 +++++++- 5 files changed, 192 insertions(+), 234 deletions(-) delete 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 dc00072aa0a..1be1635d5f6 100644 --- a/src/gallium/drivers/panfrost/meson.build +++ b/src/gallium/drivers/panfrost/meson.build @@ -29,7 +29,6 @@ files_panfrost = files( 'pan_blit.c', 'pan_job.c', 'pan_assemble.c', - 'pan_blend_cso.c', 'pan_cmdstream.c', 'pan_compute.c', 'pan_mempool.c', diff --git a/src/gallium/drivers/panfrost/pan_blend_cso.c b/src/gallium/drivers/panfrost/pan_blend_cso.c deleted file mode 100644 index 7d63b807fb3..00000000000 --- a/src/gallium/drivers/panfrost/pan_blend_cso.c +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Copyright (C) 2019 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. - * - * Authors (Collabora): - * Alyssa Rosenzweig - * - */ - -#include -#include "util/u_memory.h" -#include "gallium/auxiliary/util/u_blend.h" -#include "pan_context.h" -#include "pan_blend_cso.h" -#include "pan_bo.h" -#include "panfrost-quirks.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, so blend shaders are keyed to a particular - * framebuffer format. As an example, the tilebuffer format is identical for - * RG16F and RG16UI -- both are simply 32-bit raw pixels -- so both require - * blend shaders. - * - * All of this state is encapsulated in the panfrost_blend_state struct - * (our subclass of pipe_blend_state). - */ - -/* 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_device *dev = pan_device(pipe->screen); - struct panfrost_blend_state *so = rzalloc(ctx, struct panfrost_blend_state); - so->base = *blend; - - so->pan.logicop_enable = blend->logicop_enable; - so->pan.logicop_func = blend->logicop_func; - so->pan.rt_count = blend->max_rt + 1; - - for (unsigned c = 0; c < so->pan.rt_count; ++c) { - unsigned g = blend->independent_blend_enable ? c : 0; - const struct pipe_rt_blend_state pipe = blend->rt[g]; - struct pan_blend_equation equation; - - equation.color_mask = pipe.colormask; - equation.blend_enable = pipe.blend_enable; - - if (pipe.blend_enable) { - 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); - } - - /* Determine some common properties */ - unsigned constant_mask = pan_blend_constant_mask(equation); - so->info[c] = (struct pan_blend_info) { - .no_colour = (equation.color_mask == 0), - .opaque = pan_blend_is_opaque(equation), - .constant_mask = constant_mask, - - /* TODO: check the dest for the logicop */ - .load_dest = blend->logicop_enable || - pan_blend_reads_dest(equation), - - /* Could this possibly be fixed-function? */ - .fixed_function = !blend->logicop_enable && - pan_blend_can_fixed_function(equation) && - (!constant_mask || - pan_blend_supports_constant(dev->arch, c)) - }; - - so->pan.rts[c].equation = equation; - - /* Bifrost needs to know if any render target loads its - * destination in the hot draw path, so precompute this */ - if (so->info[c].load_dest) - so->load_dest_mask |= BITFIELD_BIT(c); - - /* Converting equations to Mali style is expensive, do it at - * CSO create time instead of draw-time */ - if (so->info[c].fixed_function) { - pan_pack(&so->equation[c], BLEND_EQUATION, cfg) - pan_blend_to_fixed_function_equation(equation, &cfg); - } - } - - return so; -} - -static void -panfrost_bind_blend_state(struct pipe_context *pipe, void *cso) -{ - struct panfrost_context *ctx = pan_context(pipe); - ctx->blend = cso; - ctx->dirty_shader[PIPE_SHADER_FRAGMENT] |= PAN_DIRTY_STAGE_RENDERER; -} - -static void -panfrost_delete_blend_state(struct pipe_context *pipe, void *cso) -{ - ralloc_free(cso); -} - -static void -panfrost_set_blend_color(struct pipe_context *pipe, - const struct pipe_blend_color *blend_color) -{ - struct panfrost_context *ctx = pan_context(pipe); - ctx->dirty_shader[PIPE_SHADER_FRAGMENT] |= PAN_DIRTY_STAGE_RENDERER; - - if (blend_color) - ctx->blend_color = *blend_color; -} - -/* Create a final blend given the context */ - -mali_ptr -panfrost_get_blend(struct panfrost_batch *batch, unsigned rti, struct panfrost_bo **bo, unsigned *shader_offset) -{ - struct panfrost_context *ctx = batch->ctx; - struct panfrost_device *dev = pan_device(ctx->base.screen); - struct panfrost_blend_state *blend = ctx->blend; - struct pan_blend_info info = blend->info[rti]; - struct pipe_surface *surf = batch->key.cbufs[rti]; - enum pipe_format fmt = surf->format; - - /* Use fixed-function if the equation permits, the format is blendable, - * and no more than one unique constant is accessed */ - if (info.fixed_function && panfrost_blendable_formats[fmt].internal && - pan_blend_is_homogenous_constant(info.constant_mask, - ctx->blend_color.color)) { - return 0; - } - - /* Otherwise, we need to grab a shader */ - struct pan_blend_state pan_blend = blend->pan; - unsigned nr_samples = surf->nr_samples ? : surf->texture->nr_samples; - - 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)); - - /* Upload the shader, sharing a BO */ - if (!(*bo)) { - *bo = panfrost_batch_create_bo(batch, 4096, PAN_BO_EXECUTE, - PIPE_SHADER_FRAGMENT, "Blend shader"); - } - - struct panfrost_shader_state *ss = panfrost_get_shader_state(ctx, PIPE_SHADER_FRAGMENT); - - /* Default for Midgard */ - nir_alu_type col0_type = nir_type_float32; - nir_alu_type col1_type = nir_type_float32; - - /* Bifrost has per-output types, respect them */ - if (pan_is_bifrost(dev)) { - col0_type = ss->info.bifrost.blend[rti].type; - col1_type = ss->info.bifrost.blend_src1_type; - } - - pthread_mutex_lock(&dev->blend_shaders.lock); - struct pan_blend_shader_variant *shader = - pan_blend_get_shader_locked(dev, &pan_blend, - col0_type, col1_type, rti); - - /* Size check and upload */ - unsigned offset = *shader_offset; - assert((offset + shader->binary.size) < 4096); - memcpy((*bo)->ptr.cpu + offset, shader->binary.data, shader->binary.size); - *shader_offset += shader->binary.size; - pthread_mutex_unlock(&dev->blend_shaders.lock); - - return ((*bo)->ptr.gpu + offset) | shader->first_tag; -} - -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_cso.h b/src/gallium/drivers/panfrost/pan_blend_cso.h index 5e7940f5b16..ee2c7a350d1 100644 --- a/src/gallium/drivers/panfrost/pan_blend_cso.h +++ b/src/gallium/drivers/panfrost/pan_blend_cso.h @@ -52,9 +52,6 @@ struct panfrost_blend_state { unsigned load_dest_mask : PIPE_MAX_COLOR_BUFS; }; -void -panfrost_blend_context_init(struct pipe_context *pipe); - mali_ptr panfrost_get_blend(struct panfrost_batch *batch, unsigned rt, struct panfrost_bo **bo, unsigned *shader_offset); diff --git a/src/gallium/drivers/panfrost/pan_cmdstream.c b/src/gallium/drivers/panfrost/pan_cmdstream.c index 84d1865eb9a..e5f972ff3d5 100644 --- a/src/gallium/drivers/panfrost/pan_cmdstream.c +++ b/src/gallium/drivers/panfrost/pan_cmdstream.c @@ -30,6 +30,7 @@ #include "util/u_draw.h" #include "util/u_memory.h" #include "indices/u_primconvert.h" +#include "gallium/auxiliary/util/u_blend.h" #include "panfrost-quirks.h" @@ -3423,6 +3424,104 @@ panfrost_create_sampler_view( return (struct pipe_sampler_view *) so; } +/* 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, so blend shaders are keyed to a particular + * framebuffer format. As an example, the tilebuffer format is identical for + * RG16F and RG16UI -- both are simply 32-bit raw pixels -- so both require + * blend shaders. + * + * All of this state is encapsulated in the panfrost_blend_state struct + * (our subclass of pipe_blend_state). + */ + +/* 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_device *dev = pan_device(pipe->screen); + struct panfrost_blend_state *so = rzalloc(ctx, struct panfrost_blend_state); + so->base = *blend; + + so->pan.logicop_enable = blend->logicop_enable; + so->pan.logicop_func = blend->logicop_func; + so->pan.rt_count = blend->max_rt + 1; + + for (unsigned c = 0; c < so->pan.rt_count; ++c) { + unsigned g = blend->independent_blend_enable ? c : 0; + const struct pipe_rt_blend_state pipe = blend->rt[g]; + struct pan_blend_equation equation; + + equation.color_mask = pipe.colormask; + equation.blend_enable = pipe.blend_enable; + + if (pipe.blend_enable) { + 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); + } + + /* Determine some common properties */ + unsigned constant_mask = pan_blend_constant_mask(equation); + so->info[c] = (struct pan_blend_info) { + .no_colour = (equation.color_mask == 0), + .opaque = pan_blend_is_opaque(equation), + .constant_mask = constant_mask, + + /* TODO: check the dest for the logicop */ + .load_dest = blend->logicop_enable || + pan_blend_reads_dest(equation), + + /* Could this possibly be fixed-function? */ + .fixed_function = !blend->logicop_enable && + pan_blend_can_fixed_function(equation) && + (!constant_mask || + pan_blend_supports_constant(dev->arch, c)) + }; + + so->pan.rts[c].equation = equation; + + /* Bifrost needs to know if any render target loads its + * destination in the hot draw path, so precompute this */ + if (so->info[c].load_dest) + so->load_dest_mask |= BITFIELD_BIT(c); + + /* Converting equations to Mali style is expensive, do it at + * CSO create time instead of draw-time */ + if (so->info[c].fixed_function) { + pan_pack(&so->equation[c], BLEND_EQUATION, cfg) + pan_blend_to_fixed_function_equation(equation, &cfg); + } + } + + return so; +} + static void prepare_rsd(struct panfrost_device *dev, struct panfrost_shader_state *state, @@ -3459,4 +3558,5 @@ panfrost_cmdstream_context_init(struct pipe_context *pipe) pipe->create_depth_stencil_alpha_state = panfrost_create_depth_stencil_state; pipe->create_sampler_view = panfrost_create_sampler_view; pipe->create_sampler_state = panfrost_create_sampler_state; + pipe->create_blend_state = panfrost_create_blend_state; } diff --git a/src/gallium/drivers/panfrost/pan_context.c b/src/gallium/drivers/panfrost/pan_context.c index dbce6fd7cbd..04659fe6eff 100644 --- a/src/gallium/drivers/panfrost/pan_context.c +++ b/src/gallium/drivers/panfrost/pan_context.c @@ -134,6 +134,93 @@ panfrost_generic_cso_delete(struct pipe_context *pctx, void *hwcso) free(hwcso); } +static void +panfrost_bind_blend_state(struct pipe_context *pipe, void *cso) +{ + struct panfrost_context *ctx = pan_context(pipe); + ctx->blend = cso; + ctx->dirty_shader[PIPE_SHADER_FRAGMENT] |= PAN_DIRTY_STAGE_RENDERER; +} + +static void +panfrost_delete_blend_state(struct pipe_context *pipe, void *cso) +{ + ralloc_free(cso); +} + +static void +panfrost_set_blend_color(struct pipe_context *pipe, + const struct pipe_blend_color *blend_color) +{ + struct panfrost_context *ctx = pan_context(pipe); + ctx->dirty_shader[PIPE_SHADER_FRAGMENT] |= PAN_DIRTY_STAGE_RENDERER; + + if (blend_color) + ctx->blend_color = *blend_color; +} + +/* Create a final blend given the context */ + +mali_ptr +panfrost_get_blend(struct panfrost_batch *batch, unsigned rti, struct panfrost_bo **bo, unsigned *shader_offset) +{ + struct panfrost_context *ctx = batch->ctx; + struct panfrost_device *dev = pan_device(ctx->base.screen); + struct panfrost_blend_state *blend = ctx->blend; + struct pan_blend_info info = blend->info[rti]; + struct pipe_surface *surf = batch->key.cbufs[rti]; + enum pipe_format fmt = surf->format; + + /* Use fixed-function if the equation permits, the format is blendable, + * and no more than one unique constant is accessed */ + if (info.fixed_function && panfrost_blendable_formats[fmt].internal && + pan_blend_is_homogenous_constant(info.constant_mask, + ctx->blend_color.color)) { + return 0; + } + + /* Otherwise, we need to grab a shader */ + struct pan_blend_state pan_blend = blend->pan; + unsigned nr_samples = surf->nr_samples ? : surf->texture->nr_samples; + + 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)); + + /* Upload the shader, sharing a BO */ + if (!(*bo)) { + *bo = panfrost_batch_create_bo(batch, 4096, PAN_BO_EXECUTE, + PIPE_SHADER_FRAGMENT, "Blend shader"); + } + + struct panfrost_shader_state *ss = panfrost_get_shader_state(ctx, PIPE_SHADER_FRAGMENT); + + /* Default for Midgard */ + nir_alu_type col0_type = nir_type_float32; + nir_alu_type col1_type = nir_type_float32; + + /* Bifrost has per-output types, respect them */ + if (pan_is_bifrost(dev)) { + col0_type = ss->info.bifrost.blend[rti].type; + col1_type = ss->info.bifrost.blend_src1_type; + } + + pthread_mutex_lock(&dev->blend_shaders.lock); + struct pan_blend_shader_variant *shader = + pan_blend_get_shader_locked(dev, &pan_blend, + col0_type, col1_type, rti); + + /* Size check and upload */ + unsigned offset = *shader_offset; + assert((offset + shader->binary.size) < 4096); + memcpy((*bo)->ptr.cpu + offset, shader->binary.data, shader->binary.size); + *shader_offset += shader->binary.size; + pthread_mutex_unlock(&dev->blend_shaders.lock); + + return ((*bo)->ptr.gpu + offset) | shader->first_tag; +} + static void panfrost_bind_rasterizer_state( struct pipe_context *pctx, @@ -1031,9 +1118,13 @@ panfrost_create_context(struct pipe_screen *screen, void *priv, unsigned flags) gallium->stream_output_target_destroy = panfrost_stream_output_target_destroy; gallium->set_stream_output_targets = panfrost_set_stream_output_targets; + gallium->bind_blend_state = panfrost_bind_blend_state; + gallium->delete_blend_state = panfrost_delete_blend_state; + + gallium->set_blend_color = panfrost_set_blend_color; + panfrost_cmdstream_context_init(gallium); panfrost_resource_context_init(gallium); - panfrost_blend_context_init(gallium); panfrost_compute_context_init(gallium); gallium->stream_uploader = u_upload_create_default(gallium);