tgsi/ureg: add support for output array declarations
[mesa.git] / src / gallium / state_trackers / nine / nine_shader.c
index ae609b050ffa723e43d790f9214843ab6cbac11d..22a58825f78d649820dc42e1cd820f34a1dfc20a 100644 (file)
@@ -27,6 +27,7 @@
 #include "nine_debug.h"
 #include "nine_state.h"
 
+#include "util/macros.h"
 #include "util/u_memory.h"
 #include "util/u_inlines.h"
 #include "pipe/p_shader_tokens.h"
@@ -495,6 +496,7 @@ struct shader_translator
     struct sm1_local_const lconstb[NINE_MAX_CONST_B];
 
     boolean indirect_const_access;
+    boolean failure;
 
     struct nine_shader_info *info;
 
@@ -503,6 +505,9 @@ struct shader_translator
 
 #define IS_VS (tx->processor == TGSI_PROCESSOR_VERTEX)
 #define IS_PS (tx->processor == TGSI_PROCESSOR_FRAGMENT)
+#define NINE_MAX_CONST_F_SHADER (tx->processor == TGSI_PROCESSOR_VERTEX ? NINE_MAX_CONST_F : NINE_MAX_CONST_F_PS3)
+
+#define FAILURE_VOID(cond) if ((cond)) {tx->failure=1;return;}
 
 static void
 sm1_read_semantic(struct shader_translator *, struct sm1_semantic *);
@@ -523,7 +528,10 @@ 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 >= NINE_MAX_CONST_F_SHADER) {
+       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,7 +543,10 @@ 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 (index < 0 || index >= NINE_MAX_CONST_I) {
+       tx->failure = TRUE;
+       return FALSE;
+   }
    if (tx->lconsti[index].idx == index)
       *src = tx->lconsti[index].reg;
    return tx->lconsti[index].idx == index;
@@ -543,7 +554,10 @@ tx_lconsti(struct shader_translator *tx, struct ureg_src *src, INT index)
 static boolean
 tx_lconstb(struct shader_translator *tx, struct ureg_src *src, INT index)
 {
-   assert(index >= 0 && index < NINE_MAX_CONST_B);
+   if (index < 0 || index >= NINE_MAX_CONST_B) {
+       tx->failure = TRUE;
+       return FALSE;
+   }
    if (tx->lconstb[index].idx == index)
       *src = tx->lconstb[index].reg;
    return tx->lconstb[index].idx == index;
@@ -554,9 +568,8 @@ 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)
+    FAILURE_VOID(index < 0 || index >= NINE_MAX_CONST_F_SHADER)
+    if (IS_VS && index >= NINE_MAX_CONST_F_SHADER)
         WARN("lconstf index %i too high, indirect access won't work\n", index);
 
     for (n = 0; n < tx->num_lconstf; ++n)
@@ -579,7 +592,7 @@ tx_set_lconstf(struct shader_translator *tx, INT index, float f[4])
 static void
 tx_set_lconsti(struct shader_translator *tx, INT index, int i[4])
 {
-    assert(index >= 0 && index < NINE_MAX_CONST_I);
+    FAILURE_VOID(index < 0 || index >= NINE_MAX_CONST_I)
     tx->lconsti[index].idx = index;
     tx->lconsti[index].reg = tx->native_integers ?
        ureg_imm4i(tx->ureg, i[0], i[1], i[2], i[3]) :
@@ -588,7 +601,7 @@ tx_set_lconsti(struct shader_translator *tx, INT index, int i[4])
 static void
 tx_set_lconstb(struct shader_translator *tx, INT index, BOOL b)
 {
-    assert(index >= 0 && index < NINE_MAX_CONST_B);
+    FAILURE_VOID(index < 0 || index >= NINE_MAX_CONST_B)
     tx->lconstb[index].idx = index;
     tx->lconstb[index].reg = tx->native_integers ?
        ureg_imm1u(tx->ureg, b ? 0xffffffff : 0) :
@@ -598,7 +611,10 @@ tx_set_lconstb(struct shader_translator *tx, INT index, BOOL b)
 static INLINE struct ureg_dst
 tx_scratch(struct shader_translator *tx)
 {
-    assert(tx->num_scratch < Elements(tx->regs.t));
+    if (tx->num_scratch >= Elements(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++];
@@ -620,24 +636,6 @@ 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
 tx_temp_alloc(struct shader_translator *tx, INT idx)
 {
@@ -835,6 +833,7 @@ 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)) {
@@ -858,19 +857,20 @@ 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);
+        /* 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);
             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);
+           nine_info_mark_const_b_used(tx->info, param->idx);
            src = ureg_src_register(TGSI_FILE_CONSTANT,
                                    tx->info->const_b_base + r);
            src = ureg_swizzle(src, s, s, s, s);
@@ -1098,7 +1098,7 @@ _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:
@@ -1966,7 +1966,7 @@ DECL_SPECIAL(DCL)
                 tx->info->position_t = TRUE;
             assert(sem.reg.idx < Elements(tx->regs.o));
             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);
 
             if (tgsi.Name == TGSI_SEMANTIC_PSIZE)
                 tx->regs.oPts = tx->regs.o[sem.reg.idx];
@@ -1979,12 +1979,13 @@ DECL_SPECIAL(DCL)
                 ureg, tgsi.Name, tgsi.Index,
                 nine_tgsi_to_interp_mode(&tgsi),
                 0, /* cylwrap */
-                sem.reg.mod & NINED3DSPDM_CENTROID);
+                sem.reg.mod & NINED3DSPDM_CENTROID, 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 +2042,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;
@@ -2127,22 +2145,62 @@ DECL_SPECIAL(TEXBEML)
 
 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)
 {
-    STUB(D3DERR_INVALIDCALL);
+    return D3D_OK; /* this is just padding */
 }
 
 DECL_SPECIAL(TEXM3x2TEX)
 {
-    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 - 1;
+    const int n = tx->insn.src[0].idx;
+    assert(m >= 0 && m > n);
+
+    tx_texcoord_alloc(tx, m);
+    tx_texcoord_alloc(tx, m+1);
+
+    /* performs the matrix multiplication */
+    ureg_DP3(ureg, ureg_writemask(dst, TGSI_WRITEMASK_X), tx->regs.vT[m], ureg_src(tx->regs.tS[n]));
+    ureg_DP3(ureg, ureg_writemask(dst, TGSI_WRITEMASK_Y), tx->regs.vT[m+1], ureg_src(tx->regs.tS[n]));
+
+    sample = ureg_DECL_sampler(ureg, m + 1);
+    tx->info->sampler_mask |= 1 << (m + 1);
+    ureg_TEX(ureg, dst, ps1x_sampler_type(tx->info, m + 1), ureg_src(dst), sample);
+
+    return D3D_OK;
 }
 
 DECL_SPECIAL(TEXM3x3PAD)
@@ -2152,60 +2210,181 @@ DECL_SPECIAL(TEXM3x3PAD)
 
 DECL_SPECIAL(TEXM3x3SPEC)
 {
-    STUB(D3DERR_INVALIDCALL);
-}
+    struct ureg_program *ureg = tx->ureg;
+    struct ureg_dst dst = tx_dst_param(tx, &tx->insn.dst[0]);
+    struct ureg_src E = tx_src_param(tx, &tx->insn.src[1]);
+    struct ureg_src sample;
+    struct ureg_dst tmp;
+    const int m = tx->insn.dst[0].idx - 2;
+    const int n = tx->insn.src[0].idx;
+    assert(m >= 0 && m > n);
 
-DECL_SPECIAL(TEXM3x3VSPEC)
-{
-    STUB(D3DERR_INVALIDCALL);
+    tx_texcoord_alloc(tx, m);
+    tx_texcoord_alloc(tx, m+1);
+    tx_texcoord_alloc(tx, m+2);
+
+    ureg_DP3(ureg, ureg_writemask(dst, TGSI_WRITEMASK_X), tx->regs.vT[m], ureg_src(tx->regs.tS[n]));
+    ureg_DP3(ureg, ureg_writemask(dst, TGSI_WRITEMASK_Y), tx->regs.vT[m+1], ureg_src(tx->regs.tS[n]));
+    ureg_DP3(ureg, ureg_writemask(dst, TGSI_WRITEMASK_Z), tx->regs.vT[m+2], ureg_src(tx->regs.tS[n]));
+
+    sample = ureg_DECL_sampler(ureg, m + 2);
+    tx->info->sampler_mask |= 1 << (m + 2);
+    tmp = ureg_writemask(tx_scratch(tx), TGSI_WRITEMASK_XYZ);
+
+    /* At this step, dst = N = (u', w', z').
+     * We want dst to be the texture sampled at (u'', w'', z''), with
+     * (u'', w'', z'') = 2 * (N.E / N.N) * N - E */
+    ureg_DP3(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_X), ureg_src(dst), ureg_src(dst));
+    ureg_RCP(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_X), ureg_scalar(ureg_src(tmp), TGSI_SWIZZLE_X));
+    /* at this step tmp.x = 1/N.N */
+    ureg_DP3(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_Y), ureg_src(dst), E);
+    /* at this step tmp.y = N.E */
+    ureg_MUL(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_X), ureg_scalar(ureg_src(tmp), TGSI_SWIZZLE_X), ureg_scalar(ureg_src(tmp), TGSI_SWIZZLE_Y));
+    /* at this step tmp.x = N.E/N.N */
+    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_TEX(ureg, dst, ps1x_sampler_type(tx->info, m + 2), ureg_src(tmp), sample);
+
+    return D3D_OK;
 }
 
 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)
 {
-    STUB(D3DERR_INVALIDCALL);
+    struct ureg_program *ureg = tx->ureg;
+    struct ureg_dst tmp;
+    const int m = tx->insn.dst[0].idx - 1;
+    const int n = tx->insn.src[0].idx;
+    assert(m >= 0 && m > n);
+
+    tx_texcoord_alloc(tx, m);
+    tx_texcoord_alloc(tx, m+1);
+
+    tmp = tx_scratch(tx);
+
+    /* performs the matrix multiplication */
+    ureg_DP3(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_X), tx->regs.vT[m], ureg_src(tx->regs.tS[n]));
+    ureg_DP3(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_Y), tx->regs.vT[m+1], ureg_src(tx->regs.tS[n]));
+
+    ureg_RCP(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_Z), ureg_scalar(ureg_src(tmp), TGSI_SWIZZLE_Y));
+    /* tmp.x = 'z', tmp.y = 'w', tmp.z = 1/'w'. */
+    ureg_MUL(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_X), ureg_scalar(ureg_src(tmp), TGSI_SWIZZLE_X), ureg_scalar(ureg_src(tmp), TGSI_SWIZZLE_Z));
+    /* res = 'w' == 0 ? 1.0 : z/w */
+    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, 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;
 }
 
 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)
 {
     struct ureg_program *ureg = tx->ureg;
     struct ureg_dst dst = tx_dst_param(tx, &tx->insn.dst[0]);
-    struct ureg_src src[4];
-    int s;
+    struct ureg_src sample;
+    struct ureg_dst E, tmp;
     const int m = tx->insn.dst[0].idx - 2;
     const int n = tx->insn.src[0].idx;
     assert(m >= 0 && m > n);
 
-    for (s = m; s <= (m + 2); ++s) {
-        tx_texcoord_alloc(tx, s);
-        src[s] = tx->regs.vT[s];
-    }
-    ureg_DP3(ureg, ureg_writemask(dst, TGSI_WRITEMASK_X), src[0], ureg_src(tx->regs.tS[n]));
-    ureg_DP3(ureg, ureg_writemask(dst, TGSI_WRITEMASK_Y), src[1], ureg_src(tx->regs.tS[n]));
-    ureg_DP3(ureg, ureg_writemask(dst, TGSI_WRITEMASK_Z), src[2], ureg_src(tx->regs.tS[n]));
+    tx_texcoord_alloc(tx, m);
+    tx_texcoord_alloc(tx, m+1);
+    tx_texcoord_alloc(tx, m+2);
+
+    ureg_DP3(ureg, ureg_writemask(dst, TGSI_WRITEMASK_X), tx->regs.vT[m], ureg_src(tx->regs.tS[n]));
+    ureg_DP3(ureg, ureg_writemask(dst, TGSI_WRITEMASK_Y), tx->regs.vT[m+1], ureg_src(tx->regs.tS[n]));
+    ureg_DP3(ureg, ureg_writemask(dst, TGSI_WRITEMASK_Z), tx->regs.vT[m+2], ureg_src(tx->regs.tS[n]));
 
     switch (tx->insn.opcode) {
     case D3DSIO_TEXM3x3:
         ureg_MOV(ureg, ureg_writemask(dst, TGSI_WRITEMASK_W), ureg_imm1f(ureg, 1.0f));
         break;
     case D3DSIO_TEXM3x3TEX:
-        src[3] = ureg_DECL_sampler(ureg, m + 2);
+        sample = ureg_DECL_sampler(ureg, m + 2);
+        tx->info->sampler_mask |= 1 << (m + 2);
+        ureg_TEX(ureg, dst, ps1x_sampler_type(tx->info, m + 2), ureg_src(dst), sample);
+        break;
+    case D3DSIO_TEXM3x3VSPEC:
+        sample = ureg_DECL_sampler(ureg, m + 2);
         tx->info->sampler_mask |= 1 << (m + 2);
-        ureg_TEX(ureg, dst, ps1x_sampler_type(tx->info, m + 2), ureg_src(dst), src[3]);
+        E = tx_scratch(tx);
+        tmp = ureg_writemask(tx_scratch(tx), TGSI_WRITEMASK_XYZ);
+        ureg_MOV(ureg, ureg_writemask(E, TGSI_WRITEMASK_X), ureg_scalar(tx->regs.vT[m], TGSI_SWIZZLE_W));
+        ureg_MOV(ureg, ureg_writemask(E, TGSI_WRITEMASK_Y), ureg_scalar(tx->regs.vT[m+1], TGSI_SWIZZLE_W));
+        ureg_MOV(ureg, ureg_writemask(E, TGSI_WRITEMASK_Z), ureg_scalar(tx->regs.vT[m+2], TGSI_SWIZZLE_W));
+        /* At this step, dst = N = (u', w', z').
+         * We want dst to be the texture sampled at (u'', w'', z''), with
+         * (u'', w'', z'') = 2 * (N.E / N.N) * N - E */
+        ureg_DP3(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_X), ureg_src(dst), ureg_src(dst));
+        ureg_RCP(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_X), ureg_scalar(ureg_src(tmp), TGSI_SWIZZLE_X));
+        /* at this step tmp.x = 1/N.N */
+        ureg_DP3(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_Y), ureg_src(dst), ureg_src(E));
+        /* at this step tmp.y = N.E */
+        ureg_MUL(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_X), ureg_scalar(ureg_src(tmp), TGSI_SWIZZLE_X), ureg_scalar(ureg_src(tmp), TGSI_SWIZZLE_Y));
+        /* at this step tmp.x = N.E/N.N */
+        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_TEX(ureg, dst, ps1x_sampler_type(tx->info, m + 2), ureg_src(tmp), sample);
         break;
     default:
         return D3DERR_INVALIDCALL;
@@ -2215,7 +2394,29 @@ 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)
@@ -2296,8 +2497,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 < Elements(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]);
@@ -2312,8 +2513,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 < Elements(tx->sampler_targets));
     target = tx->sampler_targets[tx->insn.src[1].idx];
 
     ureg_TXL(tx->ureg, dst, target, src[0], src[1]);
@@ -2363,7 +2564,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 */
@@ -2374,12 +2575,12 @@ struct sm1_op_info inst_table[] =
     _OPI(M3x3, NOP, V(0,0), V(3,0), V(0,0), V(3,0), 1, 2, SPECIAL(M3x3)),
     _OPI(M3x2, NOP, V(0,0), V(3,0), V(0,0), V(3,0), 1, 2, SPECIAL(M3x2)),
 
-    _OPI(CALL,    CAL,     V(2,0), V(3,0), V(2,1), V(3,0), 0, 0, SPECIAL(CALL)),
-    _OPI(CALLNZ,  CAL,     V(2,0), V(3,0), V(2,1), V(3,0), 0, 0, SPECIAL(CALLNZ)),
+    _OPI(CALL,    CAL,     V(2,0), V(3,0), V(2,1), V(3,0), 0, 1, SPECIAL(CALL)),
+    _OPI(CALLNZ,  CAL,     V(2,0), V(3,0), V(2,1), V(3,0), 0, 2, SPECIAL(CALLNZ)),
     _OPI(LOOP,    BGNLOOP, V(2,0), V(3,0), V(3,0), V(3,0), 0, 2, SPECIAL(LOOP)),
     _OPI(RET,     RET,     V(2,0), V(3,0), V(2,1), V(3,0), 0, 0, SPECIAL(RET)),
     _OPI(ENDLOOP, ENDLOOP, V(2,0), V(3,0), V(3,0), V(3,0), 0, 0, SPECIAL(ENDLOOP)),
-    _OPI(LABEL,   NOP,     V(2,0), V(3,0), V(2,1), V(3,0), 0, 0, SPECIAL(LABEL)),
+    _OPI(LABEL,   NOP,     V(2,0), V(3,0), V(2,1), V(3,0), 0, 1, SPECIAL(LABEL)),
 
     _OPI(DCL, NOP, V(0,0), V(3,0), V(0,0), V(3,0), 0, 0, SPECIAL(DCL)),
 
@@ -2414,16 +2615,16 @@ struct sm1_op_info inst_table[] =
     _OPI(TEX,          TEX, V(0,0), V(0,0), V(0,0), V(1,3), 1, 0, SPECIAL(TEX)),
     _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), 0, 0, SPECIAL(TEXBEM)),
-    _OPI(TEXBEML,      TEX, V(0,0), V(0,0), V(0,0), V(1,3), 0, 0, SPECIAL(TEXBEML)),
-    _OPI(TEXREG2AR,    TEX, V(0,0), V(0,0), V(0,0), V(1,3), 0, 0, SPECIAL(TEXREG2AR)),
-    _OPI(TEXREG2GB,    TEX, V(0,0), V(0,0), V(0,0), V(1,3), 0, 0, SPECIAL(TEXREG2GB)),
-    _OPI(TEXM3x2PAD,   TEX, V(0,0), V(0,0), V(0,0), V(1,3), 0, 0, SPECIAL(TEXM3x2PAD)),
-    _OPI(TEXM3x2TEX,   TEX, V(0,0), V(0,0), V(0,0), V(1,3), 0, 0, SPECIAL(TEXM3x2TEX)),
-    _OPI(TEXM3x3PAD,   TEX, V(0,0), V(0,0), V(0,0), V(1,3), 0, 0, SPECIAL(TEXM3x3PAD)),
-    _OPI(TEXM3x3TEX,   TEX, V(0,0), V(0,0), V(0,0), V(1,3), 0, 0, SPECIAL(TEXM3x3)),
-    _OPI(TEXM3x3SPEC,  TEX, V(0,0), V(0,0), V(0,0), V(1,3), 0, 0, SPECIAL(TEXM3x3SPEC)),
-    _OPI(TEXM3x3VSPEC, TEX, V(0,0), V(0,0), V(0,0), V(1,3), 0, 0, SPECIAL(TEXM3x3VSPEC)),
+    _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(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)),
+    _OPI(TEXM3x2TEX,   TEX, V(0,0), V(0,0), V(0,0), V(1,3), 1, 1, SPECIAL(TEXM3x2TEX)),
+    _OPI(TEXM3x3PAD,   TEX, V(0,0), V(0,0), V(0,0), V(1,3), 1, 1, SPECIAL(TEXM3x3PAD)),
+    _OPI(TEXM3x3TEX,   TEX, V(0,0), V(0,0), V(0,0), V(1,3), 1, 1, SPECIAL(TEXM3x3)),
+    _OPI(TEXM3x3SPEC,  TEX, V(0,0), V(0,0), V(0,0), V(1,3), 1, 2, SPECIAL(TEXM3x3SPEC)),
+    _OPI(TEXM3x3VSPEC, TEX, V(0,0), V(0,0), V(0,0), V(1,3), 1, 1, SPECIAL(TEXM3x3)),
 
     _OPI(EXPP, EXP, V(0,0), V(1,1), V(0,0), V(0,0), 1, 1, NULL),
     _OPI(EXPP, EX2, V(2,0), V(3,0), V(0,0), V(0,0), 1, 1, NULL),
@@ -2433,23 +2634,23 @@ struct sm1_op_info inst_table[] =
     _OPI(DEF, NOP, V(0,0), V(3,0), V(0,0), V(3,0), 1, 0, SPECIAL(DEF)),
 
     /* More tex stuff */
-    _OPI(TEXREG2RGB,   TEX, V(0,0), V(0,0), V(1,2), V(1,3), 0, 0, SPECIAL(TEXREG2RGB)),
-    _OPI(TEXDP3TEX,    TEX, V(0,0), V(0,0), V(1,2), V(1,3), 0, 0, SPECIAL(TEXDP3TEX)),
-    _OPI(TEXM3x2DEPTH, TEX, V(0,0), V(0,0), V(1,3), V(1,3), 0, 0, SPECIAL(TEXM3x2DEPTH)),
-    _OPI(TEXDP3,       TEX, V(0,0), V(0,0), V(1,2), V(1,3), 0, 0, SPECIAL(TEXDP3)),
-    _OPI(TEXM3x3,      TEX, V(0,0), V(0,0), V(1,2), V(1,3), 0, 0, SPECIAL(TEXM3x3)),
-    _OPI(TEXDEPTH,     TEX, V(0,0), V(0,0), V(1,4), V(1,4), 0, 0, SPECIAL(TEXDEPTH)),
+    _OPI(TEXREG2RGB,   TEX, V(0,0), V(0,0), V(1,2), V(1,3), 1, 1, SPECIAL(TEXREG2RGB)),
+    _OPI(TEXDP3TEX,    TEX, V(0,0), V(0,0), V(1,2), V(1,3), 1, 1, SPECIAL(TEXDP3TEX)),
+    _OPI(TEXM3x2DEPTH, TEX, V(0,0), V(0,0), V(1,3), V(1,3), 1, 1, SPECIAL(TEXM3x2DEPTH)),
+    _OPI(TEXDP3,       TEX, V(0,0), V(0,0), V(1,2), V(1,3), 1, 1, SPECIAL(TEXDP3)),
+    _OPI(TEXM3x3,      TEX, V(0,0), V(0,0), V(1,2), V(1,3), 1, 1, SPECIAL(TEXM3x3)),
+    _OPI(TEXDEPTH,     TEX, V(0,0), V(0,0), V(1,4), V(1,4), 1, 0, SPECIAL(TEXDEPTH)),
 
     /* Misc */
     _OPI(CMP,    CMP,  V(0,0), V(0,0), V(1,2), V(3,0), 1, 3, SPECIAL(CMP)), /* reversed */
-    _OPI(BEM,    NOP,  V(0,0), V(0,0), V(1,4), V(1,4), 0, 0, SPECIAL(BEM)),
+    _OPI(BEM,    NOP,  V(0,0), V(0,0), V(1,4), V(1,4), 1, 2, SPECIAL(BEM)),
     _OPI(DP2ADD, NOP,  V(0,0), V(0,0), V(2,0), V(3,0), 1, 3, SPECIAL(DP2ADD)),
     _OPI(DSX,    DDX,  V(0,0), V(0,0), V(2,1), V(3,0), 1, 1, NULL),
     _OPI(DSY,    DDY,  V(0,0), V(0,0), V(2,1), V(3,0), 1, 1, NULL),
     _OPI(TEXLDD, TXD,  V(0,0), V(0,0), V(2,1), V(3,0), 1, 4, SPECIAL(TEXLDD)),
-    _OPI(SETP,   NOP,  V(0,0), V(3,0), V(2,1), V(3,0), 0, 0, SPECIAL(SETP)),
+    _OPI(SETP,   NOP,  V(0,0), V(3,0), V(2,1), V(3,0), 1, 2, SPECIAL(SETP)),
     _OPI(TEXLDL, TXL,  V(3,0), V(3,0), V(3,0), V(3,0), 1, 2, SPECIAL(TEXLDL)),
-    _OPI(BREAKP, BRK,  V(0,0), V(3,0), V(2,1), V(3,0), 0, 0, SPECIAL(BREAKP))
+    _OPI(BREAKP, BRK,  V(0,0), V(3,0), V(2,1), V(3,0), 0, 1, SPECIAL(BREAKP))
 };
 
 struct sm1_op_info inst_phase =
@@ -2598,7 +2799,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);
     }
@@ -2812,7 +3013,9 @@ tx_ctor(struct shader_translator *tx, struct nine_shader_info *info)
     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;
@@ -2882,6 +3085,8 @@ nine_translate_shader(struct NineDevice9 *device, struct nine_shader_info *info)
     struct shader_translator *tx;
     HRESULT hr = D3D_OK;
     const unsigned processor = tgsi_processor_from_type(info->type);
+    unsigned s, slot_max;
+    unsigned max_const_f;
 
     user_assert(processor != ~0, D3DERR_INVALIDCALL);
 
@@ -2909,7 +3114,6 @@ 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);
@@ -2930,10 +3134,17 @@ 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))
+    while (!sm1_parse_eof(tx) && !tx->failure)
         sm1_parse_instruction(tx);
     tx->parse++; /* for byte_size */
 
+    if (tx->failure) {
+        ERR("Encountered buggy shader\n");
+        ureg_destroy(tx->ureg);
+        hr = D3DERR_INVALIDCALL;
+        goto out;
+    }
+
     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]));
@@ -2948,13 +3159,6 @@ nine_translate_shader(struct NineDevice9 *device, struct nine_shader_info *info)
     if (IS_VS && !ureg_dst_is_undef(tx->regs.oPts))
         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);
-    }
-
     /* record local constants */
     if (tx->num_lconstf && tx->indirect_const_access) {
         struct nine_range *ranges;
@@ -3013,8 +3217,33 @@ 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))
+        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;
+
+    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);
+
+    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);
+    }
 
     info->cso = ureg_create_shader_and_destroy(tx->ureg, device->pipe);
     if (!info->cso) {