Merge branch 'gallium-polygon-stipple'
authorBrian Paul <brianp@vmware.com>
Thu, 21 Jul 2011 16:38:21 +0000 (10:38 -0600)
committerBrian Paul <brianp@vmware.com>
Thu, 21 Jul 2011 16:38:21 +0000 (10:38 -0600)
19 files changed:
src/gallium/auxiliary/tgsi/tgsi_scan.c
src/gallium/auxiliary/tgsi/tgsi_scan.h
src/gallium/auxiliary/util/u_pstipple.c
src/gallium/drivers/softpipe/sp_clear.c
src/gallium/drivers/softpipe/sp_context.c
src/gallium/drivers/softpipe/sp_context.h
src/gallium/drivers/softpipe/sp_draw_arrays.c
src/gallium/drivers/softpipe/sp_fs.h
src/gallium/drivers/softpipe/sp_fs_exec.c
src/gallium/drivers/softpipe/sp_fs_sse.c
src/gallium/drivers/softpipe/sp_quad_blend.c
src/gallium/drivers/softpipe/sp_quad_depth_test.c
src/gallium/drivers/softpipe/sp_quad_fs.c
src/gallium/drivers/softpipe/sp_quad_pipe.c
src/gallium/drivers/softpipe/sp_setup.c
src/gallium/drivers/softpipe/sp_state.h
src/gallium/drivers/softpipe/sp_state_derived.c
src/gallium/drivers/softpipe/sp_state_sampler.c
src/gallium/drivers/softpipe/sp_state_shader.c

index 83c6ac75e54c701533f331bc67f6b1ac85bd613f..f165f8240e652aeef70c1199cbab2aef2100bbcd 100644 (file)
@@ -200,19 +200,20 @@ tgsi_scan_shader(const struct tgsi_token *tokens,
             info->file_max[file] = MAX2(info->file_max[file], (int)reg);
          }
          break;
+
       case TGSI_TOKEN_TYPE_PROPERTY:
-      {
-         const struct tgsi_full_property *fullprop
-            = &parse.FullToken.FullProperty;
+         {
+            const struct tgsi_full_property *fullprop
+               = &parse.FullToken.FullProperty;
 
-         info->properties[info->num_properties].name =
-            fullprop->Property.PropertyName;
-         memcpy(info->properties[info->num_properties].data,
-                fullprop->u, 8 * sizeof(unsigned));;
+            info->properties[info->num_properties].name =
+               fullprop->Property.PropertyName;
+            memcpy(info->properties[info->num_properties].data,
+                   fullprop->u, 8 * sizeof(unsigned));;
 
-         ++info->num_properties;
-      }
-      break;
+            ++info->num_properties;
+         }
+         break;
 
       default:
          assert( 0 );
@@ -222,6 +223,23 @@ tgsi_scan_shader(const struct tgsi_token *tokens,
    info->uses_kill = (info->opcode_count[TGSI_OPCODE_KIL] ||
                       info->opcode_count[TGSI_OPCODE_KILP]);
 
+   /* extract simple properties */
+   for (i = 0; i < info->num_properties; ++i) {
+      switch (info->properties[i].name) {
+      case TGSI_PROPERTY_FS_COORD_ORIGIN:
+         info->origin_lower_left = info->properties[i].data[0];
+         break;
+      case TGSI_PROPERTY_FS_COORD_PIXEL_CENTER:
+         info->pixel_center_integer = info->properties[i].data[0];
+         break;
+      case TGSI_PROPERTY_FS_COLOR0_WRITES_ALL_CBUFS:
+         info->color0_writes_all_cbufs = info->properties[i].data[0];
+         break;
+      default:
+         ;
+      }
+   }
+
    tgsi_parse_free (&parse);
 }
 
index 53ab3d509dd300f83e6ba87100215a467e83d23a..d6e593b3968de26d6be41a2b2f7e92256eae91cc 100644 (file)
@@ -68,6 +68,9 @@ struct tgsi_shader_info
    boolean writes_edgeflag; /**< vertex shader outputs edgeflag */
    boolean uses_kill;  /**< KIL or KILP instruction used? */
    boolean uses_instanceid;
+   boolean origin_lower_left;
+   boolean pixel_center_integer;
+   boolean color0_writes_all_cbufs;
 
    /**
     * Bitmask indicating which register files are accessed with
index f79a6938d1d48ee7e9c4112d8dd74f12c693551b..ac0df8c1a9c8df09cccd17c5202e1a9287e58199 100644 (file)
@@ -52,6 +52,7 @@
 
 #include "tgsi/tgsi_transform.h"
 #include "tgsi/tgsi_dump.h"
+#include "tgsi/tgsi_scan.h"
 
 /** Approx number of new tokens for instructions in pstip_transform_inst() */
 #define NUM_NEW_TOKENS 50
@@ -175,6 +176,7 @@ util_pstipple_create_sampler(struct pipe_context *pipe)
  */
 struct pstip_transform_context {
    struct tgsi_transform_context base;
+   struct tgsi_shader_info info;
    uint tempsUsed;  /**< bitmask */
    int wincoordInput;
    int maxInput;
@@ -183,12 +185,13 @@ struct pstip_transform_context {
    int texTemp;  /**< temp registers */
    int numImmed;
    boolean firstInstruction;
+   uint coordOrigin;
 };
 
 
 /**
  * TGSI declaration transform callback.
- * Look for a free sampler, a free input attrib, and two free temp regs.
+ * Track samplers used, temps used, inputs used.
  */
 static void
 pstip_transform_decl(struct tgsi_transform_context *ctx,
@@ -197,10 +200,11 @@ pstip_transform_decl(struct tgsi_transform_context *ctx,
    struct pstip_transform_context *pctx =
       (struct pstip_transform_context *) ctx;
 
+   /* XXX we can use tgsi_shader_info instead of some of this */
+
    if (decl->Declaration.File == TGSI_FILE_SAMPLER) {
       uint i;
-      for (i = decl->Range.First;
-           i <= decl->Range.Last; i++) {
+      for (i = decl->Range.First; i <= decl->Range.Last; i++) {
          pctx->samplersUsed |= 1 << i;
       }
    }
@@ -211,8 +215,7 @@ pstip_transform_decl(struct tgsi_transform_context *ctx,
    }
    else if (decl->Declaration.File == TGSI_FILE_TEMPORARY) {
       uint i;
-      for (i = decl->Range.First;
-           i <= decl->Range.Last; i++) {
+      for (i = decl->Range.First; i <= decl->Range.Last; i++) {
          pctx->tempsUsed |= (1 << i);
       }
    }
@@ -243,8 +246,16 @@ free_bit(uint bitfield)
 
 /**
  * TGSI instruction transform callback.
- * Replace writes to result.color w/ a temp reg.
- * Upon END instruction, insert texture sampling code for antialiasing.
+ * Before the first instruction, insert our new code to sample the
+ * stipple texture (using the fragment coord register) then kill the
+ * fragment if the stipple texture bit is off.
+ *
+ * Insert:
+ *   declare new registers
+ *   MUL texTemp, INPUT[wincoord], 1/32;
+ *   TEX texTemp, texTemp, sampler;
+ *   KIL -texTemp;   # if -texTemp < 0, KILL fragment
+ *   [...original code...]
  */
 static void
 pstip_transform_inst(struct tgsi_transform_context *ctx,
@@ -261,7 +272,7 @@ pstip_transform_inst(struct tgsi_transform_context *ctx,
       uint i;
       int wincoordInput;
 
-      /* find free sampler */
+      /* find free texture sampler */
       pctx->freeSampler = free_bit(pctx->samplersUsed);
       if (pctx->freeSampler >= PIPE_MAX_SAMPLERS)
          pctx->freeSampler = PIPE_MAX_SAMPLERS - 1;
@@ -271,7 +282,7 @@ pstip_transform_inst(struct tgsi_transform_context *ctx,
       else
          wincoordInput = pctx->wincoordInput;
 
-      /* find one free temp reg */
+      /* find one free temp register */
       for (i = 0; i < 32; i++) {
          if ((pctx->tempsUsed & (1 << i)) == 0) {
             /* found a free temp */
@@ -397,6 +408,7 @@ util_pstipple_create_fragment_shader(struct pipe_context *pipe,
    struct pipe_shader_state *new_fs;
    struct pstip_transform_context transform;
    const uint newLen = tgsi_num_tokens(fs->tokens) + NUM_NEW_TOKENS;
+   unsigned i;
 
    new_fs = MALLOC(sizeof(*new_fs));
    if (!new_fs)
@@ -408,22 +420,33 @@ util_pstipple_create_fragment_shader(struct pipe_context *pipe,
       return NULL;
    }
 
+   /* Setup shader transformation info/context.
+    */
    memset(&transform, 0, sizeof(transform));
    transform.wincoordInput = -1;
    transform.maxInput = -1;
    transform.texTemp = -1;
    transform.firstInstruction = TRUE;
+   transform.coordOrigin = TGSI_FS_COORD_ORIGIN_UPPER_LEFT;
    transform.base.transform_instruction = pstip_transform_inst;
    transform.base.transform_declaration = pstip_transform_decl;
    transform.base.transform_immediate = pstip_transform_immed;
 
+   tgsi_scan_shader(fs->tokens, &transform.info);
+
+   /* find fragment coordinate origin property */
+   for (i = 0; i < transform.info.num_properties; i++) {
+      if (transform.info.properties[i].name == TGSI_PROPERTY_FS_COORD_ORIGIN)
+         transform.coordOrigin = transform.info.properties[i].data[0];
+   }
+
    tgsi_transform_shader(fs->tokens,
                          (struct tgsi_token *) new_fs->tokens,
                          newLen, &transform.base);
 
 #if 0 /* DEBUG */
    tgsi_dump(fs->tokens, 0);
-   tgsi_dump(pstip_fs.tokens, 0);
+   tgsi_dump(new_fs->tokens, 0);
 #endif
 
    assert(transform.freeSampler < PIPE_MAX_SAMPLERS);
index ae3f00f33874e5c5ab29c79836f53e9072d88389..22e8a2e58170dbc641158ca62c652606d93fb7b2 100644 (file)
@@ -60,7 +60,7 @@ softpipe_clear(struct pipe_context *pipe, unsigned buffers, const float *rgba,
       return;
 
 #if 0
-   softpipe_update_derived(softpipe); /* not needed?? */
+   softpipe_update_derived(softpipe, PIPE_PRIM_TRIANGLES); /* not needed?? */
 #endif
 
    if (buffers & PIPE_CLEAR_COLOR) {
index 2c43602ea1ca5d5ec1bca8212ae3c9b9c2f52128..c97b0333035c9e1899c6143bb3a62dc4dd2ded8d 100644 (file)
@@ -35,6 +35,7 @@
 #include "pipe/p_defines.h"
 #include "util/u_math.h"
 #include "util/u_memory.h"
+#include "util/u_pstipple.h"
 #include "util/u_inlines.h"
 #include "tgsi/tgsi_exec.h"
 #include "vl/vl_decoder.h"
@@ -90,6 +91,14 @@ softpipe_destroy( struct pipe_context *pipe )
    struct softpipe_context *softpipe = softpipe_context( pipe );
    uint i;
 
+#if DO_PSTIPPLE_IN_HELPER_MODULE
+   if (softpipe->pstipple.sampler)
+      pipe->delete_sampler_state(pipe, softpipe->pstipple.sampler);
+
+   pipe_resource_reference(&softpipe->pstipple.texture, NULL);
+   pipe_sampler_view_reference(&softpipe->pstipple.sampler_view, NULL);
+#endif
+
    if (softpipe->draw)
       draw_destroy( softpipe->draw );
 
@@ -346,6 +355,11 @@ softpipe_create_context( struct pipe_screen *screen,
 
    sp_init_surface_functions(softpipe);
 
+#if DO_PSTIPPLE_IN_HELPER_MODULE
+   /* create the polgon stipple sampler */
+   softpipe->pstipple.sampler = util_pstipple_create_sampler(&softpipe->pipe);
+#endif
+
    return &softpipe->pipe;
 
  fail:
index a572ee8cf0020c99dbc4f330e5c83dd4908a9f7e..410b0a65792734cbb0f2be91fb6a5150f6498e11 100644 (file)
 #include "sp_quad_pipe.h"
 
 
-/** Do polygon stipple in the driver here, or in the draw module? */
-#define DO_PSTIPPLE_IN_DRAW_MODULE 1
+/** Do polygon stipple in the draw module? */
+#define DO_PSTIPPLE_IN_DRAW_MODULE 0
+
+/** Do polygon stipple with the util module? */
+#define DO_PSTIPPLE_IN_HELPER_MODULE 1
 
 
 struct softpipe_vbuf_render;
@@ -64,6 +67,7 @@ struct softpipe_context {
    struct pipe_depth_stencil_alpha_state *depth_stencil;
    struct pipe_rasterizer_state *rasterizer;
    struct sp_fragment_shader *fs;
+   struct sp_fragment_shader_variant *fs_variant;
    struct sp_vertex_shader *vs;
    struct sp_geometry_shader *gs;
    struct sp_velems_state *velems;
@@ -143,6 +147,13 @@ struct softpipe_context {
    struct pipe_query *render_cond_query;
    uint render_cond_mode;
 
+   /** Polygon stipple items */
+   struct {
+      struct pipe_resource *texture;
+      struct pipe_sampler_state *sampler;
+      struct pipe_sampler_view *sampler_view;
+   } pstipple;
+
    /** Software quad rendering pipeline */
    struct {
       struct quad_stage *shade;
index 01b4ca985d0ea8cbdb212cc2619df3c060f32654..69b5b96b4fd0b6268292ad23c094349cc36218b5 100644 (file)
@@ -64,7 +64,7 @@ softpipe_draw_stream_output(struct pipe_context *pipe, unsigned mode)
    sp->reduced_api_prim = u_reduced_prim(mode);
 
    if (sp->dirty) {
-      softpipe_update_derived(sp);
+      softpipe_update_derived(sp, sp->reduced_api_prim);
    }
 
    softpipe_map_transfers(sp);
@@ -122,7 +122,7 @@ softpipe_draw_vbo(struct pipe_context *pipe,
    sp->reduced_api_prim = u_reduced_prim(info->mode);
 
    if (sp->dirty) {
-      softpipe_update_derived(sp);
+      softpipe_update_derived(sp, sp->reduced_api_prim);
    }
 
    softpipe_map_transfers(sp);
index 4792ace3a3389627d5006f1004e3e1e7792a737d..d46d7d5a65782b4b678e277459e13fa8789411bf 100644 (file)
 #ifndef SP_FS_H
 #define SP_FS_H
 
-struct sp_fragment_shader *
-softpipe_create_fs_exec(struct softpipe_context *softpipe,
-                      const struct pipe_shader_state *templ);
 
-struct sp_fragment_shader *
-softpipe_create_fs_sse(struct softpipe_context *softpipe,
-                      const struct pipe_shader_state *templ);
+struct sp_fragment_shader_variant *
+softpipe_create_fs_variant_exec(struct softpipe_context *softpipe,
+                                const struct pipe_shader_state *templ);
+
+struct sp_fragment_shader_variant *
+softpipe_create_fs_variant_sse(struct softpipe_context *softpipe,
+                               const struct pipe_shader_state *templ);
 
-struct sp_fragment_shader *
-softpipe_create_fs_llvm(struct softpipe_context *softpipe,
-                       const struct pipe_shader_state *templ);
 
 struct tgsi_interp_coef;
 struct tgsi_exec_vector;
index 346e1b402baba023916102fdc59789429216e3ab..779b8c4995c98e1a9a3a18af5f08dab025718879 100644 (file)
 
 
 /**
- * Subclass of sp_fragment_shader
+ * Subclass of sp_fragment_shader_variant
  */
 struct sp_exec_fragment_shader
 {
-   struct sp_fragment_shader base;
+   struct sp_fragment_shader_variant base;
    /* No other members for now */
 };
 
 
 /** cast wrapper */
 static INLINE struct sp_exec_fragment_shader *
-sp_exec_fragment_shader(const struct sp_fragment_shader *base)
+sp_exec_fragment_shader(const struct sp_fragment_shader_variant *var)
 {
-   return (struct sp_exec_fragment_shader *) base;
+   return (struct sp_exec_fragment_shader *) var;
 }
 
 
 static void
-exec_prepare( const struct sp_fragment_shader *base,
+exec_prepare( const struct sp_fragment_shader_variant *var,
              struct tgsi_exec_machine *machine,
              struct tgsi_sampler **samplers )
 {
@@ -68,9 +68,9 @@ exec_prepare( const struct sp_fragment_shader *base,
     * Bind tokens/shader to the interpreter's machine state.
     * Avoid redundant binding.
     */
-   if (machine->Tokens != base->shader.tokens) {
+   if (machine->Tokens != var->tokens) {
       tgsi_exec_machine_bind_shader( machine,
-                                     base->shader.tokens,
+                                     var->tokens,
                                      PIPE_MAX_SAMPLERS,
                                      samplers );
    }
@@ -118,7 +118,7 @@ setup_pos_vector(const struct tgsi_interp_coef *coef,
  * interface:
  */
 static unsigned 
-exec_run( const struct sp_fragment_shader *base,
+exec_run( const struct sp_fragment_shader_variant *var,
          struct tgsi_exec_machine *machine,
          struct quad_header *quad )
 {
@@ -136,9 +136,9 @@ exec_run( const struct sp_fragment_shader *base,
 
    /* store outputs */
    {
-      const ubyte *sem_name = base->info.output_semantic_name;
-      const ubyte *sem_index = base->info.output_semantic_index;
-      const uint n = base->info.num_outputs;
+      const ubyte *sem_name = var->info.output_semantic_name;
+      const ubyte *sem_index = var->info.output_semantic_index;
+      const uint n = var->info.num_outputs;
       uint i;
       for (i = 0; i < n; i++) {
          switch (sem_name[i]) {
@@ -180,29 +180,23 @@ exec_run( const struct sp_fragment_shader *base,
 
 
 static void 
-exec_delete( struct sp_fragment_shader *base )
+exec_delete( struct sp_fragment_shader_variant *var )
 {
-   FREE((void *) base->shader.tokens);
-   FREE(base);
+   FREE( (void *) var->tokens );
+   FREE(var);
 }
 
 
-struct sp_fragment_shader *
-softpipe_create_fs_exec(struct softpipe_context *softpipe,
-                       const struct pipe_shader_state *templ)
+struct sp_fragment_shader_variant *
+softpipe_create_fs_variant_exec(struct softpipe_context *softpipe,
+                                const struct pipe_shader_state *templ)
 {
    struct sp_exec_fragment_shader *shader;
 
-   /* Decide whether we'll be codegenerating this shader and if so do
-    * that now.
-    */
-
    shader = CALLOC_STRUCT(sp_exec_fragment_shader);
    if (!shader)
       return NULL;
 
-   /* we need to keep a local copy of the tokens */
-   shader->base.shader.tokens = tgsi_dup_tokens(templ->tokens);
    shader->base.prepare = exec_prepare;
    shader->base.run = exec_run;
    shader->base.delete = exec_delete;
index 5b18cd035e36f35211b8af04cf6bcf82bd5f71af..c873af125bd94c1d9a32d97df7c87d1f3cf240a7 100644 (file)
 
 
 /**
- * Subclass of sp_fragment_shader
+ * Subclass of sp_fragment_shader_variant
  */
 struct sp_sse_fragment_shader
 {
-   struct sp_fragment_shader base;
+   struct sp_fragment_shader_variant base;
    struct x86_function sse2_program;
    tgsi_sse2_fs_function func;
    float immediates[TGSI_EXEC_NUM_IMMEDIATES][4];
@@ -61,14 +61,14 @@ struct sp_sse_fragment_shader
 
 /** cast wrapper */
 static INLINE struct sp_sse_fragment_shader *
-sp_sse_fragment_shader(const struct sp_fragment_shader *base)
+sp_sse_fragment_shader(const struct sp_fragment_shader_variant *base)
 {
    return (struct sp_sse_fragment_shader *) base;
 }
 
 
 static void
-fs_sse_prepare( const struct sp_fragment_shader *base,
+fs_sse_prepare( const struct sp_fragment_shader_variant *base,
                struct tgsi_exec_machine *machine,
                struct tgsi_sampler **samplers )
 {
@@ -119,7 +119,7 @@ setup_pos_vector(const struct tgsi_interp_coef *coef,
  * TODO: process >1 quad at a time
  */
 static unsigned 
-fs_sse_run( const struct sp_fragment_shader *base,
+fs_sse_run( const struct sp_fragment_shader_variant *base,
            struct tgsi_exec_machine *machine,
            struct quad_header *quad )
 {
@@ -189,7 +189,7 @@ fs_sse_run( const struct sp_fragment_shader *base,
 
 
 static void 
-fs_sse_delete( struct sp_fragment_shader *base )
+fs_sse_delete( struct sp_fragment_shader_variant *base )
 {
    struct sp_sse_fragment_shader *shader = sp_sse_fragment_shader(base);
 
@@ -198,9 +198,9 @@ fs_sse_delete( struct sp_fragment_shader *base )
 }
 
 
-struct sp_fragment_shader *
-softpipe_create_fs_sse(struct softpipe_context *softpipe,
-                      const struct pipe_shader_state *templ)
+struct sp_fragment_shader_variant *
+softpipe_create_fs_variant_sse(struct softpipe_context *softpipe,
+                               const struct pipe_shader_state *templ)
 {
    struct sp_sse_fragment_shader *shader;
 
@@ -226,7 +226,6 @@ softpipe_create_fs_sse(struct softpipe_context *softpipe,
       return NULL;
    }
 
-   shader->base.shader.tokens = NULL; /* don't hold reference to templ->tokens */
    shader->base.prepare = fs_sse_prepare;
    shader->base.run = fs_sse_run;
    shader->base.delete = fs_sse_delete;
@@ -239,9 +238,9 @@ softpipe_create_fs_sse(struct softpipe_context *softpipe,
 
 /* Maybe put this variant in the header file.
  */
-struct sp_fragment_shader *
-softpipe_create_fs_sse(struct softpipe_context *softpipe,
-                      const struct pipe_shader_state *templ)
+struct sp_fragment_shader_variant *
+softpipe_create_fs_variant_sse(struct softpipe_context *softpipe,
+                               const struct pipe_shader_state *templ)
 {
    return NULL;
 }
index 76cfc0bf51c904295e54369ce1f00fd303fcf570..04bfd14b7c6dbbad58de83ce38fa1bbc6f287e6c 100644 (file)
@@ -797,7 +797,7 @@ blend_fallback(struct quad_stage *qs,
    unsigned cbuf;
    boolean write_all;
 
-   write_all = softpipe->fs->color0_writes_all_cbufs;
+   write_all = softpipe->fs_variant->info.color0_writes_all_cbufs;
 
    for (cbuf = 0; cbuf < softpipe->framebuffer.nr_cbufs; cbuf++) 
    {
index 15f3a8fd813903fb74416c21bfb361b32b9a2c9c..a349f0d1f3c9e5a2c937967d661bcd248d67760b 100644 (file)
@@ -727,9 +727,9 @@ depth_test_quads_fallback(struct quad_stage *qs,
                           unsigned nr)
 {
    unsigned i, pass = 0;
-   const struct sp_fragment_shader *fs = qs->softpipe->fs;
-   boolean interp_depth = !fs->info.writes_z;
-   boolean shader_stencil_ref = fs->info.writes_stencil;
+   const struct tgsi_shader_info *fsInfo = &qs->softpipe->fs_variant->info;
+   boolean interp_depth = !fsInfo->writes_z;
+   boolean shader_stencil_ref = fsInfo->writes_stencil;
    struct depth_data data;
 
    data.use_shader_stencil_refs = FALSE;
@@ -838,7 +838,9 @@ choose_depth_test(struct quad_stage *qs,
                   struct quad_header *quads[],
                   unsigned nr)
 {
-   boolean interp_depth = !qs->softpipe->fs->info.writes_z;
+   const struct tgsi_shader_info *fsInfo = &qs->softpipe->fs_variant->info;
+
+   boolean interp_depth = !fsInfo->writes_z;
 
    boolean alpha = qs->softpipe->depth_stencil->alpha.enabled;
 
index 90f4787d59952d786822b7533ff8115602e4b6b8..d74d6d4914e90210874fe54cfc408e17be6bcb8b 100644 (file)
@@ -74,7 +74,7 @@ shade_quad(struct quad_stage *qs, struct quad_header *quad)
    struct tgsi_exec_machine *machine = softpipe->fs_machine;
 
    /* run shader */
-   return softpipe->fs->run( softpipe->fs, machine, quad );
+   return softpipe->fs_variant->run( softpipe->fs_variant, machine, quad );
 }
 
 
@@ -140,10 +140,10 @@ shade_begin(struct quad_stage *qs)
 {
    struct softpipe_context *softpipe = qs->softpipe;
 
-   softpipe->fs->prepare( softpipe->fs
-                         softpipe->fs_machine,
-                         (struct tgsi_sampler **)
-                             softpipe->tgsi.frag_samplers_list );
+   softpipe->fs_variant->prepare( softpipe->fs_variant
+                                  softpipe->fs_machine,
+                                  (struct tgsi_sampler **)
+                                  softpipe->tgsi.frag_samplers_list );
 
    qs->next->begin(qs->next);
 }
index 2cfd02a22c6019e982e1cb345cc89e61f8e3b31b..0c4506ae8f4b3c3690b819c9f1cb8595d1bbec22 100644 (file)
@@ -30,9 +30,9 @@
 #include "sp_state.h"
 #include "pipe/p_shader_tokens.h"
 
+
 static void
-sp_push_quad_first( struct softpipe_context *sp,
-                    struct quad_stage *quad )
+insert_stage_at_head(struct softpipe_context *sp, struct quad_stage *quad)
 {
    quad->next = sp->quad.first;
    sp->quad.first = quad;
@@ -46,24 +46,24 @@ sp_build_quad_pipeline(struct softpipe_context *sp)
       sp->depth_stencil->depth.enabled &&
       sp->framebuffer.zsbuf &&
       !sp->depth_stencil->alpha.enabled &&
-      !sp->fs->info.uses_kill &&
-      !sp->fs->info.writes_z &&
-      !sp->fs->info.writes_stencil;
+      !sp->fs_variant->info.uses_kill &&
+      !sp->fs_variant->info.writes_z &&
+      !sp->fs_variant->info.writes_stencil;
 
    sp->quad.first = sp->quad.blend;
 
    if (early_depth_test) {
-      sp_push_quad_first( sp, sp->quad.shade );
-      sp_push_quad_first( sp, sp->quad.depth_test );
+      insert_stage_at_head( sp, sp->quad.shade );
+      insert_stage_at_head( sp, sp->quad.depth_test );
    }
    else {
-      sp_push_quad_first( sp, sp->quad.depth_test );
-      sp_push_quad_first( sp, sp->quad.shade );
+      insert_stage_at_head( sp, sp->quad.depth_test );
+      insert_stage_at_head( sp, sp->quad.shade );
    }
 
-#if !DO_PSTIPPLE_IN_DRAW_MODULE
+#if !DO_PSTIPPLE_IN_DRAW_MODULE && !DO_PSTIPPLE_IN_HELPER_MODULE
    if (sp->rasterizer->poly_stipple_enable)
-      sp_push_quad_first( sp, sp->quad.pstipple );
+      insert_stage_at_head( sp, sp->quad.pstipple );
 #endif
 }
 
index 0ce28f4c6ee09d070b8f15f43b26e49165fd0b79..656d001809fa2789dbb9957b77f1b6b0f3c63037 100644 (file)
@@ -568,17 +568,18 @@ tri_persp_coeff(struct setup_context *setup,
 static void
 setup_fragcoord_coeff(struct setup_context *setup, uint slot)
 {
-   struct sp_fragment_shader* spfs = setup->softpipe->fs;
+   const struct tgsi_shader_info *fsInfo = &setup->softpipe->fs_variant->info;
+
    /*X*/
-   setup->coef[slot].a0[0] = spfs->pixel_center_integer ? 0.0 : 0.5;
+   setup->coef[slot].a0[0] = fsInfo->pixel_center_integer ? 0.0 : 0.5;
    setup->coef[slot].dadx[0] = 1.0;
    setup->coef[slot].dady[0] = 0.0;
    /*Y*/
    setup->coef[slot].a0[1] =
-                  (spfs->origin_lower_left ? setup->softpipe->framebuffer.height-1 : 0)
-                  + (spfs->pixel_center_integer ? 0.0 : 0.5);
+                  (fsInfo->origin_lower_left ? setup->softpipe->framebuffer.height-1 : 0)
+                  + (fsInfo->pixel_center_integer ? 0.0 : 0.5);
    setup->coef[slot].dadx[1] = 0.0;
-   setup->coef[slot].dady[1] = spfs->origin_lower_left ? -1.0 : 1.0;
+   setup->coef[slot].dady[1] = fsInfo->origin_lower_left ? -1.0 : 1.0;
    /*Z*/
    setup->coef[slot].a0[2] = setup->posCoef.a0[2];
    setup->coef[slot].dadx[2] = setup->posCoef.dadx[2];
@@ -599,7 +600,7 @@ static void
 setup_tri_coefficients(struct setup_context *setup)
 {
    struct softpipe_context *softpipe = setup->softpipe;
-   const struct sp_fragment_shader *spfs = softpipe->fs;
+   const struct tgsi_shader_info *fsInfo = &setup->softpipe->fs_variant->info;
    const struct vertex_info *vinfo = softpipe_get_vertex_info(softpipe);
    uint fragSlot;
    float v[3];
@@ -618,7 +619,7 @@ setup_tri_coefficients(struct setup_context *setup)
 
    /* setup interpolation for all the remaining attributes:
     */
-   for (fragSlot = 0; fragSlot < spfs->info.num_inputs; fragSlot++) {
+   for (fragSlot = 0; fragSlot < fsInfo->num_inputs; fragSlot++) {
       const uint vertSlot = vinfo->attrib[fragSlot].src_index;
       uint j;
 
@@ -632,7 +633,7 @@ setup_tri_coefficients(struct setup_context *setup)
             tri_apply_cylindrical_wrap(setup->vmin[vertSlot][j],
                                        setup->vmid[vertSlot][j],
                                        setup->vmax[vertSlot][j],
-                                       spfs->info.input_cylindrical_wrap[fragSlot] & (1 << j),
+                                       fsInfo->input_cylindrical_wrap[fragSlot] & (1 << j),
                                        v);
             tri_linear_coeff(setup, &setup->coef[fragSlot], j, v);
          }
@@ -642,7 +643,7 @@ setup_tri_coefficients(struct setup_context *setup)
             tri_apply_cylindrical_wrap(setup->vmin[vertSlot][j],
                                        setup->vmid[vertSlot][j],
                                        setup->vmax[vertSlot][j],
-                                       spfs->info.input_cylindrical_wrap[fragSlot] & (1 << j),
+                                       fsInfo->input_cylindrical_wrap[fragSlot] & (1 << j),
                                        v);
             tri_persp_coeff(setup, &setup->coef[fragSlot], j, v);
          }
@@ -654,7 +655,7 @@ setup_tri_coefficients(struct setup_context *setup)
          assert(0);
       }
 
-      if (spfs->info.input_semantic_name[fragSlot] == TGSI_SEMANTIC_FACE) {
+      if (fsInfo->input_semantic_name[fragSlot] == TGSI_SEMANTIC_FACE) {
          /* convert 0 to 1.0 and 1 to -1.0 */
          setup->coef[fragSlot].a0[0] = setup->facing * -2.0f + 1.0f;
          setup->coef[fragSlot].dadx[0] = 0.0;
@@ -939,7 +940,7 @@ setup_line_coefficients(struct setup_context *setup,
                         const float (*v1)[4])
 {
    struct softpipe_context *softpipe = setup->softpipe;
-   const struct sp_fragment_shader *spfs = softpipe->fs;
+   const struct tgsi_shader_info *fsInfo = &setup->softpipe->fs_variant->info;
    const struct vertex_info *vinfo = softpipe_get_vertex_info(softpipe);
    uint fragSlot;
    float area;
@@ -974,7 +975,7 @@ setup_line_coefficients(struct setup_context *setup,
 
    /* setup interpolation for all the remaining attributes:
     */
-   for (fragSlot = 0; fragSlot < spfs->info.num_inputs; fragSlot++) {
+   for (fragSlot = 0; fragSlot < fsInfo->num_inputs; fragSlot++) {
       const uint vertSlot = vinfo->attrib[fragSlot].src_index;
       uint j;
 
@@ -987,7 +988,7 @@ setup_line_coefficients(struct setup_context *setup,
          for (j = 0; j < NUM_CHANNELS; j++) {
             line_apply_cylindrical_wrap(setup->vmin[vertSlot][j],
                                         setup->vmax[vertSlot][j],
-                                        spfs->info.input_cylindrical_wrap[fragSlot] & (1 << j),
+                                        fsInfo->input_cylindrical_wrap[fragSlot] & (1 << j),
                                         v);
             line_linear_coeff(setup, &setup->coef[fragSlot], j, v);
          }
@@ -996,7 +997,7 @@ setup_line_coefficients(struct setup_context *setup,
          for (j = 0; j < NUM_CHANNELS; j++) {
             line_apply_cylindrical_wrap(setup->vmin[vertSlot][j],
                                         setup->vmax[vertSlot][j],
-                                        spfs->info.input_cylindrical_wrap[fragSlot] & (1 << j),
+                                        fsInfo->input_cylindrical_wrap[fragSlot] & (1 << j),
                                         v);
             line_persp_coeff(setup, &setup->coef[fragSlot], j, v);
          }
@@ -1008,7 +1009,7 @@ setup_line_coefficients(struct setup_context *setup,
          assert(0);
       }
 
-      if (spfs->info.input_semantic_name[fragSlot] == TGSI_SEMANTIC_FACE) {
+      if (fsInfo->input_semantic_name[fragSlot] == TGSI_SEMANTIC_FACE) {
          /* convert 0 to 1.0 and 1 to -1.0 */
          setup->coef[fragSlot].a0[0] = setup->facing * -2.0f + 1.0f;
          setup->coef[fragSlot].dadx[0] = 0.0;
@@ -1188,7 +1189,7 @@ sp_setup_point(struct setup_context *setup,
                const float (*v0)[4])
 {
    struct softpipe_context *softpipe = setup->softpipe;
-   const struct sp_fragment_shader *spfs = softpipe->fs;
+   const struct tgsi_shader_info *fsInfo = &setup->softpipe->fs_variant->info;
    const int sizeAttr = setup->softpipe->psize_slot;
    const float size
       = sizeAttr > 0 ? v0[sizeAttr][0]
@@ -1232,7 +1233,7 @@ sp_setup_point(struct setup_context *setup,
    const_coeff(setup, &setup->posCoef, 0, 2);
    const_coeff(setup, &setup->posCoef, 0, 3);
 
-   for (fragSlot = 0; fragSlot < spfs->info.num_inputs; fragSlot++) {
+   for (fragSlot = 0; fragSlot < fsInfo->num_inputs; fragSlot++) {
       const uint vertSlot = vinfo->attrib[fragSlot].src_index;
       uint j;
 
@@ -1255,7 +1256,7 @@ sp_setup_point(struct setup_context *setup,
          assert(0);
       }
 
-      if (spfs->info.input_semantic_name[fragSlot] == TGSI_SEMANTIC_FACE) {
+      if (fsInfo->input_semantic_name[fragSlot] == TGSI_SEMANTIC_FACE) {
          /* convert 0 to 1.0 and 1 to -1.0 */
          setup->coef[fragSlot].a0[0] = setup->facing * -2.0f + 1.0f;
          setup->coef[fragSlot].dadx[0] = 0.0;
@@ -1396,7 +1397,7 @@ sp_setup_prepare(struct setup_context *setup)
    struct softpipe_context *sp = setup->softpipe;
 
    if (sp->dirty) {
-      softpipe_update_derived(sp);
+      softpipe_update_derived(sp, sp->reduced_api_prim);
    }
 
    /* Note: nr_attrs is only used for debugging (vertex printing) */
index bb19f8cff209a2fbaa25fada4edbd88588f8b887..ec4c8cf5e4dd530bd4167f0e66c26789f6191d53 100644 (file)
@@ -60,34 +60,45 @@ struct tgsi_exec_machine;
 struct vertex_info;
 
 
-/**
- * Subclass of pipe_shader_state (though it doesn't really need to be).
- *
- * This is starting to look an awful lot like a quad pipeline stage...
- */
-struct sp_fragment_shader {
-   struct pipe_shader_state shader;
+struct sp_fragment_shader_variant_key
+{
+   boolean polygon_stipple;
+};
 
+
+struct sp_fragment_shader_variant
+{
+   const struct tgsi_token *tokens;
+   struct sp_fragment_shader_variant_key key;
    struct tgsi_shader_info info;
 
+   unsigned stipple_sampler_unit;
+
+   /* See comments about this elsewhere */
+#if 0
    struct draw_fragment_shader *draw_shader;
+#endif
 
-   boolean origin_lower_left; /**< fragment shader uses lower left position origin? */
-   boolean pixel_center_integer; /**< fragment shader uses integer pixel center? */
-   boolean color0_writes_all_cbufs; /**< fragment shader writes color0 to all bound cbufs */
-   void (*prepare)( const struct sp_fragment_shader *shader,
-                   struct tgsi_exec_machine *machine,
-                   struct tgsi_sampler **samplers);
+   void (*prepare)(const struct sp_fragment_shader_variant *shader,
+                  struct tgsi_exec_machine *machine,
+                  struct tgsi_sampler **samplers);
 
-   /* Run the shader - this interface will get cleaned up in the
-    * future:
-    */
-   unsigned (*run)( const struct sp_fragment_shader *shader,
-                   struct tgsi_exec_machine *machine,
-                   struct quad_header *quad );
+   unsigned (*run)(const struct sp_fragment_shader_variant *shader,
+                  struct tgsi_exec_machine *machine,
+                  struct quad_header *quad);
 
+   /* Deletes this instance of the object */
+   void (*delete)(struct sp_fragment_shader_variant *shader);
 
-   void (*delete)( struct sp_fragment_shader * );
+   struct sp_fragment_shader_variant *next;
+};
+
+
+/** Subclass of pipe_shader_state */
+struct sp_fragment_shader {
+   struct pipe_shader_state shader;
+   struct sp_fragment_shader_variant *variants;
+   struct draw_fragment_shader *draw_shader;
 };
 
 
@@ -141,7 +152,7 @@ softpipe_set_framebuffer_state(struct pipe_context *,
                                const struct pipe_framebuffer_state *);
 
 void
-softpipe_update_derived( struct softpipe_context *softpipe );
+softpipe_update_derived(struct softpipe_context *softpipe, unsigned prim);
 
 void
 softpipe_draw_vbo(struct pipe_context *pipe,
@@ -170,4 +181,16 @@ struct vertex_info *
 softpipe_get_vbuf_vertex_info(struct softpipe_context *softpipe);
 
 
+struct sp_fragment_shader_variant *
+softpipe_find_fs_variant(struct softpipe_context *softpipe,
+                         struct sp_fragment_shader *fs,
+                         const struct sp_fragment_shader_variant_key *key);
+
+
+struct sp_fragment_shader_variant *
+softpipe_find_fs_variant(struct softpipe_context *softpipe,
+                         struct sp_fragment_shader *fs,
+                         const struct sp_fragment_shader_variant_key *key);
+
+
 #endif
index f9590eb0b24c97b3799d03712da7e1d5cf66f059..fd688089a3e6a2bd317a5ff8abd035538ef6c949 100644 (file)
  * 
  **************************************************************************/
 
+#include "util/u_inlines.h"
 #include "util/u_math.h"
 #include "util/u_memory.h"
+#include "util/u_pstipple.h"
 #include "pipe/p_shader_tokens.h"
 #include "draw/draw_context.h"
 #include "draw/draw_vertex.h"
@@ -64,7 +66,7 @@ softpipe_get_vertex_info(struct softpipe_context *softpipe)
 
    if (vinfo->num_attribs == 0) {
       /* compute vertex layout now */
-      const struct sp_fragment_shader *spfs = softpipe->fs;
+      const struct tgsi_shader_info *fsInfo = &softpipe->fs_variant->info;
       struct vertex_info *vinfo_vbuf = &softpipe->vertex_info_vbuf;
       const uint num = draw_num_shader_outputs(softpipe->draw);
       uint i;
@@ -84,11 +86,11 @@ softpipe_get_vertex_info(struct softpipe_context *softpipe)
        * from the vertex shader.
        */
       vinfo->num_attribs = 0;
-      for (i = 0; i < spfs->info.num_inputs; i++) {
+      for (i = 0; i < fsInfo->num_inputs; i++) {
          int src;
          enum interp_mode interp;
 
-         switch (spfs->info.input_interpolate[i]) {
+         switch (fsInfo->input_interpolate[i]) {
          case TGSI_INTERPOLATE_CONSTANT:
             interp = INTERP_CONSTANT;
             break;
@@ -103,7 +105,7 @@ softpipe_get_vertex_info(struct softpipe_context *softpipe)
             interp = INTERP_LINEAR;
          }
 
-         switch (spfs->info.input_semantic_name[i]) {
+         switch (fsInfo->input_semantic_name[i]) {
          case TGSI_SEMANTIC_POSITION:
             interp = INTERP_POS;
             break;
@@ -117,8 +119,8 @@ softpipe_get_vertex_info(struct softpipe_context *softpipe)
 
          /* this includes texcoords and varying vars */
          src = draw_find_shader_output(softpipe->draw,
-                                       spfs->info.input_semantic_name[i],
-                                       spfs->info.input_semantic_index[i]);
+                                       fsInfo->input_semantic_name[i],
+                                       fsInfo->input_semantic_index[i]);
          draw_emit_vertex_attr(vinfo, EMIT_4F, interp, src);
       }
 
@@ -241,10 +243,101 @@ update_tgsi_samplers( struct softpipe_context *softpipe )
 }
 
 
+static void
+update_fragment_shader(struct softpipe_context *softpipe, unsigned prim)
+{
+   struct sp_fragment_shader_variant_key key;
+
+   memset(&key, 0, sizeof(key));
+
+   if (prim == PIPE_PRIM_TRIANGLES)
+      key.polygon_stipple = softpipe->rasterizer->poly_stipple_enable;
+
+   if (softpipe->fs) {
+      softpipe->fs_variant = softpipe_find_fs_variant(softpipe,
+                                                      softpipe->fs, &key);
+   }
+   else {
+      softpipe->fs_variant = NULL;
+   }
+
+   /* This would be the logical place to pass the fragment shader
+    * to the draw module.  However, doing this here, during state
+    * validation, causes problems with the 'draw' module helpers for
+    * wide/AA/stippled lines.
+    * In principle, the draw's fragment shader should be per-variant
+    * but that doesn't work.  So we use a single draw fragment shader
+    * per fragment shader, not per variant.
+    */
+#if 0
+   if (softpipe->fs_variant) {
+      draw_bind_fragment_shader(softpipe->draw,
+                                softpipe->fs_variant->draw_shader);
+   }
+   else {
+      draw_bind_fragment_shader(softpipe->draw, NULL);
+   }
+#endif
+}
+
+
+/**
+ * This should be called when the polygon stipple pattern changes.
+ * We create a new texture from the stipple pattern and create a new
+ * sampler view.
+ */
+static void
+update_polygon_stipple_pattern(struct softpipe_context *softpipe)
+{
+   struct pipe_resource *tex;
+   struct pipe_sampler_view *view;
+
+   tex = util_pstipple_create_stipple_texture(&softpipe->pipe,
+                                              softpipe->poly_stipple.stipple);
+   pipe_resource_reference(&softpipe->pstipple.texture, tex);
+
+   view = util_pstipple_create_sampler_view(&softpipe->pipe, tex);
+   pipe_sampler_view_reference(&softpipe->pstipple.sampler_view, view);
+}
+
+
+/**
+ * Should be called when polygon stipple is enabled/disabled or when
+ * the fragment shader changes.
+ * We add/update the fragment sampler and sampler views to sample from
+ * the polygon stipple texture.  The texture unit that we use depends on
+ * the fragment shader (we need to use a unit not otherwise used by the
+ * shader).
+ */
+static void
+update_polygon_stipple_enable(struct softpipe_context *softpipe, unsigned prim)
+{
+   if (prim == PIPE_PRIM_TRIANGLES &&
+       softpipe->fs_variant->key.polygon_stipple) {
+      const unsigned unit = softpipe->fs_variant->stipple_sampler_unit;
+
+      assert(unit >= softpipe->num_fragment_samplers);
+
+      /* sampler state */
+      softpipe->fragment_samplers[unit] = softpipe->pstipple.sampler;
+
+      /* sampler view */
+      pipe_sampler_view_reference(&softpipe->fragment_sampler_views[unit],
+                                  softpipe->pstipple.sampler_view);
+
+      sp_tex_tile_cache_set_sampler_view(softpipe->fragment_tex_cache[unit],
+                                         softpipe->pstipple.sampler_view);
+
+      softpipe->dirty |= SP_NEW_SAMPLER;
+   }
+}
+
+
 /* Hopefully this will remain quite simple, otherwise need to pull in
  * something like the state tracker mechanism.
  */
-void softpipe_update_derived( struct softpipe_context *softpipe )
+void
+softpipe_update_derived(struct softpipe_context *softpipe, unsigned prim)
 {
    struct softpipe_screen *sp_screen = softpipe_screen(softpipe->pipe.screen);
 
@@ -254,7 +347,24 @@ void softpipe_update_derived( struct softpipe_context *softpipe )
       softpipe->tex_timestamp = sp_screen->timestamp;
       softpipe->dirty |= SP_NEW_TEXTURE;
    }
-      
+
+#if DO_PSTIPPLE_IN_HELPER_MODULE
+   if (softpipe->dirty & SP_NEW_STIPPLE)
+      /* before updating samplers! */
+      update_polygon_stipple_pattern(softpipe);
+#endif
+
+   if (softpipe->dirty & (SP_NEW_RASTERIZER |
+                          SP_NEW_FS))
+      update_fragment_shader(softpipe, prim);
+
+#if DO_PSTIPPLE_IN_HELPER_MODULE
+   if (softpipe->dirty & (SP_NEW_RASTERIZER |
+                          SP_NEW_STIPPLE |
+                          SP_NEW_FS))
+      update_polygon_stipple_enable(softpipe, prim);
+#endif
+
    if (softpipe->dirty & (SP_NEW_SAMPLER |
                           SP_NEW_TEXTURE |
                           SP_NEW_FS | 
index 60331bc49763bff20d59f91818f844845908964a..16023c990a708a5bbb646468c1780881e1b00705 100644 (file)
@@ -373,8 +373,9 @@ softpipe_reset_sampler_variants(struct softpipe_context *softpipe)
       }
    }
 
-   for (i = 0; i <= softpipe->fs->info.file_max[TGSI_FILE_SAMPLER]; i++) {
+   for (i = 0; i <= softpipe->fs_variant->info.file_max[TGSI_FILE_SAMPLER]; i++) {
       if (softpipe->fragment_samplers[i]) {
+         assert(softpipe->fragment_sampler_views[i]->texture);
          softpipe->tgsi.frag_samplers_list[i] =
             get_sampler_variant( i,
                                  sp_sampler(softpipe->fragment_samplers[i]),
index 3dec5de3cc44c41c0bb2c6ff86a1987088f9a262..da895270aa97b398b1ad248b455a9e71d0b8fa30 100644 (file)
@@ -33,6 +33,7 @@
 #include "pipe/p_defines.h"
 #include "util/u_memory.h"
 #include "util/u_inlines.h"
+#include "util/u_pstipple.h"
 #include "draw/draw_context.h"
 #include "draw/draw_vs.h"
 #include "draw/draw_gs.h"
 #include "tgsi/tgsi_parse.h"
 
 
+/**
+ * Create a new fragment shader variant.
+ */
+static struct sp_fragment_shader_variant *
+create_fs_variant(struct softpipe_context *softpipe,
+                  struct sp_fragment_shader *fs,
+                  const struct sp_fragment_shader_variant_key *key)
+{
+   struct sp_fragment_shader_variant *var;
+   struct pipe_shader_state *stipple_fs = NULL, *curfs = &fs->shader;
+   unsigned unit = 0;
+
+   if (key->polygon_stipple) {
+      /* get new shader that implements polygon stippling */
+      stipple_fs = util_pstipple_create_fragment_shader(&softpipe->pipe,
+                                                        curfs, &unit);
+      curfs = stipple_fs;
+   }
+
+   /* codegen, create variant object */
+   var = softpipe_create_fs_variant_sse(softpipe, curfs);
+   if (!var) {
+      var = softpipe_create_fs_variant_exec(softpipe, curfs);
+   }
+
+   if (var) {
+      var->key = *key;
+      var->tokens = tgsi_dup_tokens(curfs->tokens);
+      var->stipple_sampler_unit = unit;
+
+      tgsi_scan_shader(var->tokens, &var->info);
+
+      /* See comments elsewhere about draw fragment shaders */
+#if 0
+      /* draw's fs state */
+      var->draw_shader = draw_create_fragment_shader(softpipe->draw,
+                                                     &fs->shader);
+      if (!var->draw_shader) {
+         var->delete(var);
+         FREE((void *) var->tokens);
+         return NULL;
+      }
+#endif
+
+      /* insert variant into linked list */
+      var->next = fs->variants;
+      fs->variants = var;
+   }
+
+   if (stipple_fs) {
+      free((void *) stipple_fs->tokens);
+      free(stipple_fs);
+   }
+
+   return var;
+}
+
+
+struct sp_fragment_shader_variant *
+softpipe_find_fs_variant(struct softpipe_context *sp,
+                         struct sp_fragment_shader *fs,
+                         const struct sp_fragment_shader_variant_key *key)
+{
+   struct sp_fragment_shader_variant *var;
+
+   for (var = fs->variants; var; var = var->next) {
+      if (memcmp(&var->key, key, sizeof(*key)) == 0) {
+         /* found it */
+         return var;
+      }
+   }
+
+   return create_fs_variant(sp, fs, key);
+}
+
+
 static void *
 softpipe_create_fs_state(struct pipe_context *pipe,
                          const struct pipe_shader_state *templ)
 {
    struct softpipe_context *softpipe = softpipe_context(pipe);
-   struct sp_fragment_shader *state;
-   unsigned i;
+   struct sp_fragment_shader *state = CALLOC_STRUCT(sp_fragment_shader);
 
    /* debug */
    if (softpipe->dump_fs) 
       tgsi_dump(templ->tokens, 0);
 
-   /* codegen */
-   state = softpipe_create_fs_sse( softpipe, templ );
-   if (!state) {
-      state = softpipe_create_fs_exec( softpipe, templ );
-   }
-
-   if (!state)
-      return NULL;
+   /* we need to keep a local copy of the tokens */
+   state->shader.tokens = tgsi_dup_tokens(templ->tokens);
 
    /* draw's fs state */
-   state->draw_shader = draw_create_fragment_shader(softpipe->draw, templ);
+   state->draw_shader = draw_create_fragment_shader(softpipe->draw,
+                                                    &state->shader);
    if (!state->draw_shader) {
-      state->delete( state );
+      FREE((void *) state->shader.tokens);
+      FREE(state);
       return NULL;
    }
 
-   /* get/save the summary info for this shader */
-   tgsi_scan_shader(templ->tokens, &state->info);
-
-   for (i = 0; i < state->info.num_properties; ++i) {
-      if (state->info.properties[i].name == TGSI_PROPERTY_FS_COORD_ORIGIN)
-         state->origin_lower_left = state->info.properties[i].data[0];
-      else if (state->info.properties[i].name == TGSI_PROPERTY_FS_COORD_PIXEL_CENTER)
-        state->pixel_center_integer = state->info.properties[i].data[0];
-      else if (state->info.properties[i].name == TGSI_PROPERTY_FS_COLOR0_WRITES_ALL_CBUFS)
-        state->color0_writes_all_cbufs = state->info.properties[i].data[0];
-   }
-
    return state;
 }
 
@@ -90,6 +150,7 @@ static void
 softpipe_bind_fs_state(struct pipe_context *pipe, void *fs)
 {
    struct softpipe_context *softpipe = softpipe_context(pipe);
+   struct sp_fragment_shader *state = (struct sp_fragment_shader *) fs;
 
    if (softpipe->fs == fs)
       return;
@@ -98,8 +159,14 @@ 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));
+   if (fs == NULL)
+      softpipe->fs_variant = NULL;
+
+   if (state)
+      draw_bind_fragment_shader(softpipe->draw,
+                                state->draw_shader);
+   else
+      draw_bind_fragment_shader(softpipe->draw, NULL);
 
    softpipe->dirty |= SP_NEW_FS;
 }
@@ -110,8 +177,9 @@ softpipe_delete_fs_state(struct pipe_context *pipe, void *fs)
 {
    struct softpipe_context *softpipe = softpipe_context(pipe);
    struct sp_fragment_shader *state = fs;
+   struct sp_fragment_shader_variant *var, *next_var;
 
-   assert(fs != softpipe_context(pipe)->fs);
+   assert(fs != softpipe->fs);
 
    if (softpipe->fs_machine->Tokens == state->shader.tokens) {
       /* unbind the shader from the tgsi executor if we're
@@ -120,9 +188,23 @@ softpipe_delete_fs_state(struct pipe_context *pipe, void *fs)
       tgsi_exec_machine_bind_shader(softpipe->fs_machine, NULL, 0, NULL);
    }
 
+   /* delete variants */
+   for (var = state->variants; var; var = next_var) {
+      next_var = var->next;
+
+      assert(var != softpipe->fs_variant);
+
+      /* See comments elsewhere about draw fragment shaders */
+#if 0
+      draw_delete_fragment_shader(softpipe->draw, var->draw_shader);
+#endif
+
+      var->delete(var);
+   }
+
    draw_delete_fragment_shader(softpipe->draw, state->draw_shader);
 
-   state->delete( state );
+   FREE((void *) state->shader.tokens);
 }