draw: create specialized vs varients incorporating fetch & emit
authorKeith Whitwell <keith@tungstengraphics.com>
Thu, 15 May 2008 11:39:08 +0000 (12:39 +0100)
committerKeith Whitwell <keith@tungstengraphics.com>
Fri, 23 May 2008 08:16:55 +0000 (09:16 +0100)
src/gallium/auxiliary/draw/Makefile
src/gallium/auxiliary/draw/draw_private.h
src/gallium/auxiliary/draw/draw_pt_fetch_shade_emit.c [new file with mode: 0644]
src/gallium/auxiliary/draw/draw_vs.c
src/gallium/auxiliary/draw/draw_vs.h
src/gallium/auxiliary/draw/draw_vs_exec.c
src/gallium/auxiliary/draw/draw_vs_llvm.c
src/gallium/auxiliary/draw/draw_vs_sse.c
src/gallium/auxiliary/draw/draw_vs_varient.c [new file with mode: 0644]

index 3053682..8487799 100644 (file)
@@ -26,7 +26,7 @@ C_SOURCES = \
        draw_pt_emit.c \
        draw_pt_fetch.c \
        draw_pt_fetch_emit.c \
-       draw_pt_middle_fse.c \
+       draw_pt_fetch_shade_emit.c \
        draw_pt_fetch_shade_pipeline.c \
        draw_pt_post_vs.c \
         draw_pt_util.c \
@@ -34,6 +34,7 @@ C_SOURCES = \
        draw_pt_vcache.c \
        draw_vertex.c \
        draw_vs.c \
+       draw_vs_varient.c \
        draw_vs_exec.c \
        draw_vs_llvm.c \
        draw_vs_sse.c 
index 3418ee2..c095bf3 100644 (file)
@@ -184,7 +184,9 @@ struct draw_context
       struct gallivm_cpu_engine *engine;   
 
 
+      struct translate *fetch;
       struct translate_cache *fetch_cache;
+      struct translate *emit;
       struct translate_cache *emit_cache;
    } vs;
 
diff --git a/src/gallium/auxiliary/draw/draw_pt_fetch_shade_emit.c b/src/gallium/auxiliary/draw/draw_pt_fetch_shade_emit.c
new file mode 100644 (file)
index 0000000..74945dc
--- /dev/null
@@ -0,0 +1,338 @@
+/**************************************************************************
+ * 
+ * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ * 
+ **************************************************************************/
+
+ /*
+  * Authors:
+  *   Keith Whitwell <keith@tungstengraphics.com>
+  */
+
+
+#include "pipe/p_util.h"
+#include "draw/draw_context.h"
+#include "draw/draw_private.h"
+#include "draw/draw_vbuf.h"
+#include "draw/draw_vertex.h"
+#include "draw/draw_pt.h"
+#include "draw/draw_vs.h"
+
+#include "translate/translate.h"
+
+struct fetch_shade_emit;
+
+
+/* Prototype fetch, shade, emit-hw-verts all in one go.
+ */
+struct fetch_shade_emit {
+   struct draw_pt_middle_end base;
+   struct draw_context *draw;
+
+
+   /* Temporaries:
+    */
+   const float *constants;
+   unsigned pitch[PIPE_MAX_ATTRIBS];
+   const ubyte *src[PIPE_MAX_ATTRIBS];
+   unsigned prim;
+
+   struct draw_vs_varient_key key;
+   struct draw_vs_varient *active;
+};
+
+
+
+                              
+static void fse_prepare( struct draw_pt_middle_end *middle,
+                         unsigned prim, 
+                         unsigned opt )
+{
+   struct fetch_shade_emit *fse = (struct fetch_shade_emit *)middle;
+   struct draw_context *draw = fse->draw;
+   unsigned num_vs_inputs = draw->vs.vertex_shader->info.num_inputs;
+   unsigned num_vs_outputs = draw->vs.vertex_shader->info.num_outputs;
+   const struct vertex_info *vinfo;
+   unsigned i;
+   boolean need_psize = 0;
+   
+
+   if (draw->pt.user.elts) {
+      assert(0);
+      return ;
+   }
+
+   if (!draw->render->set_primitive( draw->render, 
+                                     prim )) {
+      assert(0);
+      return;
+   }
+
+   /* Must do this after set_primitive() above:
+    */
+   vinfo = draw->render->get_vertex_info(draw->render);
+   
+
+
+   fse->key.nr_elements = MAX2(num_vs_outputs,     /* outputs - translate to hw format */
+                               num_vs_inputs);     /* inputs - fetch from api format */
+
+   fse->key.output_stride = vinfo->size * 4;
+   memset(fse->key.element, 0, 
+          fse->key.nr_elements * sizeof(fse->key.element[0]));
+
+   for (i = 0; i < num_vs_inputs; i++) {
+      const struct pipe_vertex_element *src = &draw->pt.vertex_element[i];
+      fse->key.element[i].in.format = src->src_format;
+
+      /* Consider ignoring these, ie make generated programs
+       * independent of this state:
+       */
+      fse->key.element[i].in.buffer = src->vertex_buffer_index;
+      fse->key.element[i].in.offset = src->src_offset;
+   }
+   
+
+   {
+      unsigned dst_offset = 0;
+
+      for (i = 0; i < vinfo->num_attribs; i++) {
+         unsigned emit_sz = 0;
+         unsigned output_format = PIPE_FORMAT_NONE;
+         unsigned vs_output = vinfo->src_index[i];
+
+         switch (vinfo->emit[i]) {
+         case EMIT_4F:
+            output_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
+            emit_sz = 4 * sizeof(float);
+            break;
+         case EMIT_3F:
+            output_format = PIPE_FORMAT_R32G32B32_FLOAT;
+            emit_sz = 3 * sizeof(float);
+            break;
+         case EMIT_2F:
+            output_format = PIPE_FORMAT_R32G32_FLOAT;
+            emit_sz = 2 * sizeof(float);
+            break;
+         case EMIT_1F:
+            output_format = PIPE_FORMAT_R32_FLOAT;
+            emit_sz = 1 * sizeof(float);
+            break;
+         case EMIT_1F_PSIZE:
+            need_psize = 1;
+            output_format = PIPE_FORMAT_R32_FLOAT;
+            emit_sz = 1 * sizeof(float);
+            vs_output = num_vs_outputs + 1;
+         
+            break;
+         default:
+            assert(0);
+            break;
+         }
+
+         /* The elements in the key correspond to vertex shader output
+          * numbers, not to positions in the hw vertex description --
+          * that's handled by the output_offset field.
+          */
+         fse->key.element[vs_output].out.format = output_format;
+         fse->key.element[vs_output].out.offset = dst_offset;
+      
+         dst_offset += emit_sz;
+         assert(fse->key.output_stride >= dst_offset);
+      }
+   }
+
+   /* To make psize work, really need to tell the vertex shader to
+    * copy that value from input->output.  For 'translate' this was
+    * implicit for all elements.
+    */
+#if 0
+   if (need_psize) {
+      unsigned input = num_vs_inputs + 1;
+      const struct pipe_vertex_element *src = &draw->pt.vertex_element[i];
+      fse->key.element[i].input_format = PIPE_FORMAT_R32_FLOAT;
+      fse->key.element[i].input_buffer = 0; //nr_buffers + 1;
+      fse->key.element[i].input_offset = 0; 
+
+      fse->key.nr_elements += 1;
+      
+   }
+#endif
+
+   /* Would normally look up a vertex shader and peruse its list of
+    * varients somehow.  We omitted that step and put all the
+    * hardcoded "shaders" into an array.  We're just making the
+    * assumption that this happens to be a matching shader...  ie
+    * you're running isosurf, aren't you?
+    */
+   fse->active = draw_vs_lookup_varient( draw->vs.vertex_shader, 
+                                         &fse->key );
+
+   if (!fse->active) {
+      assert(0);
+      return ;
+   }
+
+   /* Now set buffer pointers:
+    */
+   for (i = 0; i < num_vs_inputs; i++) {
+      unsigned buf = draw->pt.vertex_element[i].vertex_buffer_index;
+
+      fse->active->set_input( fse->active, 
+                              i, 
+                              
+                              ((const ubyte *) draw->pt.user.vbuffer[buf] + 
+                               draw->pt.vertex_buffer[buf].buffer_offset),
+                              
+                              draw->pt.vertex_buffer[buf].pitch );
+   }
+
+   fse->active->set_constants( fse->active,
+                               (const float (*)[4])draw->pt.user.constants );
+
+   //return TRUE;
+}
+
+
+
+
+
+
+
+static void fse_run_linear( struct draw_pt_middle_end *middle, 
+                            unsigned start, 
+                            unsigned count )
+{
+   struct fetch_shade_emit *fse = (struct fetch_shade_emit *)middle;
+   struct draw_context *draw = fse->draw;
+   unsigned alloc_count = align(count, 4);
+   char *hw_verts;
+
+   /* XXX: need to flush to get prim_vbuf.c to release its allocation??
+    */
+   draw_do_flush( draw, DRAW_FLUSH_BACKEND );
+
+   hw_verts = draw->render->allocate_vertices( draw->render,
+                                               (ushort)fse->key.output_stride,
+                                               (ushort)alloc_count );
+
+   if (!hw_verts) {
+      assert(0);
+      return;
+   }
+
+   /* Single routine to fetch vertices, run shader and emit HW verts.
+    * Clipping and viewport transformation are done elsewhere --
+    * either by the API or on hardware, or for some other reason not
+    * required...
+    */
+   fse->active->run_linear( fse->active, 
+                            start, count,
+                            hw_verts );
+
+   /* Draw arrays path to avoid re-emitting index list again and
+    * again.
+    */
+   draw->render->draw_arrays( draw->render,
+                              0,
+                              count );
+   
+
+   draw->render->release_vertices( draw->render, 
+                                  hw_verts, 
+                                  fse->key.output_stride, 
+                                  count );
+}
+
+
+static void
+fse_run(struct draw_pt_middle_end *middle,
+        const unsigned *fetch_elts,
+        unsigned fetch_count,
+        const ushort *draw_elts,
+        unsigned draw_count )
+{
+   struct fetch_shade_emit *fse = (struct fetch_shade_emit *)middle;
+   struct draw_context *draw = fse->draw;
+   unsigned alloc_count = align(fetch_count, 4);
+   void *hw_verts;
+   
+   /* XXX: need to flush to get prim_vbuf.c to release its allocation?? 
+    */
+   draw_do_flush( draw, DRAW_FLUSH_BACKEND );
+
+   hw_verts = draw->render->allocate_vertices( draw->render,
+                                               (ushort)fse->key.output_stride,
+                                               (ushort)alloc_count );
+   if (!hw_verts) {
+      assert(0);
+      return;
+   }
+         
+                                       
+   /* Single routine to fetch vertices, run shader and emit HW verts.
+    */
+   fse->active->run_elts( fse->active, 
+                          fetch_elts,
+                          fetch_count,
+                          hw_verts );
+
+   draw->render->draw( draw->render, 
+                       draw_elts, 
+                       draw_count );
+
+   draw->render->release_vertices( draw->render, 
+                                   hw_verts, 
+                                   fse->key.output_stride, 
+                                   fetch_count );
+
+}
+
+
+static void fse_finish( struct draw_pt_middle_end *middle )
+{
+}
+
+
+static void
+fse_destroy( struct draw_pt_middle_end *middle ) 
+{
+   FREE(middle);
+}
+
+struct draw_pt_middle_end *draw_pt_middle_fse( struct draw_context *draw )
+{
+   struct fetch_shade_emit *fse = CALLOC_STRUCT(fetch_shade_emit);
+   if (!fse)
+      return NULL;
+
+   fse->base.prepare = fse_prepare;
+   fse->base.run = fse_run;
+   fse->base.run_linear = fse_run_linear;
+   fse->base.finish = fse_finish;
+   fse->base.destroy = fse_destroy;
+   fse->draw = draw;
+
+   return &fse->base;
+}
index 4142dd9..9b899d4 100644 (file)
@@ -36,6 +36,8 @@
 #include "draw_private.h"
 #include "draw_context.h"
 #include "draw_vs.h"
+#include "translate/translate.h"
+#include "translate/translate_cache.h"
 
 
 
@@ -90,11 +92,25 @@ boolean
 draw_vs_init( struct draw_context *draw )
 {
    tgsi_exec_machine_init(&draw->vs.machine);
+
    /* FIXME: give this machine thing a proper constructor:
     */
    draw->vs.machine.Inputs = align_malloc(PIPE_MAX_ATTRIBS * sizeof(struct tgsi_exec_vector), 16);
-   draw->vs.machine.Outputs = align_malloc(PIPE_MAX_ATTRIBS * sizeof(struct tgsi_exec_vector), 16);
+   if (!draw->vs.machine.Inputs)
+      return FALSE;
 
+   draw->vs.machine.Outputs = align_malloc(PIPE_MAX_ATTRIBS * sizeof(struct tgsi_exec_vector), 16);
+   if (!draw->vs.machine.Outputs)
+      return FALSE;
+
+   draw->vs.emit_cache = translate_cache_create();
+   if (!draw->vs.emit_cache) 
+      return FALSE;
+      
+   draw->vs.fetch_cache = translate_cache_create();
+   if (!draw->vs.fetch_cache) 
+      return FALSE;
+      
    return TRUE;
 }
 
@@ -107,6 +123,71 @@ draw_vs_destroy( struct draw_context *draw )
    if (draw->vs.machine.Outputs)
       align_free(draw->vs.machine.Outputs);
 
+   if (draw->vs.fetch_cache)
+      translate_cache_destroy(draw->vs.fetch_cache);
+
+   if (draw->vs.emit_cache)
+      translate_cache_destroy(draw->vs.emit_cache);
+
    tgsi_exec_machine_free_data(&draw->vs.machine);
 
 }
+
+
+struct draw_vs_varient *
+draw_vs_lookup_varient( struct draw_vertex_shader *vs,
+                        const struct draw_vs_varient_key *key )
+{
+   struct draw_vs_varient *varient;
+   unsigned i;
+
+   /* Lookup existing varient: 
+    */
+   for (i = 0; i < vs->nr_varients; i++)
+      if (draw_vs_varient_key_compare(key, &vs->varient[i]->key) == 0)
+         return vs->varient[i];
+   
+   /* Else have to create a new one: 
+    */
+   varient = vs->create_varient( vs, key );
+   if (varient == NULL)
+      return NULL;
+
+   /* Add it to our list: 
+    */
+   assert(vs->nr_varients < Elements(vs->varient));
+   vs->varient[vs->nr_varients++] = varient;
+
+   /* Done 
+    */
+   return varient;
+}
+
+
+struct translate *
+draw_vs_get_fetch( struct draw_context *draw,
+                   struct translate_key *key )
+{
+   if (!draw->vs.fetch ||
+       translate_key_compare(&draw->vs.fetch->key, key) != 0) 
+   {
+      translate_key_sanitize(key);
+      draw->vs.fetch = translate_cache_find(draw->vs.fetch_cache, key);
+   }
+   
+   return draw->vs.fetch;
+}
+
+struct translate *
+draw_vs_get_emit( struct draw_context *draw,
+                  struct translate_key *key )
+{
+   if (!draw->vs.emit ||
+       translate_key_compare(&draw->vs.emit->key, key) != 0) 
+   {
+      translate_key_sanitize(key);
+      draw->vs.emit = translate_cache_find(draw->vs.emit_cache, key);
+   }
+   
+   return draw->vs.emit;
+}
index f9772b8..677be0d 100644 (file)
 struct draw_context;
 struct pipe_shader_state;
 
+struct draw_vs_input 
+{
+   enum pipe_format format;
+   unsigned buffer;
+   unsigned offset; 
+};
+
+struct draw_vs_output
+{
+   enum pipe_format format;
+   unsigned offset;
+};
+
+struct draw_vs_element {
+   struct draw_vs_input in;
+   struct draw_vs_output out;
+};
+
+struct draw_vs_varient_key {
+   unsigned output_stride;
+   unsigned nr_elements;
+   struct draw_vs_element element[PIPE_MAX_ATTRIBS];
+};
+
+struct draw_vs_varient {
+   struct draw_vs_varient_key key;
+
+   struct draw_vertex_shader *vs;
+
+   void (*set_input)( struct draw_vs_varient *,
+                      unsigned i,
+                      const void *ptr,
+                      unsigned stride );
+
+   void (*set_constants)( struct draw_vs_varient *,
+                          const float (*constants)[4] );
+
+
+   void (*run_linear)( struct draw_vs_varient *shader,
+                       unsigned start,
+                      unsigned count,
+                      void *output_buffer );
+
+   void (*run_elts)( struct draw_vs_varient *shader,
+                     const unsigned *elts,
+                     unsigned count,
+                     void *output_buffer );
+
+   void (*destroy)( struct draw_vs_varient * );
+};
+
+
 /**
  * Private version of the compiled vertex_shader
  */
 struct draw_vertex_shader {
+   struct draw_context *draw;
 
    /* This member will disappear shortly:
     */
@@ -49,6 +102,14 @@ struct draw_vertex_shader {
 
    struct tgsi_shader_info info;
 
+   /* 
+    */
+   struct draw_vs_varient *varient[16];
+   unsigned nr_varients;
+   struct draw_vs_varient *(*create_varient)( struct draw_vertex_shader *shader,
+                                              const struct draw_vs_varient_key *key );
+
+
    void (*prepare)( struct draw_vertex_shader *shader,
                    struct draw_context *draw );
 
@@ -68,6 +129,15 @@ struct draw_vertex_shader {
 };
 
 
+struct draw_vs_varient *
+draw_vs_lookup_varient( struct draw_vertex_shader *base,
+                        const struct draw_vs_varient_key *key );
+
+
+/********************************************************************************
+ * Internal functions:
+ */
+
 struct draw_vertex_shader *
 draw_create_vs_exec(struct draw_context *draw,
                    const struct pipe_shader_state *templ);
@@ -80,8 +150,43 @@ struct draw_vertex_shader *
 draw_create_vs_llvm(struct draw_context *draw,
                    const struct pipe_shader_state *templ);
 
+/********************************************************************************
+ * Helpers for vs implementations that don't do their own fetch/emit varients.
+ * Means these can be shared between shaders.
+ */
+struct translate;
+struct translate_key;
+
+struct translate *draw_vs_get_fetch( struct draw_context *draw,
+                                     struct translate_key *key );
+
+
+struct translate *draw_vs_get_emit( struct draw_context *draw,
+                                    struct translate_key *key );
+
+struct draw_vs_varient *draw_vs_varient_generic( struct draw_vertex_shader *vs,
+                                                 const struct draw_vs_varient_key *key );
+
+
+
+static INLINE int draw_vs_varient_keysize( const struct draw_vs_varient_key *key )
+{
+   return 2 * sizeof(int) + key->nr_elements * sizeof(struct draw_vs_element);
+}
+
+static INLINE int draw_vs_varient_key_compare( const struct draw_vs_varient_key *a,
+                                         const struct draw_vs_varient_key *b )
+{
+   int keysize = draw_vs_varient_keysize(a);
+   return memcmp(a, b, keysize);
+}
+
+
+
+
 
 #define MAX_TGSI_VERTICES 4
    
 
+
 #endif
index cb80d00..4501877 100644 (file)
@@ -179,9 +179,11 @@ draw_create_vs_exec(struct draw_context *draw,
 
    tgsi_scan_shader(state->tokens, &vs->base.info);
 
+   vs->base.draw = draw;
    vs->base.prepare = vs_exec_prepare;
    vs->base.run_linear = vs_exec_run_linear;
    vs->base.delete = vs_exec_delete;
+   vs->base.create_varient = draw_vs_varient_generic;
    vs->machine = &draw->vs.machine;
 
    return &vs->base;
index 171da51..621472e 100644 (file)
@@ -114,7 +114,9 @@ draw_create_vs_llvm(struct draw_context *draw,
 
    tgsi_scan_shader(vs->base.state.tokens, &vs->base.info);
 
+   vs->base.draw = draw;
    vs->base.prepare = vs_llvm_prepare;
+   vs->base.create_varient = draw_vs_varient_generic;
    vs->base.run_linear = vs_llvm_run_linear;
    vs->base.delete = vs_llvm_delete;
    vs->machine = &draw->machine;
index 13ad032..df94a7e 100644 (file)
@@ -155,6 +155,8 @@ draw_create_vs_sse(struct draw_context *draw,
 
    tgsi_scan_shader(templ->tokens, &vs->base.info);
 
+   vs->base.draw = draw;
+   vs->base.create_varient = draw_vs_varient_generic;
    vs->base.prepare = vs_sse_prepare;
    vs->base.run_linear = vs_sse_run_linear;
    vs->base.delete = vs_sse_delete;
diff --git a/src/gallium/auxiliary/draw/draw_vs_varient.c b/src/gallium/auxiliary/draw/draw_vs_varient.c
new file mode 100644 (file)
index 0000000..d27b0f6
--- /dev/null
@@ -0,0 +1,229 @@
+/**************************************************************************
+ * 
+ * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ * 
+ **************************************************************************/
+
+ /*
+  * Authors:
+  *   Keith Whitwell <keith@tungstengraphics.com>
+  */
+
+#include "pipe/p_util.h"
+#include "draw/draw_context.h"
+#include "draw/draw_private.h"
+#include "draw/draw_vbuf.h"
+#include "draw/draw_vertex.h"
+#include "draw/draw_vs.h"
+#include "translate/translate.h"
+#include "translate/translate_cache.h"
+
+/* A first pass at incorporating vertex fetch/emit functionality into 
+ */
+struct draw_vs_varient_generic {
+   struct draw_vs_varient base;
+
+
+
+   struct draw_vertex_shader *shader;
+   struct draw_context *draw;
+   
+   /* Basic plan is to run these two translate functions before/after
+    * the vertex shader's existing run_linear() routine to simulate
+    * the inclusion of this functionality into the shader...  
+    * 
+    * Next will look at actually including it.
+    */
+   struct translate *fetch;
+   struct translate *emit;
+
+   const float (*constants)[4];
+};
+
+
+
+
+static void vsvg_set_constants( struct draw_vs_varient *varient,
+                                const float (*constants)[4] )
+{
+   struct draw_vs_varient_generic *vsvg = (struct draw_vs_varient_generic *)varient;
+
+   vsvg->constants = constants;
+}
+
+
+static void vsvg_set_input( struct draw_vs_varient *varient,
+                            unsigned buffer,
+                            const void *ptr,
+                            unsigned stride )
+{
+   struct draw_vs_varient_generic *vsvg = (struct draw_vs_varient_generic *)varient;
+
+   vsvg->fetch->set_buffer(vsvg->fetch, 
+                           buffer, 
+                           ptr, 
+                           stride);
+}
+
+
+static void vsvg_run_elts( struct draw_vs_varient *varient,
+                           const unsigned *elts,
+                           unsigned count,
+                           void *output_buffer)
+{
+   struct draw_vs_varient_generic *vsvg = (struct draw_vs_varient_generic *)varient;
+                       
+   /* Want to do this in small batches for cache locality?
+    */
+   
+   vsvg->fetch->run_elts( vsvg->fetch, 
+                          elts,
+                          count,
+                          output_buffer );
+
+   //if (!vsvg->base.vs->is_passthrough) 
+   {
+      vsvg->base.vs->run_linear( vsvg->base.vs, 
+                                 output_buffer,
+                                 output_buffer,
+                                 vsvg->constants,
+                                 count,
+                                 vsvg->base.key.output_stride, 
+                                 vsvg->base.key.output_stride);
+
+      //if (!vsvg->already_in_emit_format)
+
+      vsvg->emit->set_buffer( vsvg->emit,
+                              0, 
+                              output_buffer,
+                              vsvg->base.key.output_stride );
+
+
+      vsvg->emit->run( vsvg->emit,
+                       0, count,
+                       output_buffer );
+   }
+}
+
+
+static void vsvg_run_linear( struct draw_vs_varient *varient,
+                                   unsigned start,
+                                   unsigned count,
+                                   void *output_buffer )
+{
+   struct draw_vs_varient_generic *vsvg = (struct draw_vs_varient_generic *)varient;
+       
+   //debug_printf("%s %d %d\n", __FUNCTION__, start, count);
+   
+                               
+   vsvg->fetch->run( vsvg->fetch, 
+                     start,
+                     count,
+                     output_buffer );
+
+   //if (!vsvg->base.vs->is_passthrough) 
+   {
+      vsvg->base.vs->run_linear( vsvg->base.vs, 
+                                 output_buffer,
+                                 output_buffer,
+                                 vsvg->constants,
+                                 count,
+                                 vsvg->base.key.output_stride, 
+                                 vsvg->base.key.output_stride);
+
+      //if (!vsvg->already_in_emit_format)
+      vsvg->emit->set_buffer( vsvg->emit,
+                              0, 
+                              output_buffer,
+                              vsvg->base.key.output_stride );
+
+
+      vsvg->emit->run( vsvg->emit,
+                       0, count,
+                       output_buffer );
+   }
+}
+
+
+
+static void vsvg_destroy( struct draw_vs_varient *varient )
+{
+   FREE(varient);
+}
+
+
+struct draw_vs_varient *draw_vs_varient_generic( struct draw_vertex_shader *vs,
+                                                 const struct draw_vs_varient_key *key )
+{
+   unsigned i;
+   struct translate_key fetch, emit;
+
+   struct draw_vs_varient_generic *vsvg = CALLOC_STRUCT( draw_vs_varient_generic );
+   if (vsvg == NULL)
+      return NULL;
+
+   vsvg->base.key = *key;
+   vsvg->base.vs = vs;
+   vsvg->base.set_input     = vsvg_set_input;
+   vsvg->base.set_constants = vsvg_set_constants;
+   vsvg->base.run_elts      = vsvg_run_elts;
+   vsvg->base.run_linear    = vsvg_run_linear;
+   vsvg->base.destroy       = vsvg_destroy;
+
+
+
+   /* OK, have to build a new one: 
+    */
+   fetch.nr_elements = vs->info.num_inputs;
+   fetch.output_stride = 0;
+   for (i = 0; i < vs->info.num_inputs; i++) {
+      fetch.element[i].input_format = key->element[i].in.format;
+      fetch.element[i].input_buffer = key->element[i].in.buffer;
+      fetch.element[i].input_offset = key->element[i].in.offset;
+      fetch.element[i].output_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
+      fetch.element[i].output_offset = fetch.output_stride;
+      fetch.output_stride += 4 * sizeof(float);
+   }
+
+
+   emit.nr_elements = vs->info.num_outputs;
+   emit.output_stride = key->output_stride;
+   for (i = 0; i < vs->info.num_outputs; i++) {
+      emit.element[i].input_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
+      emit.element[i].input_buffer = 0;
+      emit.element[i].input_offset = i * 4 * sizeof(float);
+      emit.element[i].output_format = key->element[i].out.format;
+      emit.element[i].output_offset = key->element[i].out.offset;
+   }
+
+   vsvg->fetch = draw_vs_get_fetch( vs->draw, &fetch );
+   vsvg->emit = draw_vs_get_emit( vs->draw, &emit );
+
+   return &vsvg->base;
+}
+
+
+
+
+