Mesa (master): softpipe: implement fragment shader variants

Brian Paul brianp at kemper.freedesktop.org
Thu Jul 21 16:52:29 UTC 2011


Module: Mesa
Branch: master
Commit: c534f11164bbecf25eb2b1e697f9511eceb0c86f
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=c534f11164bbecf25eb2b1e697f9511eceb0c86f

Author: Brian Paul <brianp at vmware.com>
Date:   Thu Jul 21 09:55:22 2011 -0600

softpipe: implement fragment shader variants

We'll need shader variants to accomodate the new polygon stipple utility.

---

 src/gallium/drivers/softpipe/sp_context.h         |    1 +
 src/gallium/drivers/softpipe/sp_fs.h              |   16 ++--
 src/gallium/drivers/softpipe/sp_fs_exec.c         |   36 +++----
 src/gallium/drivers/softpipe/sp_fs_sse.c          |   25 ++---
 src/gallium/drivers/softpipe/sp_quad_blend.c      |    2 +-
 src/gallium/drivers/softpipe/sp_quad_depth_test.c |   10 +-
 src/gallium/drivers/softpipe/sp_quad_fs.c         |   10 +-
 src/gallium/drivers/softpipe/sp_quad_pipe.c       |    6 +-
 src/gallium/drivers/softpipe/sp_setup.c           |   37 ++++----
 src/gallium/drivers/softpipe/sp_state.h           |   54 +++++++----
 src/gallium/drivers/softpipe/sp_state_derived.c   |   54 +++++++++--
 src/gallium/drivers/softpipe/sp_state_sampler.c   |    3 +-
 src/gallium/drivers/softpipe/sp_state_shader.c    |  114 +++++++++++++++++----
 13 files changed, 251 insertions(+), 117 deletions(-)

diff --git a/src/gallium/drivers/softpipe/sp_context.h b/src/gallium/drivers/softpipe/sp_context.h
index a572ee8..79291ab 100644
--- a/src/gallium/drivers/softpipe/sp_context.h
+++ b/src/gallium/drivers/softpipe/sp_context.h
@@ -64,6 +64,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;
diff --git a/src/gallium/drivers/softpipe/sp_fs.h b/src/gallium/drivers/softpipe/sp_fs.h
index 4792ace..d46d7d5 100644
--- a/src/gallium/drivers/softpipe/sp_fs.h
+++ b/src/gallium/drivers/softpipe/sp_fs.h
@@ -31,17 +31,15 @@
 #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;
diff --git a/src/gallium/drivers/softpipe/sp_fs_exec.c b/src/gallium/drivers/softpipe/sp_fs_exec.c
index 85e7141..779b8c4 100644
--- a/src/gallium/drivers/softpipe/sp_fs_exec.c
+++ b/src/gallium/drivers/softpipe/sp_fs_exec.c
@@ -42,25 +42,25 @@
 
 
 /**
- * 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,16 +180,16 @@ 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;
 
@@ -197,8 +197,6 @@ softpipe_create_fs_exec(struct softpipe_context *softpipe,
    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;
diff --git a/src/gallium/drivers/softpipe/sp_fs_sse.c b/src/gallium/drivers/softpipe/sp_fs_sse.c
index 5b18cd0..c873af1 100644
--- a/src/gallium/drivers/softpipe/sp_fs_sse.c
+++ b/src/gallium/drivers/softpipe/sp_fs_sse.c
@@ -48,11 +48,11 @@
 
 
 /**
- * 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;
 }
diff --git a/src/gallium/drivers/softpipe/sp_quad_blend.c b/src/gallium/drivers/softpipe/sp_quad_blend.c
index 4a4e002..04bfd14 100644
--- a/src/gallium/drivers/softpipe/sp_quad_blend.c
+++ b/src/gallium/drivers/softpipe/sp_quad_blend.c
@@ -797,7 +797,7 @@ blend_fallback(struct quad_stage *qs,
    unsigned cbuf;
    boolean write_all;
 
-   write_all = softpipe->fs->info.color0_writes_all_cbufs;
+   write_all = softpipe->fs_variant->info.color0_writes_all_cbufs;
 
    for (cbuf = 0; cbuf < softpipe->framebuffer.nr_cbufs; cbuf++) 
    {
diff --git a/src/gallium/drivers/softpipe/sp_quad_depth_test.c b/src/gallium/drivers/softpipe/sp_quad_depth_test.c
index 89b2a91..9e98801 100644
--- a/src/gallium/drivers/softpipe/sp_quad_depth_test.c
+++ b/src/gallium/drivers/softpipe/sp_quad_depth_test.c
@@ -726,9 +726,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;
@@ -837,7 +837,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;
 
diff --git a/src/gallium/drivers/softpipe/sp_quad_fs.c b/src/gallium/drivers/softpipe/sp_quad_fs.c
index 90f4787..d74d6d4 100644
--- a/src/gallium/drivers/softpipe/sp_quad_fs.c
+++ b/src/gallium/drivers/softpipe/sp_quad_fs.c
@@ -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);
 }
diff --git a/src/gallium/drivers/softpipe/sp_quad_pipe.c b/src/gallium/drivers/softpipe/sp_quad_pipe.c
index addd47e..a98f8b7 100644
--- a/src/gallium/drivers/softpipe/sp_quad_pipe.c
+++ b/src/gallium/drivers/softpipe/sp_quad_pipe.c
@@ -46,9 +46,9 @@ 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;
 
diff --git a/src/gallium/drivers/softpipe/sp_setup.c b/src/gallium/drivers/softpipe/sp_setup.c
index 48f29f8..b82594c 100644
--- a/src/gallium/drivers/softpipe/sp_setup.c
+++ b/src/gallium/drivers/softpipe/sp_setup.c
@@ -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->info.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->info.origin_lower_left ? setup->softpipe->framebuffer.height-1 : 0)
-		   + (spfs->info.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->info.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;
diff --git a/src/gallium/drivers/softpipe/sp_state.h b/src/gallium/drivers/softpipe/sp_state.h
index 6c14dd1..243f7aa 100644
--- a/src/gallium/drivers/softpipe/sp_state.h
+++ b/src/gallium/drivers/softpipe/sp_state.h
@@ -60,31 +60,43 @@ 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
+{
+   int foo;  /* XXX temporary */
+};
+
 
+struct sp_fragment_shader_variant
+{
+   const struct tgsi_token *tokens;
+   struct sp_fragment_shader_variant_key key;
    struct tgsi_shader_info info;
 
+   /* See comments about this elsewhere */
+#if 0
    struct draw_fragment_shader *draw_shader;
+#endif
+
+   void (*prepare)(const struct sp_fragment_shader_variant *shader,
+		   struct tgsi_exec_machine *machine,
+		   struct tgsi_sampler **samplers);
 
-   void (*prepare)( const struct sp_fragment_shader *shader,
-		    struct tgsi_exec_machine *machine,
-		    struct tgsi_sampler **samplers);
+   unsigned (*run)(const struct sp_fragment_shader_variant *shader,
+		   struct tgsi_exec_machine *machine,
+		   struct quad_header *quad);
 
-   /* 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 );
+   /* Deletes this instance of the object */
+   void (*delete)(struct sp_fragment_shader_variant *shader);
+
+   struct sp_fragment_shader_variant *next;
+};
 
 
-   void (*delete)( struct sp_fragment_shader * );
+/** 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;
 };
 
 
@@ -138,7 +150,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);
 
 void
 softpipe_draw_vbo(struct pipe_context *pipe,
@@ -167,4 +179,10 @@ 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);
+
+
 #endif
diff --git a/src/gallium/drivers/softpipe/sp_state_derived.c b/src/gallium/drivers/softpipe/sp_state_derived.c
index f9590eb..583d0bd 100644
--- a/src/gallium/drivers/softpipe/sp_state_derived.c
+++ b/src/gallium/drivers/softpipe/sp_state_derived.c
@@ -64,7 +64,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 +84,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 +103,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 +117,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 +241,46 @@ update_tgsi_samplers( struct softpipe_context *softpipe )
 }
 
 
+static void
+update_fragment_shader(struct softpipe_context *softpipe)
+{
+   struct sp_fragment_shader_variant_key key;
+
+   memset(&key, 0, sizeof(key));
+
+   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
+}
+
+
 /* 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)
 {
    struct softpipe_screen *sp_screen = softpipe_screen(softpipe->pipe.screen);
 
@@ -255,6 +291,10 @@ void softpipe_update_derived( struct softpipe_context *softpipe )
       softpipe->dirty |= SP_NEW_TEXTURE;
    }
       
+   if (softpipe->dirty & (SP_NEW_RASTERIZER |
+                          SP_NEW_FS))
+      update_fragment_shader(softpipe);
+
    if (softpipe->dirty & (SP_NEW_SAMPLER |
                           SP_NEW_TEXTURE |
                           SP_NEW_FS | 
diff --git a/src/gallium/drivers/softpipe/sp_state_sampler.c b/src/gallium/drivers/softpipe/sp_state_sampler.c
index 60331bc..16023c9 100644
--- a/src/gallium/drivers/softpipe/sp_state_sampler.c
+++ b/src/gallium/drivers/softpipe/sp_state_sampler.c
@@ -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]),
diff --git a/src/gallium/drivers/softpipe/sp_state_shader.c b/src/gallium/drivers/softpipe/sp_state_shader.c
index 80af257..ddb9a98 100644
--- a/src/gallium/drivers/softpipe/sp_state_shader.c
+++ b/src/gallium/drivers/softpipe/sp_state_shader.c
@@ -42,37 +42,91 @@
 #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 *curfs = &fs->shader;
+
+   /* 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);
+
+      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;
+   }
+
+   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);
-
    return state;
 }
 
@@ -81,6 +135,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;
@@ -89,8 +144,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;
 }
@@ -101,8 +162,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
@@ -111,9 +173,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);
 }
 
 




More information about the mesa-commit mailing list