Mesa (main): lima: implement dual source blend

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Mon Nov 29 19:45:00 UTC 2021


Module: Mesa
Branch: main
Commit: d1d3ebb48cc693d66b064871c1118c498b6667c0
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=d1d3ebb48cc693d66b064871c1118c498b6667c0

Author: Vasily Khoruzhick <anarsoul at gmail.com>
Date:   Thu Nov 18 20:53:18 2021 -0800

lima: implement dual source blend

It was a bit trickier to RE, since blob doesn't expose this
functionality at all, however we had a clue from the very beginning:
lima_blend_factor is 3 bits, i.e. 8 values, but only 5 of them were
used, it just waited till someone tried what 3 unused values do.

Interestingly enough, it turns out "5" works just as "0" (which is
PIPE_BLENDFACTOR_*SRC_*), but only if output register for gl_FragColor
is $0, So it looks suspiciously similar with PIPE_BLENDFACTOR_*SRC1_*
behavior, and looks like secondary output is taken from $0.

Since output regs for all other outputs are configured via RSW, there
must be a field in RSW for output register for secondary color, it's
likely 4 bits and it's currently set to 0 for reg $0.

Then it was just a matter of brute-forcing various consecutive 4 bits
in RSW - and indeed, setting top 4 bits of rsw->aux0 to the index of
gl_FragColor output register fixes blending tests when we use "5"
blend factor instead of "0".

So it must be a register number for gl_SecondaryFragColor. Unlike
gl_FragColor, the field is only repeated once in RSW.

Wire it up in compiler, and piglit arb_blend_func_extended now passes.

Reviewed-by: Andreas Baierl <ichgeh at imkreisrum.de>
Reviewed-by: Erico Nunes <nunes.erico at gmail.com>
Signed-off-by: Vasily Khoruzhick <anarsoul at gmail.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/13873>

---

 docs/features.txt                         |   2 +-
 src/gallium/drivers/lima/ir/pp/nir.c      |   4 +-
 src/gallium/drivers/lima/ir/pp/ppir.h     |  14 ++--
 src/gallium/drivers/lima/ir/pp/regalloc.c |   9 ++-
 src/gallium/drivers/lima/lima_context.h   |   3 +-
 src/gallium/drivers/lima/lima_draw.c      | 122 ++++++++----------------------
 src/gallium/drivers/lima/lima_parser.c    |   5 ++
 src/gallium/drivers/lima/lima_parser.h    |  10 ++-
 src/gallium/drivers/lima/lima_screen.c    |   3 +
 9 files changed, 68 insertions(+), 104 deletions(-)

diff --git a/docs/features.txt b/docs/features.txt
index bc57eba78ee..458c2d79815 100644
--- a/docs/features.txt
+++ b/docs/features.txt
@@ -99,7 +99,7 @@ GL 3.2, GLSL 1.50 --- all DONE: freedreno, i965, nv50, nvc0, r600, radeonsi, llv
 
 GL 3.3, GLSL 3.30 --- all DONE: freedreno, i965, nv50, nvc0, r600, radeonsi, llvmpipe, softpipe, virgl, zink, d3d12
 
-  GL_ARB_blend_func_extended                            DONE (freedreno/a3xx, freedreno/a6xx, swr, panfrost)
+  GL_ARB_blend_func_extended                            DONE (freedreno/a3xx, freedreno/a6xx, swr, panfrost, lima)
   GL_ARB_explicit_attrib_location                       DONE (all drivers that support GLSL)
   GL_ARB_occlusion_query2                               DONE (swr, v3d, vc4, panfrost, lima)
   GL_ARB_sampler_objects                                DONE (all drivers)
diff --git a/src/gallium/drivers/lima/ir/pp/nir.c b/src/gallium/drivers/lima/ir/pp/nir.c
index fc8030fc745..1d58708ae70 100644
--- a/src/gallium/drivers/lima/ir/pp/nir.c
+++ b/src/gallium/drivers/lima/ir/pp/nir.c
@@ -351,7 +351,8 @@ static bool ppir_emit_intrinsic(ppir_block *block, nir_instr *ni)
       nir_io_semantics io = nir_intrinsic_io_semantics(instr);
       unsigned offset = nir_src_as_uint(instr->src[1]);
       unsigned slot = io.location + offset;
-      ppir_output_type out_type = ppir_nir_output_to_ppir(slot);
+      ppir_output_type out_type = ppir_nir_output_to_ppir(slot,
+         block->comp->dual_source_blend ? io.dual_source_blend_index : 0);
       if (out_type == ppir_output_invalid) {
          ppir_debug("Unsupported output type: %d\n", slot);
          return false;
@@ -916,6 +917,7 @@ bool ppir_compile_nir(struct lima_fs_compiled_shader *prog, struct nir_shader *n
 
    comp->ra = ra;
    comp->uses_discard = nir->info.fs.uses_discard;
+   comp->dual_source_blend = nir->info.fs.color_is_dual_source;
 
    /* 1st pass: create ppir blocks */
    nir_foreach_function(function, nir) {
diff --git a/src/gallium/drivers/lima/ir/pp/ppir.h b/src/gallium/drivers/lima/ir/pp/ppir.h
index f434786f4cf..70b95590697 100644
--- a/src/gallium/drivers/lima/ir/pp/ppir.h
+++ b/src/gallium/drivers/lima/ir/pp/ppir.h
@@ -180,7 +180,8 @@ typedef enum {
 } ppir_pipeline;
 
 typedef enum {
-   ppir_output_color,
+   ppir_output_color0,
+   ppir_output_color1,
    ppir_output_depth,
    ppir_output_num,
    ppir_output_invalid = -1,
@@ -189,8 +190,10 @@ typedef enum {
 static inline const char *ppir_output_type_to_str(ppir_output_type type)
 {
    switch (type) {
-   case ppir_output_color:
-      return "OUTPUT_COLOR";
+   case ppir_output_color0:
+      return "OUTPUT_COLOR0";
+   case ppir_output_color1:
+      return "OUTPUT_COLOR1";
    case ppir_output_depth:
       return "OUTPUT_DEPTH";
    default:
@@ -198,12 +201,12 @@ static inline const char *ppir_output_type_to_str(ppir_output_type type)
    }
 }
 
-static inline ppir_output_type ppir_nir_output_to_ppir(gl_frag_result res)
+static inline ppir_output_type ppir_nir_output_to_ppir(gl_frag_result res, int dual_src_index)
 {
    switch (res) {
    case FRAG_RESULT_COLOR:
    case FRAG_RESULT_DATA0:
-      return ppir_output_color;
+      return ppir_output_color0 + dual_src_index;
    case FRAG_RESULT_DEPTH:
       return ppir_output_depth;
    default:
@@ -417,6 +420,7 @@ typedef struct ppir_compiler {
    struct ra_regs *ra;
    struct lima_fs_compiled_shader *prog;
    bool uses_discard;
+   bool dual_source_blend;
 
    /* for scheduler */
    int sched_instr_base;
diff --git a/src/gallium/drivers/lima/ir/pp/regalloc.c b/src/gallium/drivers/lima/ir/pp/regalloc.c
index 37b54b5a4bf..08cc3e76c85 100644
--- a/src/gallium/drivers/lima/ir/pp/regalloc.c
+++ b/src/gallium/drivers/lima/ir/pp/regalloc.c
@@ -617,7 +617,8 @@ bool ppir_regalloc_prog(ppir_compiler *comp)
 
    /* No registers? Probably shader consists of discard instruction */
    if (list_is_empty(&comp->reg_list)) {
-      comp->prog->state.frag_color_reg = 0;
+      comp->prog->state.frag_color0_reg = 0;
+      comp->prog->state.frag_color1_reg = -1;
       comp->prog->state.frag_depth_reg = -1;
       return true;
    }
@@ -628,8 +629,10 @@ bool ppir_regalloc_prog(ppir_compiler *comp)
       if (!spilled)
          return false;
 
-   comp->prog->state.frag_color_reg =
-      comp->out_type_to_reg[ppir_output_color];
+   comp->prog->state.frag_color0_reg =
+      comp->out_type_to_reg[ppir_output_color0];
+   comp->prog->state.frag_color1_reg =
+      comp->out_type_to_reg[ppir_output_color1];
    comp->prog->state.frag_depth_reg =
       comp->out_type_to_reg[ppir_output_depth];
 
diff --git a/src/gallium/drivers/lima/lima_context.h b/src/gallium/drivers/lima/lima_context.h
index bea1ddeb477..3adf67ce3c4 100644
--- a/src/gallium/drivers/lima/lima_context.h
+++ b/src/gallium/drivers/lima/lima_context.h
@@ -49,7 +49,8 @@ struct lima_fs_compiled_shader {
    struct {
       int shader_size;
       int stack_size;
-      int frag_color_reg;
+      int frag_color0_reg;
+      int frag_color1_reg;
       int frag_depth_reg;
       bool uses_discard;
    } state;
diff --git a/src/gallium/drivers/lima/lima_draw.c b/src/gallium/drivers/lima/lima_draw.c
index 889f0192179..bde83281e14 100644
--- a/src/gallium/drivers/lima/lima_draw.c
+++ b/src/gallium/drivers/lima/lima_draw.c
@@ -449,107 +449,56 @@ lima_blend_func(enum pipe_blend_func pipe)
    return -1;
 }
 
-static int
-lima_blend_factor_has_alpha(enum pipe_blendfactor pipe)
-{
-   /* Bit 4 is set if the blendfactor uses alpha */
-   switch (pipe) {
-   case PIPE_BLENDFACTOR_SRC_ALPHA:
-   case PIPE_BLENDFACTOR_DST_ALPHA:
-   case PIPE_BLENDFACTOR_CONST_ALPHA:
-   case PIPE_BLENDFACTOR_INV_SRC_ALPHA:
-   case PIPE_BLENDFACTOR_INV_DST_ALPHA:
-   case PIPE_BLENDFACTOR_INV_CONST_ALPHA:
-      return 1;
-
-   case PIPE_BLENDFACTOR_SRC_COLOR:
-   case PIPE_BLENDFACTOR_INV_SRC_COLOR:
-   case PIPE_BLENDFACTOR_DST_COLOR:
-   case PIPE_BLENDFACTOR_INV_DST_COLOR:
-   case PIPE_BLENDFACTOR_CONST_COLOR:
-   case PIPE_BLENDFACTOR_INV_CONST_COLOR:
-   case PIPE_BLENDFACTOR_ZERO:
-   case PIPE_BLENDFACTOR_ONE:
-   case PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE:
-      return 0;
-
-   case PIPE_BLENDFACTOR_SRC1_COLOR:
-   case PIPE_BLENDFACTOR_SRC1_ALPHA:
-   case PIPE_BLENDFACTOR_INV_SRC1_COLOR:
-   case PIPE_BLENDFACTOR_INV_SRC1_ALPHA:
-      return -1; /* not supported */
-   }
-   return -1;
-}
-
-static int
-lima_blend_factor_is_inv(enum pipe_blendfactor pipe)
-{
-   /* Bit 3 is set if the blendfactor type is inverted */
-   switch (pipe) {
-   case PIPE_BLENDFACTOR_INV_SRC_COLOR:
-   case PIPE_BLENDFACTOR_INV_SRC_ALPHA:
-   case PIPE_BLENDFACTOR_INV_DST_COLOR:
-   case PIPE_BLENDFACTOR_INV_DST_ALPHA:
-   case PIPE_BLENDFACTOR_INV_CONST_COLOR:
-   case PIPE_BLENDFACTOR_INV_CONST_ALPHA:
-   case PIPE_BLENDFACTOR_ONE:
-      return 1;
-
-   case PIPE_BLENDFACTOR_SRC_COLOR:
-   case PIPE_BLENDFACTOR_SRC_ALPHA:
-   case PIPE_BLENDFACTOR_DST_COLOR:
-   case PIPE_BLENDFACTOR_DST_ALPHA:
-   case PIPE_BLENDFACTOR_CONST_COLOR:
-   case PIPE_BLENDFACTOR_CONST_ALPHA:
-   case PIPE_BLENDFACTOR_ZERO:
-   case PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE:
-      return 0;
-
-   case PIPE_BLENDFACTOR_SRC1_COLOR:
-   case PIPE_BLENDFACTOR_SRC1_ALPHA:
-   case PIPE_BLENDFACTOR_INV_SRC1_COLOR:
-   case PIPE_BLENDFACTOR_INV_SRC1_ALPHA:
-      return -1; /* not supported */
-   }
-   return -1;
-}
-
 static int
 lima_blend_factor(enum pipe_blendfactor pipe)
 {
-   /* Bits 0-2 indicate the blendfactor type */
+   /* Bits 0-2 indicate the blendfactor type,
+    * Bit 3 is set if blendfactor is inverted
+    * Bit 4 is set if blendfactor has alpha */
    switch (pipe) {
    case PIPE_BLENDFACTOR_SRC_COLOR:
+      return 0 << 4 | 0 << 3 | 0;
    case PIPE_BLENDFACTOR_SRC_ALPHA:
+      return 1 << 4 | 0 << 3 | 0;
    case PIPE_BLENDFACTOR_INV_SRC_COLOR:
+      return 0 << 4 | 1 << 3 | 0;
    case PIPE_BLENDFACTOR_INV_SRC_ALPHA:
-      return 0;
+      return 1 << 4 | 1 << 3 | 0;
 
    case PIPE_BLENDFACTOR_DST_COLOR:
+      return 0 << 4 | 0 << 3 | 1;
    case PIPE_BLENDFACTOR_DST_ALPHA:
+      return 1 << 4 | 0 << 3 | 1;
    case PIPE_BLENDFACTOR_INV_DST_COLOR:
+      return 0 << 4 | 1 << 3 | 1;
    case PIPE_BLENDFACTOR_INV_DST_ALPHA:
-      return 1;
+      return 1 << 4 | 1 << 3 | 1;
 
    case PIPE_BLENDFACTOR_CONST_COLOR:
+      return 0 << 4 | 0 << 3 | 2;
    case PIPE_BLENDFACTOR_CONST_ALPHA:
+      return 1 << 4 | 0 << 3 | 2;
    case PIPE_BLENDFACTOR_INV_CONST_COLOR:
+      return 0 << 4 | 1 << 3 | 2;
    case PIPE_BLENDFACTOR_INV_CONST_ALPHA:
-      return 2;
+      return 1 << 4 | 1 << 3 | 2;
 
    case PIPE_BLENDFACTOR_ZERO:
+      return 0 << 4 | 0 << 3 | 3;
    case PIPE_BLENDFACTOR_ONE:
-      return 3;
+      return 0 << 4 | 1 << 3 | 3;
 
    case PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE:
-      return 4;
+      return 0 << 4 | 0 << 3 | 4;
 
    case PIPE_BLENDFACTOR_SRC1_COLOR:
+      return 0 << 4 | 0 << 3 | 5;
    case PIPE_BLENDFACTOR_SRC1_ALPHA:
+      return 1 << 4 | 0 << 3 | 5;
    case PIPE_BLENDFACTOR_INV_SRC1_COLOR:
+      return 0 << 4 | 1 << 3 | 5;
    case PIPE_BLENDFACTOR_INV_SRC1_ALPHA:
-      return -1; /* not supported */
+      return 1 << 4 | 1 << 3 | 5;
    }
    return -1;
 }
@@ -567,20 +516,11 @@ lima_calculate_alpha_blend(enum pipe_blend_func rgb_func, enum pipe_blend_func a
 
    return lima_blend_func(rgb_func) |
       (lima_blend_func(alpha_func) << 3) |
-
       (lima_blend_factor(rgb_src_factor) << 6) |
-      (lima_blend_factor_is_inv(rgb_src_factor) << 9) |
-      (lima_blend_factor_has_alpha(rgb_src_factor) << 10) |
-
       (lima_blend_factor(rgb_dst_factor) << 11) |
-      (lima_blend_factor_is_inv(rgb_dst_factor) << 14) |
-      (lima_blend_factor_has_alpha(rgb_dst_factor) << 15) |
-
-      (lima_blend_factor(alpha_src_factor) << 16) |
-      (lima_blend_factor_is_inv(alpha_src_factor) << 19) |
-
-      (lima_blend_factor(alpha_dst_factor) << 20) |
-      (lima_blend_factor_is_inv(alpha_dst_factor) << 23) |
+      /* alpha_src and alpha_dst are 4 bit, so need to mask 5th bit */
+      ((lima_blend_factor(alpha_src_factor) & 0xf) << 16) |
+      ((lima_blend_factor(alpha_dst_factor) & 0xf) << 20) |
       0x0C000000; /* need to check if this is GLESv1 glAlphaFunc */
 }
 
@@ -736,10 +676,10 @@ lima_pack_render_state(struct lima_context *ctx, const struct pipe_draw_info *in
       render->multi_sample |= 0x68;
 
    /* Set gl_FragColor register, need to specify it 4 times */
-   render->multi_sample |= (fs->state.frag_color_reg << 28) |
-                           (fs->state.frag_color_reg << 24) |
-                           (fs->state.frag_color_reg << 20) |
-                           (fs->state.frag_color_reg << 16);
+   render->multi_sample |= (fs->state.frag_color0_reg << 28) |
+                           (fs->state.frag_color0_reg << 24) |
+                           (fs->state.frag_color0_reg << 20) |
+                           (fs->state.frag_color0_reg << 16);
 
    /* alpha test */
    if (ctx->zsa->base.alpha_enabled) {
@@ -807,6 +747,10 @@ lima_pack_render_state(struct lima_context *ctx, const struct pipe_draw_info *in
       render->aux1 |= 0x10000;
    }
 
+   /* Set secondary output color */
+   if (fs->state.frag_color1_reg != -1)
+      render->aux0 |= (fs->state.frag_color1_reg << 28);
+
    if (ctx->vs->state.num_varyings) {
       render->varying_types = 0x00000000;
       render->varyings_address = ctx->gp_output->va +
diff --git a/src/gallium/drivers/lima/lima_parser.c b/src/gallium/drivers/lima/lima_parser.c
index bcacd290aff..f885c771340 100644
--- a/src/gallium/drivers/lima/lima_parser.c
+++ b/src/gallium/drivers/lima/lima_parser.c
@@ -674,6 +674,11 @@ parse_rsw(FILE *fp, uint32_t *value, int i, uint32_t *helper)
 
       if ((*value & 0x00002000) == 0x00002000) /* bit 13 unknown */
          fprintf(fp, ", bit 13 set");
+
+      fprintf(fp, " */\n");
+      fprintf(fp, "\n\t\t\t\t\t\t/* %s(3):", render_state_infos[i].info);
+      fprintf(fp, " register for gl_SecondaryFragColor: $%d",
+         (*value & 0xf0000000) >> 28);
       fprintf(fp, " */\n");
       break;
    case 14: /* AUX1 */
diff --git a/src/gallium/drivers/lima/lima_parser.h b/src/gallium/drivers/lima/lima_parser.h
index dc99d49164b..eed7926fb5e 100644
--- a/src/gallium/drivers/lima/lima_parser.h
+++ b/src/gallium/drivers/lima/lima_parser.h
@@ -61,7 +61,7 @@ static const char *PIPE_BLENDFACTOR_STRING[] = {
    "CONST_COLOR",      /* 2 */
    "ZERO",             /* 3 */
    "UNKNOWN_4",        /* 4 */
-   "UNKNOWN_5",        /* 5 */
+   "SRC2_COLOR",       /* 5 */
    "UNKNOWN_6",        /* 6 */
    "SRC_ALPHA_SAT",    /* 7 */
    "INV_SRC_COLOR",    /* 8 */
@@ -69,7 +69,7 @@ static const char *PIPE_BLENDFACTOR_STRING[] = {
    "INV_CONST_COLOR",  /* 10 */
    "ONE",              /* 11 */
    "UNKNOWN_12",       /* 12 */
-   "UNKNOWN_13",       /* 13 */
+   "INV_SRC2_COLOR",   /* 13 */
    "UNKNOWN_14",       /* 14 */
    "UNKNOWN_15",       /* 15 */
    "SRC_ALPHA",        /* 16 */
@@ -77,13 +77,15 @@ static const char *PIPE_BLENDFACTOR_STRING[] = {
    "CONST_ALPHA",      /* 18 */
    "UNKNOWN_19",       /* 19 */
    "UNKNOWN_20",       /* 20 */
-   "UNKNOWN_21",       /* 21 */
+   "SRC2_ALPHA",       /* 21 */
    "UNKNOWN_22",       /* 22 */
    "UNKNOWN_23",       /* 23 */
    "INV_SRC_ALPHA",    /* 24 */
    "INV_DST_ALPHA",    /* 25 */
    "INV_CONST_ALPHA",  /* 26 */
-
+   "UNKNOWN_27",       /* 27 */
+   "UNKNOWN_28",       /* 28 */
+   "INV_SRC2_ALPHA",   /* 29 */
 };
 
 static const char *LIMA_WRAP_MODE_STRING[] = {
diff --git a/src/gallium/drivers/lima/lima_screen.c b/src/gallium/drivers/lima/lima_screen.c
index d86d37c1b11..f3d9a4be026 100644
--- a/src/gallium/drivers/lima/lima_screen.c
+++ b/src/gallium/drivers/lima/lima_screen.c
@@ -168,6 +168,9 @@ lima_screen_get_param(struct pipe_screen *pscreen, enum pipe_cap param)
    case PIPE_CAP_PREFER_POT_ALIGNED_VARYINGS:
       return 1;
 
+   case PIPE_CAP_MAX_DUAL_SOURCE_RENDER_TARGETS:
+      return 1;
+
    default:
       return u_pipe_screen_get_param_defaults(pscreen, param);
    }



More information about the mesa-commit mailing list