svga: detect constant color writes in fragment shaders
authorBrian Paul <brianp@vmware.com>
Thu, 22 Oct 2015 21:36:25 +0000 (15:36 -0600)
committerBrian Paul <brianp@vmware.com>
Thu, 22 Oct 2015 23:19:20 +0000 (17:19 -0600)
Examine the fragment shader to try to detect TGSI shaders which use
"MOV OUT[0], CONST[i]" to write a constant value for the fragment color.
In this case, all fragments will have the same color (unless blending is
enabled).

This is a common case for OpenGL code such as: glColor(), glBegin(),
glVertex(), ..., glEnd() when lighting/fog/etc are disabled.  In this
case, the Mesa/gallium state tracker actually generates a simple
"MOV OUT[0], CONST[i]" fragment shader.

This will be used by the next commit to avoid provoking vertex conversion
(creating/rewriting an index buffer) when drawing flat-shaded primitives.

Reviewed-by: Charmaine Lee <charmainel@vmware.com>
Reviewed-by: José Fonseca <jfonseca@vmware.com>
src/gallium/drivers/svga/svga_shader.h
src/gallium/drivers/svga/svga_tgsi.c
src/gallium/drivers/svga/svga_tgsi_emit.h
src/gallium/drivers/svga/svga_tgsi_insn.c
src/gallium/drivers/svga/svga_tgsi_vgpu10.c

index efcac4086264ee16eda653ffd25cfabd1eb74f09..f49fdb46d0e8330d35965dc73023589f8349498d 100644 (file)
@@ -155,6 +155,9 @@ struct svga_shader_variant
                                 *  applied to any of the varyings.
                                 */
 
+   /** Is the color output just a constant value? (fragment shader only) */
+   boolean constant_color_output;
+
    /** For FS-based polygon stipple */
    unsigned pstipple_sampler_unit;
 
index 202eee276b7c01bae57ea4727672f50c50945414..4c16f4313a0bc2c7b9529254c997db112af6af6f 100644 (file)
@@ -240,6 +240,13 @@ svga_tgsi_vgpu9_translate(struct svga_context *svga,
 
    variant->pstipple_sampler_unit = emit.pstipple_sampler_unit;
 
+   /* If there was exactly one write to a fragment shader output register
+    * and it came from a constant buffer, we know all fragments will have
+    * the same color (except for blending).
+    */
+   variant->constant_color_output =
+      emit.constant_color_output && emit.num_output_writes == 1;
+
 #if 0
    if (!svga_shader_verify(variant->tokens, variant->nr_tokens) ||
        SVGA_DEBUG & DEBUG_TGSI) {
index 0b82483ab2ef72132d6b91bff1a80cb883bd590d..83f0c8bd4d001bf4e88f6e2b37a4e9394899ce66 100644 (file)
@@ -84,6 +84,9 @@ struct svga_shader_emitter
 
    int dynamic_branching_level;
 
+   unsigned num_output_writes;
+   boolean constant_color_output;
+
    boolean in_main_func;
 
    boolean created_common_immediate;
index 00c91a4fa61ac26df4e66b52f367534be20f98a8..dbb90f7654e10f177b0a4331ce9f71e0cc381719 100644 (file)
@@ -99,6 +99,7 @@ translate_dst_register( struct svga_shader_emitter *emit,
        * Need to lookup a table built at decl time:
        */
       dest = emit->output_map[reg->Register.Index];
+      emit->num_output_writes++;
       break;
 
    default:
@@ -2102,6 +2103,29 @@ emit_simple_instruction(struct svga_shader_emitter *emit,
 }
 
 
+/**
+ * TGSI_OPCODE_MOVE is only special-cased here to detect the
+ * svga_fragment_shader::constant_color_output case.
+ */
+static boolean
+emit_mov(struct svga_shader_emitter *emit,
+         const struct tgsi_full_instruction *insn)
+{
+   const struct tgsi_full_src_register *src = &insn->Src[0];
+   const struct tgsi_full_dst_register *dst = &insn->Dst[0];
+
+   if (emit->unit == PIPE_SHADER_FRAGMENT &&
+       dst->Register.File == TGSI_FILE_OUTPUT &&
+       dst->Register.Index == 0 &&
+       src->Register.File == TGSI_FILE_CONSTANT &&
+       !src->Register.Indirect) {
+      emit->constant_color_output = TRUE;
+   }
+
+   return emit_simple_instruction(emit, SVGA3DOP_MOV, insn);
+}
+
+
 /**
  * Translate/emit TGSI DDX, DDY instructions.
  */
@@ -3045,6 +3069,9 @@ svga_emit_instruction(struct svga_shader_emitter *emit,
    case TGSI_OPCODE_SSG:
       return emit_ssg( emit, insn );
 
+   case TGSI_OPCODE_MOV:
+      return emit_mov( emit, insn );
+
    default:
       {
          unsigned opcode = translate_opcode(insn->Instruction.Opcode);
index 332904f88b44f8f752bbad1731999edb1d2c7c1f..e70ee689c59cf4d2c85353422a183ddec0bbe1d2 100644 (file)
@@ -202,6 +202,9 @@ struct svga_shader_emitter_v10
    /* user clip plane constant slot indexes */
    unsigned clip_plane_const[PIPE_MAX_CLIP_PLANES];
 
+   unsigned num_output_writes;
+   boolean constant_color_output;
+
    boolean uses_flat_interp;
 
    /* For all shaders: const reg index for RECT coord scaling */
@@ -913,6 +916,8 @@ emit_dst_register(struct svga_shader_emitter_v10 *emit,
              */
             assert(sem_name == TGSI_SEMANTIC_COLOR);
             index = emit->info.output_semantic_index[index];
+
+            emit->num_output_writes++;
          }
       }
    }
@@ -5572,6 +5577,29 @@ emit_simple(struct svga_shader_emitter_v10 *emit,
 }
 
 
+/**
+ * We only special case the MOV instruction to try to detect constant
+ * color writes in the fragment shader.
+ */
+static boolean
+emit_mov(struct svga_shader_emitter_v10 *emit,
+         const struct tgsi_full_instruction *inst)
+{
+   const struct tgsi_full_src_register *src = &inst->Src[0];
+   const struct tgsi_full_dst_register *dst = &inst->Dst[0];
+
+   if (emit->unit == PIPE_SHADER_FRAGMENT &&
+       dst->Register.File == TGSI_FILE_OUTPUT &&
+       dst->Register.Index == 0 &&
+       src->Register.File == TGSI_FILE_CONSTANT &&
+       !src->Register.Indirect) {
+      emit->constant_color_output = TRUE;
+   }
+
+   return emit_simple(emit, inst);
+}
+
+
 /**
  * Emit a simple VGPU10 instruction which writes to multiple dest registers,
  * where TGSI only uses one dest register.
@@ -5652,7 +5680,6 @@ emit_vgpu10_instruction(struct svga_shader_emitter_v10 *emit,
    case TGSI_OPCODE_MAD:
    case TGSI_OPCODE_MAX:
    case TGSI_OPCODE_MIN:
-   case TGSI_OPCODE_MOV:
    case TGSI_OPCODE_MUL:
    case TGSI_OPCODE_NOP:
    case TGSI_OPCODE_NOT:
@@ -5677,7 +5704,8 @@ emit_vgpu10_instruction(struct svga_shader_emitter_v10 *emit,
       /* simple instructions */
       return emit_simple(emit, inst);
 
-
+   case TGSI_OPCODE_MOV:
+      return emit_mov(emit, inst);
    case TGSI_OPCODE_EMIT:
       return emit_vertex(emit, inst);
    case TGSI_OPCODE_ENDPRIM:
@@ -6762,6 +6790,13 @@ svga_tgsi_vgpu10_translate(struct svga_context *svga,
 
    variant->pstipple_sampler_unit = emit->fs.pstipple_sampler_unit;
 
+   /* If there was exactly one write to a fragment shader output register
+    * and it came from a constant buffer, we know all fragments will have
+    * the same color (except for blending).
+    */
+   variant->constant_color_output =
+      emit->constant_color_output && emit->num_output_writes == 1;
+
    /** keep track in the variant if flat interpolation is used
     *  for any of the varyings.
     */