gallium: remove TGSI opcode BREAKC
[mesa.git] / src / gallium / state_trackers / nine / nine_shader.c
index 0edf7e8b66961049ff52ead8f97370e1f47753e0..50750cb547b796b40fc612c46e3b8fd2fc059152 100644 (file)
@@ -26,7 +26,9 @@
 #include "device9.h"
 #include "nine_debug.h"
 #include "nine_state.h"
+#include "vertexdeclaration9.h"
 
+#include "util/macros.h"
 #include "util/u_memory.h"
 #include "util/u_inlines.h"
 #include "pipe/p_shader_tokens.h"
@@ -42,7 +44,7 @@ struct shader_translator;
 
 typedef HRESULT (*translate_instruction_func)(struct shader_translator *);
 
-static INLINE const char *d3dsio_to_string(unsigned opcode);
+static inline const char *d3dsio_to_string(unsigned opcode);
 
 
 #define NINED3D_SM1_VS 0xfffe
@@ -88,6 +90,15 @@ static INLINE const char *d3dsio_to_string(unsigned opcode);
 #define NINE_SWIZZLE4(x,y,z,w) \
    TGSI_SWIZZLE_##x, TGSI_SWIZZLE_##y, TGSI_SWIZZLE_##z, TGSI_SWIZZLE_##w
 
+#define NINE_CONSTANT_SRC(index) \
+   ureg_src_register(TGSI_FILE_CONSTANT, index)
+
+#define NINE_APPLY_SWIZZLE(src, s) \
+   ureg_swizzle(src, NINE_SWIZZLE4(s, s, s, s))
+
+#define NINE_CONSTANT_SRC_SWIZZLE(index, s) \
+   NINE_APPLY_SWIZZLE(NINE_CONSTANT_SRC(index), s)
+
 #define NINED3DSPDM_SATURATE (D3DSPDM_SATURATE >> D3DSP_DSTMOD_SHIFT)
 #define NINED3DSPDM_PARTIALP (D3DSPDM_PARTIALPRECISION >> D3DSP_DSTMOD_SHIFT)
 #define NINED3DSPDM_CENTROID (D3DSPDM_MSAMPCENTROID >> D3DSP_DSTMOD_SHIFT)
@@ -238,7 +249,7 @@ struct sm1_dst_param
     BYTE type;
 };
 
-static INLINE void
+static inline void
 assert_replicate_swizzle(const struct ureg_src *reg)
 {
     assert(reg->SwizzleY == reg->SwizzleX &&
@@ -401,12 +412,12 @@ sm1_dump_instruction(struct sm1_instruction *insn, unsigned indent)
         DUMP("_co");
     DUMP(" ");
 
-    for (i = 0; i < insn->ndst && i < Elements(insn->dst); ++i) {
+    for (i = 0; i < insn->ndst && i < ARRAY_SIZE(insn->dst); ++i) {
         sm1_dump_dst_param(&insn->dst[i]);
         DUMP(" ");
     }
 
-    for (i = 0; i < insn->nsrc && i < Elements(insn->src); ++i) {
+    for (i = 0; i < insn->nsrc && i < ARRAY_SIZE(insn->src); ++i) {
         sm1_dump_src_param(&insn->src[i]);
         DUMP(" ");
     }
@@ -422,11 +433,7 @@ struct sm1_local_const
 {
     INT idx;
     struct ureg_src reg;
-    union {
-        boolean b;
-        float f[4];
-        int32_t i[4];
-    } imm;
+    float f[4]; /* for indirect addressing of float constants */
 };
 
 struct shader_translator
@@ -442,13 +449,17 @@ struct shader_translator
         BYTE major;
         BYTE minor;
     } version;
-    unsigned processor; /* TGSI_PROCESSOR_VERTEX/FRAMGENT */
+    unsigned processor; /* PIPE_SHADER_VERTEX/FRAMGENT */
+    unsigned num_constf_allowed;
+    unsigned num_consti_allowed;
+    unsigned num_constb_allowed;
 
     boolean native_integers;
     boolean inline_subroutines;
-    boolean lower_preds;
     boolean want_texcoord;
     boolean shift_wpos;
+    boolean wpos_is_sysval;
+    boolean face_is_sysval_integer;
     unsigned texcoord_sn;
 
     struct sm1_instruction insn; /* current instruction */
@@ -456,12 +467,14 @@ struct shader_translator
     struct {
         struct ureg_dst *r;
         struct ureg_dst oPos;
+        struct ureg_dst oPos_out; /* the real output when doing streamout */
         struct ureg_dst oFog;
         struct ureg_dst oPts;
         struct ureg_dst oCol[4];
         struct ureg_dst o[PIPE_MAX_SHADER_OUTPUTS];
         struct ureg_dst oDepth;
         struct ureg_src v[PIPE_MAX_SHADER_INPUTS];
+        struct ureg_src v_consecutive; /* copy in temp array of ps inputs for rel addressing */
         struct ureg_src vPos;
         struct ureg_src vFace;
         struct ureg_src s;
@@ -475,7 +488,7 @@ struct shader_translator
         struct ureg_src vT[8]; /* PS texcoord in */
         struct ureg_dst rL[NINE_MAX_LOOP_DEPTH]; /* loop ctr */
     } regs;
-    unsigned num_temp; /* Elements(regs.r) */
+    unsigned num_temp; /* ARRAY_SIZE(regs.r) */
     unsigned num_scratch;
     unsigned loop_depth;
     unsigned loop_depth_max;
@@ -491,18 +504,26 @@ struct shader_translator
 
     struct sm1_local_const *lconstf;
     unsigned num_lconstf;
-    struct sm1_local_const lconsti[NINE_MAX_CONST_I];
-    struct sm1_local_const lconstb[NINE_MAX_CONST_B];
+    struct sm1_local_const *lconsti;
+    unsigned num_lconsti;
+    struct sm1_local_const *lconstb;
+    unsigned num_lconstb;
 
     boolean indirect_const_access;
+    boolean failure;
+
+    struct nine_vs_output_info output_info[16];
+    int num_outputs;
 
     struct nine_shader_info *info;
 
     int16_t op_info_map[D3DSIO_BREAKP + 1];
 };
 
-#define IS_VS (tx->processor == TGSI_PROCESSOR_VERTEX)
-#define IS_PS (tx->processor == TGSI_PROCESSOR_FRAGMENT)
+#define IS_VS (tx->processor == PIPE_SHADER_VERTEX)
+#define IS_PS (tx->processor == PIPE_SHADER_FRAGMENT)
+
+#define FAILURE_VOID(cond) if ((cond)) {tx->failure=1;return;}
 
 static void
 sm1_read_semantic(struct shader_translator *, struct sm1_semantic *);
@@ -519,11 +540,26 @@ sm1_instruction_check(const struct sm1_instruction *insn)
     }
 }
 
+static void
+nine_record_outputs(struct shader_translator *tx, BYTE Usage, BYTE UsageIndex,
+                    int mask, int output_index)
+{
+    tx->output_info[tx->num_outputs].output_semantic = Usage;
+    tx->output_info[tx->num_outputs].output_semantic_index = UsageIndex;
+    tx->output_info[tx->num_outputs].mask = mask;
+    tx->output_info[tx->num_outputs].output_index = output_index;
+    tx->num_outputs++;
+}
+
 static boolean
 tx_lconstf(struct shader_translator *tx, struct ureg_src *src, INT index)
 {
    INT i;
-   assert(index >= 0 && index < (NINE_MAX_CONST_F * 2));
+
+   if (index < 0 || index >= tx->num_constf_allowed) {
+       tx->failure = TRUE;
+       return FALSE;
+   }
    for (i = 0; i < tx->num_lconstf; ++i) {
       if (tx->lconstf[i].idx == index) {
          *src = tx->lconstf[i].reg;
@@ -535,18 +571,36 @@ tx_lconstf(struct shader_translator *tx, struct ureg_src *src, INT index)
 static boolean
 tx_lconsti(struct shader_translator *tx, struct ureg_src *src, INT index)
 {
-   assert(index >= 0 && index < NINE_MAX_CONST_I);
-   if (tx->lconsti[index].idx == index)
-      *src = tx->lconsti[index].reg;
-   return tx->lconsti[index].idx == index;
+   int i;
+
+   if (index < 0 || index >= tx->num_consti_allowed) {
+       tx->failure = TRUE;
+       return FALSE;
+   }
+   for (i = 0; i < tx->num_lconsti; ++i) {
+      if (tx->lconsti[i].idx == index) {
+         *src = tx->lconsti[i].reg;
+         return TRUE;
+      }
+   }
+   return FALSE;
 }
 static boolean
 tx_lconstb(struct shader_translator *tx, struct ureg_src *src, INT index)
 {
-   assert(index >= 0 && index < NINE_MAX_CONST_B);
-   if (tx->lconstb[index].idx == index)
-      *src = tx->lconstb[index].reg;
-   return tx->lconstb[index].idx == index;
+   int i;
+
+   if (index < 0 || index >= tx->num_constb_allowed) {
+       tx->failure = TRUE;
+       return FALSE;
+   }
+   for (i = 0; i < tx->num_lconstb; ++i) {
+      if (tx->lconstb[i].idx == index) {
+         *src = tx->lconstb[i].reg;
+         return TRUE;
+      }
+   }
+   return FALSE;
 }
 
 static void
@@ -554,10 +608,7 @@ tx_set_lconstf(struct shader_translator *tx, INT index, float f[4])
 {
     unsigned n;
 
-    /* Anno1404 sets out of range constants. */
-    assert(index >= 0 && index < (NINE_MAX_CONST_F * 2));
-    if (index >= NINE_MAX_CONST_F)
-        WARN("lconstf index %i too high, indirect access won't work\n", index);
+    FAILURE_VOID(index < 0 || index >= tx->num_constf_allowed)
 
     for (n = 0; n < tx->num_lconstf; ++n)
         if (tx->lconstf[n].idx == index)
@@ -574,43 +625,78 @@ tx_set_lconstf(struct shader_translator *tx, INT index, float f[4])
     tx->lconstf[n].idx = index;
     tx->lconstf[n].reg = ureg_imm4f(tx->ureg, f[0], f[1], f[2], f[3]);
 
-    memcpy(tx->lconstf[n].imm.f, f, sizeof(tx->lconstf[n].imm.f));
+    memcpy(tx->lconstf[n].f, f, sizeof(tx->lconstf[n].f));
 }
 static void
 tx_set_lconsti(struct shader_translator *tx, INT index, int i[4])
 {
-    assert(index >= 0 && index < NINE_MAX_CONST_I);
-    tx->lconsti[index].idx = index;
-    tx->lconsti[index].reg = tx->native_integers ?
+    unsigned n;
+
+    FAILURE_VOID(index < 0 || index >= tx->num_consti_allowed)
+
+    for (n = 0; n < tx->num_lconsti; ++n)
+        if (tx->lconsti[n].idx == index)
+            break;
+    if (n == tx->num_lconsti) {
+       if ((n % 8) == 0) {
+          tx->lconsti = REALLOC(tx->lconsti,
+                                (n + 0) * sizeof(tx->lconsti[0]),
+                                (n + 8) * sizeof(tx->lconsti[0]));
+          assert(tx->lconsti);
+       }
+       tx->num_lconsti++;
+    }
+
+    tx->lconsti[n].idx = index;
+    tx->lconsti[n].reg = tx->native_integers ?
        ureg_imm4i(tx->ureg, i[0], i[1], i[2], i[3]) :
        ureg_imm4f(tx->ureg, i[0], i[1], i[2], i[3]);
 }
 static void
 tx_set_lconstb(struct shader_translator *tx, INT index, BOOL b)
 {
-    assert(index >= 0 && index < NINE_MAX_CONST_B);
-    tx->lconstb[index].idx = index;
-    tx->lconstb[index].reg = tx->native_integers ?
+    unsigned n;
+
+    FAILURE_VOID(index < 0 || index >= tx->num_constb_allowed)
+
+    for (n = 0; n < tx->num_lconstb; ++n)
+        if (tx->lconstb[n].idx == index)
+            break;
+    if (n == tx->num_lconstb) {
+       if ((n % 8) == 0) {
+          tx->lconstb = REALLOC(tx->lconstb,
+                                (n + 0) * sizeof(tx->lconstb[0]),
+                                (n + 8) * sizeof(tx->lconstb[0]));
+          assert(tx->lconstb);
+       }
+       tx->num_lconstb++;
+    }
+
+    tx->lconstb[n].idx = index;
+    tx->lconstb[n].reg = tx->native_integers ?
        ureg_imm1u(tx->ureg, b ? 0xffffffff : 0) :
        ureg_imm1f(tx->ureg, b ? 1.0f : 0.0f);
 }
 
-static INLINE struct ureg_dst
+static inline struct ureg_dst
 tx_scratch(struct shader_translator *tx)
 {
-    assert(tx->num_scratch < Elements(tx->regs.t));
+    if (tx->num_scratch >= ARRAY_SIZE(tx->regs.t)) {
+        tx->failure = TRUE;
+        return tx->regs.t[0];
+    }
     if (ureg_dst_is_undef(tx->regs.t[tx->num_scratch]))
         tx->regs.t[tx->num_scratch] = ureg_DECL_local_temporary(tx->ureg);
     return tx->regs.t[tx->num_scratch++];
 }
 
-static INLINE struct ureg_dst
+static inline struct ureg_dst
 tx_scratch_scalar(struct shader_translator *tx)
 {
     return ureg_writemask(tx_scratch(tx), TGSI_WRITEMASK_X);
 }
 
-static INLINE struct ureg_src
+static inline struct ureg_src
 tx_src_scalar(struct ureg_dst dst)
 {
     struct ureg_src src = ureg_src(dst);
@@ -620,25 +706,7 @@ tx_src_scalar(struct ureg_dst dst)
     return src;
 }
 
-/* Need to declare all constants if indirect addressing is used,
- * otherwise we could scan the shader to determine the maximum.
- * TODO: It doesn't really matter for nv50 so I won't do the scan,
- * but radeon drivers might care, if they don't infer it from TGSI.
- */
-static void
-tx_decl_constants(struct shader_translator *tx)
-{
-    unsigned i, n = 0;
-
-    for (i = 0; i < NINE_MAX_CONST_F; ++i)
-        ureg_DECL_constant(tx->ureg, n++);
-    for (i = 0; i < NINE_MAX_CONST_I; ++i)
-        ureg_DECL_constant(tx->ureg, n++);
-    for (i = 0; i < (NINE_MAX_CONST_B / 4); ++i)
-        ureg_DECL_constant(tx->ureg, n++);
-}
-
-static INLINE void
+static inline void
 tx_temp_alloc(struct shader_translator *tx, INT idx)
 {
     assert(idx >= 0);
@@ -656,7 +724,7 @@ tx_temp_alloc(struct shader_translator *tx, INT idx)
         tx->regs.r[idx] = ureg_DECL_temporary(tx->ureg);
 }
 
-static INLINE void
+static inline void
 tx_addr_alloc(struct shader_translator *tx, INT idx)
 {
     assert(idx == 0);
@@ -666,25 +734,65 @@ tx_addr_alloc(struct shader_translator *tx, INT idx)
         tx->regs.a0 = ureg_DECL_temporary(tx->ureg);
 }
 
-static INLINE void
-tx_pred_alloc(struct shader_translator *tx, INT idx)
+/* NOTE: It's not very clear on which ps1.1-ps1.3 instructions
+ * the projection should be applied on the texture. It doesn't
+ * apply on texkill.
+ * The doc is very imprecise here (it says the projection is done
+ * before rasterization, thus in vs, which seems wrong since ps instructions
+ * are affected differently)
+ * For now we only apply to the ps TEX instruction and TEXBEM.
+ * Perhaps some other instructions would need it */
+static inline void
+apply_ps1x_projection(struct shader_translator *tx, struct ureg_dst dst,
+                      struct ureg_src src, INT idx)
 {
-    assert(idx == 0);
-    if (ureg_dst_is_undef(tx->regs.p))
-        tx->regs.p = ureg_DECL_predicate(tx->ureg);
+    struct ureg_dst tmp;
+    unsigned dim = 1 + ((tx->info->projected >> (2 * idx)) & 3);
+
+    /* no projection */
+    if (dim == 1) {
+        ureg_MOV(tx->ureg, dst, src);
+    } else {
+        tmp = tx_scratch_scalar(tx);
+        ureg_RCP(tx->ureg, tmp, ureg_scalar(src, dim-1));
+        ureg_MUL(tx->ureg, dst, tx_src_scalar(tmp), src);
+    }
+}
+
+static inline void
+TEX_with_ps1x_projection(struct shader_translator *tx, struct ureg_dst dst,
+                         unsigned target, struct ureg_src src0,
+                         struct ureg_src src1, INT idx)
+{
+    unsigned dim = 1 + ((tx->info->projected >> (2 * idx)) & 3);
+    struct ureg_dst tmp;
+
+    /* dim == 1: no projection
+     * Looks like must be disabled when it makes no
+     * sense according the texture dimensions
+     */
+    if (dim == 1 || dim <= target) {
+        ureg_TEX(tx->ureg, dst, target, src0, src1);
+    } else if (dim == 4) {
+        ureg_TXP(tx->ureg, dst, target, src0, src1);
+    } else {
+        tmp = tx_scratch(tx);
+        apply_ps1x_projection(tx, tmp, src0, idx);
+        ureg_TEX(tx->ureg, dst, target, ureg_src(tmp), src1);
+    }
 }
 
-static INLINE void
+static inline void
 tx_texcoord_alloc(struct shader_translator *tx, INT idx)
 {
     assert(IS_PS);
-    assert(idx >= 0 && idx < Elements(tx->regs.vT));
+    assert(idx >= 0 && idx < ARRAY_SIZE(tx->regs.vT));
     if (ureg_src_is_undef(tx->regs.vT[idx]))
        tx->regs.vT[idx] = ureg_DECL_fs_input(tx->ureg, tx->texcoord_sn, idx,
                                              TGSI_INTERPOLATE_PERSPECTIVE);
 }
 
-static INLINE unsigned *
+static inline unsigned *
 tx_bgnloop(struct shader_translator *tx)
 {
     tx->loop_depth++;
@@ -694,7 +802,7 @@ tx_bgnloop(struct shader_translator *tx)
     return &tx->loop_labels[tx->loop_depth - 1];
 }
 
-static INLINE unsigned *
+static inline unsigned *
 tx_endloop(struct shader_translator *tx)
 {
     assert(tx->loop_depth);
@@ -743,7 +851,7 @@ tx_get_loopal(struct shader_translator *tx)
     return ureg_src_undef();
 }
 
-static INLINE unsigned *
+static inline unsigned *
 tx_cond(struct shader_translator *tx)
 {
    assert(tx->cond_depth <= NINE_MAX_COND_DEPTH);
@@ -751,14 +859,14 @@ tx_cond(struct shader_translator *tx)
    return &tx->cond_labels[tx->cond_depth - 1];
 }
 
-static INLINE unsigned *
+static inline unsigned *
 tx_elsecond(struct shader_translator *tx)
 {
    assert(tx->cond_depth);
    return &tx->cond_labels[tx->cond_depth - 1];
 }
 
-static INLINE void
+static inline void
 tx_endcond(struct shader_translator *tx)
 {
    assert(tx->cond_depth);
@@ -767,12 +875,24 @@ tx_endcond(struct shader_translator *tx)
                     ureg_get_instruction_number(tx->ureg));
 }
 
-static INLINE struct ureg_dst
+static inline struct ureg_dst
 nine_ureg_dst_register(unsigned file, int index)
 {
     return ureg_dst(ureg_src_register(file, index));
 }
 
+static inline struct ureg_src
+nine_get_position_input(struct shader_translator *tx)
+{
+    struct ureg_program *ureg = tx->ureg;
+
+    if (tx->wpos_is_sysval)
+        return ureg_DECL_system_value(ureg, TGSI_SEMANTIC_POSITION, 0);
+    else
+        return ureg_DECL_fs_input(ureg, TGSI_SEMANTIC_POSITION,
+                                  0, TGSI_INTERPOLATE_LINEAR);
+}
+
 static struct ureg_src
 tx_src_param(struct shader_translator *tx, const struct sm1_src_param *param)
 {
@@ -795,7 +915,12 @@ tx_src_param(struct shader_translator *tx, const struct sm1_src_param *param)
             /* the address register (vs only) must be
              * assigned before use */
             assert(!ureg_dst_is_undef(tx->regs.a0));
-            ureg_ARR(ureg, tx->regs.address, ureg_src(tx->regs.a0));
+            /* Round to lowest for vs1.1 (contrary to the doc), else
+             * round to nearest */
+            if (tx->version.major < 2 && tx->version.minor < 2)
+                ureg_ARL(ureg, tx->regs.address, ureg_src(tx->regs.a0));
+            else
+                ureg_ARR(ureg, tx->regs.address, ureg_src(tx->regs.a0));
             src = ureg_src(tx->regs.address);
         } else {
             if (tx->version.major < 2 && tx->version.minor < 4) {
@@ -813,20 +938,44 @@ tx_src_param(struct shader_translator *tx, const struct sm1_src_param *param)
         } else {
             if (tx->version.major < 3) {
                 assert(!param->rel);
-                src = ureg_DECL_fs_input(tx->ureg, TGSI_SEMANTIC_COLOR,
-                                         param->idx,
-                                         TGSI_INTERPOLATE_PERSPECTIVE);
+                src = ureg_DECL_fs_input_cyl_centroid(
+                    ureg, TGSI_SEMANTIC_COLOR, param->idx,
+                    TGSI_INTERPOLATE_COLOR, 0,
+                    tx->info->force_color_in_centroid ?
+                      TGSI_INTERPOLATE_LOC_CENTROID : 0,
+                    0, 1);
             } else {
-                assert(!param->rel); /* TODO */
-                assert(param->idx < Elements(tx->regs.v));
-                src = tx->regs.v[param->idx];
+                if(param->rel) {
+                    /* Copy all inputs (non consecutive)
+                     * to temp array (consecutive).
+                     * This is not good for performance.
+                     * A better way would be to have inputs
+                     * consecutive (would need implement alternative
+                     * way to match vs outputs and ps inputs).
+                     * However even with the better way, the temp array
+                     * copy would need to be used if some inputs
+                     * are not GENERIC or if they have different
+                     * interpolation flag. */
+                    if (ureg_src_is_undef(tx->regs.v_consecutive)) {
+                        int i;
+                        tx->regs.v_consecutive = ureg_src(ureg_DECL_array_temporary(ureg, 10, 0));
+                        for (i = 0; i < 10; i++) {
+                            if (!ureg_src_is_undef(tx->regs.v[i]))
+                                ureg_MOV(ureg, ureg_dst_array_offset(ureg_dst(tx->regs.v_consecutive), i), tx->regs.v[i]);
+                            else
+                                ureg_MOV(ureg, ureg_dst_array_offset(ureg_dst(tx->regs.v_consecutive), i), ureg_imm4f(ureg, 0.0f, 0.0f, 0.0f, 1.0f));
+                        }
+                    }
+                    src = ureg_src_array_offset(tx->regs.v_consecutive, param->idx);
+                } else {
+                    assert(param->idx < ARRAY_SIZE(tx->regs.v));
+                    src = tx->regs.v[param->idx];
+                }
             }
         }
         break;
     case D3DSPR_PREDICATE:
-        assert(!param->rel);
-        tx_pred_alloc(tx, param->idx);
-        src = ureg_src(tx->regs.p);
+        assert(!"D3DSPR_PREDICATE");
         break;
     case D3DSPR_SAMPLER:
         assert(param->mod == NINED3DSPSM_NONE);
@@ -835,12 +984,32 @@ tx_src_param(struct shader_translator *tx, const struct sm1_src_param *param)
         src = ureg_src_register(TGSI_FILE_SAMPLER, param->idx);
         break;
     case D3DSPR_CONST:
+        assert(!param->rel || IS_VS);
         if (param->rel)
             tx->indirect_const_access = TRUE;
         if (param->rel || !tx_lconstf(tx, &src, param->idx)) {
             if (!param->rel)
                 nine_info_mark_const_f_used(tx->info, param->idx);
-            src = ureg_src_register(TGSI_FILE_CONSTANT, param->idx);
+            /* vswp constant handling: we use two buffers
+             * to fit all the float constants. The special handling
+             * doesn't need to be elsewhere, because all the instructions
+             * accessing the constants directly are VS1, and swvp
+             * is VS >= 2 */
+            if (IS_VS && tx->info->swvp_on) {
+                if (!param->rel) {
+                    if (param->idx < 4096) {
+                        src = ureg_src_register(TGSI_FILE_CONSTANT, param->idx);
+                        src = ureg_src_dimension(src, 0);
+                    } else {
+                        src = ureg_src_register(TGSI_FILE_CONSTANT, param->idx - 4096);
+                        src = ureg_src_dimension(src, 1);
+                    }
+                } else {
+                    src = ureg_src_register(TGSI_FILE_CONSTANT, param->idx); /* TODO: swvp rel > 4096 */
+                    src = ureg_src_dimension(src, 0);
+                }
+            } else
+                src = ureg_src_register(TGSI_FILE_CONSTANT, param->idx);
         }
         if (!IS_VS && tx->version.major < 2) {
             /* ps 1.X clamps constants */
@@ -858,21 +1027,30 @@ tx_src_param(struct shader_translator *tx, const struct sm1_src_param *param)
         src = ureg_imm1f(ureg, 0.0f);
         break;
     case D3DSPR_CONSTINT:
-        if (param->rel || !tx_lconsti(tx, &src, param->idx)) {
-            if (!param->rel)
-                nine_info_mark_const_i_used(tx->info, param->idx);
-            src = ureg_src_register(TGSI_FILE_CONSTANT,
-                                    tx->info->const_i_base + param->idx);
+        /* relative adressing only possible for float constants in vs */
+        assert(!param->rel);
+        if (!tx_lconsti(tx, &src, param->idx)) {
+            nine_info_mark_const_i_used(tx->info, param->idx);
+            if (IS_VS && tx->info->swvp_on) {
+                src = ureg_src_register(TGSI_FILE_CONSTANT, param->idx);
+                src = ureg_src_dimension(src, 2);
+            } else
+                src = ureg_src_register(TGSI_FILE_CONSTANT,
+                                        tx->info->const_i_base + param->idx);
         }
         break;
     case D3DSPR_CONSTBOOL:
-        if (param->rel || !tx_lconstb(tx, &src, param->idx)) {
+        assert(!param->rel);
+        if (!tx_lconstb(tx, &src, param->idx)) {
            char r = param->idx / 4;
            char s = param->idx & 3;
-           if (!param->rel)
-               nine_info_mark_const_b_used(tx->info, param->idx);
-           src = ureg_src_register(TGSI_FILE_CONSTANT,
-                                   tx->info->const_b_base + r);
+           nine_info_mark_const_b_used(tx->info, param->idx);
+           if (IS_VS && tx->info->swvp_on) {
+               src = ureg_src_register(TGSI_FILE_CONSTANT, r);
+               src = ureg_src_dimension(src, 3);
+           } else
+               src = ureg_src_register(TGSI_FILE_CONSTANT,
+                                       tx->info->const_b_base + r);
            src = ureg_swizzle(src, s, s, s, s);
         }
         break;
@@ -889,14 +1067,12 @@ tx_src_param(struct shader_translator *tx, const struct sm1_src_param *param)
         switch (param->idx) {
         case D3DSMO_POSITION:
            if (ureg_src_is_undef(tx->regs.vPos))
-               tx->regs.vPos = ureg_DECL_fs_input(ureg,
-                                                  TGSI_SEMANTIC_POSITION, 0,
-                                                  TGSI_INTERPOLATE_LINEAR);
+              tx->regs.vPos = nine_get_position_input(tx);
            if (tx->shift_wpos) {
                /* TODO: do this only once */
                struct ureg_dst wpos = tx_scratch(tx);
-               ureg_SUB(ureg, wpos, tx->regs.vPos,
-                        ureg_imm4f(ureg, 0.5f, 0.5f, 0.0f, 0.0f));
+               ureg_ADD(ureg, wpos, tx->regs.vPos,
+                        ureg_imm4f(ureg, -0.5f, -0.5f, 0.0f, 0.0f));
                src = ureg_src(wpos);
            } else {
                src = tx->regs.vPos;
@@ -904,9 +1080,20 @@ tx_src_param(struct shader_translator *tx, const struct sm1_src_param *param)
            break;
         case D3DSMO_FACE:
            if (ureg_src_is_undef(tx->regs.vFace)) {
-               tx->regs.vFace = ureg_DECL_fs_input(ureg,
-                                                   TGSI_SEMANTIC_FACE, 0,
-                                                   TGSI_INTERPOLATE_CONSTANT);
+               if (tx->face_is_sysval_integer) {
+                   tmp = tx_scratch(tx);
+                   tx->regs.vFace =
+                       ureg_DECL_system_value(ureg, TGSI_SEMANTIC_FACE, 0);
+
+                   /* convert bool to float */
+                   ureg_UCMP(ureg, tmp, ureg_scalar(tx->regs.vFace, TGSI_SWIZZLE_X),
+                             ureg_imm1f(ureg, 1), ureg_imm1f(ureg, -1));
+                   tx->regs.vFace = ureg_src(tmp);
+               } else {
+                   tx->regs.vFace = ureg_DECL_fs_input(ureg,
+                                                       TGSI_SEMANTIC_FACE, 0,
+                                                       TGSI_INTERPOLATE_CONSTANT);
+               }
                tx->regs.vFace = ureg_scalar(tx->regs.vFace, TGSI_SWIZZLE_X);
            }
            src = tx->regs.vFace;
@@ -929,14 +1116,14 @@ tx_src_param(struct shader_translator *tx, const struct sm1_src_param *param)
     case NINED3DSPSM_DW:
         tmp = tx_scratch(tx);
         /* NOTE: app is not allowed to read w with this modifier */
-        ureg_RCP(ureg, ureg_writemask(tmp, NINED3DSP_WRITEMASK_3), src);
+        ureg_RCP(ureg, ureg_writemask(tmp, NINED3DSP_WRITEMASK_3), ureg_scalar(src, TGSI_SWIZZLE_W));
         ureg_MUL(ureg, tmp, src, ureg_swizzle(ureg_src(tmp), NINE_SWIZZLE4(W,W,W,W)));
         src = ureg_src(tmp);
         break;
     case NINED3DSPSM_DZ:
         tmp = tx_scratch(tx);
         /* NOTE: app is not allowed to read z with this modifier */
-        ureg_RCP(ureg, ureg_writemask(tmp, NINED3DSP_WRITEMASK_2), src);
+        ureg_RCP(ureg, ureg_writemask(tmp, NINED3DSP_WRITEMASK_2), ureg_scalar(src, TGSI_SWIZZLE_Z));
         ureg_MUL(ureg, tmp, src, ureg_swizzle(ureg_src(tmp), NINE_SWIZZLE4(Z,Z,Z,Z)));
         src = ureg_src(tmp);
         break;
@@ -963,12 +1150,12 @@ tx_src_param(struct shader_translator *tx, const struct sm1_src_param *param)
         break;
     case NINED3DSPSM_BIAS:
         tmp = tx_scratch(tx);
-        ureg_SUB(ureg, tmp, src, ureg_imm1f(ureg, 0.5f));
+        ureg_ADD(ureg, tmp, src, ureg_imm1f(ureg, -0.5f));
         src = ureg_src(tmp);
         break;
     case NINED3DSPSM_BIASNEG:
         tmp = tx_scratch(tx);
-        ureg_SUB(ureg, tmp, ureg_imm1f(ureg, 0.5f), src);
+        ureg_ADD(ureg, tmp, ureg_imm1f(ureg, 0.5f), ureg_negate(src));
         src = ureg_src(tmp);
         break;
     case NINED3DSPSM_NOT:
@@ -981,7 +1168,7 @@ tx_src_param(struct shader_translator *tx, const struct sm1_src_param *param)
         /* fall through */
     case NINED3DSPSM_COMP:
         tmp = tx_scratch(tx);
-        ureg_SUB(ureg, tmp, ureg_imm1f(ureg, 1.0f), src);
+        ureg_ADD(ureg, tmp, ureg_imm1f(ureg, 1.0f), ureg_negate(src));
         src = ureg_src(tmp);
         break;
     case NINED3DSPSM_DZ:
@@ -1061,8 +1248,7 @@ _tx_dst_param(struct shader_translator *tx, const struct sm1_dst_param *param)
             break;
         case 2:
             if (ureg_dst_is_undef(tx->regs.oPts))
-                tx->regs.oPts =
-                    ureg_saturate(ureg_DECL_output(tx->ureg, TGSI_SEMANTIC_PSIZE, 0));
+                tx->regs.oPts = ureg_DECL_temporary(tx->ureg);
             dst = tx->regs.oPts;
             break;
         default:
@@ -1077,7 +1263,7 @@ _tx_dst_param(struct shader_translator *tx, const struct sm1_dst_param *param)
             dst = ureg_DECL_output(tx->ureg, tx->texcoord_sn, param->idx);
         } else {
             assert(!param->rel); /* TODO */
-            assert(param->idx < Elements(tx->regs.o));
+            assert(param->idx < ARRAY_SIZE(tx->regs.o));
             dst = tx->regs.o[param->idx];
         }
         break;
@@ -1086,9 +1272,15 @@ _tx_dst_param(struct shader_translator *tx, const struct sm1_dst_param *param)
         assert(param->idx >= 0 && param->idx < 4);
         assert(!param->rel);
         tx->info->rt_mask |= 1 << param->idx;
-        if (ureg_dst_is_undef(tx->regs.oCol[param->idx]))
-            tx->regs.oCol[param->idx] =
-               ureg_DECL_output(tx->ureg, TGSI_SEMANTIC_COLOR, param->idx);
+        if (ureg_dst_is_undef(tx->regs.oCol[param->idx])) {
+            /* ps < 3: oCol[0] will have fog blending afterward */
+            if (!IS_VS && tx->version.major < 3 && param->idx == 0) {
+                tx->regs.oCol[0] = ureg_DECL_temporary(tx->ureg);
+            } else {
+                tx->regs.oCol[param->idx] =
+                    ureg_DECL_output(tx->ureg, TGSI_SEMANTIC_COLOR, param->idx);
+            }
+        }
         dst = tx->regs.oCol[param->idx];
         if (IS_VS && tx->version.major < 3)
             dst = ureg_saturate(dst);
@@ -1098,13 +1290,11 @@ _tx_dst_param(struct shader_translator *tx, const struct sm1_dst_param *param)
         if (ureg_dst_is_undef(tx->regs.oDepth))
            tx->regs.oDepth =
               ureg_DECL_output_masked(tx->ureg, TGSI_SEMANTIC_POSITION, 0,
-                                      TGSI_WRITEMASK_Z);
+                                      TGSI_WRITEMASK_Z, 0, 1);
         dst = tx->regs.oDepth; /* XXX: must write .z component */
         break;
     case D3DSPR_PREDICATE:
-        assert(!param->rel);
-        tx_pred_alloc(tx, param->idx);
-        dst = tx->regs.p;
+        assert(!"D3DSPR_PREDICATE");
         break;
     case D3DSPR_TEMPFLOAT16:
         DBG("unhandled D3DSPR: %u\n", param->file);
@@ -1168,7 +1358,7 @@ tx_dst_param_as_src(struct shader_translator *tx, const struct sm1_dst_param *pa
             src = ureg_src_register(TGSI_FILE_INPUT, param->idx);
         } else {
             assert(!param->rel);
-            assert(param->idx < Elements(tx->regs.v));
+            assert(param->idx < ARRAY_SIZE(tx->regs.v));
             src = tx->regs.v[param->idx];
         }
         break;
@@ -1240,7 +1430,7 @@ NineTranslateInstruction_Mkxn(struct shader_translator *tx, const unsigned k, co
 #define VNOTSUPPORTED   0, 0
 #define V(maj, min)     (((maj) << 8) | (min))
 
-static INLINE const char *
+static inline const char *
 d3dsio_to_string( unsigned opcode )
 {
     static const char *names[] = {
@@ -1343,7 +1533,7 @@ d3dsio_to_string( unsigned opcode )
         "BREAKP"
     };
 
-    if (opcode < Elements(names)) return names[opcode];
+    if (opcode < ARRAY_SIZE(names)) return names[opcode];
 
     switch (opcode) {
     case D3DSIO_PHASE: return "PHASE";
@@ -1370,6 +1560,57 @@ d3dsio_to_string( unsigned opcode )
 static HRESULT
 NineTranslateInstruction_Generic(struct shader_translator *);
 
+DECL_SPECIAL(NOP)
+{
+    /* Nothing to do. NOP was used to avoid hangs
+     * with very old d3d drivers. */
+    return D3D_OK;
+}
+
+DECL_SPECIAL(SUB)
+{
+    struct ureg_program *ureg = tx->ureg;
+    struct ureg_dst dst = tx_dst_param(tx, &tx->insn.dst[0]);
+    struct ureg_src src0 = tx_src_param(tx, &tx->insn.src[0]);
+    struct ureg_src src1 = tx_src_param(tx, &tx->insn.src[1]);
+
+    ureg_ADD(ureg, dst, src0, ureg_negate(src1));
+    return D3D_OK;
+}
+
+DECL_SPECIAL(ABS)
+{
+    struct ureg_program *ureg = tx->ureg;
+    struct ureg_dst dst = tx_dst_param(tx, &tx->insn.dst[0]);
+    struct ureg_src src = tx_src_param(tx, &tx->insn.src[0]);
+
+    ureg_MOV(ureg, dst, ureg_abs(src));
+    return D3D_OK;
+}
+
+DECL_SPECIAL(XPD)
+{
+    struct ureg_program *ureg = tx->ureg;
+    struct ureg_dst dst = tx_dst_param(tx, &tx->insn.dst[0]);
+    struct ureg_src src0 = tx_src_param(tx, &tx->insn.src[0]);
+    struct ureg_src src1 = tx_src_param(tx, &tx->insn.src[1]);
+
+    ureg_MUL(ureg, ureg_writemask(dst, TGSI_WRITEMASK_XYZ),
+             ureg_swizzle(src0, TGSI_SWIZZLE_Y, TGSI_SWIZZLE_Z,
+                          TGSI_SWIZZLE_X, 0),
+             ureg_swizzle(src1, TGSI_SWIZZLE_Z, TGSI_SWIZZLE_X,
+                          TGSI_SWIZZLE_Y, 0));
+    ureg_MAD(ureg, ureg_writemask(dst, TGSI_WRITEMASK_XYZ),
+             ureg_swizzle(src0, TGSI_SWIZZLE_Z, TGSI_SWIZZLE_X,
+                          TGSI_SWIZZLE_Y, 0),
+             ureg_negate(ureg_swizzle(src1, TGSI_SWIZZLE_Y,
+                                      TGSI_SWIZZLE_Z, TGSI_SWIZZLE_X, 0)),
+             ureg_src(dst));
+    ureg_MOV(ureg, ureg_writemask(dst, TGSI_WRITEMASK_W),
+             ureg_imm1f(ureg, 1));
+    return D3D_OK;
+}
+
 DECL_SPECIAL(M4x4)
 {
     return NineTranslateInstruction_Mkxn(tx, 4, 4);
@@ -1458,25 +1699,6 @@ DECL_SPECIAL(CALLNZ)
     return D3D_OK;
 }
 
-DECL_SPECIAL(MOV_vs1x)
-{
-    if (tx->insn.dst[0].file == D3DSPR_ADDR) {
-        /* Implementation note: We don't write directly
-         * to the addr register, but to an intermediate
-         * float register.
-         * Contrary to the doc, when writing to ADDR here,
-         * the rounding is not to nearest, but to lowest
-         * (wine test).
-         * Since we use ARR next, substract 0.5. */
-        ureg_SUB(tx->ureg,
-                 tx_dst_param(tx, &tx->insn.dst[0]),
-                 tx_src_param(tx, &tx->insn.src[0]),
-                 ureg_imm1f(tx->ureg, 0.5f));
-        return D3D_OK;
-    }
-    return NineTranslateInstruction_Generic(tx);
-}
-
 DECL_SPECIAL(LOOP)
 {
     struct ureg_program *ureg = tx->ureg;
@@ -1657,7 +1879,7 @@ DECL_SPECIAL(IF)
     return D3D_OK;
 }
 
-static INLINE unsigned
+static inline unsigned
 sm1_insn_flags_to_tgsi_setop(BYTE flags)
 {
     switch (flags) {
@@ -1680,7 +1902,7 @@ DECL_SPECIAL(IFC)
     struct ureg_dst tmp = ureg_writemask(tx_scratch(tx), TGSI_WRITEMASK_X);
     src[0] = tx_src_param(tx, &tx->insn.src[0]);
     src[1] = tx_src_param(tx, &tx->insn.src[1]);
-    ureg_insn(tx->ureg, cmp_op, &tmp, 1, src, 2);
+    ureg_insn(tx->ureg, cmp_op, &tmp, 1, src, 2, 0);
     ureg_IF(tx->ureg, ureg_scalar(ureg_src(tmp), TGSI_SWIZZLE_X), tx_cond(tx));
     return D3D_OK;
 }
@@ -1698,7 +1920,7 @@ DECL_SPECIAL(BREAKC)
     struct ureg_dst tmp = ureg_writemask(tx_scratch(tx), TGSI_WRITEMASK_X);
     src[0] = tx_src_param(tx, &tx->insn.src[0]);
     src[1] = tx_src_param(tx, &tx->insn.src[1]);
-    ureg_insn(tx->ureg, cmp_op, &tmp, 1, src, 2);
+    ureg_insn(tx->ureg, cmp_op, &tmp, 1, src, 2, 0);
     ureg_IF(tx->ureg, ureg_scalar(ureg_src(tmp), TGSI_SWIZZLE_X), tx_cond(tx));
     ureg_BRK(tx->ureg);
     tx_endcond(tx);
@@ -1724,7 +1946,7 @@ static const char *sm1_declusage_names[] =
     [D3DDECLUSAGE_SAMPLE] = "SAMPLE"
 };
 
-static INLINE unsigned
+static inline unsigned
 sm1_to_nine_declusage(struct sm1_semantic *dcl)
 {
     return nine_d3d9_to_nine_declusage(dcl->usage, dcl->usage_idx);
@@ -1824,7 +2046,7 @@ sm1_declusage_to_tgsi(struct tgsi_declaration_semantic *sem,
         sem->Index = 0;
         break;
     default:
-        assert(!"Invalid DECLUSAGE.");
+        unreachable("Invalid DECLUSAGE.");
         break;
     }
 }
@@ -1833,7 +2055,7 @@ sm1_declusage_to_tgsi(struct tgsi_declaration_semantic *sem,
 #define NINED3DSTT_2D     (D3DSTT_2D >> D3DSP_TEXTURETYPE_SHIFT)
 #define NINED3DSTT_VOLUME (D3DSTT_VOLUME >> D3DSP_TEXTURETYPE_SHIFT)
 #define NINED3DSTT_CUBE   (D3DSTT_CUBE >> D3DSP_TEXTURETYPE_SHIFT)
-static INLINE unsigned
+static inline unsigned
 d3dstt_to_tgsi_tex(BYTE sampler_type)
 {
     switch (sampler_type) {
@@ -1846,7 +2068,7 @@ d3dstt_to_tgsi_tex(BYTE sampler_type)
         return TGSI_TEXTURE_UNKNOWN;
     }
 }
-static INLINE unsigned
+static inline unsigned
 d3dstt_to_tgsi_tex_shadow(BYTE sampler_type)
 {
     switch (sampler_type) {
@@ -1859,7 +2081,7 @@ d3dstt_to_tgsi_tex_shadow(BYTE sampler_type)
         return TGSI_TEXTURE_UNKNOWN;
     }
 }
-static INLINE unsigned
+static inline unsigned
 ps1x_sampler_type(const struct nine_shader_info *info, unsigned stage)
 {
     switch ((info->sampler_ps1xtypes >> (stage * 2)) & 0x3) {
@@ -1884,7 +2106,7 @@ sm1_sampler_type_name(BYTE sampler_type)
     }
 }
 
-static INLINE unsigned
+static inline unsigned
 nine_tgsi_to_interp_mode(struct tgsi_declaration_semantic *sem)
 {
     switch (sem->Name) {
@@ -1893,6 +2115,7 @@ nine_tgsi_to_interp_mode(struct tgsi_declaration_semantic *sem)
         return TGSI_INTERPOLATE_LINEAR;
     case TGSI_SEMANTIC_BCOLOR:
     case TGSI_SEMANTIC_COLOR:
+        return TGSI_INTERPOLATE_COLOR;
     case TGSI_SEMANTIC_FOG:
     case TGSI_SEMANTIC_GENERIC:
     case TGSI_SEMANTIC_TEXCOORD:
@@ -1954,9 +2177,9 @@ DECL_SPECIAL(DCL)
         if (is_input) {
             /* linkage outside of shader with vertex declaration */
             ureg_DECL_vs_input(ureg, sem.reg.idx);
-            assert(sem.reg.idx < Elements(tx->info->input_map));
+            assert(sem.reg.idx < ARRAY_SIZE(tx->info->input_map));
             tx->info->input_map[sem.reg.idx] = sm1_to_nine_declusage(&sem);
-            tx->info->num_inputs = sem.reg.idx + 1;
+            tx->info->num_inputs = MAX2(tx->info->num_inputs, sem.reg.idx + 1);
             /* NOTE: preserving order in case of indirect access */
         } else
         if (tx->version.major >= 3) {
@@ -1964,27 +2187,56 @@ DECL_SPECIAL(DCL)
             assert(sem.reg.mask != 0);
             if (sem.usage == D3DDECLUSAGE_POSITIONT)
                 tx->info->position_t = TRUE;
-            assert(sem.reg.idx < Elements(tx->regs.o));
+            assert(sem.reg.idx < ARRAY_SIZE(tx->regs.o));
+            assert(ureg_dst_is_undef(tx->regs.o[sem.reg.idx]) && "Nine doesn't support yet packing");
             tx->regs.o[sem.reg.idx] = ureg_DECL_output_masked(
-                ureg, tgsi.Name, tgsi.Index, sem.reg.mask);
+                ureg, tgsi.Name, tgsi.Index, sem.reg.mask, 0, 1);
+            nine_record_outputs(tx, sem.usage, sem.usage_idx, sem.reg.mask, sem.reg.idx);
+            if (tx->info->process_vertices && sem.usage == D3DDECLUSAGE_POSITION && sem.usage_idx == 0) {
+                tx->regs.oPos_out = tx->regs.o[sem.reg.idx];
+                tx->regs.o[sem.reg.idx] = ureg_DECL_temporary(ureg);
+                tx->regs.oPos = tx->regs.o[sem.reg.idx];
+            }
 
-            if (tgsi.Name == TGSI_SEMANTIC_PSIZE)
+            if (tgsi.Name == TGSI_SEMANTIC_PSIZE) {
+                tx->regs.o[sem.reg.idx] = ureg_DECL_temporary(ureg);
                 tx->regs.oPts = tx->regs.o[sem.reg.idx];
+            }
         }
     } else {
         if (is_input && tx->version.major >= 3) {
+            unsigned interp_location = 0;
             /* SM3 only, SM2 input semantic determined by file */
-            assert(sem.reg.idx < Elements(tx->regs.v));
+            assert(sem.reg.idx < ARRAY_SIZE(tx->regs.v));
+            assert(ureg_src_is_undef(tx->regs.v[sem.reg.idx]) && "Nine doesn't support yet packing");
+            /* PositionT and tessfactor forbidden */
+            if (sem.usage == D3DDECLUSAGE_POSITIONT || sem.usage == D3DDECLUSAGE_TESSFACTOR)
+                return D3DERR_INVALIDCALL;
+
+            if (tgsi.Name == TGSI_SEMANTIC_POSITION) {
+                /* Position0 is forbidden (likely because vPos already does that) */
+                if (sem.usage == D3DDECLUSAGE_POSITION)
+                    return D3DERR_INVALIDCALL;
+                /* Following code is for depth */
+                tx->regs.v[sem.reg.idx] = nine_get_position_input(tx);
+                return D3D_OK;
+            }
+
+            if (sem.reg.mod & NINED3DSPDM_CENTROID ||
+                (tgsi.Name == TGSI_SEMANTIC_COLOR && tx->info->force_color_in_centroid))
+                interp_location = TGSI_INTERPOLATE_LOC_CENTROID;
+
             tx->regs.v[sem.reg.idx] = ureg_DECL_fs_input_cyl_centroid(
                 ureg, tgsi.Name, tgsi.Index,
                 nine_tgsi_to_interp_mode(&tgsi),
                 0, /* cylwrap */
-                sem.reg.mod & NINED3DSPDM_CENTROID);
+                interp_location, 0, 1);
         } else
         if (!is_input && 0) { /* declare in COLOROUT/DEPTHOUT case */
             /* FragColor or FragDepth */
             assert(sem.reg.mask != 0);
-            ureg_DECL_output_masked(ureg, tgsi.Name, tgsi.Index, sem.reg.mask);
+            ureg_DECL_output_masked(ureg, tgsi.Name, tgsi.Index, sem.reg.mask,
+                                    0, 1);
         }
     }
     return D3D_OK;
@@ -2041,6 +2293,23 @@ DECL_SPECIAL(LOG)
     return D3D_OK;
 }
 
+DECL_SPECIAL(LIT)
+{
+    struct ureg_program *ureg = tx->ureg;
+    struct ureg_dst tmp = tx_scratch(tx);
+    struct ureg_dst dst = tx_dst_param(tx, &tx->insn.dst[0]);
+    struct ureg_src src = tx_src_param(tx, &tx->insn.src[0]);
+    ureg_LIT(ureg, tmp, src);
+    /* d3d9 LIT is the same than gallium LIT. One difference is that d3d9
+     * states that dst.z is 0 when src.y <= 0. Gallium definition can assign
+     * it 0^0 if src.w=0, which value is driver dependent. */
+    ureg_CMP(ureg, ureg_writemask(dst, TGSI_WRITEMASK_Z),
+             ureg_negate(ureg_scalar(src, TGSI_SWIZZLE_Y)),
+             ureg_src(tmp), ureg_imm1f(ureg, 0.0f));
+    ureg_MOV(ureg, ureg_writemask(dst, TGSI_WRITEMASK_XYW), ureg_src(tmp));
+    return D3D_OK;
+}
+
 DECL_SPECIAL(NRM)
 {
     struct ureg_program *ureg = tx->ureg;
@@ -2117,22 +2386,111 @@ DECL_SPECIAL(TEXKILL)
 
 DECL_SPECIAL(TEXBEM)
 {
-    STUB(D3DERR_INVALIDCALL);
-}
+    struct ureg_program *ureg = tx->ureg;
+    struct ureg_dst dst = tx_dst_param(tx, &tx->insn.dst[0]);
+    struct ureg_dst tmp, tmp2, texcoord;
+    struct ureg_src sample, m00, m01, m10, m11;
+    struct ureg_src bumpenvlscale, bumpenvloffset;
+    const int m = tx->insn.dst[0].idx;
+    const int n = tx->insn.src[0].idx;
 
-DECL_SPECIAL(TEXBEML)
-{
-    STUB(D3DERR_INVALIDCALL);
+    assert(tx->version.major == 1);
+
+    sample = ureg_DECL_sampler(ureg, m);
+    tx->info->sampler_mask |= 1 << m;
+
+    tx_texcoord_alloc(tx, m);
+
+    tmp = tx_scratch(tx);
+    tmp2 = tx_scratch(tx);
+    texcoord = tx_scratch(tx);
+    /*
+     * Bump-env-matrix:
+     * 00 is X
+     * 01 is Y
+     * 10 is Z
+     * 11 is W
+     */
+    nine_info_mark_const_f_used(tx->info, 8 + 8 + m/2);
+    m00 = NINE_CONSTANT_SRC_SWIZZLE(8 + m, X);
+    m01 = NINE_CONSTANT_SRC_SWIZZLE(8 + m, Y);
+    m10 = NINE_CONSTANT_SRC_SWIZZLE(8 + m, Z);
+    m11 = NINE_CONSTANT_SRC_SWIZZLE(8 + m, W);
+
+    /* These two attributes are packed as X=scale0 Y=offset0 Z=scale1 W=offset1 etc */
+    if (m % 2 == 0) {
+        bumpenvlscale = NINE_CONSTANT_SRC_SWIZZLE(8 + 8 + m / 2, X);
+        bumpenvloffset = NINE_CONSTANT_SRC_SWIZZLE(8 + 8 + m / 2, Y);
+    } else {
+        bumpenvlscale = NINE_CONSTANT_SRC_SWIZZLE(8 + 8 + m / 2, Z);
+        bumpenvloffset = NINE_CONSTANT_SRC_SWIZZLE(8 + 8 + m / 2, W);
+    }
+
+    apply_ps1x_projection(tx, texcoord, tx->regs.vT[m], m);
+
+    /* u' = TextureCoordinates(stage m)u + D3DTSS_BUMPENVMAT00(stage m)*t(n)R  */
+    ureg_MAD(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_X), m00,
+             NINE_APPLY_SWIZZLE(ureg_src(tx->regs.tS[n]), X), ureg_src(texcoord));
+    /* u' = u' + D3DTSS_BUMPENVMAT10(stage m)*t(n)G */
+    ureg_MAD(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_X), m10,
+             NINE_APPLY_SWIZZLE(ureg_src(tx->regs.tS[n]), Y),
+             NINE_APPLY_SWIZZLE(ureg_src(tmp), X));
+
+    /* v' = TextureCoordinates(stage m)v + D3DTSS_BUMPENVMAT01(stage m)*t(n)R */
+    ureg_MAD(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_Y), m01,
+             NINE_APPLY_SWIZZLE(ureg_src(tx->regs.tS[n]), X), ureg_src(texcoord));
+    /* v' = v' + D3DTSS_BUMPENVMAT11(stage m)*t(n)G*/
+    ureg_MAD(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_Y), m11,
+             NINE_APPLY_SWIZZLE(ureg_src(tx->regs.tS[n]), Y),
+             NINE_APPLY_SWIZZLE(ureg_src(tmp), Y));
+
+    /* Now the texture coordinates are in tmp.xy */
+
+    if (tx->insn.opcode == D3DSIO_TEXBEM) {
+        ureg_TEX(ureg, dst, ps1x_sampler_type(tx->info, m), ureg_src(tmp), sample);
+    } else if (tx->insn.opcode == D3DSIO_TEXBEML) {
+        /* t(m)RGBA = t(m)RGBA * [(t(n)B * D3DTSS_BUMPENVLSCALE(stage m)) + D3DTSS_BUMPENVLOFFSET(stage m)] */
+        ureg_TEX(ureg, tmp, ps1x_sampler_type(tx->info, m), ureg_src(tmp), sample);
+        ureg_MAD(ureg, tmp2, NINE_APPLY_SWIZZLE(ureg_src(tx->regs.tS[n]), Z),
+                 bumpenvlscale, bumpenvloffset);
+        ureg_MUL(ureg, dst, ureg_src(tmp), ureg_src(tmp2));
+    }
+
+    tx->info->bumpenvmat_needed = 1;
+
+    return D3D_OK;
 }
 
 DECL_SPECIAL(TEXREG2AR)
 {
-    STUB(D3DERR_INVALIDCALL);
+    struct ureg_program *ureg = tx->ureg;
+    struct ureg_dst dst = tx_dst_param(tx, &tx->insn.dst[0]);
+    struct ureg_src sample;
+    const int m = tx->insn.dst[0].idx;
+    const int n = tx->insn.src[0].idx;
+    assert(m >= 0 && m > n);
+
+    sample = ureg_DECL_sampler(ureg, m);
+    tx->info->sampler_mask |= 1 << m;
+    ureg_TEX(ureg, dst, ps1x_sampler_type(tx->info, m), ureg_swizzle(ureg_src(tx->regs.tS[n]), NINE_SWIZZLE4(W,X,X,X)), sample);
+
+    return D3D_OK;
 }
 
 DECL_SPECIAL(TEXREG2GB)
 {
-    STUB(D3DERR_INVALIDCALL);
+    struct ureg_program *ureg = tx->ureg;
+    struct ureg_dst dst = tx_dst_param(tx, &tx->insn.dst[0]);
+    struct ureg_src sample;
+    const int m = tx->insn.dst[0].idx;
+    const int n = tx->insn.src[0].idx;
+    assert(m >= 0 && m > n);
+
+    sample = ureg_DECL_sampler(ureg, m);
+    tx->info->sampler_mask |= 1 << m;
+    ureg_TEX(ureg, dst, ps1x_sampler_type(tx->info, m), ureg_swizzle(ureg_src(tx->regs.tS[n]), NINE_SWIZZLE4(Y,Z,Z,Z)), sample);
+
+    return D3D_OK;
 }
 
 DECL_SPECIAL(TEXM3x2PAD)
@@ -2204,7 +2562,7 @@ DECL_SPECIAL(TEXM3x3SPEC)
     ureg_MUL(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_X), ureg_scalar(ureg_src(tmp), TGSI_SWIZZLE_X), ureg_imm1f(ureg, 2.0f));
     ureg_MUL(ureg, tmp, ureg_scalar(ureg_src(tmp), TGSI_SWIZZLE_X), ureg_src(dst));
     /* at this step tmp.xyz = 2 * (N.E / N.N) * N */
-    ureg_SUB(ureg, tmp, ureg_src(tmp), E);
+    ureg_ADD(ureg, tmp, ureg_src(tmp), ureg_negate(E));
     ureg_TEX(ureg, dst, ps1x_sampler_type(tx->info, m + 2), ureg_src(tmp), sample);
 
     return D3D_OK;
@@ -2212,12 +2570,41 @@ DECL_SPECIAL(TEXM3x3SPEC)
 
 DECL_SPECIAL(TEXREG2RGB)
 {
-    STUB(D3DERR_INVALIDCALL);
+    struct ureg_program *ureg = tx->ureg;
+    struct ureg_dst dst = tx_dst_param(tx, &tx->insn.dst[0]);
+    struct ureg_src sample;
+    const int m = tx->insn.dst[0].idx;
+    const int n = tx->insn.src[0].idx;
+    assert(m >= 0 && m > n);
+
+    sample = ureg_DECL_sampler(ureg, m);
+    tx->info->sampler_mask |= 1 << m;
+    ureg_TEX(ureg, dst, ps1x_sampler_type(tx->info, m), ureg_src(tx->regs.tS[n]), sample);
+
+    return D3D_OK;
 }
 
 DECL_SPECIAL(TEXDP3TEX)
 {
-    STUB(D3DERR_INVALIDCALL);
+    struct ureg_program *ureg = tx->ureg;
+    struct ureg_dst dst = tx_dst_param(tx, &tx->insn.dst[0]);
+    struct ureg_dst tmp;
+    struct ureg_src sample;
+    const int m = tx->insn.dst[0].idx;
+    const int n = tx->insn.src[0].idx;
+    assert(m >= 0 && m > n);
+
+    tx_texcoord_alloc(tx, m);
+
+    tmp = tx_scratch(tx);
+    ureg_DP3(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_X), tx->regs.vT[m], ureg_src(tx->regs.tS[n]));
+    ureg_MOV(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_YZ), ureg_imm1f(ureg, 0.0f));
+
+    sample = ureg_DECL_sampler(ureg, m);
+    tx->info->sampler_mask |= 1 << m;
+    ureg_TEX(ureg, dst, ps1x_sampler_type(tx->info, m), ureg_src(tmp), sample);
+
+    return D3D_OK;
 }
 
 DECL_SPECIAL(TEXM3x2DEPTH)
@@ -2244,7 +2631,8 @@ DECL_SPECIAL(TEXM3x2DEPTH)
     ureg_CMP(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_X), ureg_negate(ureg_abs(ureg_scalar(ureg_src(tmp), TGSI_SWIZZLE_Y))),
              ureg_scalar(ureg_src(tmp), TGSI_SWIZZLE_X), ureg_imm1f(ureg, 1.0f));
     /* replace the depth for depth testing with the result */
-    tx->regs.oDepth = ureg_DECL_output_masked(ureg, TGSI_SEMANTIC_POSITION, 0, TGSI_WRITEMASK_Z);
+    tx->regs.oDepth = ureg_DECL_output_masked(ureg, TGSI_SEMANTIC_POSITION, 0,
+                                              TGSI_WRITEMASK_Z, 0, 1);
     ureg_MOV(ureg, tx->regs.oDepth, ureg_scalar(ureg_src(tmp), TGSI_SWIZZLE_X));
     /* note that we write nothing to the destination, since it's disallowed to use it afterward */
     return D3D_OK;
@@ -2252,7 +2640,17 @@ DECL_SPECIAL(TEXM3x2DEPTH)
 
 DECL_SPECIAL(TEXDP3)
 {
-    STUB(D3DERR_INVALIDCALL);
+    struct ureg_program *ureg = tx->ureg;
+    struct ureg_dst dst = tx_dst_param(tx, &tx->insn.dst[0]);
+    const int m = tx->insn.dst[0].idx;
+    const int n = tx->insn.src[0].idx;
+    assert(m >= 0 && m > n);
+
+    tx_texcoord_alloc(tx, m);
+
+    ureg_DP3(ureg, dst, tx->regs.vT[m], ureg_src(tx->regs.tS[n]));
+
+    return D3D_OK;
 }
 
 DECL_SPECIAL(TEXM3x3)
@@ -2303,7 +2701,7 @@ DECL_SPECIAL(TEXM3x3)
         ureg_MUL(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_X), ureg_scalar(ureg_src(tmp), TGSI_SWIZZLE_X), ureg_imm1f(ureg, 2.0f));
         ureg_MUL(ureg, tmp, ureg_scalar(ureg_src(tmp), TGSI_SWIZZLE_X), ureg_src(dst));
         /* at this step tmp.xyz = 2 * (N.E / N.N) * N */
-        ureg_SUB(ureg, tmp, ureg_src(tmp), ureg_src(E));
+        ureg_ADD(ureg, tmp, ureg_src(tmp), ureg_negate(ureg_src(E)));
         ureg_TEX(ureg, dst, ps1x_sampler_type(tx->info, m + 2), ureg_src(tmp), sample);
         break;
     default:
@@ -2314,12 +2712,70 @@ DECL_SPECIAL(TEXM3x3)
 
 DECL_SPECIAL(TEXDEPTH)
 {
-    STUB(D3DERR_INVALIDCALL);
+    struct ureg_program *ureg = tx->ureg;
+    struct ureg_dst r5;
+    struct ureg_src r5r, r5g;
+
+    assert(tx->insn.dst[0].idx == 5); /* instruction must get r5 here */
+
+    /* we must replace the depth by r5.g == 0 ? 1.0f : r5.r/r5.g.
+     * r5 won't be used afterward, thus we can use r5.ba */
+    r5 = tx->regs.r[5];
+    r5r = ureg_scalar(ureg_src(r5), TGSI_SWIZZLE_X);
+    r5g = ureg_scalar(ureg_src(r5), TGSI_SWIZZLE_Y);
+
+    ureg_RCP(ureg, ureg_writemask(r5, TGSI_WRITEMASK_Z), r5g);
+    ureg_MUL(ureg, ureg_writemask(r5, TGSI_WRITEMASK_X), r5r, ureg_scalar(ureg_src(r5), TGSI_SWIZZLE_Z));
+    /* r5.r = r/g */
+    ureg_CMP(ureg, ureg_writemask(r5, TGSI_WRITEMASK_X), ureg_negate(ureg_abs(r5g)),
+             r5r, ureg_imm1f(ureg, 1.0f));
+    /* replace the depth for depth testing with the result */
+    tx->regs.oDepth = ureg_DECL_output_masked(ureg, TGSI_SEMANTIC_POSITION, 0,
+                                              TGSI_WRITEMASK_Z, 0, 1);
+    ureg_MOV(ureg, tx->regs.oDepth, r5r);
+
+    return D3D_OK;
 }
 
 DECL_SPECIAL(BEM)
 {
-    STUB(D3DERR_INVALIDCALL);
+    struct ureg_program *ureg = tx->ureg;
+    struct ureg_dst dst = tx_dst_param(tx, &tx->insn.dst[0]);
+    struct ureg_src src0 = tx_src_param(tx, &tx->insn.src[0]);
+    struct ureg_src src1 = tx_src_param(tx, &tx->insn.src[1]);
+    struct ureg_src m00, m01, m10, m11;
+    const int m = tx->insn.dst[0].idx;
+    struct ureg_dst tmp;
+    /*
+     * Bump-env-matrix:
+     * 00 is X
+     * 01 is Y
+     * 10 is Z
+     * 11 is W
+     */
+    nine_info_mark_const_f_used(tx->info, 8 + m);
+    m00 = NINE_CONSTANT_SRC_SWIZZLE(8 + m, X);
+    m01 = NINE_CONSTANT_SRC_SWIZZLE(8 + m, Y);
+    m10 = NINE_CONSTANT_SRC_SWIZZLE(8 + m, Z);
+    m11 = NINE_CONSTANT_SRC_SWIZZLE(8 + m, W);
+    /* dest.r = src0.r + D3DTSS_BUMPENVMAT00(stage n) * src1.r  */
+    ureg_MAD(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_X), m00,
+             NINE_APPLY_SWIZZLE(src1, X), NINE_APPLY_SWIZZLE(src0, X));
+    /* dest.r = dest.r + D3DTSS_BUMPENVMAT10(stage n) * src1.g; */
+    ureg_MAD(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_X), m10,
+             NINE_APPLY_SWIZZLE(src1, Y), NINE_APPLY_SWIZZLE(ureg_src(tmp), X));
+
+    /* dest.g = src0.g + D3DTSS_BUMPENVMAT01(stage n) * src1.r */
+    ureg_MAD(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_Y), m01,
+             NINE_APPLY_SWIZZLE(src1, X), src0);
+    /* dest.g = dest.g + D3DTSS_BUMPENVMAT11(stage n) * src1.g */
+    ureg_MAD(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_Y), m11,
+             NINE_APPLY_SWIZZLE(src1, Y), NINE_APPLY_SWIZZLE(ureg_src(tmp), Y));
+    ureg_MOV(ureg, ureg_writemask(dst, TGSI_WRITEMASK_XY), ureg_src(tmp));
+
+    tx->info->bumpenvmat_needed = 1;
+
+    return D3D_OK;
 }
 
 DECL_SPECIAL(TEXLD)
@@ -2332,7 +2788,7 @@ DECL_SPECIAL(TEXLD)
         tx_src_param(tx, &tx->insn.src[1])
     };
     assert(tx->insn.src[1].idx >= 0 &&
-           tx->insn.src[1].idx < Elements(tx->sampler_targets));
+           tx->insn.src[1].idx < ARRAY_SIZE(tx->sampler_targets));
     target = tx->sampler_targets[tx->insn.src[1].idx];
 
     switch (tx->insn.flags) {
@@ -2380,7 +2836,7 @@ DECL_SPECIAL(TEX)
     src[1] = ureg_DECL_sampler(ureg, s);
     tx->info->sampler_mask |= 1 << s;
 
-    ureg_TEX(ureg, dst, t, src[0], src[1]);
+    TEX_with_ps1x_projection(tx, dst, t, src[0], src[1], s);
 
     return D3D_OK;
 }
@@ -2395,8 +2851,8 @@ DECL_SPECIAL(TEXLDD)
         tx_src_param(tx, &tx->insn.src[2]),
         tx_src_param(tx, &tx->insn.src[3])
     };
-    assert(tx->insn.src[3].idx >= 0 &&
-           tx->insn.src[3].idx < Elements(tx->sampler_targets));
+    assert(tx->insn.src[1].idx >= 0 &&
+           tx->insn.src[1].idx < ARRAY_SIZE(tx->sampler_targets));
     target = tx->sampler_targets[tx->insn.src[1].idx];
 
     ureg_TXD(tx->ureg, dst, target, src[0], src[2], src[3], src[1]);
@@ -2411,8 +2867,8 @@ DECL_SPECIAL(TEXLDL)
        tx_src_param(tx, &tx->insn.src[0]),
        tx_src_param(tx, &tx->insn.src[1])
     };
-    assert(tx->insn.src[3].idx >= 0 &&
-           tx->insn.src[3].idx < Elements(tx->sampler_targets));
+    assert(tx->insn.src[1].idx >= 0 &&
+           tx->insn.src[1].idx < ARRAY_SIZE(tx->sampler_targets));
     target = tx->sampler_targets[tx->insn.src[1].idx];
 
     ureg_TXL(tx->ureg, dst, target, src[0], src[1]);
@@ -2445,11 +2901,10 @@ DECL_SPECIAL(COMMENT)
 
 struct sm1_op_info inst_table[] =
 {
-    _OPI(NOP, NOP, V(0,0), V(3,0), V(0,0), V(3,0), 0, 0, NULL), /* 0 */
-    _OPI(MOV, MOV, V(0,0), V(1,1), V(0,0), V(0,0), 1, 1, SPECIAL(MOV_vs1x)),
-    _OPI(MOV, MOV, V(2,0), V(3,0), V(0,0), V(3,0), 1, 1, NULL),
+    _OPI(NOP, NOP, V(0,0), V(3,0), V(0,0), V(3,0), 0, 0, SPECIAL(NOP)), /* 0 */
+    _OPI(MOV, MOV, V(0,0), V(3,0), V(0,0), V(3,0), 1, 1, NULL),
     _OPI(ADD, ADD, V(0,0), V(3,0), V(0,0), V(3,0), 1, 2, NULL), /* 2 */
-    _OPI(SUB, SUB, V(0,0), V(3,0), V(0,0), V(3,0), 1, 2, NULL), /* 3 */
+    _OPI(SUB, NOP, V(0,0), V(3,0), V(0,0), V(3,0), 1, 2, SPECIAL(SUB)), /* 3 */
     _OPI(MAD, MAD, V(0,0), V(3,0), V(0,0), V(3,0), 1, 3, NULL), /* 4 */
     _OPI(MUL, MUL, V(0,0), V(3,0), V(0,0), V(3,0), 1, 2, NULL), /* 5 */
     _OPI(RCP, RCP, V(0,0), V(3,0), V(0,0), V(3,0), 1, 1, NULL), /* 6 */
@@ -2462,7 +2917,7 @@ struct sm1_op_info inst_table[] =
     _OPI(SGE, SGE, V(0,0), V(3,0), V(0,0), V(3,0), 1, 2, NULL), /* 13 */
     _OPI(EXP, EX2, V(0,0), V(3,0), V(0,0), V(3,0), 1, 1, NULL), /* 14 */
     _OPI(LOG, LG2, V(0,0), V(3,0), V(0,0), V(3,0), 1, 1, SPECIAL(LOG)), /* 15 */
-    _OPI(LIT, LIT, V(0,0), V(3,0), V(0,0), V(0,0), 1, 1, NULL), /* 16 */
+    _OPI(LIT, LIT, V(0,0), V(3,0), V(0,0), V(0,0), 1, 1, SPECIAL(LIT)), /* 16 */
     _OPI(DST, DST, V(0,0), V(3,0), V(0,0), V(3,0), 1, 2, NULL), /* 17 */
     _OPI(LRP, LRP, V(0,0), V(3,0), V(0,0), V(3,0), 1, 3, NULL), /* 18 */
     _OPI(FRC, FRC, V(0,0), V(3,0), V(0,0), V(3,0), 1, 1, NULL), /* 19 */
@@ -2483,9 +2938,9 @@ struct sm1_op_info inst_table[] =
     _OPI(DCL, NOP, V(0,0), V(3,0), V(0,0), V(3,0), 0, 0, SPECIAL(DCL)),
 
     _OPI(POW, POW, V(0,0), V(3,0), V(0,0), V(3,0), 1, 2, SPECIAL(POW)),
-    _OPI(CRS, XPD, V(0,0), V(3,0), V(0,0), V(3,0), 1, 2, NULL), /* XXX: .w */
+    _OPI(CRS, NOP, V(0,0), V(3,0), V(0,0), V(3,0), 1, 2, SPECIAL(XPD)), /* XXX: .w */
     _OPI(SGN, SSG, V(2,0), V(3,0), V(0,0), V(0,0), 1, 3, SPECIAL(SGN)), /* ignore src1,2 */
-    _OPI(ABS, ABS, V(0,0), V(3,0), V(0,0), V(3,0), 1, 1, NULL),
+    _OPI(ABS, NOP, V(0,0), V(3,0), V(0,0), V(3,0), 1, 1, SPECIAL(ABS)),
     _OPI(NRM, NOP, V(0,0), V(3,0), V(0,0), V(3,0), 1, 1, SPECIAL(NRM)), /* NRM doesn't fit */
 
     _OPI(SINCOS, SCS, V(2,0), V(2,1), V(2,0), V(2,1), 1, 3, SPECIAL(SINCOS)),
@@ -2499,7 +2954,7 @@ struct sm1_op_info inst_table[] =
     _OPI(ELSE,   ELSE,   V(2,0), V(3,0), V(2,1), V(3,0), 0, 0, SPECIAL(ELSE)),
     _OPI(ENDIF,  ENDIF,  V(2,0), V(3,0), V(2,1), V(3,0), 0, 0, SPECIAL(ENDIF)),
     _OPI(BREAK,  BRK,    V(2,1), V(3,0), V(2,1), V(3,0), 0, 0, NULL),
-    _OPI(BREAKC, BREAKC, V(2,1), V(3,0), V(2,1), V(3,0), 0, 2, SPECIAL(BREAKC)),
+    _OPI(BREAKC, NOP,    V(2,1), V(3,0), V(2,1), V(3,0), 0, 2, SPECIAL(BREAKC)),
     /* we don't write to the address register, but a normal register (copied
      * when needed to the address register), thus we don't use ARR */
     _OPI(MOVA, MOV, V(2,0), V(3,0), V(0,0), V(0,0), 1, 1, NULL),
@@ -2514,7 +2969,7 @@ struct sm1_op_info inst_table[] =
     _OPI(TEX,          TEX, V(0,0), V(0,0), V(1,4), V(1,4), 1, 1, SPECIAL(TEXLD_14)),
     _OPI(TEX,          TEX, V(0,0), V(0,0), V(2,0), V(3,0), 1, 2, SPECIAL(TEXLD)),
     _OPI(TEXBEM,       TEX, V(0,0), V(0,0), V(0,0), V(1,3), 1, 1, SPECIAL(TEXBEM)),
-    _OPI(TEXBEML,      TEX, V(0,0), V(0,0), V(0,0), V(1,3), 1, 1, SPECIAL(TEXBEML)),
+    _OPI(TEXBEML,      TEX, V(0,0), V(0,0), V(0,0), V(1,3), 1, 1, SPECIAL(TEXBEM)),
     _OPI(TEXREG2AR,    TEX, V(0,0), V(0,0), V(0,0), V(1,3), 1, 1, SPECIAL(TEXREG2AR)),
     _OPI(TEXREG2GB,    TEX, V(0,0), V(0,0), V(0,0), V(1,3), 1, 1, SPECIAL(TEXREG2GB)),
     _OPI(TEXM3x2PAD,   TEX, V(0,0), V(0,0), V(0,0), V(1,3), 1, 1, SPECIAL(TEXM3x2PAD)),
@@ -2563,19 +3018,19 @@ create_op_info_map(struct shader_translator *tx)
     const unsigned version = (tx->version.major << 8) | tx->version.minor;
     unsigned i;
 
-    for (i = 0; i < Elements(tx->op_info_map); ++i)
+    for (i = 0; i < ARRAY_SIZE(tx->op_info_map); ++i)
         tx->op_info_map[i] = -1;
 
-    if (tx->processor == TGSI_PROCESSOR_VERTEX) {
-        for (i = 0; i < Elements(inst_table); ++i) {
-            assert(inst_table[i].sio < Elements(tx->op_info_map));
+    if (tx->processor == PIPE_SHADER_VERTEX) {
+        for (i = 0; i < ARRAY_SIZE(inst_table); ++i) {
+            assert(inst_table[i].sio < ARRAY_SIZE(tx->op_info_map));
             if (inst_table[i].vert_version.min <= version &&
                 inst_table[i].vert_version.max >= version)
                 tx->op_info_map[inst_table[i].sio] = i;
         }
     } else {
-        for (i = 0; i < Elements(inst_table); ++i) {
-            assert(inst_table[i].sio < Elements(tx->op_info_map));
+        for (i = 0; i < ARRAY_SIZE(inst_table); ++i) {
+            assert(inst_table[i].sio < ARRAY_SIZE(tx->op_info_map));
             if (inst_table[i].frag_version.min <= version &&
                 inst_table[i].frag_version.max >= version)
                 tx->op_info_map[inst_table[i].sio] = i;
@@ -2583,37 +3038,37 @@ create_op_info_map(struct shader_translator *tx)
     }
 }
 
-static INLINE HRESULT
+static inline HRESULT
 NineTranslateInstruction_Generic(struct shader_translator *tx)
 {
     struct ureg_dst dst[1];
     struct ureg_src src[4];
     unsigned i;
 
-    for (i = 0; i < tx->insn.ndst && i < Elements(dst); ++i)
+    for (i = 0; i < tx->insn.ndst && i < ARRAY_SIZE(dst); ++i)
         dst[i] = tx_dst_param(tx, &tx->insn.dst[i]);
-    for (i = 0; i < tx->insn.nsrc && i < Elements(src); ++i)
+    for (i = 0; i < tx->insn.nsrc && i < ARRAY_SIZE(src); ++i)
         src[i] = tx_src_param(tx, &tx->insn.src[i]);
 
     ureg_insn(tx->ureg, tx->insn.info->opcode,
               dst, tx->insn.ndst,
-              src, tx->insn.nsrc);
+              src, tx->insn.nsrc, 0);
     return D3D_OK;
 }
 
-static INLINE DWORD
+static inline DWORD
 TOKEN_PEEK(struct shader_translator *tx)
 {
     return *(tx->parse);
 }
 
-static INLINE DWORD
+static inline DWORD
 TOKEN_NEXT(struct shader_translator *tx)
 {
     return *(tx->parse)++;
 }
 
-static INLINE void
+static inline void
 TOKEN_JUMP(struct shader_translator *tx)
 {
     if (tx->parse_next && tx->parse != tx->parse_next) {
@@ -2622,7 +3077,7 @@ TOKEN_JUMP(struct shader_translator *tx)
     }
 }
 
-static INLINE boolean
+static inline boolean
 sm1_parse_eof(struct shader_translator *tx)
 {
     return TOKEN_PEEK(tx) == NINED3DSP_END;
@@ -2637,8 +3092,8 @@ sm1_read_version(struct shader_translator *tx)
     tx->version.minor = D3DSHADER_VERSION_MINOR(tok);
 
     switch (tok >> 16) {
-    case NINED3D_SM1_VS: tx->processor = TGSI_PROCESSOR_VERTEX; break;
-    case NINED3D_SM1_PS: tx->processor = TGSI_PROCESSOR_FRAGMENT; break;
+    case NINED3D_SM1_VS: tx->processor = PIPE_SHADER_VERTEX; break;
+    case NINED3D_SM1_PS: tx->processor = PIPE_SHADER_FRAGMENT; break;
     default:
        DBG("Invalid shader type: %x\n", tok);
        tx->processor = ~0;
@@ -2697,7 +3152,7 @@ sm1_parse_get_param(struct shader_translator *tx, DWORD *reg, DWORD *rel)
             *rel = (1 << 31) |
                 ((D3DSPR_ADDR << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2) |
                 ((D3DSPR_ADDR << D3DSP_REGTYPE_SHIFT)  & D3DSP_REGTYPE_MASK) |
-                (D3DSP_NOSWIZZLE << D3DSP_SWIZZLE_SHIFT);
+                D3DSP_NOSWIZZLE;
         else
             *rel = TOKEN_NEXT(tx);
     }
@@ -2706,7 +3161,7 @@ sm1_parse_get_param(struct shader_translator *tx, DWORD *reg, DWORD *rel)
 static void
 sm1_parse_dst_param(struct sm1_dst_param *dst, DWORD tok)
 {
-    uint8_t shift;
+    int8_t shift;
     dst->file =
         (tok & D3DSP_REGTYPE_MASK)  >> D3DSP_REGTYPE_SHIFT |
         (tok & D3DSP_REGTYPE_MASK2) >> D3DSP_REGTYPE_SHIFT2;
@@ -2716,7 +3171,7 @@ sm1_parse_dst_param(struct sm1_dst_param *dst, DWORD tok)
     dst->mask = (tok & NINED3DSP_WRITEMASK_MASK) >> NINED3DSP_WRITEMASK_SHIFT;
     dst->mod = (tok & D3DSP_DSTMOD_MASK) >> D3DSP_DSTMOD_SHIFT;
     shift = (tok & D3DSP_DSTSHIFT_MASK) >> D3DSP_DSTSHIFT_SHIFT;
-    dst->shift = (shift & 0x8) ? -(shift & 0x7) : shift & 0x7;
+    dst->shift = (shift & 0x7) - (shift & 0x8);
 }
 
 static void
@@ -2820,6 +3275,7 @@ static void
 sm1_parse_instruction(struct shader_translator *tx)
 {
     struct sm1_instruction *insn = &tx->insn;
+    HRESULT hr;
     DWORD tok;
     struct sm1_op_info *info = NULL;
     unsigned i;
@@ -2834,10 +3290,10 @@ sm1_parse_instruction(struct shader_translator *tx)
     insn->coissue = !!(tok & D3DSI_COISSUE);
     insn->predicated = !!(tok & NINED3DSHADER_INST_PREDICATED);
 
-    if (insn->opcode < Elements(tx->op_info_map)) {
+    if (insn->opcode < ARRAY_SIZE(tx->op_info_map)) {
         int k = tx->op_info_map[insn->opcode];
         if (k >= 0) {
-            assert(k < Elements(inst_table));
+            assert(k < ARRAY_SIZE(inst_table));
             info = &inst_table[k];
         }
     } else {
@@ -2884,11 +3340,13 @@ sm1_parse_instruction(struct shader_translator *tx)
     sm1_instruction_check(insn);
 
     if (info->handler)
-        info->handler(tx);
+        hr = info->handler(tx);
     else
-       NineTranslateInstruction_Generic(tx);
+        hr = NineTranslateInstruction_Generic(tx);
     tx_apply_dst0_modifiers(tx);
 
+    if (hr != D3D_OK)
+        tx->failure = TRUE;
     tx->num_scratch = 0; /* reset */
 
     TOKEN_JUMP(tx);
@@ -2904,14 +3362,16 @@ tx_ctor(struct shader_translator *tx, struct nine_shader_info *info)
     tx->byte_code = info->byte_code;
     tx->parse = info->byte_code;
 
-    for (i = 0; i < Elements(info->input_map); ++i)
+    for (i = 0; i < ARRAY_SIZE(info->input_map); ++i)
         info->input_map[i] = NINE_DECLUSAGE_NONE;
     info->num_inputs = 0;
 
     info->position_t = FALSE;
     info->point_size = FALSE;
 
-    tx->info->const_used_size = 0;
+    tx->info->const_float_slots = 0;
+    tx->info->const_int_slots = 0;
+    tx->info->const_bool_slots = 0;
 
     info->sampler_mask = 0x0;
     info->rt_mask = 0x0;
@@ -2919,7 +3379,9 @@ tx_ctor(struct shader_translator *tx, struct nine_shader_info *info)
     info->lconstf.data = NULL;
     info->lconstf.ranges = NULL;
 
-    for (i = 0; i < Elements(tx->regs.rL); ++i) {
+    info->bumpenvmat_needed = 0;
+
+    for (i = 0; i < ARRAY_SIZE(tx->regs.rL); ++i) {
         tx->regs.rL[i] = ureg_dst_undef();
     }
     tx->regs.address = ureg_dst_undef();
@@ -2928,24 +3390,21 @@ tx_ctor(struct shader_translator *tx, struct nine_shader_info *info)
     tx->regs.oDepth = ureg_dst_undef();
     tx->regs.vPos = ureg_src_undef();
     tx->regs.vFace = ureg_src_undef();
-    for (i = 0; i < Elements(tx->regs.o); ++i)
+    for (i = 0; i < ARRAY_SIZE(tx->regs.o); ++i)
         tx->regs.o[i] = ureg_dst_undef();
-    for (i = 0; i < Elements(tx->regs.oCol); ++i)
+    for (i = 0; i < ARRAY_SIZE(tx->regs.oCol); ++i)
         tx->regs.oCol[i] = ureg_dst_undef();
-    for (i = 0; i < Elements(tx->regs.vC); ++i)
+    for (i = 0; i < ARRAY_SIZE(tx->regs.vC); ++i)
         tx->regs.vC[i] = ureg_src_undef();
-    for (i = 0; i < Elements(tx->regs.vT); ++i)
+    for (i = 0; i < ARRAY_SIZE(tx->regs.vT); ++i)
         tx->regs.vT[i] = ureg_src_undef();
 
-    for (i = 0; i < Elements(tx->lconsti); ++i)
-        tx->lconsti[i].idx = -1;
-    for (i = 0; i < Elements(tx->lconstb); ++i)
-        tx->lconstb[i].idx = -1;
-
     sm1_read_version(tx);
 
     info->version = (tx->version.major << 4) | tx->version.minor;
 
+    tx->num_outputs = 0;
+
     create_op_info_map(tx);
 }
 
@@ -2959,28 +3418,89 @@ tx_dtor(struct shader_translator *tx)
     FREE(tx);
 }
 
-static INLINE unsigned
-tgsi_processor_from_type(unsigned shader_type)
+/* CONST[0].xyz = width/2, -height/2, zmax-zmin
+ * CONST[1].xyz = x+width/2, y+height/2, zmin */
+static void
+shader_add_vs_viewport_transform(struct shader_translator *tx)
 {
-    switch (shader_type) {
-    case PIPE_SHADER_VERTEX: return TGSI_PROCESSOR_VERTEX;
-    case PIPE_SHADER_FRAGMENT: return TGSI_PROCESSOR_FRAGMENT;
-    default:
-        return ~0;
+    struct ureg_program *ureg = tx->ureg;
+    struct ureg_src c0 = NINE_CONSTANT_SRC(0);
+    struct ureg_src c1 = NINE_CONSTANT_SRC(1);
+    /* struct ureg_dst pos_tmp = ureg_DECL_temporary(ureg);*/
+
+    c0 = ureg_src_dimension(c0, 4);
+    c1 = ureg_src_dimension(c1, 4);
+    /* TODO: find out when we need to apply the viewport transformation or not.
+     * Likely will be XYZ vs XYZRHW in vdecl_out
+     * ureg_MUL(ureg, ureg_writemask(pos_tmp, TGSI_WRITEMASK_XYZ), ureg_src(tx->regs.oPos), c0);
+     * ureg_ADD(ureg, ureg_writemask(tx->regs.oPos_out, TGSI_WRITEMASK_XYZ), ureg_src(pos_tmp), c1);
+     */
+    ureg_MOV(ureg, ureg_writemask(tx->regs.oPos_out, TGSI_WRITEMASK_XYZ), ureg_src(tx->regs.oPos));
+}
+
+static void
+shader_add_ps_fog_stage(struct shader_translator *tx, struct ureg_src src_col)
+{
+    struct ureg_program *ureg = tx->ureg;
+    struct ureg_dst oCol0 = ureg_DECL_output(ureg, TGSI_SEMANTIC_COLOR, 0);
+    struct ureg_src fog_end, fog_coeff, fog_density;
+    struct ureg_src fog_vs, depth, fog_color;
+    struct ureg_dst fog_factor;
+
+    if (!tx->info->fog_enable) {
+        ureg_MOV(ureg, oCol0, src_col);
+        return;
+    }
+
+    if (tx->info->fog_mode != D3DFOG_NONE) {
+        depth = nine_get_position_input(tx);
+        depth = ureg_scalar(depth, TGSI_SWIZZLE_Z);
+    }
+
+    nine_info_mark_const_f_used(tx->info, 33);
+    fog_color = NINE_CONSTANT_SRC(32);
+    fog_factor = tx_scratch_scalar(tx);
+
+    if (tx->info->fog_mode == D3DFOG_LINEAR) {
+        fog_end = NINE_CONSTANT_SRC_SWIZZLE(33, X);
+        fog_coeff = NINE_CONSTANT_SRC_SWIZZLE(33, Y);
+        ureg_ADD(ureg, fog_factor, fog_end, ureg_negate(depth));
+        ureg_MUL(ureg, ureg_saturate(fog_factor), tx_src_scalar(fog_factor), fog_coeff);
+    } else if (tx->info->fog_mode == D3DFOG_EXP) {
+        fog_density = NINE_CONSTANT_SRC_SWIZZLE(33, X);
+        ureg_MUL(ureg, fog_factor, depth, fog_density);
+        ureg_MUL(ureg, fog_factor, tx_src_scalar(fog_factor), ureg_imm1f(ureg, -1.442695f));
+        ureg_EX2(ureg, fog_factor, tx_src_scalar(fog_factor));
+    } else if (tx->info->fog_mode == D3DFOG_EXP2) {
+        fog_density = NINE_CONSTANT_SRC_SWIZZLE(33, X);
+        ureg_MUL(ureg, fog_factor, depth, fog_density);
+        ureg_MUL(ureg, fog_factor, tx_src_scalar(fog_factor), tx_src_scalar(fog_factor));
+        ureg_MUL(ureg, fog_factor, tx_src_scalar(fog_factor), ureg_imm1f(ureg, -1.442695f));
+        ureg_EX2(ureg, fog_factor, tx_src_scalar(fog_factor));
+    } else {
+        fog_vs = ureg_scalar(ureg_DECL_fs_input(ureg, TGSI_SEMANTIC_FOG, 0,
+                                            TGSI_INTERPOLATE_PERSPECTIVE),
+                                            TGSI_SWIZZLE_X);
+        ureg_MOV(ureg, fog_factor, fog_vs);
     }
+
+    ureg_LRP(ureg, ureg_writemask(oCol0, TGSI_WRITEMASK_XYZ),
+             tx_src_scalar(fog_factor), src_col, fog_color);
+    ureg_MOV(ureg, ureg_writemask(oCol0, TGSI_WRITEMASK_W), src_col);
 }
 
-#define GET_CAP(n) device->screen->get_param( \
-      device->screen, PIPE_CAP_##n)
-#define GET_SHADER_CAP(n) device->screen->get_shader_param( \
-      device->screen, info->type, PIPE_SHADER_CAP_##n)
+#define GET_CAP(n) screen->get_param( \
+      screen, PIPE_CAP_##n)
+#define GET_SHADER_CAP(n) screen->get_shader_param( \
+      screen, info->type, PIPE_SHADER_CAP_##n)
 
 HRESULT
-nine_translate_shader(struct NineDevice9 *device, struct nine_shader_info *info)
+nine_translate_shader(struct NineDevice9 *device, struct nine_shader_info *info, struct pipe_context *pipe)
 {
     struct shader_translator *tx;
     HRESULT hr = D3D_OK;
-    const unsigned processor = tgsi_processor_from_type(info->type);
+    const unsigned processor = info->type;
+    struct pipe_screen *screen = info->process_vertices ? device->screen_sw : device->screen;
 
     user_assert(processor != ~0, D3DERR_INVALIDCALL);
 
@@ -3000,7 +3520,7 @@ nine_translate_shader(struct NineDevice9 *device, struct nine_shader_info *info)
         DBG("Shader type mismatch: %u / %u !\n", tx->processor, processor);
         goto out;
     }
-    DUMP("%s%u.%u\n", processor == TGSI_PROCESSOR_VERTEX ? "VS" : "PS",
+    DUMP("%s%u.%u\n", processor == PIPE_SHADER_VERTEX ? "VS" : "PS",
          tx->version.major, tx->version.minor);
 
     tx->ureg = ureg_create(processor);
@@ -3008,15 +3528,39 @@ nine_translate_shader(struct NineDevice9 *device, struct nine_shader_info *info)
         hr = E_OUTOFMEMORY;
         goto out;
     }
-    tx_decl_constants(tx);
 
     tx->native_integers = GET_SHADER_CAP(INTEGERS);
     tx->inline_subroutines = !GET_SHADER_CAP(SUBROUTINES);
-    tx->lower_preds = !GET_SHADER_CAP(MAX_PREDS);
     tx->want_texcoord = GET_CAP(TGSI_TEXCOORD);
     tx->shift_wpos = !GET_CAP(TGSI_FS_COORD_PIXEL_CENTER_INTEGER);
     tx->texcoord_sn = tx->want_texcoord ?
         TGSI_SEMANTIC_TEXCOORD : TGSI_SEMANTIC_GENERIC;
+    tx->wpos_is_sysval = GET_CAP(TGSI_FS_POSITION_IS_SYSVAL);
+    tx->face_is_sysval_integer = GET_CAP(TGSI_FS_FACE_IS_INTEGER_SYSVAL);
+
+    if (IS_VS) {
+        tx->num_constf_allowed = NINE_MAX_CONST_F;
+    } else if (tx->version.major < 2) {/* IS_PS v1 */
+        tx->num_constf_allowed = 8;
+    } else if (tx->version.major == 2) {/* IS_PS v2 */
+        tx->num_constf_allowed = 32;
+    } else {/* IS_PS v3 */
+        tx->num_constf_allowed = NINE_MAX_CONST_F_PS3;
+    }
+
+    if (tx->version.major < 2) {
+        tx->num_consti_allowed = 0;
+        tx->num_constb_allowed = 0;
+    } else {
+        tx->num_consti_allowed = NINE_MAX_CONST_I;
+        tx->num_constb_allowed = NINE_MAX_CONST_B;
+    }
+
+    if (IS_VS && tx->version.major >= 2 && info->swvp_on) {
+        tx->num_constf_allowed = 8192;
+        tx->num_consti_allowed = 2048;
+        tx->num_constb_allowed = 2048;
+    }
 
     /* VS must always write position. Declare it here to make it the 1st output.
      * (Some drivers like nv50 are buggy and rely on that.)
@@ -3029,31 +3573,53 @@ nine_translate_shader(struct NineDevice9 *device, struct nine_shader_info *info)
             ureg_property(tx->ureg, TGSI_PROPERTY_FS_COORD_PIXEL_CENTER, TGSI_FS_COORD_PIXEL_CENTER_INTEGER);
     }
 
-    while (!sm1_parse_eof(tx))
+    if (GET_CAP(TGSI_MUL_ZERO_WINS))
+       ureg_property(tx->ureg, TGSI_PROPERTY_MUL_ZERO_WINS, 1);
+
+    while (!sm1_parse_eof(tx) && !tx->failure)
         sm1_parse_instruction(tx);
     tx->parse++; /* for byte_size */
 
-    if (IS_PS && (tx->version.major < 2) && tx->num_temp) {
-        ureg_MOV(tx->ureg, ureg_DECL_output(tx->ureg, TGSI_SEMANTIC_COLOR, 0),
-                 ureg_src(tx->regs.r[0]));
-        info->rt_mask |= 0x1;
+    if (tx->failure) {
+        /* For VS shaders, we print the warning later,
+         * we first try with swvp. */
+        if (IS_PS)
+            ERR("Encountered buggy shader\n");
+        ureg_destroy(tx->ureg);
+        hr = D3DERR_INVALIDCALL;
+        goto out;
+    }
+
+    if (IS_PS && tx->version.major < 3) {
+        if (tx->version.major < 2) {
+            assert(tx->num_temp); /* there must be color output */
+            info->rt_mask |= 0x1;
+            shader_add_ps_fog_stage(tx, ureg_src(tx->regs.r[0]));
+        } else {
+            shader_add_ps_fog_stage(tx, ureg_src(tx->regs.oCol[0]));
+        }
+    }
+
+    if (IS_VS && tx->version.major < 3 && ureg_dst_is_undef(tx->regs.oFog) && info->fog_enable) {
+        tx->regs.oFog = ureg_DECL_output(tx->ureg, TGSI_SEMANTIC_FOG, 0);
+        ureg_MOV(tx->ureg, ureg_writemask(tx->regs.oFog, TGSI_WRITEMASK_X), ureg_imm1f(tx->ureg, 0.0f));
     }
 
     if (info->position_t)
         ureg_property(tx->ureg, TGSI_PROPERTY_VS_WINDOW_SPACE_POSITION, TRUE);
 
-    ureg_END(tx->ureg);
-
-    if (IS_VS && !ureg_dst_is_undef(tx->regs.oPts))
+    if (IS_VS && !ureg_dst_is_undef(tx->regs.oPts)) {
+        struct ureg_dst oPts = ureg_DECL_output(tx->ureg, TGSI_SEMANTIC_PSIZE, 0);
+        ureg_MAX(tx->ureg, tx->regs.oPts, ureg_src(tx->regs.oPts), ureg_imm1f(tx->ureg, info->point_size_min));
+        ureg_MIN(tx->ureg, oPts, ureg_src(tx->regs.oPts), ureg_imm1f(tx->ureg, info->point_size_max));
         info->point_size = TRUE;
-
-    if (debug_get_bool_option("NINE_TGSI_DUMP", FALSE)) {
-        unsigned count;
-        const struct tgsi_token *toks = ureg_get_tokens(tx->ureg, &count);
-        tgsi_dump(toks, 0);
-        ureg_free_tokens(toks);
     }
 
+    if (info->process_vertices)
+        shader_add_vs_viewport_transform(tx);
+
+    ureg_END(tx->ureg);
+
     /* record local constants */
     if (tx->num_lconstf && tx->indirect_const_access) {
         struct nine_range *ranges;
@@ -3079,7 +3645,7 @@ nine_translate_shader(struct NineDevice9 *device, struct nine_shader_info *info)
                     k = i;
             }
             indices[n] = tx->lconstf[k].idx;
-            memcpy(&data[n * 4], &tx->lconstf[k].imm.f[0], 4 * sizeof(float));
+            memcpy(&data[n * 4], &tx->lconstf[k].f[0], 4 * sizeof(float));
             tx->lconstf[k].idx = INT_MAX;
         }
 
@@ -3112,10 +3678,55 @@ nine_translate_shader(struct NineDevice9 *device, struct nine_shader_info *info)
         hr = D3D_OK;
     }
 
-    if (tx->indirect_const_access)
-        info->const_used_size = ~0;
+    /* r500 */
+    if (info->const_float_slots > device->max_vs_const_f &&
+        (info->const_int_slots || info->const_bool_slots) &&
+        (!IS_VS || !info->swvp_on))
+        ERR("Overlapping constant slots. The shader is likely to be buggy\n");
+
+
+    if (tx->indirect_const_access) /* vs only */
+        info->const_float_slots = device->max_vs_const_f;
+
+    if (!IS_VS || !info->swvp_on) {
+        unsigned s, slot_max;
+        unsigned max_const_f = IS_VS ? device->max_vs_const_f : device->max_ps_const_f;
+
+        slot_max = info->const_bool_slots > 0 ?
+                       max_const_f + NINE_MAX_CONST_I
+                       + DIV_ROUND_UP(info->const_bool_slots, 4) :
+                           info->const_int_slots > 0 ?
+                               max_const_f + info->const_int_slots :
+                                   info->const_float_slots;
+
+        info->const_used_size = sizeof(float[4]) * slot_max; /* slots start from 1 */
+
+        for (s = 0; s < slot_max; s++)
+            ureg_DECL_constant(tx->ureg, s);
+    } else {
+         ureg_DECL_constant2D(tx->ureg, 0, 4095, 0);
+         ureg_DECL_constant2D(tx->ureg, 0, 4095, 1);
+         ureg_DECL_constant2D(tx->ureg, 0, 2047, 2);
+         ureg_DECL_constant2D(tx->ureg, 0, 511, 3);
+    }
+
+    if (info->process_vertices)
+        ureg_DECL_constant2D(tx->ureg, 0, 2, 4); /* Viewport data */
+
+    if (debug_get_bool_option("NINE_TGSI_DUMP", FALSE)) {
+        const struct tgsi_token *toks = ureg_get_tokens(tx->ureg, NULL);
+        tgsi_dump(toks, 0);
+        ureg_free_tokens(toks);
+    }
 
-    info->cso = ureg_create_shader_and_destroy(tx->ureg, device->pipe);
+    if (info->process_vertices) {
+        NineVertexDeclaration9_FillStreamOutputInfo(info->vdecl_out,
+                                                    tx->output_info,
+                                                    tx->num_outputs,
+                                                    &(info->so));
+        info->cso = ureg_create_shader_with_so_and_destroy(tx->ureg, pipe, &(info->so));
+    } else
+        info->cso = ureg_create_shader_and_destroy(tx->ureg, pipe);
     if (!info->cso) {
         hr = D3DERR_DRIVERINTERNALERROR;
         FREE(info->lconstf.data);