gallium: rework handling of sprite_coord_enable state
authorBrian Paul <brianp@vmware.com>
Sat, 18 Sep 2010 00:41:30 +0000 (18:41 -0600)
committerBrian Paul <brianp@vmware.com>
Sat, 18 Sep 2010 00:45:13 +0000 (18:45 -0600)
Implement the pipe_rasterizer_state::sprite_coord_enable field
in the draw module (and softpipe) according to what's specified
in the documentation.

The draw module can now add any number of extra vertex attributes
to a post-transformed vertex and generate texcoords for those
attributes per sprite_coord_enable.  Auto-generated texcoords
for sprites only worked for one texcoord unit before.

The frag shader gl_PointCoord input is now implemented like any
other generic/texcoord attribute.

The draw module now needs to be informed about fragment shaders
since we need to look at the fragment shader's inputs to know
which ones need auto-generated texcoords.

Only softpipe has been updated so far.

12 files changed:
src/gallium/auxiliary/Makefile
src/gallium/auxiliary/SConscript
src/gallium/auxiliary/draw/draw_context.c
src/gallium/auxiliary/draw/draw_context.h
src/gallium/auxiliary/draw/draw_pipe_aaline.c
src/gallium/auxiliary/draw/draw_pipe_aapoint.c
src/gallium/auxiliary/draw/draw_pipe_wide_point.c
src/gallium/auxiliary/draw/draw_private.h
src/gallium/drivers/softpipe/sp_state.h
src/gallium/drivers/softpipe/sp_state_fs.c
src/mesa/state_tracker/st_atom_rasterizer.c
src/mesa/state_tracker/st_program.c

index 2de764c4ee301354e2da4b5ab69d910708aa090d..f05538bbac46c2479c8032c5f73c5a116016feca 100644 (file)
@@ -8,6 +8,7 @@ C_SOURCES = \
        cso_cache/cso_context.c \
        cso_cache/cso_hash.c \
        draw/draw_context.c \
+       draw/draw_fs.c \
        draw/draw_gs.c \
        draw/draw_pipe.c \
        draw/draw_pipe_aaline.c \
index 294df300947b28ef305b572d827a6b292d910e0a..baaa26fea926ebbfdcb089519bfee2faead7a4a2 100644 (file)
@@ -54,6 +54,7 @@ source = [
     'cso_cache/cso_context.c',
     'cso_cache/cso_hash.c',
     'draw/draw_context.c',
+    'draw/draw_fs.c',
     'draw/draw_gs.c',
     'draw/draw_pipe.c',
     'draw/draw_pipe_aaline.c',
index 937b0934798ce48b7bf2d0853c53c324860f7fb3..b07de76a498aa098996a5959f86ce11b540af7d1 100644 (file)
@@ -413,6 +413,42 @@ draw_set_force_passthrough( struct draw_context *draw, boolean enable )
 }
 
 
+
+/**
+ * Allocate an extra vertex/geometry shader vertex attribute.
+ * This is used by some of the optional draw module stages such
+ * as wide_point which may need to allocate additional generic/texcoord
+ * attributes.
+ */
+int
+draw_alloc_extra_vertex_attrib(struct draw_context *draw,
+                               uint semantic_name, uint semantic_index)
+{
+   const int num_outputs = draw_current_shader_outputs(draw);
+   const int n = draw->extra_shader_outputs.num;
+
+   assert(n < Elements(draw->extra_shader_outputs.semantic_name));
+
+   draw->extra_shader_outputs.semantic_name[n] = semantic_name;
+   draw->extra_shader_outputs.semantic_index[n] = semantic_index;
+   draw->extra_shader_outputs.slot[n] = num_outputs + n;
+   draw->extra_shader_outputs.num++;
+
+   return draw->extra_shader_outputs.slot[n];
+}
+
+
+/**
+ * Remove all extra vertex attributes that were allocated with
+ * draw_alloc_extra_vertex_attrib().
+ */
+void
+draw_remove_extra_vertex_attribs(struct draw_context *draw)
+{
+   draw->extra_shader_outputs.num = 0;
+}
+
+
 /**
  * Ask the draw module for the location/slot of the given vertex attribute in
  * a post-transformed vertex.
@@ -446,12 +482,12 @@ draw_find_shader_output(const struct draw_context *draw,
          return i;
    }
 
-   /* XXX there may be more than one extra vertex attrib.
-    * For example, simulated gl_FragCoord and gl_PointCoord.
-    */
-   if (draw->extra_shader_outputs.semantic_name == semantic_name &&
-       draw->extra_shader_outputs.semantic_index == semantic_index) {
-      return draw->extra_shader_outputs.slot;
+   /* Search the extra vertex attributes */
+   for (i = 0; i < draw->extra_shader_outputs.num; i++) {
+      if (draw->extra_shader_outputs.semantic_name[i] == semantic_name &&
+          draw->extra_shader_outputs.semantic_index[i] == semantic_index) {
+         return draw->extra_shader_outputs.slot[i];
+      }
    }
 
    return 0;
@@ -470,16 +506,18 @@ draw_find_shader_output(const struct draw_context *draw,
 uint
 draw_num_shader_outputs(const struct draw_context *draw)
 {
-   uint count = draw->vs.vertex_shader->info.num_outputs;
+   uint count;
 
    /* If a geometry shader is present, its outputs go to the
     * driver, else the vertex shader's outputs.
     */
    if (draw->gs.geometry_shader)
       count = draw->gs.geometry_shader->info.num_outputs;
+   else
+      count = draw->vs.vertex_shader->info.num_outputs;
+
+   count += draw->extra_shader_outputs.num;
 
-   if (draw->extra_shader_outputs.slot > 0)
-      count++;
    return count;
 }
 
index 4f0d30123a4bc018a780e699c2865df72ea2f5de..1f27cbf488a9bb0a1e359601faa64b44394e19c5 100644 (file)
@@ -46,6 +46,7 @@ struct draw_context;
 struct draw_stage;
 struct draw_vertex_shader;
 struct draw_geometry_shader;
+struct draw_fragment_shader;
 struct tgsi_sampler;
 
 #define DRAW_MAX_TEXTURE_LEVELS 13  /* 4K x 4K for now */
@@ -137,6 +138,17 @@ void draw_delete_vertex_shader(struct draw_context *draw,
                                struct draw_vertex_shader *dvs);
 
 
+/*
+ * Fragment shader functions
+ */
+struct draw_fragment_shader *
+draw_create_fragment_shader(struct draw_context *draw,
+                            const struct pipe_shader_state *shader);
+void draw_bind_fragment_shader(struct draw_context *draw,
+                               struct draw_fragment_shader *dvs);
+void draw_delete_fragment_shader(struct draw_context *draw,
+                                 struct draw_fragment_shader *dvs);
+
 /*
  * Geometry shader functions
  */
index eac21110be41dd83b92a5c9b9e5179da29833f6d..d1aba763098e9e4977edd19a9aac74d5e0fa9bbb 100644 (file)
@@ -688,10 +688,9 @@ aaline_first_line(struct draw_stage *stage, struct prim_header *header)
    aaline->tex_slot = draw_current_shader_outputs(draw);
    aaline->pos_slot = draw_current_shader_position_output(draw);;
 
-   /* advertise the extra post-transformed vertex attribute */
-   draw->extra_shader_outputs.semantic_name = TGSI_SEMANTIC_GENERIC;
-   draw->extra_shader_outputs.semantic_index = aaline->fs->generic_attrib;
-   draw->extra_shader_outputs.slot = aaline->tex_slot;
+   /* allocate the extra post-transformed vertex attribute */
+   (void) draw_alloc_extra_vertex_attrib(draw, TGSI_SEMANTIC_GENERIC,
+                                         aaline->fs->generic_attrib);
 
    /* how many samplers? */
    /* we'll use sampler/texture[pstip->sampler_unit] for the stipple */
@@ -744,7 +743,7 @@ aaline_flush(struct draw_stage *stage, unsigned flags)
 
    draw->suspend_flushing = FALSE;
 
-   draw->extra_shader_outputs.slot = 0;
+   draw_remove_extra_vertex_attribs(draw);
 }
 
 
index d406a86ccb537c601234c2c8c0c2924ad82dc54b..5ea552f51c1130a13819f5c6df98ba6f60d507d3 100644 (file)
@@ -701,9 +701,9 @@ aapoint_first_point(struct draw_stage *stage, struct prim_header *header)
 
    aapoint->pos_slot = draw_current_shader_position_output(draw);
 
-   draw->extra_shader_outputs.semantic_name = TGSI_SEMANTIC_GENERIC;
-   draw->extra_shader_outputs.semantic_index = aapoint->fs->generic_attrib;
-   draw->extra_shader_outputs.slot = aapoint->tex_slot;
+   /* allocate the extra post-transformed vertex attribute */
+   (void) draw_alloc_extra_vertex_attrib(draw, TGSI_SEMANTIC_GENERIC,
+                                         aapoint->fs->generic_attrib);
 
    /* find psize slot in post-transform vertex */
    aapoint->psize_slot = -1;
@@ -754,7 +754,7 @@ aapoint_flush(struct draw_stage *stage, unsigned flags)
 
    draw->suspend_flushing = FALSE;
 
-   draw->extra_shader_outputs.slot = 0;
+   draw_remove_extra_vertex_attribs(draw);
 }
 
 
index ee2945c7c97363d8e90c26651c7247565d9ad283..40843c58c2090ea7229f06faa24a18c960da77d7 100644 (file)
 #include "util/u_memory.h"
 #include "pipe/p_defines.h"
 #include "pipe/p_shader_tokens.h"
+#include "draw_fs.h"
 #include "draw_vs.h"
 #include "draw_pipe.h"
 
 
 struct widepoint_stage {
-   struct draw_stage stage;
+   struct draw_stage stage;  /**< base class */
 
    float half_point_size;
 
    float xbias;
    float ybias;
 
-   uint texcoord_slot[PIPE_MAX_SHADER_OUTPUTS];
-   uint texcoord_enable[PIPE_MAX_SHADER_OUTPUTS];
-   uint num_texcoords;
-   uint texcoord_mode;
+   /** for automatic texcoord generation/replacement */
+   uint num_texcoord_gen;
+   uint texcoord_gen_slot[PIPE_MAX_SHADER_OUTPUTS];
 
    int psize_slot;
-
-   int point_coord_fs_input;  /**< input for pointcoord */
 };
 
 
@@ -96,30 +94,20 @@ widepoint_stage( struct draw_stage *stage )
 static void set_texcoords(const struct widepoint_stage *wide,
                           struct vertex_header *v, const float tc[4])
 {
+   const struct draw_context *draw = wide->stage.draw;
+   const struct pipe_rasterizer_state *rast = draw->rasterizer;
+   const uint texcoord_mode = rast->sprite_coord_mode;
    uint i;
-   for (i = 0; i < wide->num_texcoords; i++) {
-      if (wide->texcoord_enable[i]) {
-         uint j = wide->texcoord_slot[i];
-         v->data[j][0] = tc[0];
-         if (wide->texcoord_mode == PIPE_SPRITE_COORD_LOWER_LEFT)
-            v->data[j][1] = 1.0f - tc[1];
-         else
-            v->data[j][1] = tc[1];
-         v->data[j][2] = tc[2];
-         v->data[j][3] = tc[3];
-      }
-   }
 
-   if (wide->point_coord_fs_input >= 0) {
-      /* put gl_PointCoord into the extra vertex slot */
-      uint slot = wide->stage.draw->extra_shader_outputs.slot;
+   for (i = 0; i < wide->num_texcoord_gen; i++) {
+      const uint slot = wide->texcoord_gen_slot[i];
       v->data[slot][0] = tc[0];
-      if (wide->texcoord_mode == PIPE_SPRITE_COORD_LOWER_LEFT)
+      if (texcoord_mode == PIPE_SPRITE_COORD_LOWER_LEFT)
          v->data[slot][1] = 1.0f - tc[1];
       else
          v->data[slot][1] = tc[1];
-      v->data[slot][2] = 0.0F;
-      v->data[slot][3] = 1.0F;
+      v->data[slot][2] = tc[2];
+      v->data[slot][3] = tc[3];
    }
 }
 
@@ -201,18 +189,9 @@ static void widepoint_point( struct draw_stage *stage,
 }
 
 
-static int
-find_pntc_input_attrib(struct draw_context *draw)
-{
-   /* Scan the fragment program's input decls to find the pointcoord
-    * attribute.  The xy components will store the point coord.
-    */
-   return 0; /* XXX fix this */
-}
-
-
-static void widepoint_first_point( struct draw_stage *stage, 
-                             struct prim_header *header )
+static void
+widepoint_first_point(struct draw_stage *stage, 
+                      struct prim_header *header)
 {
    struct widepoint_stage *wide = widepoint_stage(stage);
    struct draw_context *draw = stage->draw;
@@ -244,31 +223,45 @@ static void widepoint_first_point( struct draw_stage *stage,
       stage->point = draw_pipe_passthrough_point;
    }
 
+   draw_remove_extra_vertex_attribs(draw);
+
    if (rast->point_quad_rasterization) {
-      /* find vertex shader texcoord outputs */
-      const struct draw_vertex_shader *vs = draw->vs.vertex_shader;
-      uint i, j = 0;
-      wide->texcoord_mode = rast->sprite_coord_mode;
-      for (i = 0; i < vs->info.num_outputs; i++) {
-         if (vs->info.output_semantic_name[i] == TGSI_SEMANTIC_GENERIC) {
-            wide->texcoord_slot[j] = i;
-            wide->texcoord_enable[j] = (rast->sprite_coord_enable >> j) & 1;
-            j++;
+      const struct draw_fragment_shader *fs = draw->fs.fragment_shader;
+      uint i;
+
+      wide->num_texcoord_gen = 0;
+
+      /* Loop over fragment shader inputs looking for generic inputs
+       * for which bit 'k' in sprite_coord_enable is set.
+       */
+      for (i = 0; i < fs->info.num_inputs; i++) {
+         if (fs->info.input_semantic_name[i] == TGSI_SEMANTIC_GENERIC) {
+            const int generic_index = fs->info.input_semantic_index[i];
+            if (rast->sprite_coord_enable & (1 << generic_index)) {
+               /* OK, this generic attribute needs to be replaced with a
+                * texcoord (see above).
+                */
+               int slot = draw_find_shader_output(draw,
+                                                  TGSI_SEMANTIC_GENERIC,
+                                                  generic_index);
+
+               if (slot > 0) {
+                  /* there's already a post-vertex shader attribute
+                   * for this fragment shader input attribute.
+                   */
+               }
+               else {
+                  /* need to allocate a new post-vertex shader attribute */
+                  slot = draw_alloc_extra_vertex_attrib(draw,
+                                                        TGSI_SEMANTIC_GENERIC,
+                                                        generic_index);
+               }
+
+               /* add this slot to the texcoord-gen list */
+               wide->texcoord_gen_slot[wide->num_texcoord_gen++] = slot;
+            }
          }
       }
-      wide->num_texcoords = j;
-
-      /* find fragment shader PointCoord input */
-      wide->point_coord_fs_input = find_pntc_input_attrib(draw);
-
-      /* setup extra vp output (point coord implemented as a texcoord) */
-      draw->extra_shader_outputs.semantic_name = TGSI_SEMANTIC_GENERIC;
-      draw->extra_shader_outputs.semantic_index = 0;
-      draw->extra_shader_outputs.slot = draw_current_shader_outputs(draw);
-   }
-   else {
-      wide->point_coord_fs_input = -1;
-      draw->extra_shader_outputs.slot = 0;
    }
 
    wide->psize_slot = -1;
@@ -295,7 +288,8 @@ static void widepoint_flush( struct draw_stage *stage, unsigned flags )
 
    stage->point = widepoint_first_point;
    stage->next->flush( stage->next, flags );
-   stage->draw->extra_shader_outputs.slot = 0;
+
+   draw_remove_extra_vertex_attribs(draw);
 
    /* restore original rasterizer state */
    if (draw->rast_handle) {
index 362f563ba6a75ad8cf474db08353f35e8dee201c..d417f825a0f50bac346f912c5d7a19f1e6f705bf 100644 (file)
@@ -250,6 +250,11 @@ struct draw_context
       struct tgsi_sampler **samplers;
    } gs;
 
+   /** Fragment shader state */
+   struct {
+      struct draw_fragment_shader *fragment_shader;
+   } fs;
+
    /** Stream output (vertex feedback) state */
    struct {
       struct pipe_stream_output_state state;
@@ -266,9 +271,10 @@ struct draw_context
    /* If a prim stage introduces new vertex attributes, they'll be stored here
     */
    struct {
-      uint semantic_name;
-      uint semantic_index;
-      int slot;
+      uint num;
+      uint semantic_name[10];
+      uint semantic_index[10];
+      uint slot[10];
    } extra_shader_outputs;
 
    unsigned reduced_prim;
@@ -362,6 +368,11 @@ void draw_gs_destroy( struct draw_context *draw );
 uint draw_current_shader_outputs(const struct draw_context *draw);
 uint draw_current_shader_position_output(const struct draw_context *draw);
 
+int draw_alloc_extra_vertex_attrib(struct draw_context *draw,
+                                   uint semantic_name, uint semantic_index);
+void draw_remove_extra_vertex_attribs(struct draw_context *draw);
+
+
 /*******************************************************************************
  * Vertex processing (was passthrough) code:
  */
index 39d204de8a92988f5eca7e3bc5d48e7ce1ba680c..c5d61f840f20dc6e279960e3e75deb991dc1068b 100644 (file)
@@ -70,6 +70,8 @@ struct sp_fragment_shader {
 
    struct tgsi_shader_info info;
 
+   struct draw_fragment_shader *draw_shader;
+
    boolean origin_lower_left; /**< fragment shader uses lower left position origin? */
    boolean pixel_center_integer; /**< fragment shader uses integer pixel center? */
 
index ded242d3dc54219b145faabdc920a6b73d4e6c21..50bc2eea5ffc0a2f930fe76e14d0f8fabbd9615e 100644 (file)
@@ -60,7 +60,15 @@ softpipe_create_fs_state(struct pipe_context *pipe,
       state = softpipe_create_fs_exec( softpipe, templ );
    }
 
-   assert(state);
+   if (!state)
+      return NULL;
+
+   /* draw's fs state */
+   state->draw_shader = draw_create_fragment_shader(softpipe->draw, templ);
+   if (!state->draw_shader) {
+      state->delete( state );
+      return NULL;
+   }
 
    /* get/save the summary info for this shader */
    tgsi_scan_shader(templ->tokens, &state->info);
@@ -90,6 +98,9 @@ softpipe_bind_fs_state(struct pipe_context *pipe, void *fs)
 
    softpipe->fs = fs;
 
+   draw_bind_fragment_shader(softpipe->draw,
+                             (softpipe->fs ? softpipe->fs->draw_shader : NULL));
+
    softpipe->dirty |= SP_NEW_FS;
 }
 
@@ -109,6 +120,8 @@ softpipe_delete_fs_state(struct pipe_context *pipe, void *fs)
       tgsi_exec_machine_bind_shader(softpipe->fs_machine, NULL, 0, NULL);
    }
 
+   draw_delete_fragment_shader(softpipe->draw, state->draw_shader);
+
    state->delete( state );
 }
 
index 2599bd5ca0339b6b9a81608b0c8782a60cc4e158..0fe333ae8aa2072dae9a56a73c110d9bcc3f350e 100644 (file)
@@ -60,6 +60,7 @@ static void update_raster_state( struct st_context *st )
    GLcontext *ctx = st->ctx;
    struct pipe_rasterizer_state *raster = &st->state.rasterizer;
    const struct gl_vertex_program *vertProg = ctx->VertexProgram._Current;
+   const struct gl_fragment_program *fragProg = ctx->FragmentProgram._Current;
    uint i;
 
    memset(raster, 0, sizeof(*raster));
@@ -175,17 +176,30 @@ static void update_raster_state( struct st_context *st )
    if (!ctx->Point.PointSprite && ctx->Point.SmoothFlag)
       raster->point_smooth = 1;
 
+   /* _NEW_POINT | _NEW_PROGRAM
+    */
    if (ctx->Point.PointSprite) {
+      /* origin */
       if ((ctx->Point.SpriteOrigin == GL_UPPER_LEFT) ^
           (st_fb_orientation(ctx->DrawBuffer) == Y_0_BOTTOM))
          raster->sprite_coord_mode = PIPE_SPRITE_COORD_UPPER_LEFT;
       else 
          raster->sprite_coord_mode = PIPE_SPRITE_COORD_LOWER_LEFT;
+
+      /* Coord replacement flags.  If bit 'k' is set that means
+       * that we need to replace GENERIC[k] attrib with an automatically
+       * computed texture coord.
+       */
       for (i = 0; i < MAX_TEXTURE_COORD_UNITS; i++) {
          if (ctx->Point.CoordReplace[i]) {
             raster->sprite_coord_enable |= 1 << i;
          }
       }
+      if (fragProg->Base.InputsRead & FRAG_BIT_PNTC) {
+         raster->sprite_coord_enable |=
+            1 << (FRAG_ATTRIB_PNTC - FRAG_ATTRIB_TEX0);
+      }
+
       raster->point_quad_rasterization = 1;
    }
 
index 8c2d8b6154bbef7f5f68f9e0ce2e1a57933fa141..18a7bbe0f9065643162b08f713fa96d282e97a83 100644 (file)
@@ -338,17 +338,6 @@ st_translate_fragment_program(struct st_context *st,
             input_semantic_index[slot] = 0;
             interpMode[slot] = TGSI_INTERPOLATE_CONSTANT;
             break;
-         case FRAG_ATTRIB_PNTC:
-            /* This is a hack.  We really need a new semantic label for
-             * point coord.  The draw module needs to know which fragment
-             * shader input is the point coord attribute so that it can set
-             * up the right vertex attribute values.
-             */
-            input_semantic_name[slot] = TGSI_SEMANTIC_GENERIC;
-            input_semantic_index[slot] = 0;
-            interpMode[slot] = TGSI_INTERPOLATE_PERSPECTIVE;
-            break;
-
             /* In most cases, there is nothing special about these
              * inputs, so adopt a convention to use the generic
              * semantic name and the mesa FRAG_ATTRIB_ number as the
@@ -364,6 +353,7 @@ st_translate_fragment_program(struct st_context *st,
              * zero or be restricted to a particular range -- nobody
              * should be building tables based on semantic index.
              */
+         case FRAG_ATTRIB_PNTC:
          case FRAG_ATTRIB_TEX0:
          case FRAG_ATTRIB_TEX1:
          case FRAG_ATTRIB_TEX2:
@@ -380,7 +370,10 @@ st_translate_fragment_program(struct st_context *st,
             assert(attr >= FRAG_ATTRIB_TEX0);
             input_semantic_index[slot] = (attr - FRAG_ATTRIB_TEX0);
             input_semantic_name[slot] = TGSI_SEMANTIC_GENERIC;
-            interpMode[slot] = TGSI_INTERPOLATE_PERSPECTIVE;
+            if (attr == FRAG_ATTRIB_PNTC)
+               interpMode[slot] = TGSI_INTERPOLATE_LINEAR;
+            else
+               interpMode[slot] = TGSI_INTERPOLATE_PERSPECTIVE;
             break;
          }
       }