Merge branch '7.8'
[mesa.git] / src / gallium / auxiliary / translate / translate_generic.c
index 7e75ba8365ef7314284ce3abda9857dce0fa45f4..c3ec9ae3f4b611b9d048432c2557bff6c01e0f68 100644 (file)
@@ -30,7 +30,7 @@
   *   Keith Whitwell <keith@tungstengraphics.com>
   */
 
-#include "pipe/p_util.h"
+#include "util/u_memory.h"
 #include "pipe/p_state.h"
 #include "translate.h"
 
@@ -46,9 +46,12 @@ struct translate_generic {
    struct translate translate;
 
    struct {
+      enum translate_element_type type;
+
       fetch_func fetch;
       unsigned buffer;
       unsigned input_offset;
+      unsigned instance_divisor;
 
       emit_func emit;
       unsigned output_offset;
@@ -59,7 +62,6 @@ struct translate_generic {
    } attrib[PIPE_MAX_ATTRIBS];
 
    unsigned nr_attrib;
-   unsigned output_stride;
 };
 
 
@@ -79,8 +81,8 @@ static struct translate_generic *translate_generic( struct translate *translate
 static void                                            \
 fetch_##NAME(const void *ptr, float *attrib)           \
 {                                                      \
-   const float defaults[4] = { 0,0,0,1 };      \
-   int i;                                              \
+   const float defaults[4] = { 0.0f,0.0f,0.0f,1.0f };  \
+   unsigned i;                                         \
                                                        \
    for (i = 0; i < SZ; i++) {                          \
       attrib[i] = FROM(i);                             \
@@ -122,24 +124,28 @@ emit_##NAME(const float *attrib, void *ptr)               \
 #define FROM_16_SNORM(i)   ((float) ((short *) ptr)[i] / 32767.0f)
 #define FROM_32_SNORM(i)   ((float) ((int *) ptr)[i] / 2147483647.0f)
 
-#define TO_64_FLOAT(f)   ((double) f)
-#define TO_32_FLOAT(f)   (f)
+#define FROM_32_FIXED(i)   (((int *) ptr)[i] / 65536.0f)
+
+#define TO_64_FLOAT(x)   ((double) x)
+#define TO_32_FLOAT(x)   (x)
+
+#define TO_8_USCALED(x)  ((unsigned char) x)
+#define TO_16_USCALED(x) ((unsigned short) x)
+#define TO_32_USCALED(x) ((unsigned int) x)
 
-#define TO_8_USCALED(f)  ((unsigned char) f)
-#define TO_16_USCALED(f) ((unsigned short) f)
-#define TO_32_USCALED(f) ((unsigned int) f)
+#define TO_8_SSCALED(x)  ((char) x)
+#define TO_16_SSCALED(x) ((short) x)
+#define TO_32_SSCALED(x) ((int) x)
 
-#define TO_8_SSCALED(f)  ((char) f)
-#define TO_16_SSCALED(f) ((short) f)
-#define TO_32_SSCALED(f) ((int) f)
+#define TO_8_UNORM(x)    ((unsigned char) (x * 255.0f))
+#define TO_16_UNORM(x)   ((unsigned short) (x * 65535.0f))
+#define TO_32_UNORM(x)   ((unsigned int) (x * 4294967295.0f))
 
-#define TO_8_UNORM(f)    ((unsigned char) (f * 255.0f))
-#define TO_16_UNORM(f)   ((unsigned short) (f * 65535.0f))
-#define TO_32_UNORM(f)   ((unsigned int) (f * 4294967295.0f))
+#define TO_8_SNORM(x)    ((char) (x * 127.0f))
+#define TO_16_SNORM(x)   ((short) (x * 32767.0f))
+#define TO_32_SNORM(x)   ((int) (x * 2147483647.0f))
 
-#define TO_8_SNORM(f)    ((char) (f * 127.0f))
-#define TO_16_SNORM(f)   ((short) (f * 32767.0f))
-#define TO_32_SNORM(f)   ((int) (f * 2147483647.0f))
+#define TO_32_FIXED(x)   ((int) (x * 65536.0f))
 
 
 
@@ -214,7 +220,12 @@ ATTRIB( R8G8_SNORM,      2, char, FROM_8_SNORM, TO_8_SNORM )
 ATTRIB( R8_SNORM,        1, char, FROM_8_SNORM, TO_8_SNORM )
 
 ATTRIB( A8R8G8B8_UNORM,       4, ubyte, FROM_8_UNORM, TO_8_UNORM )
-//ATTRIB( R8G8B8A8_UNORM,       4, ubyte, FROM_8_UNORM, TO_8_UNORM )
+/*ATTRIB( R8G8B8A8_UNORM,       4, ubyte, FROM_8_UNORM, TO_8_UNORM )*/
+
+ATTRIB( R32G32B32A32_FIXED,   4, int, FROM_32_FIXED, TO_32_FIXED )
+ATTRIB( R32G32B32_FIXED,      3, int, FROM_32_FIXED, TO_32_FIXED )
+ATTRIB( R32G32_FIXED,         2, int, FROM_32_FIXED, TO_32_FIXED )
+ATTRIB( R32_FIXED,            1, int, FROM_32_FIXED, TO_32_FIXED )
 
 
 
@@ -256,140 +267,149 @@ static fetch_func get_fetch_func( enum pipe_format format )
 {
    switch (format) {
    case PIPE_FORMAT_R64_FLOAT:
-      return fetch_R64_FLOAT;
+      return &fetch_R64_FLOAT;
    case PIPE_FORMAT_R64G64_FLOAT:
-      return fetch_R64G64_FLOAT;
+      return &fetch_R64G64_FLOAT;
    case PIPE_FORMAT_R64G64B64_FLOAT:
-      return fetch_R64G64B64_FLOAT;
+      return &fetch_R64G64B64_FLOAT;
    case PIPE_FORMAT_R64G64B64A64_FLOAT:
-      return fetch_R64G64B64A64_FLOAT;
+      return &fetch_R64G64B64A64_FLOAT;
 
    case PIPE_FORMAT_R32_FLOAT:
-      return fetch_R32_FLOAT;
+      return &fetch_R32_FLOAT;
    case PIPE_FORMAT_R32G32_FLOAT:
-      return fetch_R32G32_FLOAT;
+      return &fetch_R32G32_FLOAT;
    case PIPE_FORMAT_R32G32B32_FLOAT:
-      return fetch_R32G32B32_FLOAT;
+      return &fetch_R32G32B32_FLOAT;
    case PIPE_FORMAT_R32G32B32A32_FLOAT:
-      return fetch_R32G32B32A32_FLOAT;
+      return &fetch_R32G32B32A32_FLOAT;
 
    case PIPE_FORMAT_R32_UNORM:
-      return fetch_R32_UNORM;
+      return &fetch_R32_UNORM;
    case PIPE_FORMAT_R32G32_UNORM:
-      return fetch_R32G32_UNORM;
+      return &fetch_R32G32_UNORM;
    case PIPE_FORMAT_R32G32B32_UNORM:
-      return fetch_R32G32B32_UNORM;
+      return &fetch_R32G32B32_UNORM;
    case PIPE_FORMAT_R32G32B32A32_UNORM:
-      return fetch_R32G32B32A32_UNORM;
+      return &fetch_R32G32B32A32_UNORM;
 
    case PIPE_FORMAT_R32_USCALED:
-      return fetch_R32_USCALED;
+      return &fetch_R32_USCALED;
    case PIPE_FORMAT_R32G32_USCALED:
-      return fetch_R32G32_USCALED;
+      return &fetch_R32G32_USCALED;
    case PIPE_FORMAT_R32G32B32_USCALED:
-      return fetch_R32G32B32_USCALED;
+      return &fetch_R32G32B32_USCALED;
    case PIPE_FORMAT_R32G32B32A32_USCALED:
-      return fetch_R32G32B32A32_USCALED;
+      return &fetch_R32G32B32A32_USCALED;
 
    case PIPE_FORMAT_R32_SNORM:
-      return fetch_R32_SNORM;
+      return &fetch_R32_SNORM;
    case PIPE_FORMAT_R32G32_SNORM:
-      return fetch_R32G32_SNORM;
+      return &fetch_R32G32_SNORM;
    case PIPE_FORMAT_R32G32B32_SNORM:
-      return fetch_R32G32B32_SNORM;
+      return &fetch_R32G32B32_SNORM;
    case PIPE_FORMAT_R32G32B32A32_SNORM:
-      return fetch_R32G32B32A32_SNORM;
+      return &fetch_R32G32B32A32_SNORM;
 
    case PIPE_FORMAT_R32_SSCALED:
-      return fetch_R32_SSCALED;
+      return &fetch_R32_SSCALED;
    case PIPE_FORMAT_R32G32_SSCALED:
-      return fetch_R32G32_SSCALED;
+      return &fetch_R32G32_SSCALED;
    case PIPE_FORMAT_R32G32B32_SSCALED:
-      return fetch_R32G32B32_SSCALED;
+      return &fetch_R32G32B32_SSCALED;
    case PIPE_FORMAT_R32G32B32A32_SSCALED:
-      return fetch_R32G32B32A32_SSCALED;
+      return &fetch_R32G32B32A32_SSCALED;
 
    case PIPE_FORMAT_R16_UNORM:
-      return fetch_R16_UNORM;
+      return &fetch_R16_UNORM;
    case PIPE_FORMAT_R16G16_UNORM:
-      return fetch_R16G16_UNORM;
+      return &fetch_R16G16_UNORM;
    case PIPE_FORMAT_R16G16B16_UNORM:
-      return fetch_R16G16B16_UNORM;
+      return &fetch_R16G16B16_UNORM;
    case PIPE_FORMAT_R16G16B16A16_UNORM:
-      return fetch_R16G16B16A16_UNORM;
+      return &fetch_R16G16B16A16_UNORM;
 
    case PIPE_FORMAT_R16_USCALED:
-      return fetch_R16_USCALED;
+      return &fetch_R16_USCALED;
    case PIPE_FORMAT_R16G16_USCALED:
-      return fetch_R16G16_USCALED;
+      return &fetch_R16G16_USCALED;
    case PIPE_FORMAT_R16G16B16_USCALED:
-      return fetch_R16G16B16_USCALED;
+      return &fetch_R16G16B16_USCALED;
    case PIPE_FORMAT_R16G16B16A16_USCALED:
-      return fetch_R16G16B16A16_USCALED;
+      return &fetch_R16G16B16A16_USCALED;
 
    case PIPE_FORMAT_R16_SNORM:
-      return fetch_R16_SNORM;
+      return &fetch_R16_SNORM;
    case PIPE_FORMAT_R16G16_SNORM:
-      return fetch_R16G16_SNORM;
+      return &fetch_R16G16_SNORM;
    case PIPE_FORMAT_R16G16B16_SNORM:
-      return fetch_R16G16B16_SNORM;
+      return &fetch_R16G16B16_SNORM;
    case PIPE_FORMAT_R16G16B16A16_SNORM:
-      return fetch_R16G16B16A16_SNORM;
+      return &fetch_R16G16B16A16_SNORM;
 
    case PIPE_FORMAT_R16_SSCALED:
-      return fetch_R16_SSCALED;
+      return &fetch_R16_SSCALED;
    case PIPE_FORMAT_R16G16_SSCALED:
-      return fetch_R16G16_SSCALED;
+      return &fetch_R16G16_SSCALED;
    case PIPE_FORMAT_R16G16B16_SSCALED:
-      return fetch_R16G16B16_SSCALED;
+      return &fetch_R16G16B16_SSCALED;
    case PIPE_FORMAT_R16G16B16A16_SSCALED:
-      return fetch_R16G16B16A16_SSCALED;
+      return &fetch_R16G16B16A16_SSCALED;
 
    case PIPE_FORMAT_R8_UNORM:
-      return fetch_R8_UNORM;
+      return &fetch_R8_UNORM;
    case PIPE_FORMAT_R8G8_UNORM:
-      return fetch_R8G8_UNORM;
+      return &fetch_R8G8_UNORM;
    case PIPE_FORMAT_R8G8B8_UNORM:
-      return fetch_R8G8B8_UNORM;
+      return &fetch_R8G8B8_UNORM;
    case PIPE_FORMAT_R8G8B8A8_UNORM:
-      return fetch_R8G8B8A8_UNORM;
+      return &fetch_R8G8B8A8_UNORM;
 
    case PIPE_FORMAT_R8_USCALED:
-      return fetch_R8_USCALED;
+      return &fetch_R8_USCALED;
    case PIPE_FORMAT_R8G8_USCALED:
-      return fetch_R8G8_USCALED;
+      return &fetch_R8G8_USCALED;
    case PIPE_FORMAT_R8G8B8_USCALED:
-      return fetch_R8G8B8_USCALED;
+      return &fetch_R8G8B8_USCALED;
    case PIPE_FORMAT_R8G8B8A8_USCALED:
-      return fetch_R8G8B8A8_USCALED;
+      return &fetch_R8G8B8A8_USCALED;
 
    case PIPE_FORMAT_R8_SNORM:
-      return fetch_R8_SNORM;
+      return &fetch_R8_SNORM;
    case PIPE_FORMAT_R8G8_SNORM:
-      return fetch_R8G8_SNORM;
+      return &fetch_R8G8_SNORM;
    case PIPE_FORMAT_R8G8B8_SNORM:
-      return fetch_R8G8B8_SNORM;
+      return &fetch_R8G8B8_SNORM;
    case PIPE_FORMAT_R8G8B8A8_SNORM:
-      return fetch_R8G8B8A8_SNORM;
+      return &fetch_R8G8B8A8_SNORM;
 
    case PIPE_FORMAT_R8_SSCALED:
-      return fetch_R8_SSCALED;
+      return &fetch_R8_SSCALED;
    case PIPE_FORMAT_R8G8_SSCALED:
-      return fetch_R8G8_SSCALED;
+      return &fetch_R8G8_SSCALED;
    case PIPE_FORMAT_R8G8B8_SSCALED:
-      return fetch_R8G8B8_SSCALED;
+      return &fetch_R8G8B8_SSCALED;
    case PIPE_FORMAT_R8G8B8A8_SSCALED:
-      return fetch_R8G8B8A8_SSCALED;
+      return &fetch_R8G8B8A8_SSCALED;
+
+   case PIPE_FORMAT_B8G8R8A8_UNORM:
+      return &fetch_B8G8R8A8_UNORM;
 
    case PIPE_FORMAT_A8R8G8B8_UNORM:
-      return fetch_A8R8G8B8_UNORM;
+      return &fetch_A8R8G8B8_UNORM;
 
-   case PIPE_FORMAT_B8G8R8A8_UNORM:
-      return fetch_B8G8R8A8_UNORM;
+   case PIPE_FORMAT_R32_FIXED:
+      return &fetch_R32_FIXED;
+   case PIPE_FORMAT_R32G32_FIXED:
+      return &fetch_R32G32_FIXED;
+   case PIPE_FORMAT_R32G32B32_FIXED:
+      return &fetch_R32G32B32_FIXED;
+   case PIPE_FORMAT_R32G32B32A32_FIXED:
+      return &fetch_R32G32B32A32_FIXED;
 
    default:
       assert(0); 
-      return fetch_NULL;
+      return &fetch_NULL;
    }
 }
 
@@ -398,142 +418,148 @@ static fetch_func get_fetch_func( enum pipe_format format )
 
 static emit_func get_emit_func( enum pipe_format format )
 {
+   /* silence warnings */
+   (void) emit_R32G32B32A32_FIXED;
+   (void) emit_R32G32B32_FIXED;
+   (void) emit_R32G32_FIXED;
+   (void) emit_R32_FIXED;
+
    switch (format) {
    case PIPE_FORMAT_R64_FLOAT:
-      return emit_R64_FLOAT;
+      return &emit_R64_FLOAT;
    case PIPE_FORMAT_R64G64_FLOAT:
-      return emit_R64G64_FLOAT;
+      return &emit_R64G64_FLOAT;
    case PIPE_FORMAT_R64G64B64_FLOAT:
-      return emit_R64G64B64_FLOAT;
+      return &emit_R64G64B64_FLOAT;
    case PIPE_FORMAT_R64G64B64A64_FLOAT:
-      return emit_R64G64B64A64_FLOAT;
+      return &emit_R64G64B64A64_FLOAT;
 
    case PIPE_FORMAT_R32_FLOAT:
-      return emit_R32_FLOAT;
+      return &emit_R32_FLOAT;
    case PIPE_FORMAT_R32G32_FLOAT:
-      return emit_R32G32_FLOAT;
+      return &emit_R32G32_FLOAT;
    case PIPE_FORMAT_R32G32B32_FLOAT:
-      return emit_R32G32B32_FLOAT;
+      return &emit_R32G32B32_FLOAT;
    case PIPE_FORMAT_R32G32B32A32_FLOAT:
-      return emit_R32G32B32A32_FLOAT;
+      return &emit_R32G32B32A32_FLOAT;
 
    case PIPE_FORMAT_R32_UNORM:
-      return emit_R32_UNORM;
+      return &emit_R32_UNORM;
    case PIPE_FORMAT_R32G32_UNORM:
-      return emit_R32G32_UNORM;
+      return &emit_R32G32_UNORM;
    case PIPE_FORMAT_R32G32B32_UNORM:
-      return emit_R32G32B32_UNORM;
+      return &emit_R32G32B32_UNORM;
    case PIPE_FORMAT_R32G32B32A32_UNORM:
-      return emit_R32G32B32A32_UNORM;
+      return &emit_R32G32B32A32_UNORM;
 
    case PIPE_FORMAT_R32_USCALED:
-      return emit_R32_USCALED;
+      return &emit_R32_USCALED;
    case PIPE_FORMAT_R32G32_USCALED:
-      return emit_R32G32_USCALED;
+      return &emit_R32G32_USCALED;
    case PIPE_FORMAT_R32G32B32_USCALED:
-      return emit_R32G32B32_USCALED;
+      return &emit_R32G32B32_USCALED;
    case PIPE_FORMAT_R32G32B32A32_USCALED:
-      return emit_R32G32B32A32_USCALED;
+      return &emit_R32G32B32A32_USCALED;
 
    case PIPE_FORMAT_R32_SNORM:
-      return emit_R32_SNORM;
+      return &emit_R32_SNORM;
    case PIPE_FORMAT_R32G32_SNORM:
-      return emit_R32G32_SNORM;
+      return &emit_R32G32_SNORM;
    case PIPE_FORMAT_R32G32B32_SNORM:
-      return emit_R32G32B32_SNORM;
+      return &emit_R32G32B32_SNORM;
    case PIPE_FORMAT_R32G32B32A32_SNORM:
-      return emit_R32G32B32A32_SNORM;
+      return &emit_R32G32B32A32_SNORM;
 
    case PIPE_FORMAT_R32_SSCALED:
-      return emit_R32_SSCALED;
+      return &emit_R32_SSCALED;
    case PIPE_FORMAT_R32G32_SSCALED:
-      return emit_R32G32_SSCALED;
+      return &emit_R32G32_SSCALED;
    case PIPE_FORMAT_R32G32B32_SSCALED:
-      return emit_R32G32B32_SSCALED;
+      return &emit_R32G32B32_SSCALED;
    case PIPE_FORMAT_R32G32B32A32_SSCALED:
-      return emit_R32G32B32A32_SSCALED;
+      return &emit_R32G32B32A32_SSCALED;
 
    case PIPE_FORMAT_R16_UNORM:
-      return emit_R16_UNORM;
+      return &emit_R16_UNORM;
    case PIPE_FORMAT_R16G16_UNORM:
-      return emit_R16G16_UNORM;
+      return &emit_R16G16_UNORM;
    case PIPE_FORMAT_R16G16B16_UNORM:
-      return emit_R16G16B16_UNORM;
+      return &emit_R16G16B16_UNORM;
    case PIPE_FORMAT_R16G16B16A16_UNORM:
-      return emit_R16G16B16A16_UNORM;
+      return &emit_R16G16B16A16_UNORM;
 
    case PIPE_FORMAT_R16_USCALED:
-      return emit_R16_USCALED;
+      return &emit_R16_USCALED;
    case PIPE_FORMAT_R16G16_USCALED:
-      return emit_R16G16_USCALED;
+      return &emit_R16G16_USCALED;
    case PIPE_FORMAT_R16G16B16_USCALED:
-      return emit_R16G16B16_USCALED;
+      return &emit_R16G16B16_USCALED;
    case PIPE_FORMAT_R16G16B16A16_USCALED:
-      return emit_R16G16B16A16_USCALED;
+      return &emit_R16G16B16A16_USCALED;
 
    case PIPE_FORMAT_R16_SNORM:
-      return emit_R16_SNORM;
+      return &emit_R16_SNORM;
    case PIPE_FORMAT_R16G16_SNORM:
-      return emit_R16G16_SNORM;
+      return &emit_R16G16_SNORM;
    case PIPE_FORMAT_R16G16B16_SNORM:
-      return emit_R16G16B16_SNORM;
+      return &emit_R16G16B16_SNORM;
    case PIPE_FORMAT_R16G16B16A16_SNORM:
-      return emit_R16G16B16A16_SNORM;
+      return &emit_R16G16B16A16_SNORM;
 
    case PIPE_FORMAT_R16_SSCALED:
-      return emit_R16_SSCALED;
+      return &emit_R16_SSCALED;
    case PIPE_FORMAT_R16G16_SSCALED:
-      return emit_R16G16_SSCALED;
+      return &emit_R16G16_SSCALED;
    case PIPE_FORMAT_R16G16B16_SSCALED:
-      return emit_R16G16B16_SSCALED;
+      return &emit_R16G16B16_SSCALED;
    case PIPE_FORMAT_R16G16B16A16_SSCALED:
-      return emit_R16G16B16A16_SSCALED;
+      return &emit_R16G16B16A16_SSCALED;
 
    case PIPE_FORMAT_R8_UNORM:
-      return emit_R8_UNORM;
+      return &emit_R8_UNORM;
    case PIPE_FORMAT_R8G8_UNORM:
-      return emit_R8G8_UNORM;
+      return &emit_R8G8_UNORM;
    case PIPE_FORMAT_R8G8B8_UNORM:
-      return emit_R8G8B8_UNORM;
+      return &emit_R8G8B8_UNORM;
    case PIPE_FORMAT_R8G8B8A8_UNORM:
-      return emit_R8G8B8A8_UNORM;
+      return &emit_R8G8B8A8_UNORM;
 
    case PIPE_FORMAT_R8_USCALED:
-      return emit_R8_USCALED;
+      return &emit_R8_USCALED;
    case PIPE_FORMAT_R8G8_USCALED:
-      return emit_R8G8_USCALED;
+      return &emit_R8G8_USCALED;
    case PIPE_FORMAT_R8G8B8_USCALED:
-      return emit_R8G8B8_USCALED;
+      return &emit_R8G8B8_USCALED;
    case PIPE_FORMAT_R8G8B8A8_USCALED:
-      return emit_R8G8B8A8_USCALED;
+      return &emit_R8G8B8A8_USCALED;
 
    case PIPE_FORMAT_R8_SNORM:
-      return emit_R8_SNORM;
+      return &emit_R8_SNORM;
    case PIPE_FORMAT_R8G8_SNORM:
-      return emit_R8G8_SNORM;
+      return &emit_R8G8_SNORM;
    case PIPE_FORMAT_R8G8B8_SNORM:
-      return emit_R8G8B8_SNORM;
+      return &emit_R8G8B8_SNORM;
    case PIPE_FORMAT_R8G8B8A8_SNORM:
-      return emit_R8G8B8A8_SNORM;
+      return &emit_R8G8B8A8_SNORM;
 
    case PIPE_FORMAT_R8_SSCALED:
-      return emit_R8_SSCALED;
+      return &emit_R8_SSCALED;
    case PIPE_FORMAT_R8G8_SSCALED:
-      return emit_R8G8_SSCALED;
+      return &emit_R8G8_SSCALED;
    case PIPE_FORMAT_R8G8B8_SSCALED:
-      return emit_R8G8B8_SSCALED;
+      return &emit_R8G8B8_SSCALED;
    case PIPE_FORMAT_R8G8B8A8_SSCALED:
-      return emit_R8G8B8A8_SSCALED;
-
-   case PIPE_FORMAT_A8R8G8B8_UNORM:
-      return emit_A8R8G8B8_UNORM;
+      return &emit_R8G8B8A8_SSCALED;
 
    case PIPE_FORMAT_B8G8R8A8_UNORM:
-      return emit_B8G8R8A8_UNORM;
+      return &emit_B8G8R8A8_UNORM;
+
+   case PIPE_FORMAT_A8R8G8B8_UNORM:
+      return &emit_A8R8G8B8_UNORM;
 
    default:
       assert(0); 
-      return emit_NULL;
+      return &emit_NULL;
    }
 }
 
@@ -542,10 +568,11 @@ static emit_func get_emit_func( enum pipe_format format )
 /**
  * Fetch vertex attributes for 'count' vertices.
  */
-static void generic_run_elts( struct translate *translate,
-                             const unsigned *elts,
-                             unsigned count,
-                             void *output_buffer )
+static void PIPE_CDECL generic_run_elts( struct translate *translate,
+                                         const unsigned *elts,
+                                         unsigned count,
+                                         unsigned instance_id,
+                                         void *output_buffer )
 {
    struct translate_generic *tg = translate_generic(translate);
    char *vert = output_buffer;
@@ -560,18 +587,81 @@ static void generic_run_elts( struct translate *translate,
 
       for (attr = 0; attr < nr_attrs; attr++) {
         float data[4];
-
-        const char *src = (tg->attrib[attr].input_ptr + 
-                           tg->attrib[attr].input_stride * elt);
+         const char *src;
 
         char *dst = (vert + 
                      tg->attrib[attr].output_offset);
 
+         if (tg->attrib[attr].instance_divisor) {
+            src = tg->attrib[attr].input_ptr +
+                  tg->attrib[attr].input_stride *
+                  (instance_id / tg->attrib[attr].instance_divisor);
+         } else {
+            src = tg->attrib[attr].input_ptr +
+                  tg->attrib[attr].input_stride * elt;
+         }
+
         tg->attrib[attr].fetch( src, data );
+
+         if (0) debug_printf("vert %d/%d attr %d: %f %f %f %f\n",
+                             i, elt, attr, data[0], data[1], data[2], data[3]);
+
         tg->attrib[attr].emit( data, dst );
       }
       
-      vert += tg->output_stride;
+      vert += tg->translate.key.output_stride;
+   }
+}
+
+
+
+static void PIPE_CDECL generic_run( struct translate *translate,
+                                    unsigned start,
+                                    unsigned count,
+                                    unsigned instance_id,
+                                    void *output_buffer )
+{
+   struct translate_generic *tg = translate_generic(translate);
+   char *vert = output_buffer;
+   unsigned nr_attrs = tg->nr_attrib;
+   unsigned attr;
+   unsigned i;
+
+   /* loop over vertex attributes (vertex shader inputs)
+    */
+   for (i = 0; i < count; i++) {
+      unsigned elt = start + i;
+
+      for (attr = 0; attr < nr_attrs; attr++) {
+        float data[4];
+
+        char *dst = (vert + 
+                     tg->attrib[attr].output_offset);
+
+         if (tg->attrib[attr].type == TRANSLATE_ELEMENT_NORMAL) {
+            const char *src;
+
+            if (tg->attrib[attr].instance_divisor) {
+               src = tg->attrib[attr].input_ptr +
+                     tg->attrib[attr].input_stride *
+                     (instance_id / tg->attrib[attr].instance_divisor);
+            } else {
+               src = tg->attrib[attr].input_ptr +
+                     tg->attrib[attr].input_stride * elt;
+            }
+
+            tg->attrib[attr].fetch( src, data );
+         } else {
+            data[0] = (float)instance_id;
+         }
+
+         if (0) debug_printf("vert %d attr %d: %f %f %f %f\n",
+                             i, attr, data[0], data[1], data[2], data[3]);
+
+        tg->attrib[attr].emit( data, dst );
+      }
+      
+      vert += tg->translate.key.output_stride;
    }
 }
 
@@ -595,14 +685,14 @@ static void generic_set_buffer( struct translate *translate,
 }
 
 
-static void generic_destroy( struct translate *translate )
+static void generic_release( struct translate *translate )
 {
+   /* Refcount?
+    */
    FREE(translate);
 }
 
-struct translate *translate_generic_create( unsigned output_stride,
-                                           const struct translate_element *elements,
-                                           unsigned nr_elements )
+struct translate *translate_generic_create( const struct translate_key *key )
 {
    struct translate_generic *tg = CALLOC_STRUCT(translate_generic);
    unsigned i;
@@ -610,20 +700,26 @@ struct translate *translate_generic_create( unsigned output_stride,
    if (tg == NULL)
       return NULL;
 
-   tg->translate.destroy = generic_destroy;
+   tg->translate.key = *key;
+   tg->translate.release = generic_release;
    tg->translate.set_buffer = generic_set_buffer;
    tg->translate.run_elts = generic_run_elts;
+   tg->translate.run = generic_run;
+
+   for (i = 0; i < key->nr_elements; i++) {
+      tg->attrib[i].type = key->element[i].type;
+
+      tg->attrib[i].fetch = get_fetch_func(key->element[i].input_format);
+      tg->attrib[i].buffer = key->element[i].input_buffer;
+      tg->attrib[i].input_offset = key->element[i].input_offset;
+      tg->attrib[i].instance_divisor = key->element[i].instance_divisor;
 
-   for (i = 0; i < nr_elements; i++) {
-      tg->attrib[i].fetch = get_fetch_func(elements[i].input_format);
-      tg->attrib[i].buffer = elements[i].input_buffer;
-      tg->attrib[i].input_offset = elements[i].input_offset;
+      tg->attrib[i].emit = get_emit_func(key->element[i].output_format);
+      tg->attrib[i].output_offset = key->element[i].output_offset;
 
-      tg->attrib[i].emit = get_emit_func(elements[i].output_format);
-      tg->attrib[i].output_offset = elements[i].output_offset;
    }
 
-   tg->nr_attrib = nr_elements;
+   tg->nr_attrib = key->nr_elements;
 
 
    return &tg->translate;