[Mesa-dev] [PATCH 2/2] svga: implement MSAA alpha_to_one feature

Brian Paul brianp at vmware.com
Sat Jul 22 19:24:08 UTC 2017


The device doesn't directly support this feature so we implement it with
additional shader code which sets the color output(s) w component to
1.0 (or max_int or max_uint).

Fixes 16 Piglit ext_framebuffer_multisample/*alpha-to-one* tests.
---
 src/gallium/drivers/svga/svga_context.h     |  1 +
 src/gallium/drivers/svga/svga_pipe_blend.c  |  1 +
 src/gallium/drivers/svga/svga_shader.h      |  3 ++
 src/gallium/drivers/svga/svga_state_fs.c    | 18 +++++++++
 src/gallium/drivers/svga/svga_tgsi_vgpu10.c | 61 ++++++++++++++++++++++++++++-
 5 files changed, 83 insertions(+), 1 deletion(-)

diff --git a/src/gallium/drivers/svga/svga_context.h b/src/gallium/drivers/svga/svga_context.h
index d0306c0..0d695a6 100644
--- a/src/gallium/drivers/svga/svga_context.h
+++ b/src/gallium/drivers/svga/svga_context.h
@@ -106,6 +106,7 @@ struct svga_blend_state {
    unsigned need_white_fragments:1;
    unsigned independent_blend_enable:1;
    unsigned alpha_to_coverage:1;
+   unsigned alpha_to_one:1;
    unsigned blend_color_alpha:1;  /**< set blend color to alpha value */
 
    /** Per-render target state */
diff --git a/src/gallium/drivers/svga/svga_pipe_blend.c b/src/gallium/drivers/svga/svga_pipe_blend.c
index 408e175..a29fbd3 100644
--- a/src/gallium/drivers/svga/svga_pipe_blend.c
+++ b/src/gallium/drivers/svga/svga_pipe_blend.c
@@ -331,6 +331,7 @@ svga_create_blend_state(struct pipe_context *pipe,
    blend->independent_blend_enable = templ->independent_blend_enable;
 
    blend->alpha_to_coverage = templ->alpha_to_coverage;
+   blend->alpha_to_one = templ->alpha_to_one;
 
    if (svga_have_vgpu10(svga)) {
       define_blend_state_object(svga, blend);
diff --git a/src/gallium/drivers/svga/svga_shader.h b/src/gallium/drivers/svga/svga_shader.h
index a594d12..53c9e22 100644
--- a/src/gallium/drivers/svga/svga_shader.h
+++ b/src/gallium/drivers/svga/svga_shader.h
@@ -77,11 +77,14 @@ struct svga_compile_key
       unsigned light_twoside:1;
       unsigned front_ccw:1;
       unsigned white_fragments:1;
+      unsigned alpha_to_one:1;
       unsigned flatshade:1;
       unsigned pstipple:1;
       unsigned alpha_func:4;  /**< SVGA3D_CMP_x */
       unsigned write_color0_to_n_cbufs:4;
       unsigned aa_point:1;
+      unsigned int_render_target_mask:8;
+      unsigned uint_render_target_mask:8;
       int aa_point_coord_index;
       float alpha_ref;
    } fs;
diff --git a/src/gallium/drivers/svga/svga_state_fs.c b/src/gallium/drivers/svga/svga_state_fs.c
index bf45216..327364c 100644
--- a/src/gallium/drivers/svga/svga_state_fs.c
+++ b/src/gallium/drivers/svga/svga_state_fs.c
@@ -25,6 +25,7 @@
 
 #include "util/u_inlines.h"
 #include "pipe/p_defines.h"
+#include "util/u_format.h"
 #include "util/u_math.h"
 #include "util/u_memory.h"
 #include "util/u_bitmask.h"
@@ -234,6 +235,8 @@ make_fs_key(const struct svga_context *svga,
     */
    key->fs.white_fragments = svga->curr.blend->need_white_fragments;
 
+   key->fs.alpha_to_one = svga->curr.blend->alpha_to_one;
+
 #ifdef DEBUG
    /*
     * We expect a consistent set of samplers and sampler views.
@@ -354,6 +357,21 @@ make_fs_key(const struct svga_context *svga,
       key->fs.write_color0_to_n_cbufs = svga->curr.framebuffer.nr_cbufs;
    }
 
+   /* SVGA_NEW_FRAME_BUFFER
+    * Determine which render targets are int/uint/float.
+    */
+   const struct pipe_framebuffer_state *fb = &svga->curr.framebuffer;
+   for (i = 0; i < fb->nr_cbufs; i++) {
+      const enum pipe_format f =
+         fb->cbufs[i] ? fb->cbufs[i]->format : PIPE_FORMAT_NONE;
+      if (util_format_is_pure_sint(f)) {
+         key->fs.int_render_target_mask |= 1 << i;
+      }
+      else if (util_format_is_pure_uint(f)) {
+         key->fs.uint_render_target_mask |= 1 << i;
+      }
+   }
+
    return PIPE_OK;
 }
 
diff --git a/src/gallium/drivers/svga/svga_tgsi_vgpu10.c b/src/gallium/drivers/svga/svga_tgsi_vgpu10.c
index 9f5cd4b..8984ce5 100644
--- a/src/gallium/drivers/svga/svga_tgsi_vgpu10.c
+++ b/src/gallium/drivers/svga/svga_tgsi_vgpu10.c
@@ -167,8 +167,8 @@ struct svga_shader_emitter_v10
 
    /* For fragment shaders only */
    struct {
-      /* apha test */
       unsigned color_out_index[PIPE_MAX_COLOR_BUFS];  /**< the real color output regs */
+      unsigned num_color_outputs;
       unsigned color_tmp_index;  /**< fake/temp color output reg */
       unsigned alpha_ref_index;  /**< immediate constant for alpha ref */
 
@@ -2499,6 +2499,9 @@ emit_output_declarations(struct svga_shader_emitter_v10 *emit)
 
             emit->fs.color_out_index[semantic_index] = index;
 
+            emit->fs.num_color_outputs = MAX2(emit->fs.num_color_outputs,
+                                              index + 1);
+
             /* The semantic index is the shader's color output/buffer index */
             emit_output_declaration(emit,
                                     VGPU10_OPCODE_DCL_OUTPUT, semantic_index,
@@ -2521,6 +2524,9 @@ emit_output_declarations(struct svga_shader_emitter_v10 *emit)
                                         VGPU10_OPERAND_4_COMPONENT_MASK_ALL);
                      emit->info.output_semantic_index[idx] = j;
                   }
+
+                  emit->fs.num_color_outputs =
+                     emit->key.fs.write_color0_to_n_cbufs;
                }
             }
             else {
@@ -6300,6 +6306,15 @@ alloc_common_immediates(struct svga_shader_emitter_v10 *emit)
          alloc_immediate_int4(emit, 22, 30, 0, 0);
    }
 
+   if (emit->key.fs.int_render_target_mask) {
+      emit->common_immediate_pos[n++] =
+         alloc_immediate_int4(emit, 0x8fffffff, 0, 0, 0);
+   }
+   if (emit->key.fs.uint_render_target_mask) {
+      emit->common_immediate_pos[n++] =
+         alloc_immediate_int4(emit, 0xffffffff, 0, 0, 0);
+   }
+
    unsigned i;
 
    for (i = 0; i < PIPE_MAX_SAMPLERS; i++) {
@@ -6378,6 +6393,47 @@ emit_pre_helpers(struct svga_shader_emitter_v10 *emit)
 
 
 /**
+ * The device has no direct support for the pipe_blend_state::alpha_to_one
+ * option so we implement it here with shader code.
+ */
+static void
+emit_alpha_to_one_instructions(struct svga_shader_emitter_v10 *emit,
+                               unsigned fs_color_tmp_index)
+{
+   unsigned i;
+
+   for (i = 0; i < emit->fs.num_color_outputs; i++) {
+      struct tgsi_full_dst_register color_dst;
+
+      if (fs_color_tmp_index != INVALID_INDEX && i == 0) {
+         /* write to the temp color register */
+         color_dst = make_dst_temp_reg(fs_color_tmp_index);
+      }
+      else {
+         /* write directly to the color[i] output */
+         color_dst = make_dst_output_reg(emit->fs.color_out_index[i]);
+      }
+
+      color_dst = writemask_dst(&color_dst, TGSI_WRITEMASK_W);
+
+      /* Depending on type of the render target, we either set alpha/w to
+       * 1.0f, or max(int) or max(uint).
+       */
+      struct tgsi_full_src_register one;
+      if (emit->key.fs.int_render_target_mask & (1 << i)) {
+         one = make_immediate_reg_int(emit, 0x8fffffff);
+      } else if (emit->key.fs.uint_render_target_mask & (1 << i)) {
+         one = make_immediate_reg_int(emit, 0xffffffff);
+      } else {
+         one = make_immediate_reg_float(emit, 1.0f);
+      }
+
+      emit_instruction_op1(emit, VGPU10_OPCODE_MOV, &color_dst, &one, FALSE);
+   }
+}
+
+
+/**
  * Emit alpha test code.  This compares TEMP[fs_color_tmp_index].w
  * against the alpha reference value and discards the fragment if the
  * comparison fails.
@@ -6494,6 +6550,9 @@ emit_post_helpers(struct svga_shader_emitter_v10 *emit)
        */
       emit->fs.color_tmp_index = INVALID_INDEX;
 
+      if (emit->key.fs.alpha_to_one) {
+         emit_alpha_to_one_instructions(emit, fs_color_tmp_index);
+      }
       if (emit->key.fs.alpha_func != SVGA3D_CMP_ALWAYS) {
          emit_alpha_test_instructions(emit, fs_color_tmp_index);
       }
-- 
1.9.1



More information about the mesa-dev mailing list