draw/translate: fix instancing
[mesa.git] / src / gallium / auxiliary / translate / translate_sse.c
index 48e59590bc2db938d426faf9d4c24549e4e995bd..a4f7b243c135c03cddd23e9d0ab6c3b9fd074a11 100644 (file)
@@ -35,7 +35,7 @@
 #include "translate.h"
 
 
-#if defined(PIPE_ARCH_X86) || defined(PIPE_ARCH_X86_64)
+#if (defined(PIPE_ARCH_X86) || (defined(PIPE_ARCH_X86_64) && !defined(__MINGW32__))) && !defined(PIPE_SUBSYSTEM_EMBEDDED)
 
 #include "rtasm/rtasm_cpu.h"
 #include "rtasm/rtasm_x86sse.h"
@@ -53,7 +53,7 @@ struct translate_buffer {
    unsigned max_index;
 };
 
-struct translate_buffer_varient {
+struct translate_buffer_variant {
    unsigned buffer_index;
    unsigned instance_divisor;
    void *ptr;                    /* updated either per vertex or per instance */
@@ -62,6 +62,30 @@ struct translate_buffer_varient {
 
 #define ELEMENT_BUFFER_INSTANCE_ID  1001
 
+#define NUM_CONSTS 7
+
+enum
+{
+   CONST_IDENTITY,
+   CONST_INV_127,
+   CONST_INV_255,
+   CONST_INV_32767,
+   CONST_INV_65535,
+   CONST_INV_2147483647,
+   CONST_255
+};
+
+#define C(v) {(float)(v), (float)(v), (float)(v), (float)(v)}
+static float consts[NUM_CONSTS][4] = {
+      {0, 0, 0, 1},
+      C(1.0 / 127.0),
+      C(1.0 / 255.0),
+      C(1.0 / 32767.0),
+      C(1.0 / 65535.0),
+      C(1.0 / 2147483647.0),
+      C(255.0)
+};
+#undef C
 
 struct translate_sse {
    struct translate translate;
@@ -72,24 +96,23 @@ struct translate_sse {
    struct x86_function elt8_func;
    struct x86_function *func;
 
-   boolean loaded_identity;
-   boolean loaded_const[5];
-
-   float identity[4];
-   float const_value[5][4];
+   PIPE_ALIGN_VAR(16) float consts[NUM_CONSTS][4];
+   int8_t reg_to_const[16];
+   int8_t const_to_reg[NUM_CONSTS];
 
    struct translate_buffer buffer[PIPE_MAX_ATTRIBS];
    unsigned nr_buffers;
 
-   /* Multiple buffer varients can map to a single buffer. */
-   struct translate_buffer_varient buffer_varient[PIPE_MAX_ATTRIBS];
-   unsigned nr_buffer_varients;
+   /* Multiple buffer variants can map to a single buffer. */
+   struct translate_buffer_variant buffer_variant[PIPE_MAX_ATTRIBS];
+   unsigned nr_buffer_variants;
 
-   /* Multiple elements can map to a single buffer varient. */
-   unsigned element_to_buffer_varient[PIPE_MAX_ATTRIBS];
+   /* Multiple elements can map to a single buffer variant. */
+   unsigned element_to_buffer_variant[PIPE_MAX_ATTRIBS];
 
    boolean use_instancing;
    unsigned instance_id;
+   unsigned start_instance;
 
    /* these are actually known values, but putting them in a struct
     * like this is helpful to keep them in sync across the file.
@@ -108,69 +131,38 @@ static int get_offset( const void *a, const void *b )
    return (const char *)b - (const char *)a;
 }
 
-
-
-static struct x86_reg get_identity( struct translate_sse *p )
+static struct x86_reg get_const( struct translate_sse *p, unsigned id)
 {
-   struct x86_reg reg = x86_make_reg(file_XMM, 7);
-
-   if (!p->loaded_identity) {
-      p->loaded_identity = TRUE;
-      p->identity[0] = 0;
-      p->identity[1] = 0;
-      p->identity[2] = 0;
-      p->identity[3] = 1;
-
-      sse_movups(p->func, reg, 
-                x86_make_disp(p->machine_EDI,
-                              get_offset(p, &p->identity[0])));
-   }
+   struct x86_reg reg;
+   unsigned i;
 
-   return reg;
-}
+   if(p->const_to_reg[id] >= 0)
+      return x86_make_reg(file_XMM, p->const_to_reg[id]);
 
-static struct x86_reg get_const( struct translate_sse *p, unsigned i, float v)
-{
-   struct x86_reg reg = x86_make_reg(file_XMM, 2 + i);
-
-   if (!p->loaded_const[i]) {
-      p->loaded_const[i] = TRUE;
-      p->const_value[i][0] =
-         p->const_value[i][1] =
-         p->const_value[i][2] =
-         p->const_value[i][3] = v;
-
-      sse_movups(p->func, reg,
-                 x86_make_disp(p->machine_EDI,
-                               get_offset(p, &p->const_value[i][0])));
+   for(i = 2; i < 8; ++i)
+   {
+      if(p->reg_to_const[i] < 0)
+         break;
    }
 
-   return reg;
-}
+   /* TODO: be smarter here */
+   if(i == 8)
+      --i;
 
-static struct x86_reg get_inv_127( struct translate_sse *p )
-{
-   return get_const(p, 0, 1.0f / 127.0f);
-}
+   reg = x86_make_reg(file_XMM, i);
 
-static struct x86_reg get_inv_255( struct translate_sse *p )
-{
-   return get_const(p, 1, 1.0f / 255.0f);
-}
+   if(p->reg_to_const[i] >= 0)
+      p->const_to_reg[p->reg_to_const[i]] = -1;
 
-static struct x86_reg get_inv_32767( struct translate_sse *p )
-{
-   return get_const(p, 2, 1.0f / 32767.0f);
-}
+   p->reg_to_const[i] = id;
+   p->const_to_reg[id] = i;
 
-static struct x86_reg get_inv_65535( struct translate_sse *p )
-{
-   return get_const(p, 3, 1.0f / 65535.0f);
-}
+   /* TODO: this should happen outside the loop, if possible */
+   sse_movaps(p->func, reg,
+         x86_make_disp(p->machine_EDI,
+               get_offset(p, &p->consts[id][0])));
 
-static struct x86_reg get_inv_2147483647( struct translate_sse *p )
-{
-   return get_const(p, 4, 1.0f / 2147483647.0f);
+   return reg;
 }
 
 /* load the data in a SSE2 register, padding with zeros */
@@ -190,11 +182,13 @@ static boolean emit_load_sse2( struct translate_sse *p,
    case 2:
       x86_movzx16(p->func, tmp, src);
       sse2_movd(p->func, data, tmp);
+      break;
    case 3:
       x86_movzx8(p->func, tmp, x86_make_disp(src, 2));
       x86_shl_imm(p->func, tmp, 16);
       x86_mov16(p->func, tmp, src);
       sse2_movd(p->func, data, tmp);
+      break;
    case 4:
       sse2_movd(p->func, data, src);
       break;
@@ -245,16 +239,16 @@ static void emit_load_float32( struct translate_sse *p,
        */
       sse_movss(p->func, data, arg0);
       if(out_chans == CHANNELS_0001)
-         sse_orps(p->func, data, get_identity(p) );
+         sse_orps(p->func, data, get_const(p, CONST_IDENTITY) );
       break;
    case 2:
       /* 0 0 0 1
        * a b 0 1
        */
       if(out_chans == CHANNELS_0001)
-         sse_shufps(p->func, data, get_identity(p), SHUF(X, Y, Z, W) );
+         sse_shufps(p->func, data, get_const(p, CONST_IDENTITY), SHUF(X, Y, Z, W) );
       else if(out_chans > 2)
-         sse_movlhps(p->func, data, get_identity(p) );
+         sse_movlhps(p->func, data, get_const(p, CONST_IDENTITY) );
       sse_movlps(p->func, data, arg0);
       break;
    case 3:
@@ -267,7 +261,7 @@ static void emit_load_float32( struct translate_sse *p,
        */
       sse_movss(p->func, data, x86_make_disp(arg0, 8));
       if(out_chans == CHANNELS_0001)
-         sse_shufps(p->func, data, get_identity(p), SHUF(X,Y,Z,W) );
+         sse_shufps(p->func, data, get_const(p, CONST_IDENTITY), SHUF(X,Y,Z,W) );
       sse_shufps(p->func, data, data, SHUF(Y,Z,X,W) );
       sse_movlps(p->func, data, arg0);
       break;
@@ -296,15 +290,15 @@ static void emit_load_float64to32( struct translate_sse *p,
       else
          sse2_cvtsd2ss(p->func, data, data);
       if(out_chans == CHANNELS_0001)
-         sse_shufps(p->func, data, get_identity(p), SHUF(X, Y, Z, W)  );
+         sse_shufps(p->func, data, get_const(p, CONST_IDENTITY), SHUF(X, Y, Z, W)  );
       break;
    case 2:
       sse2_movupd(p->func, data, arg0);
       sse2_cvtpd2ps(p->func, data, data);
       if(out_chans == CHANNELS_0001)
-         sse_shufps(p->func, data, get_identity(p), SHUF(X, Y, Z, W) );
+         sse_shufps(p->func, data, get_const(p, CONST_IDENTITY), SHUF(X, Y, Z, W) );
       else if(out_chans > 2)
-         sse_movlhps(p->func, data, get_identity(p) );
+         sse_movlhps(p->func, data, get_const(p, CONST_IDENTITY) );
        break;
    case 3:
       sse2_movupd(p->func, data, arg0);
@@ -316,7 +310,7 @@ static void emit_load_float64to32( struct translate_sse *p,
          sse2_cvtsd2ss(p->func, tmpXMM, tmpXMM);
       sse_movlhps(p->func, data, tmpXMM);
       if(out_chans == CHANNELS_0001)
-         sse_orps(p->func, data, get_identity(p) );
+         sse_orps(p->func, data, get_const(p, CONST_IDENTITY) );
       break;
    case 4:
       sse2_movupd(p->func, data, arg0);
@@ -524,11 +518,11 @@ static boolean translate_attr_convert( struct translate_sse *p,
             {
             case 8:
                /* TODO: this may be inefficient due to get_identity() being used both as a float and integer register */
-               sse2_punpcklbw(p->func, dataXMM, get_identity(p));
-               sse2_punpcklbw(p->func, dataXMM, get_identity(p));
+               sse2_punpcklbw(p->func, dataXMM, get_const(p, CONST_IDENTITY));
+               sse2_punpcklbw(p->func, dataXMM, get_const(p, CONST_IDENTITY));
                break;
             case 16:
-               sse2_punpcklwd(p->func, dataXMM, get_identity(p));
+               sse2_punpcklwd(p->func, dataXMM, get_const(p, CONST_IDENTITY));
                break;
             case 32: /* we lose precision here */
                sse2_psrld_imm(p->func, dataXMM, 1);
@@ -543,13 +537,20 @@ static boolean translate_attr_convert( struct translate_sse *p,
                switch(input_desc->channel[0].size)
                {
                case 8:
-                  factor = get_inv_255(p);
+                  factor = get_const(p, CONST_INV_255);
                   break;
                case 16:
-                  factor = get_inv_65535(p);
+                  factor = get_const(p, CONST_INV_65535);
                   break;
                case 32:
-                  factor = get_inv_2147483647(p);
+                  factor = get_const(p, CONST_INV_2147483647);
+                  break;
+               default:
+                  assert(0);
+                  factor.disp = 0;
+                  factor.file = 0;
+                  factor.idx = 0;
+                  factor.mod = 0;
                   break;
                }
                sse_mulps(p->func, dataXMM, factor);
@@ -586,13 +587,20 @@ static boolean translate_attr_convert( struct translate_sse *p,
                switch(input_desc->channel[0].size)
                {
                case 8:
-                  factor = get_inv_127(p);
+                  factor = get_const(p, CONST_INV_127);
                   break;
                case 16:
-                  factor = get_inv_32767(p);
+                  factor = get_const(p, CONST_INV_32767);
                   break;
                case 32:
-                  factor = get_inv_2147483647(p);
+                  factor = get_const(p, CONST_INV_2147483647);
+                  break;
+               default:
+                  assert(0);
+                  factor.disp = 0;
+                  factor.file = 0;
+                  factor.idx = 0;
+                  factor.mod = 0;
                   break;
                }
                sse_mulps(p->func, dataXMM, factor);
@@ -734,12 +742,12 @@ static boolean translate_attr_convert( struct translate_sse *p,
                       sse2_psrlw_imm(p->func, dataXMM, 1);
             }
             else
-               sse2_punpcklbw(p->func, dataXMM, get_identity(p));
+               sse2_punpcklbw(p->func, dataXMM, get_const(p, CONST_IDENTITY));
             break;
          case UTIL_FORMAT_TYPE_SIGNED:
             if(input_desc->channel[0].normalized)
             {
-               sse2_movq(p->func, tmpXMM, get_identity(p));
+               sse2_movq(p->func, tmpXMM, get_const(p, CONST_IDENTITY));
                sse2_punpcklbw(p->func, tmpXMM, dataXMM);
                sse2_psllw_imm(p->func, dataXMM, 9);
                sse2_psrlw_imm(p->func, dataXMM, 8);
@@ -1004,6 +1012,33 @@ static boolean translate_attr_convert( struct translate_sse *p,
       }
       return TRUE;
    }
+   /* special case for draw's EMIT_4UB (RGBA) and EMIT_4UB_BGRA */
+   else if((x86_target_caps(p->func) & X86_SSE2) &&
+         a->input_format == PIPE_FORMAT_R32G32B32A32_FLOAT && (0
+               || a->output_format == PIPE_FORMAT_B8G8R8A8_UNORM
+               || a->output_format == PIPE_FORMAT_R8G8B8A8_UNORM
+         ))
+   {
+      struct x86_reg dataXMM = x86_make_reg(file_XMM, 0);
+
+      /* load */
+      sse_movups(p->func, dataXMM, src);
+
+      if (a->output_format == PIPE_FORMAT_B8G8R8A8_UNORM)
+         sse_shufps(p->func, dataXMM, dataXMM, SHUF(2,1,0,3));
+
+      /* scale by 255.0 */
+      sse_mulps(p->func, dataXMM, get_const(p, CONST_255));
+
+      /* pack and emit */
+      sse2_cvtps2dq(p->func, dataXMM, dataXMM);
+      sse2_packssdw(p->func, dataXMM, dataXMM);
+      sse2_packuswb(p->func, dataXMM, dataXMM);
+      sse2_movd(p->func, dst, dataXMM);
+
+      return TRUE;
+   }
+
    return FALSE;
 }
 
@@ -1027,16 +1062,20 @@ static boolean init_inputs( struct translate_sse *p,
    unsigned i;
    struct x86_reg instance_id = x86_make_disp(p->machine_EDI,
                                               get_offset(p, &p->instance_id));
+   struct x86_reg start_instance = x86_make_disp(p->machine_EDI,
+                                                 get_offset(p, &p->start_instance));
 
-   for (i = 0; i < p->nr_buffer_varients; i++) {
-      struct translate_buffer_varient *varient = &p->buffer_varient[i];
-      struct translate_buffer *buffer = &p->buffer[varient->buffer_index];
+   for (i = 0; i < p->nr_buffer_variants; i++) {
+      struct translate_buffer_variant *variant = &p->buffer_variant[i];
+      struct translate_buffer *buffer = &p->buffer[variant->buffer_index];
 
-      if (!index_size || varient->instance_divisor) {
+      if (!index_size || variant->instance_divisor) {
+         struct x86_reg buf_max_index = x86_make_disp(p->machine_EDI,
+                                                     get_offset(p, &buffer->max_index));
          struct x86_reg buf_stride   = x86_make_disp(p->machine_EDI,
                                                      get_offset(p, &buffer->stride));
          struct x86_reg buf_ptr      = x86_make_disp(p->machine_EDI,
-                                                     get_offset(p, &varient->ptr));
+                                                     get_offset(p, &variant->ptr));
          struct x86_reg buf_base_ptr = x86_make_disp(p->machine_EDI,
                                                      get_offset(p, &buffer->base_ptr));
          struct x86_reg elt = p->idx_ESI;
@@ -1045,40 +1084,57 @@ static boolean init_inputs( struct translate_sse *p,
          /* Calculate pointer to first attrib:
           *   base_ptr + stride * index, where index depends on instance divisor
           */
-         if (varient->instance_divisor) {
-            /* Our index is instance ID divided by instance divisor.
+         if (variant->instance_divisor) {
+            /* Start with instance = instance_id
+             * which is true if divisor is 1.
              */
             x86_mov(p->func, tmp_EAX, instance_id);
 
-            if (varient->instance_divisor != 1) {
+            if (variant->instance_divisor != 1) {
                struct x86_reg tmp_EDX = p->tmp2_EDX;
                struct x86_reg tmp_ECX = p->src_ECX;
 
+               /* instance_num = instance_id - start_instance */
+               x86_mov(p->func, tmp_EDX, start_instance);
+               x86_sub(p->func, tmp_EAX, tmp_EDX);
+
                /* TODO: Add x86_shr() to rtasm and use it whenever
                 *       instance divisor is power of two.
                 */
-
                x86_xor(p->func, tmp_EDX, tmp_EDX);
-               x86_mov_reg_imm(p->func, tmp_ECX, varient->instance_divisor);
+               x86_mov_reg_imm(p->func, tmp_ECX, variant->instance_divisor);
                x86_div(p->func, tmp_ECX);    /* EAX = EDX:EAX / ECX */
+
+               /* instance = (instance_id - start_instance) / divisor + 
+                *             start_instance 
+                */
+               x86_mov(p->func, tmp_EDX, start_instance);
+               x86_add(p->func, tmp_EAX, tmp_EDX);
             }
+
+            /* XXX we need to clamp the index here too, but to a
+             * per-array max value, not the draw->pt.max_index value
+             * that's being given to us via translate->set_buffer().
+             */
          } else {
             x86_mov(p->func, tmp_EAX, elt);
-         }
 
-         /*
-          * TODO: Respect translate_buffer::max_index.
-          */
+            /* Clamp to max_index
+             */
+            x86_cmp(p->func, tmp_EAX, buf_max_index);
+            x86_cmovcc(p->func, tmp_EAX, buf_max_index, cc_AE);
+         }
 
          x86_imul(p->func, tmp_EAX, buf_stride);
          x64_rexw(p->func);
          x86_add(p->func, tmp_EAX, buf_base_ptr);
 
+         x86_cmp(p->func, p->count_EBP, p->tmp_EAX);
 
          /* In the linear case, keep the buffer pointer instead of the
           * index number.
           */
-         if (!index_size && p->nr_buffer_varients == 1)
+         if (!index_size && p->nr_buffer_variants == 1)
          {
             x64_rexw(p->func);
             x86_mov(p->func, elt, tmp_EAX);
@@ -1104,14 +1160,14 @@ static struct x86_reg get_buffer_ptr( struct translate_sse *p,
       return x86_make_disp(p->machine_EDI,
                            get_offset(p, &p->instance_id));
    }
-   if (!index_size && p->nr_buffer_varients == 1) {
+   if (!index_size && p->nr_buffer_variants == 1) {
       return p->idx_ESI;
    }
-   else if (!index_size || p->buffer_varient[var_idx].instance_divisor) {
+   else if (!index_size || p->buffer_variant[var_idx].instance_divisor) {
       struct x86_reg ptr = p->src_ECX;
       struct x86_reg buf_ptr = 
          x86_make_disp(p->machine_EDI,
-                       get_offset(p, &p->buffer_varient[var_idx].ptr));
+                       get_offset(p, &p->buffer_variant[var_idx].ptr));
       
       x64_rexw(p->func);
       x86_mov(p->func, ptr, buf_ptr);
@@ -1119,15 +1175,19 @@ static struct x86_reg get_buffer_ptr( struct translate_sse *p,
    }
    else {
       struct x86_reg ptr = p->src_ECX;
-      const struct translate_buffer_varient *varient = &p->buffer_varient[var_idx];
+      const struct translate_buffer_variant *variant = &p->buffer_variant[var_idx];
 
       struct x86_reg buf_stride = 
          x86_make_disp(p->machine_EDI,
-                       get_offset(p, &p->buffer[varient->buffer_index].stride));
+                       get_offset(p, &p->buffer[variant->buffer_index].stride));
 
       struct x86_reg buf_base_ptr = 
          x86_make_disp(p->machine_EDI,
-                       get_offset(p, &p->buffer[varient->buffer_index].base_ptr));
+                       get_offset(p, &p->buffer[variant->buffer_index].base_ptr));
+
+      struct x86_reg buf_max_index =
+         x86_make_disp(p->machine_EDI,
+                       get_offset(p, &p->buffer[variant->buffer_index].max_index));
 
 
 
@@ -1145,6 +1205,12 @@ static struct x86_reg get_buffer_ptr( struct translate_sse *p,
          x86_mov(p->func, ptr, elt);
          break;
       }
+
+      /* Clamp to max_index
+       */
+      x86_cmp(p->func, ptr, buf_max_index);
+      x86_cmovcc(p->func, ptr, buf_max_index, cc_AE);
+
       x86_imul(p->func, ptr, buf_stride);
       x64_rexw(p->func);
       x86_add(p->func, ptr, buf_base_ptr);
@@ -1157,11 +1223,11 @@ static struct x86_reg get_buffer_ptr( struct translate_sse *p,
 static boolean incr_inputs( struct translate_sse *p, 
                             unsigned index_size )
 {
-   if (!index_size && p->nr_buffer_varients == 1) {
+   if (!index_size && p->nr_buffer_variants == 1) {
       struct x86_reg stride = x86_make_disp(p->machine_EDI,
                                             get_offset(p, &p->buffer[0].stride));
 
-      if (p->buffer_varient[0].instance_divisor == 0) {
+      if (p->buffer_variant[0].instance_divisor == 0) {
          x64_rexw(p->func);
          x86_add(p->func, p->idx_ESI, stride);
          sse_prefetchnta(p->func, x86_make_disp(p->idx_ESI, 192));
@@ -1172,14 +1238,14 @@ static boolean incr_inputs( struct translate_sse *p,
 
       /* Is this worthwhile??
        */
-      for (i = 0; i < p->nr_buffer_varients; i++) {
-         struct translate_buffer_varient *varient = &p->buffer_varient[i];
+      for (i = 0; i < p->nr_buffer_variants; i++) {
+         struct translate_buffer_variant *variant = &p->buffer_variant[i];
          struct x86_reg buf_ptr = x86_make_disp(p->machine_EDI,
-                                                get_offset(p, &varient->ptr));
+                                                get_offset(p, &variant->ptr));
          struct x86_reg buf_stride = x86_make_disp(p->machine_EDI,
-                                                   get_offset(p, &p->buffer[varient->buffer_index].stride));
+                                                   get_offset(p, &p->buffer[variant->buffer_index].stride));
 
-         if (varient->instance_divisor == 0) {
+         if (variant->instance_divisor == 0) {
             x86_mov(p->func, p->tmp_EAX, buf_stride);
             x64_rexw(p->func);
             x86_add(p->func, p->tmp_EAX, buf_ptr);
@@ -1190,6 +1256,7 @@ static boolean incr_inputs( struct translate_sse *p,
       }
    } 
    else {
+      x64_rexw(p->func);
       x86_lea(p->func, p->idx_ESI, x86_make_disp(p->idx_ESI, index_size));
    }
    
@@ -1220,6 +1287,9 @@ static boolean build_vertex_emit( struct translate_sse *p,
    int fixup, label;
    unsigned j;
 
+   memset(p->reg_to_const, 0xff, sizeof(p->reg_to_const));
+   memset(p->const_to_reg, 0xff, sizeof(p->const_to_reg));
+
    p->tmp_EAX       = x86_make_reg(file_REG32, reg_AX);
    p->idx_ESI       = x86_make_reg(file_REG32, reg_SI);
    p->outbuf_EBX    = x86_make_reg(file_REG32, reg_BX);
@@ -1229,8 +1299,6 @@ static boolean build_vertex_emit( struct translate_sse *p,
    p->src_ECX     = x86_make_reg(file_REG32, reg_CX);
 
    p->func = func;
-   memset(&p->loaded_const, 0, sizeof(p->loaded_const));
-   p->loaded_identity = FALSE;
 
    x86_init_func(p->func);
 
@@ -1257,16 +1325,23 @@ static boolean build_vertex_emit( struct translate_sse *p,
    x86_mov(p->func, p->count_EBP, x86_fn_arg(p->func, 3));
 
    if(x86_target(p->func) != X86_32)
-      x64_mov64(p->func, p->outbuf_EBX, x86_fn_arg(p->func, 5));
+      x64_mov64(p->func, p->outbuf_EBX, x86_fn_arg(p->func, 6));
    else
-      x86_mov(p->func, p->outbuf_EBX, x86_fn_arg(p->func, 5));
+      x86_mov(p->func, p->outbuf_EBX, x86_fn_arg(p->func, 6));
 
    /* Load instance ID.
     */
-   if (p->use_instancing) {
+   if (p->use_instancing) {      
       x86_mov(p->func,
-              p->tmp_EAX,
+              p->tmp2_EDX,
               x86_fn_arg(p->func, 4));
+      x86_mov(p->func,
+              x86_make_disp(p->machine_EDI, get_offset(p, &p->start_instance)),
+              p->tmp2_EDX);
+
+      x86_mov(p->func,
+              p->tmp_EAX,
+              x86_fn_arg(p->func, 5));
       x86_mov(p->func,
               x86_make_disp(p->machine_EDI, get_offset(p, &p->instance_id)),
               p->tmp_EAX);
@@ -1287,18 +1362,18 @@ static boolean build_vertex_emit( struct translate_sse *p,
    label = x86_get_label(p->func);
    {
       struct x86_reg elt = !index_size ? p->idx_ESI : x86_deref(p->idx_ESI);
-      int last_varient = -1;
+      int last_variant = -1;
       struct x86_reg vb;
 
       for (j = 0; j < p->translate.key.nr_elements; j++) {
          const struct translate_element *a = &p->translate.key.element[j];
-         unsigned varient = p->element_to_buffer_varient[j];
+         unsigned variant = p->element_to_buffer_variant[j];
 
          /* Figure out source pointer address:
           */
-         if (varient != last_varient) {
-            last_varient = varient;
-            vb = get_buffer_ptr(p, index_size, varient, elt);
+         if (variant != last_variant) {
+            last_variant = variant;
+            vb = get_buffer_ptr(p, index_size, variant, elt);
          }
          
          if (!translate_attr( p, a, 
@@ -1387,10 +1462,12 @@ static void translate_sse_release( struct translate *translate )
 {
    struct translate_sse *p = (struct translate_sse *)translate;
 
-   x86_release_func( &p->linear_func );
+   x86_release_func( &p->elt8_func );
+   x86_release_func( &p->elt16_func );
    x86_release_func( &p->elt_func );
+   x86_release_func( &p->linear_func );
 
-   FREE(p);
+   os_free_aligned(p);
 }
 
 
@@ -1403,9 +1480,11 @@ struct translate *translate_sse2_create( const struct translate_key *key )
    if (!rtasm_cpu_has_sse())
       goto fail;
 
-   p = CALLOC_STRUCT( translate_sse );
+   p = os_malloc_aligned(sizeof(struct translate_sse), 16);
    if (p == NULL) 
       goto fail;
+   memset(p, 0, sizeof(*p));
+   memcpy(p->consts, consts, sizeof(consts));
 
    p->translate.key = *key;
    p->translate.release = translate_sse_release;
@@ -1422,24 +1501,24 @@ struct translate *translate_sse2_create( const struct translate_key *key )
          }
 
          /*
-          * Map vertex element to vertex buffer varient.
+          * Map vertex element to vertex buffer variant.
           */
-         for (j = 0; j < p->nr_buffer_varients; j++) {
-            if (p->buffer_varient[j].buffer_index == key->element[i].input_buffer &&
-                p->buffer_varient[j].instance_divisor == key->element[i].instance_divisor) {
+         for (j = 0; j < p->nr_buffer_variants; j++) {
+            if (p->buffer_variant[j].buffer_index == key->element[i].input_buffer &&
+                p->buffer_variant[j].instance_divisor == key->element[i].instance_divisor) {
                break;
             }
          }
-         if (j == p->nr_buffer_varients) {
-            p->buffer_varient[j].buffer_index = key->element[i].input_buffer;
-            p->buffer_varient[j].instance_divisor = key->element[i].instance_divisor;
-            p->nr_buffer_varients++;
+         if (j == p->nr_buffer_variants) {
+            p->buffer_variant[j].buffer_index = key->element[i].input_buffer;
+            p->buffer_variant[j].instance_divisor = key->element[i].instance_divisor;
+            p->nr_buffer_variants++;
          }
-         p->element_to_buffer_varient[i] = j;
+         p->element_to_buffer_variant[i] = j;
       } else {
          assert(key->element[i].type == TRANSLATE_ELEMENT_INSTANCE_ID);
 
-         p->element_to_buffer_varient[i] = ELEMENT_BUFFER_INSTANCE_ID;
+         p->element_to_buffer_variant[i] = ELEMENT_BUFFER_INSTANCE_ID;
       }
    }
 
@@ -1457,19 +1536,19 @@ struct translate *translate_sse2_create( const struct translate_key *key )
    if (!build_vertex_emit(p, &p->elt8_func, 1))
       goto fail;
 
-   p->translate.run = (void*)x86_get_func(&p->linear_func);
+   p->translate.run = (run_func) x86_get_func(&p->linear_func);
    if (p->translate.run == NULL)
       goto fail;
 
-   p->translate.run_elts = (void*)x86_get_func(&p->elt_func);
+   p->translate.run_elts = (run_elts_func) x86_get_func(&p->elt_func);
    if (p->translate.run_elts == NULL)
       goto fail;
 
-   p->translate.run_elts16 = (void*)x86_get_func(&p->elt16_func);
+   p->translate.run_elts16 = (run_elts16_func) x86_get_func(&p->elt16_func);
    if (p->translate.run_elts16 == NULL)
       goto fail;
 
-   p->translate.run_elts8 = (void*)x86_get_func(&p->elt8_func);
+   p->translate.run_elts8 = (run_elts8_func) x86_get_func(&p->elt8_func);
    if (p->translate.run_elts8 == NULL)
       goto fail;