svga: implement point sprite suppport
authorBrian Paul <brianp@vmware.com>
Wed, 13 Jul 2011 16:58:01 +0000 (10:58 -0600)
committerBrian Paul <brianp@vmware.com>
Fri, 23 Sep 2011 13:58:47 +0000 (07:58 -0600)
Emit the SVGA3D_RS_POINTSPRITEENABLE render state.
When sprite_coord_mode=PIPE_SPRITE_COORD_LOWER_LEFT emit extra frag
shader code to invert the Y coordinate of the incoming texcoord.

src/gallium/drivers/svga/svga_context.h
src/gallium/drivers/svga/svga_pipe_rasterizer.c
src/gallium/drivers/svga/svga_state_fs.c
src/gallium/drivers/svga/svga_state_rss.c
src/gallium/drivers/svga/svga_tgsi.h
src/gallium/drivers/svga/svga_tgsi_decl_sm30.c
src/gallium/drivers/svga/svga_tgsi_emit.h
src/gallium/drivers/svga/svga_tgsi_insn.c

index f8c1ab403459ec0a3b80c9ab1ac4d4662782c15d..a03a81749bbdbc80ec0d5f013f0dd4ff01985abd 100644 (file)
@@ -141,6 +141,7 @@ struct svga_rasterizer_state {
    unsigned multisampleantialias:1;
    unsigned antialiasedlineenable:1;
    unsigned lastpixel:1;
+   unsigned pointsprite:1;
 
    unsigned linepattern;
 
index 4a1a37f1765972dcee81c1df9672f8da7a029c53..a18845e3b7ca2ff1b8b2be91fecaf3f9a7bd9a6d 100644 (file)
@@ -89,6 +89,7 @@ svga_create_rasterizer_state(struct pipe_context *pipe,
    rast->multisampleantialias = templ->multisample;
    rast->antialiasedlineenable = templ->line_smooth;
    rast->lastpixel = templ->line_last_pixel;
+   rast->pointsprite = templ->sprite_coord_enable != 0x0;
    rast->pointsize = templ->point_size;
    rast->hw_unfilled = PIPE_POLYGON_MODE_FILL;
 
index 9c04adec8ee852c17a0acd7d3e8fa34659ffefe3..8a50bfd344aaf3bc48aa2fdb6b15016d410f80c7 100644 (file)
@@ -179,6 +179,15 @@ static int make_fs_key( const struct svga_context *svga,
       }
    }
 
+   /* sprite coord gen state */
+   for (i = 0; i < svga->curr.num_samplers; ++i) {
+      key->tex[i].sprite_texgen =
+         svga->curr.rast->templ.sprite_coord_enable & (1 << i);
+   }
+
+   key->sprite_origin_lower_left = (svga->curr.rast->templ.sprite_coord_mode
+                                    == PIPE_SPRITE_COORD_LOWER_LEFT);
+
    return 0;
 }
 
index 28f32793742edc55a595917c81c49e521b28f75b..a37e1f8128bd51dda9d5db6ba84ddf28a5b53f29 100644 (file)
@@ -217,6 +217,7 @@ static int emit_rss( struct svga_context *svga,
       /* XXX still need to set this? */
       EMIT_RS_FLOAT( svga, 0.0, POINTSIZEMIN, fail );
       EMIT_RS_FLOAT( svga, SVGA_MAX_POINTSIZE, POINTSIZEMAX, fail );
+      EMIT_RS( svga, curr->pointsprite, POINTSPRITEENABLE, fail);
    }
 
    if (dirty & (SVGA_NEW_RAST | SVGA_NEW_FRAME_BUFFER | SVGA_NEW_NEED_PIPELINE))
index 7ea909c37bfe889961df19d0571de0b1d8da11e2..bd63bf5c264cb569025837345c52954d0cf03687 100644 (file)
@@ -52,12 +52,14 @@ struct svga_fs_compile_key
    unsigned white_fragments:1;
    unsigned num_textures:8;
    unsigned num_unnormalized_coords:8;
+   unsigned sprite_origin_lower_left:1;
    struct {
       unsigned compare_mode:1;
       unsigned compare_func:3;
       unsigned unnormalized:1;
       unsigned width_height_idx:7;
       unsigned texture_target:8;
+      unsigned sprite_texgen:1;
    } tex[PIPE_MAX_SAMPLERS];
 };
 
index ed4b000e4f32a913c13417175f69767abd9d273e..6f162ea7e33d60e321cd3dbd3181c3848e78079b 100644 (file)
@@ -234,7 +234,36 @@ static boolean ps30_input( struct svga_shader_emitter *emit,
       emit->input_map[idx] = src_register( SVGA3DREG_INPUT, emit->ps30_input_count++ );
       reg = dst( emit->input_map[idx] );
 
-      return emit_decl( emit, reg, usage, index );
+      if (!emit_decl( emit, reg, usage, index ))
+         return FALSE;
+
+      if (semantic.Name == TGSI_SEMANTIC_GENERIC &&
+          emit->key.fkey.sprite_origin_lower_left &&
+          index >= 1 &&
+          emit->key.fkey.tex[index - 1].sprite_texgen) {
+         /* This is a sprite texture coord with lower-left origin.
+          * We need to invert the texture T coordinate since the SVGA3D
+          * device only supports an upper-left origin.
+          */
+         unsigned unit = index - 1;
+
+         emit->inverted_texcoords |= (1 << unit);
+
+         /* save original texcoord reg */
+         emit->ps_true_texcoord[unit] = emit->input_map[idx];
+
+         /* this temp register will be the results of the MAD instruction */
+         emit->ps_inverted_texcoord[unit] =
+            src_register(SVGA3DREG_TEMP, emit->nr_hw_temp);
+         emit->nr_hw_temp++;
+
+         emit->ps_inverted_texcoord_input[unit] = idx;
+
+         /* replace input_map entry with the temp register */
+         emit->input_map[idx] = emit->ps_inverted_texcoord[unit];
+      }
+
+      return TRUE;
    }
 
 }
index b1300dc8ecdd4738132b95fce59161ec3d48f9f8..fca396e656e23bb79f5a3f48d44a05b2cb7059e7 100644 (file)
@@ -94,6 +94,11 @@ struct svga_shader_emitter
    boolean created_sincos_consts;
    int sincos_consts_idx;
 
+   unsigned inverted_texcoords;  /**< bitmask of which texcoords are flipped */
+   struct src_register ps_true_texcoord[PIPE_MAX_ATTRIBS];
+   struct src_register ps_inverted_texcoord[PIPE_MAX_ATTRIBS];
+   unsigned ps_inverted_texcoord_input[PIPE_MAX_ATTRIBS];
+
    unsigned label[32];
    unsigned nr_labels;
 
index 10688accdaaabcfc44b603a1c376e177cda0c5f1..6f03e61db550413b03d1dc8295818a3e3b6a7cc7 100644 (file)
@@ -27,6 +27,7 @@
 #include "pipe/p_shader_tokens.h"
 #include "tgsi/tgsi_parse.h"
 #include "util/u_memory.h"
+#include "util/u_math.h"
 
 #include "svga_tgsi_emit.h"
 #include "svga_context.h"
@@ -623,8 +624,11 @@ create_zero_immediate( struct svga_shader_emitter *emit )
 {
    unsigned idx = emit->nr_hw_float_const++;
 
+   /* Emit the constant (0, 0, -1, 1) and use swizzling to generate
+    * other useful vectors.
+    */
    if (!emit_def_const( emit, SVGA3D_CONST_TYPE_FLOAT,
-                        idx, 0, 0, 0, 1 ))
+                        idx, 0, 0, -1, 1 ))
       return FALSE;
 
    emit->zero_immediate_idx = idx;
@@ -731,8 +735,20 @@ get_zero_immediate( struct svga_shader_emitter *emit )
 {
    assert(emit->created_zero_immediate);
    assert(emit->zero_immediate_idx >= 0);
-   return src_register( SVGA3DREG_CONST,
-                        emit->zero_immediate_idx );
+   return swizzle(src_register( SVGA3DREG_CONST,
+                                emit->zero_immediate_idx),
+                  0, 0, 0, 3);
+}
+
+/* returns {1, 1, 1, -1} immediate */
+static INLINE struct src_register
+get_pos_neg_one_immediate( struct svga_shader_emitter *emit )
+{
+   assert(emit->created_zero_immediate);
+   assert(emit->zero_immediate_idx >= 0);
+   return swizzle(src_register( SVGA3DREG_CONST,
+                                emit->zero_immediate_idx),
+                  3, 3, 3, 2);
 }
 
 /* returns the loop const */
@@ -2849,6 +2865,50 @@ static boolean emit_frontface( struct svga_shader_emitter *emit )
    return TRUE;
 }
 
+
+/**
+ * Emit code to invert the T component of the incoming texture coordinate.
+ * This is used for drawing point sprites when
+ * pipe_rasterizer_state::sprite_coord_mode == PIPE_SPRITE_COORD_LOWER_LEFT.
+ */
+static boolean emit_inverted_texcoords( struct svga_shader_emitter *emit )
+{
+   struct src_register zero = get_zero_immediate(emit);
+   struct src_register pos_neg_one = get_pos_neg_one_immediate( emit );
+   unsigned inverted_texcoords = emit->inverted_texcoords;
+
+   while (inverted_texcoords) {
+      const unsigned unit = ffs(inverted_texcoords) - 1;
+
+      assert(emit->inverted_texcoords & (1 << unit));
+
+      assert(unit < Elements(emit->ps_true_texcoord));
+
+      assert(unit < Elements(emit->ps_inverted_texcoord_input));
+
+      assert(emit->ps_inverted_texcoord_input[unit]
+             < Elements(emit->input_map));
+
+      /* inverted = coord * (1, -1, 1, 1) + (0, 1, 0, 0) */
+      if (!submit_op3(emit, 
+                      inst_token(SVGA3DOP_MAD), 
+                      dst(emit->ps_inverted_texcoord[unit]),
+                      emit->ps_true_texcoord[unit],
+                      swizzle(pos_neg_one, 0, 3, 0, 0),  /* (1, -1, 1, 1) */
+                      swizzle(zero, 0, 3, 0, 0)))  /* (0, 1, 0, 0) */
+         return FALSE;
+
+      /* Reassign the input_map entry to the new texcoord register */
+      emit->input_map[emit->ps_inverted_texcoord_input[unit]] =
+         emit->ps_inverted_texcoord[unit];
+
+      inverted_texcoords &= ~(1 << unit);      
+   }
+
+   return TRUE;
+}
+
+
 static INLINE boolean
 needs_to_create_zero( struct svga_shader_emitter *emit )
 {
@@ -2871,6 +2931,9 @@ needs_to_create_zero( struct svga_shader_emitter *emit )
           emit->info.opcode_count[TGSI_OPCODE_SSG] >= 1 ||
           emit->info.opcode_count[TGSI_OPCODE_LIT] >= 1)
          return TRUE;
+
+      if (emit->inverted_texcoords)
+         return TRUE;
    }
 
    if (emit->unit == PIPE_SHADER_VERTEX) {
@@ -3036,6 +3099,10 @@ static boolean svga_shader_emit_helpers( struct svga_shader_emitter *emit )
          if (!emit_frontface( emit ))
             return FALSE;
       }
+      if (emit->inverted_texcoords) {
+         if (!emit_inverted_texcoords( emit ))
+            return FALSE;
+      }
    }
 
    return TRUE;