From 375d4c2c74d5a7003e03c4e610b466bd0d7d1a53 Mon Sep 17 00:00:00 2001 From: Alyssa Rosenzweig Date: Mon, 12 Aug 2019 16:14:03 -0700 Subject: [PATCH] panfrost: Extend blending to MRT Our hardware supports independent (per-RT) blending, but we need to route those settings through from Gallium. Signed-off-by: Alyssa Rosenzweig --- src/gallium/drivers/panfrost/pan_blend.h | 4 + src/gallium/drivers/panfrost/pan_blend_cso.c | 18 ++++- src/gallium/drivers/panfrost/pan_context.c | 80 ++++++++++---------- 3 files changed, 58 insertions(+), 44 deletions(-) diff --git a/src/gallium/drivers/panfrost/pan_blend.h b/src/gallium/drivers/panfrost/pan_blend.h index a29353ff001..83fe35e325c 100644 --- a/src/gallium/drivers/panfrost/pan_blend.h +++ b/src/gallium/drivers/panfrost/pan_blend.h @@ -99,6 +99,10 @@ struct panfrost_blend_final { /* Set for a shader, clear for an equation */ bool is_shader; + /* Set if the destination needs to be loaded from the tilebuffer, + * basically (for an equation) or if a shader is present */ + bool no_blending; + union { struct panfrost_blend_shader_final shader; struct panfrost_blend_equation_final equation; diff --git a/src/gallium/drivers/panfrost/pan_blend_cso.c b/src/gallium/drivers/panfrost/pan_blend_cso.c index 08a86980ca8..43121335f5e 100644 --- a/src/gallium/drivers/panfrost/pan_blend_cso.c +++ b/src/gallium/drivers/panfrost/pan_blend_cso.c @@ -108,18 +108,23 @@ panfrost_create_blend_state(struct pipe_context *pipe, assert(!blend->alpha_to_coverage); assert(!blend->alpha_to_one); - for (unsigned c = 0; c < 4; ++c) { + for (unsigned c = 0; c < PIPE_MAX_COLOR_BUFS; ++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 */ + /* Without indep blending, the first RT settings replicate */ + + unsigned g = + blend->independent_blend_enable ? c : 0; + rt->has_fixed_function = panfrost_make_fixed_blend_mode( - &blend->rt[c], + &blend->rt[g], &rt->equation, &rt->constant_mask, - blend->rt[c].colormask); + blend->rt[g].colormask); /* Regardless if that works, we also need to initialize * the blend shaders */ @@ -249,6 +254,12 @@ panfrost_get_blend_for_context(struct panfrost_context *ctx, unsigned rti) /* There's an equation and suitable constant, so we're good to go */ final.is_shader = false; final.equation.equation = &rt->equation; + + final.no_blending = + (rt->equation.rgb_mode == 0x122) && + (rt->equation.alpha_mode == 0x122) && + (rt->equation.color_mask == 0xf); + return final; } } @@ -256,6 +267,7 @@ panfrost_get_blend_for_context(struct panfrost_context *ctx, unsigned rti) /* 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.no_blending = false; final.shader.work_count = shader->work_count; final.shader.first_tag = shader->first_tag; diff --git a/src/gallium/drivers/panfrost/pan_context.c b/src/gallium/drivers/panfrost/pan_context.c index 1da61c434d3..e6ef85b1a8a 100644 --- a/src/gallium/drivers/panfrost/pan_context.c +++ b/src/gallium/drivers/panfrost/pan_context.c @@ -968,13 +968,19 @@ panfrost_emit_for_draw(struct panfrost_context *ctx, bool with_vertex_data) #undef COPY /* Get blending setup */ - struct panfrost_blend_final blend = - panfrost_get_blend_for_context(ctx, 0); + unsigned rt_count = MAX2(ctx->pipe_framebuffer.nr_cbufs, 1); - /* If there is a blend shader, work registers are shared */ + struct panfrost_blend_final blend[PIPE_MAX_COLOR_BUFS]; - 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; + for (unsigned c = 0; c < rt_count; ++c) + blend[c] = panfrost_get_blend_for_context(ctx, c); + + /* If there is a blend shader, work registers are shared. XXX: opt */ + + for (unsigned c = 0; c < rt_count; ++c) { + if (blend[c].is_shader) + ctx->fragment_shader_core.midgard1.work_count = 16; + } /* Set late due to depending on render state */ unsigned flags = ctx->fragment_shader_core.midgard1.flags; @@ -1014,22 +1020,14 @@ panfrost_emit_for_draw(struct panfrost_context *ctx, bool with_vertex_data) ctx->fragment_shader_core.midgard1.flags |= 0x400; } - /* Check if we're using the default blend descriptor (fast path) */ - - bool no_blending = - !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 (blend.is_shader) { + if (blend[0].is_shader) { ctx->fragment_shader_core.blend.shader = - blend.shader.bo->gpu | blend.shader.first_tag; + blend[0].shader.bo->gpu | blend[0].shader.first_tag; } else { ctx->fragment_shader_core.blend.shader = 0; } @@ -1040,19 +1038,19 @@ 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 (!blend.is_shader) { + if (!blend[0].is_shader) { ctx->fragment_shader_core.blend.equation = - *blend.equation.equation; + *blend[0].equation.equation; ctx->fragment_shader_core.blend.constant = - blend.equation.constant; + blend[0].equation.constant; } - if (!no_blending) { + if (!blend[0].no_blending) { ctx->fragment_shader_core.unknown2_3 |= MALI_CAN_DISCARD; } } - size_t size = sizeof(struct mali_shader_meta) + sizeof(struct midgard_blend_rt); + size_t size = sizeof(struct mali_shader_meta) + (sizeof(struct midgard_blend_rt) * rt_count); struct panfrost_transfer transfer = panfrost_allocate_transient(ctx, size); memcpy(transfer.cpu, &ctx->fragment_shader_core, sizeof(struct mali_shader_meta)); @@ -1061,27 +1059,27 @@ panfrost_emit_for_draw(struct panfrost_context *ctx, bool with_vertex_data) if (!screen->require_sfbd) { /* Additional blend descriptor tacked on for jobs using MFBD */ - unsigned blend_count = 0x200; + struct midgard_blend_rt rts[4]; - 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 */ + for (unsigned i = 0; i < rt_count; ++i) { + unsigned blend_count = 0x200; - 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 */ + if (blend[i].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(blend[i].shader.work_count >= 2); + blend_count |= MIN2(blend[i].shader.work_count, 3); + } else { + /* Otherwise, the bottom bit simply specifies if + * blending (anything other than REPLACE) is enabled */ - if (!no_blending) - blend_count |= 0x1; - } + if (!blend[i].no_blending) + blend_count |= 0x1; + } - struct midgard_blend_rt rts[4]; - for (unsigned i = 0; i < 1; ++i) { bool is_srgb = (ctx->pipe_framebuffer.nr_cbufs > i) && (ctx->pipe_framebuffer.cbufs[i]) && @@ -1101,17 +1099,17 @@ 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 && blend.is_shader)); + assert(!(is_srgb && blend[i].is_shader)); - if (blend.is_shader) { - rts[i].blend.shader = blend.shader.bo->gpu | blend.shader.first_tag; + if (blend[i].is_shader) { + rts[i].blend.shader = blend[i].shader.bo->gpu | blend[i].shader.first_tag; } else { - rts[i].blend.equation = *blend.equation.equation; - rts[i].blend.constant = blend.equation.constant; + rts[i].blend.equation = *blend[i].equation.equation; + rts[i].blend.constant = blend[i].equation.constant; } } - memcpy(transfer.cpu + sizeof(struct mali_shader_meta), rts, sizeof(rts[0]) * 1); + memcpy(transfer.cpu + sizeof(struct mali_shader_meta), rts, sizeof(rts[0]) * rt_count); } } -- 2.30.2