From f7b2165b19c29f8494ac3eb5a40ff21c8d7e1fe8 Mon Sep 17 00:00:00 2001 From: Danylo Piliaiev Date: Thu, 19 Nov 2020 11:27:33 +0200 Subject: [PATCH] freedreno/a6xx: add support for dual-source blending Signed-off-by: Danylo Piliaiev Part-of: --- .../drivers/freedreno/a6xx/fd6_blend.c | 8 +++++- .../drivers/freedreno/a6xx/fd6_blend.h | 2 ++ src/gallium/drivers/freedreno/a6xx/fd6_emit.c | 28 +++++++++++++++++-- src/gallium/drivers/freedreno/a6xx/fd6_gmem.c | 23 --------------- .../drivers/freedreno/a6xx/fd6_program.c | 5 ++++ .../drivers/freedreno/freedreno_screen.c | 2 +- 6 files changed, 40 insertions(+), 28 deletions(-) diff --git a/src/gallium/drivers/freedreno/a6xx/fd6_blend.c b/src/gallium/drivers/freedreno/a6xx/fd6_blend.c index fe63be97fd5..b645b884ab6 100644 --- a/src/gallium/drivers/freedreno/a6xx/fd6_blend.c +++ b/src/gallium/drivers/freedreno/a6xx/fd6_blend.c @@ -27,6 +27,7 @@ #include "pipe/p_state.h" #include "util/u_blend.h" +#include "util/u_dual_blend.h" #include "util/u_string.h" #include "util/u_memory.h" @@ -127,6 +128,7 @@ __fd6_setup_blend_variant(struct fd6_blend_stateobj *blend, unsigned sample_mask .unk8 = true, .alpha_to_coverage = cso->alpha_to_coverage, .enabled = !!mrt_blend, + .dual_color_in_enable = blend->use_dual_src_blend, )); OUT_REG(ring, A6XX_RB_BLEND_CNTL( @@ -134,7 +136,8 @@ __fd6_setup_blend_variant(struct fd6_blend_stateobj *blend, unsigned sample_mask .alpha_to_coverage = cso->alpha_to_coverage, .alpha_to_one = cso->alpha_to_one, .independent_blend = cso->independent_blend_enable, - .sample_mask = sample_mask + .sample_mask = sample_mask, + .dual_color_in_enable = blend->use_dual_src_blend, )); so->sample_mask = sample_mask; @@ -161,6 +164,9 @@ fd6_blend_state_create(struct pipe_context *pctx, so->reads_dest |= util_logicop_reads_dest(cso->logicop_func); } + so->use_dual_src_blend = + cso->rt[0].blend_enable && util_blend_state_is_dual(cso, 0); + unsigned nr = cso->independent_blend_enable ? cso->max_rt : 0; for (unsigned i = 0; i <= nr; i++) { const struct pipe_rt_blend_state *rt = &cso->rt[i]; diff --git a/src/gallium/drivers/freedreno/a6xx/fd6_blend.h b/src/gallium/drivers/freedreno/a6xx/fd6_blend.h index ef7dde8cf65..0878cf47c75 100644 --- a/src/gallium/drivers/freedreno/a6xx/fd6_blend.h +++ b/src/gallium/drivers/freedreno/a6xx/fd6_blend.h @@ -47,6 +47,8 @@ struct fd6_blend_variant { struct fd6_blend_stateobj { struct pipe_blend_state base; + bool use_dual_src_blend; + struct fd_context *ctx; bool reads_dest; struct util_dynarray variants; diff --git a/src/gallium/drivers/freedreno/a6xx/fd6_emit.c b/src/gallium/drivers/freedreno/a6xx/fd6_emit.c index 83afd1c6575..ca21d292da2 100644 --- a/src/gallium/drivers/freedreno/a6xx/fd6_emit.c +++ b/src/gallium/drivers/freedreno/a6xx/fd6_emit.c @@ -955,24 +955,46 @@ fd6_emit_state(struct fd_ringbuffer *ring, struct fd6_emit *emit) FD6_GROUP_RASTERIZER, ENABLE_ALL); } - if (dirty & (FD_DIRTY_FRAMEBUFFER | FD_DIRTY_RASTERIZER_DISCARD | FD_DIRTY_PROG)) { + if (dirty & (FD_DIRTY_FRAMEBUFFER | FD_DIRTY_RASTERIZER_DISCARD | + FD_DIRTY_PROG | FD_DIRTY_BLEND_DUAL)) { struct fd_ringbuffer *ring = fd_submit_new_ringbuffer( - emit->ctx->batch->submit, 5 * 4, FD_RINGBUFFER_STREAMING); + emit->ctx->batch->submit, 9 * 4, FD_RINGBUFFER_STREAMING); unsigned nr = pfb->nr_cbufs; if (ctx->rasterizer->rasterizer_discard) nr = 0; + struct fd6_blend_stateobj *blend = fd6_blend_stateobj(ctx->blend); + + if (blend->use_dual_src_blend) + nr++; + OUT_PKT4(ring, REG_A6XX_RB_FS_OUTPUT_CNTL0, 2); OUT_RING(ring, COND(fs->writes_pos, A6XX_RB_FS_OUTPUT_CNTL0_FRAG_WRITES_Z) | COND(fs->writes_smask && pfb->samples > 1, - A6XX_RB_FS_OUTPUT_CNTL0_FRAG_WRITES_SAMPMASK)); + A6XX_RB_FS_OUTPUT_CNTL0_FRAG_WRITES_SAMPMASK) | + COND(blend->use_dual_src_blend, + A6XX_RB_FS_OUTPUT_CNTL0_DUAL_COLOR_IN_ENABLE)); OUT_RING(ring, A6XX_RB_FS_OUTPUT_CNTL1_MRT(nr)); OUT_PKT4(ring, REG_A6XX_SP_FS_OUTPUT_CNTL1, 1); OUT_RING(ring, A6XX_SP_FS_OUTPUT_CNTL1_MRT(nr)); + unsigned mrt_components = 0; + for (unsigned i = 0; i < pfb->nr_cbufs; i++) { + if (!pfb->cbufs[i]) + continue; + mrt_components |= 0xf << (i * 4); + } + + /* dual source blending has an extra fs output in the 2nd slot */ + if (blend->use_dual_src_blend) + mrt_components |= 0xf << 4; + + OUT_REG(ring, A6XX_SP_FS_RENDER_COMPONENTS(.dword = mrt_components)); + OUT_REG(ring, A6XX_RB_RENDER_COMPONENTS(.dword = mrt_components)); + fd6_emit_take_group(emit, ring, FD6_GROUP_PROG_FB_RAST, ENABLE_DRAW); } diff --git a/src/gallium/drivers/freedreno/a6xx/fd6_gmem.c b/src/gallium/drivers/freedreno/a6xx/fd6_gmem.c index 5aac4d5438b..0c1348ca4b5 100644 --- a/src/gallium/drivers/freedreno/a6xx/fd6_gmem.c +++ b/src/gallium/drivers/freedreno/a6xx/fd6_gmem.c @@ -73,7 +73,6 @@ static void emit_mrt(struct fd_ringbuffer *ring, struct pipe_framebuffer_state *pfb, const struct fd_gmem_stateobj *gmem) { - unsigned char mrt_comp[A6XX_MAX_RENDER_TARGETS] = {0}; unsigned srgb_cntl = 0; unsigned i; @@ -92,8 +91,6 @@ emit_mrt(struct fd_ringbuffer *ring, struct pipe_framebuffer_state *pfb, if (!pfb->cbufs[i]) continue; - mrt_comp[i] = 0xf; - struct pipe_surface *psurf = pfb->cbufs[i]; enum pipe_format pformat = psurf->format; rsc = fd_resource(psurf->texture); @@ -142,26 +139,6 @@ emit_mrt(struct fd_ringbuffer *ring, struct pipe_framebuffer_state *pfb, OUT_REG(ring, A6XX_RB_SRGB_CNTL(.dword = srgb_cntl)); OUT_REG(ring, A6XX_SP_SRGB_CNTL(.dword = srgb_cntl)); - OUT_REG(ring, A6XX_RB_RENDER_COMPONENTS( - .rt0 = mrt_comp[0], - .rt1 = mrt_comp[1], - .rt2 = mrt_comp[2], - .rt3 = mrt_comp[3], - .rt4 = mrt_comp[4], - .rt5 = mrt_comp[5], - .rt6 = mrt_comp[6], - .rt7 = mrt_comp[7])); - - OUT_REG(ring, A6XX_SP_FS_RENDER_COMPONENTS( - .rt0 = mrt_comp[0], - .rt1 = mrt_comp[1], - .rt2 = mrt_comp[2], - .rt3 = mrt_comp[3], - .rt4 = mrt_comp[4], - .rt5 = mrt_comp[5], - .rt6 = mrt_comp[6], - .rt7 = mrt_comp[7])); - OUT_REG(ring, A6XX_GRAS_MAX_LAYER_INDEX(max_layer_index)); } diff --git a/src/gallium/drivers/freedreno/a6xx/fd6_program.c b/src/gallium/drivers/freedreno/a6xx/fd6_program.c index 6d7f7e45232..512a016a98d 100644 --- a/src/gallium/drivers/freedreno/a6xx/fd6_program.c +++ b/src/gallium/drivers/freedreno/a6xx/fd6_program.c @@ -483,9 +483,14 @@ setup_stateobj(struct fd_ringbuffer *ring, struct fd_context *ctx, OUT_PKT4(ring, REG_A6XX_SP_MODE_CONTROL, 1); OUT_RING(ring, A6XX_SP_MODE_CONTROL_CONSTANT_DEMOTION_ENABLE | 4); + bool fs_has_dual_src_color = !binning_pass && + fs->shader->nir->info.fs.color_is_dual_source; + OUT_PKT4(ring, REG_A6XX_SP_FS_OUTPUT_CNTL0, 1); OUT_RING(ring, A6XX_SP_FS_OUTPUT_CNTL0_DEPTH_REGID(posz_regid) | A6XX_SP_FS_OUTPUT_CNTL0_SAMPMASK_REGID(smask_regid) | + COND(fs_has_dual_src_color, + A6XX_SP_FS_OUTPUT_CNTL0_DUAL_COLOR_IN_ENABLE) | 0xfc000000); enum a3xx_threadsize vssz; diff --git a/src/gallium/drivers/freedreno/freedreno_screen.c b/src/gallium/drivers/freedreno/freedreno_screen.c index 705355fd373..b437f0fb853 100644 --- a/src/gallium/drivers/freedreno/freedreno_screen.c +++ b/src/gallium/drivers/freedreno/freedreno_screen.c @@ -437,7 +437,7 @@ fd_screen_get_param(struct pipe_screen *pscreen, enum pipe_cap param) case PIPE_CAP_MAX_RENDER_TARGETS: return screen->max_rts; case PIPE_CAP_MAX_DUAL_SOURCE_RENDER_TARGETS: - return is_a3xx(screen) ? 1 : 0; + return (is_a3xx(screen) || is_a6xx(screen)) ? 1 : 0; /* Queries. */ case PIPE_CAP_OCCLUSION_QUERY: