r300: Indented radeon_span.h
[mesa.git] / src / mesa / drivers / dri / nouveau / nouveau_shader_0.c
index 34475cad033e641e7c857c3978a8791776ddc366..8c203cc664baa6603e29c59723ca916ac7bc1718 100644 (file)
 #include "macros.h"
 #include "enums.h"
 
-#include "program.h"
-#include "programopt.h"
-#include "program_instruction.h"
+#include "shader/prog_instruction.h"
+#include "shader/prog_parameter.h"
+#include "shader/prog_statevars.h"
+#include "shader/programopt.h"
 
 #include "nouveau_context.h"
 #include "nouveau_shader.h"
+#include "nouveau_msg.h"
 
 static nvsFixedReg _tx_mesa_vp_dst_reg[VERT_RESULT_MAX] = {
    NVS_FR_POSITION, NVS_FR_COL0, NVS_FR_COL1, NVS_FR_FOGCOORD,
@@ -53,18 +55,6 @@ static nvsFixedReg _tx_mesa_fp_dst_reg[FRAG_RESULT_MAX] = {
    NVS_FR_UNKNOWN /* DEPR */
 };
 
-static nvsFixedReg _tx_mesa_vp_src_reg[VERT_ATTRIB_MAX] = {
-   NVS_FR_POSITION, NVS_FR_WEIGHT, NVS_FR_NORMAL, NVS_FR_COL0, NVS_FR_COL1,
-   NVS_FR_FOGCOORD, NVS_FR_UNKNOWN /* COLOR_INDEX */, NVS_FR_UNKNOWN,
-   NVS_FR_TEXCOORD0, NVS_FR_TEXCOORD1, NVS_FR_TEXCOORD2, NVS_FR_TEXCOORD3,
-   NVS_FR_TEXCOORD4, NVS_FR_TEXCOORD5, NVS_FR_TEXCOORD6, NVS_FR_TEXCOORD7,
-/* Generic attribs 0-15, aliased to the above */
-   NVS_FR_POSITION, NVS_FR_WEIGHT, NVS_FR_NORMAL, NVS_FR_COL0, NVS_FR_COL1,
-   NVS_FR_FOGCOORD, NVS_FR_UNKNOWN /* COLOR_INDEX */, NVS_FR_UNKNOWN,
-   NVS_FR_TEXCOORD0, NVS_FR_TEXCOORD1, NVS_FR_TEXCOORD2, NVS_FR_TEXCOORD3,
-   NVS_FR_TEXCOORD4, NVS_FR_TEXCOORD5, NVS_FR_TEXCOORD6, NVS_FR_TEXCOORD7
-};
-
 static nvsFixedReg _tx_mesa_fp_src_reg[FRAG_ATTRIB_MAX] = {
    NVS_FR_POSITION, NVS_FR_COL0, NVS_FR_COL1, NVS_FR_FOGCOORD,
    NVS_FR_TEXCOORD0, NVS_FR_TEXCOORD1, NVS_FR_TEXCOORD2, NVS_FR_TEXCOORD3,
@@ -116,13 +106,18 @@ static nvsOpcode _tx_mesa_opcode[] = {
 };
 
 static nvsCond _tx_mesa_condmask[] = {
-   NVS_COND_UNKNOWN, NVS_COND_GT, NVS_COND_LT, NVS_COND_UN, NVS_COND_GE,
+   NVS_COND_TR, /* workaround mesa not filling a valid value */
+   NVS_COND_GT, NVS_COND_LT, NVS_COND_UN, NVS_COND_GE,
    NVS_COND_LE, NVS_COND_NE, NVS_COND_NE, NVS_COND_TR, NVS_COND_FL
 };
 
 struct pass0_rec {
    int nvs_ipos;
    int next_temp;
+
+   int mesa_const_base;
+   int mesa_const_last;
+
    int swzconst_done;
    int swzconst_id;
    nvsRegister const_half;
@@ -133,578 +128,923 @@ struct pass0_rec {
 #define Z NVS_SWZ_Z
 #define W NVS_SWZ_W
 
+#define FILL_CONDITION_FLAGS(fragment) do {                                    \
+       (fragment)->cond =                                                     \
+       pass0_make_condmask(inst->DstReg.CondMask);                            \
+       if ((fragment)->cond != NVS_COND_TR)                                   \
+               (fragment)->cond_test = 1;                                     \
+       (fragment)->cond_reg = inst->CondDst;                                  \
+       pass0_make_swizzle((fragment)->cond_swizzle, inst->DstReg.CondSwizzle);\
+} while(0)
+
+#define ARITH(op,dest,mask,sat,s0,s1,s2) do {               \
+       nvsinst = pass0_emit(nvs, parent, fpos, (op),       \
+                  (dest), (mask), (sat), (s0), (s1), (s2));\
+       FILL_CONDITION_FLAGS(nvsinst);                      \
+} while(0)
+
+#define ARITHu(op,dest,mask,sat,s0,s1,s2) do {              \
+       nvsinst = pass0_emit(nvs, parent, fpos, (op),       \
+                  (dest), (mask), (sat), (s0), (s1), (s2));\
+} while(0)
+
 static void
-pass0_append_fragment(nouveauShader *nvs, nvsFragmentHeader *fragment)
+pass0_append_fragment(nvsFragmentHeader *parent,
+                     nvsFragmentHeader *fragment,
+                     int pos)
 {
-   nvsFragmentList *list = calloc(1, sizeof(nvsFragmentList));
-   if (!list)
-      return;
-
-   list->fragment = fragment;
-   list->prev     = nvs->list_tail;
-   if ( nvs->list_tail)
-      nvs->list_tail->next = list;
-   if (!nvs->list_head)
-      nvs->list_head = list;
-   nvs->list_tail = list;
-
-   nvs->inst_count++;
+       nvsFragmentHeader **head, **tail;
+       assert(parent && fragment);
+
+       switch (parent->type) {
+       case NVS_BRANCH:
+               if (pos == 0) {
+                       head = &((nvsBranch *)parent)->target_head;
+                       tail = &((nvsBranch *)parent)->target_tail;
+               } else {
+                       head = &((nvsBranch *)parent)->else_head;
+                       tail = &((nvsBranch *)parent)->else_tail;
+               }
+               break;
+       case NVS_LOOP:
+               head = &((nvsLoop *)parent)->insn_head;
+               tail = &((nvsLoop *)parent)->insn_tail;
+               break;
+       case NVS_SUBROUTINE:
+               head = &((nvsSubroutine *)parent)->insn_head;
+               tail = &((nvsSubroutine *)parent)->insn_tail;
+               break;
+       default:
+               assert(0);
+               break;
+       }
+
+       fragment->parent = parent;
+       fragment->prev   = *tail;
+       fragment->next   = NULL;
+       if (!(*head))
+               *head = fragment;
+       else
+               (*tail)->next = fragment;
+       *tail = fragment;
+
+}
+
+static nvsSubroutine *
+pass0_create_subroutine(nouveauShader *nvs, const char *label)
+{
+       nvsSubroutine *sub;
+
+       sub = CALLOC_STRUCT(nvs_subroutine);
+       if (sub) {
+               sub->header.type = NVS_SUBROUTINE;
+               sub->label       = strdup(label);
+               if (!nvs->program_tree)
+                       nvs->program_tree = &sub->header;
+               else
+                       pass0_append_fragment(nvs->program_tree,
+                                             &sub->header, 0);
+       }
+
+       return sub;
 }
 
 static void
 pass0_make_reg(nouveauShader *nvs, nvsRegister *reg,
-              nvsRegFile file, unsigned int index)
+              nvsRegFile file, unsigned int index)
 {
-   struct pass0_rec *rec = nvs->pass_rec;
-
-   /* defaults */
-   *reg = nvr_unused;
-   /* -1 == quick-and-dirty temp alloc */
-   if (file == NVS_FILE_TEMP && index == -1) {
-      index = rec->next_temp++;
-      assert(index < NVS_MAX_TEMPS);
-   }
-   reg->file   = file;
-   reg->index  = index;
+       struct pass0_rec *rec = nvs->pass_rec;
+
+       /* defaults */
+       *reg = nvr_unused;
+       /* -1 == quick-and-dirty temp alloc */
+       if (file == NVS_FILE_TEMP && index == -1) {
+               index = rec->next_temp++;
+               assert(index < NVS_MAX_TEMPS);
+       }
+       reg->file   = file;
+       reg->index  = index;
 }
 
 static void
 pass0_make_swizzle(nvsSwzComp *swz, unsigned int mesa)
 {
-   int i;
+       int i;
 
-   for (i=0;i<4;i++)
-      swz[i] = _tx_mesa_swizzle[GET_SWZ(mesa, i)];
+       for (i=0;i<4;i++)
+               swz[i] = _tx_mesa_swizzle[GET_SWZ(mesa, i)];
 }
 
 static nvsOpcode
 pass0_make_opcode(enum prog_opcode op)
 {
-   if (op > MAX_OPCODE)
-      return NVS_OP_UNKNOWN;
-   return _tx_mesa_opcode[op];
+       if (op > MAX_OPCODE)
+               return NVS_OP_UNKNOWN;
+       return _tx_mesa_opcode[op];
 }
 
 static nvsCond
 pass0_make_condmask(GLuint mesa)
 {
-   if (mesa > COND_FL)
-      return NVS_COND_UNKNOWN;
-   return _tx_mesa_condmask[mesa];
+       if (mesa > COND_FL)
+               return NVS_COND_UNKNOWN;
+       return _tx_mesa_condmask[mesa];
 }
 
 static unsigned int
 pass0_make_mask(GLuint mesa_mask)
 {
-   unsigned int mask = 0;
+       unsigned int mask = 0;
 
-   if (mesa_mask & WRITEMASK_X) mask |= SMASK_X;
-   if (mesa_mask & WRITEMASK_Y) mask |= SMASK_Y;
-   if (mesa_mask & WRITEMASK_Z) mask |= SMASK_Z;
-   if (mesa_mask & WRITEMASK_W) mask |= SMASK_W;
+       if (mesa_mask & WRITEMASK_X) mask |= SMASK_X;
+       if (mesa_mask & WRITEMASK_Y) mask |= SMASK_Y;
+       if (mesa_mask & WRITEMASK_Z) mask |= SMASK_Z;
+       if (mesa_mask & WRITEMASK_W) mask |= SMASK_W;
 
-   return mask;
+       return mask;
+}
+
+static GLboolean
+pass0_opcode_is_tex(enum prog_opcode op)
+{
+       switch (op) {
+       case OPCODE_TEX:
+       case OPCODE_TXB:
+       case OPCODE_TXD:
+       case OPCODE_TXL:
+       case OPCODE_TXP:
+               return GL_TRUE;
+       default:
+               break;
+       }
+
+       return GL_FALSE;
 }
 
 static nvsTexTarget
 pass0_make_tex_target(GLuint mesa)
 {
-   switch (mesa) {
-   case TEXTURE_1D_INDEX:   return NVS_TEX_TARGET_1D;
-   case TEXTURE_2D_INDEX:   return NVS_TEX_TARGET_2D;
-   case TEXTURE_3D_INDEX:   return NVS_TEX_TARGET_3D;
-   case TEXTURE_CUBE_INDEX: return NVS_TEX_TARGET_CUBE;
-   case TEXTURE_RECT_INDEX: return NVS_TEX_TARGET_RECT;
-   default:
-      return NVS_TEX_TARGET_UNKNOWN;
-   }
+       switch (mesa) {
+       case TEXTURE_1D_INDEX: return NVS_TEX_TARGET_1D;
+       case TEXTURE_2D_INDEX: return NVS_TEX_TARGET_2D;
+       case TEXTURE_3D_INDEX: return NVS_TEX_TARGET_3D;
+       case TEXTURE_CUBE_INDEX: return NVS_TEX_TARGET_CUBE;
+       case TEXTURE_RECT_INDEX: return NVS_TEX_TARGET_RECT;
+       default:
+               return NVS_TEX_TARGET_UNKNOWN;
+       }
 }
 
 static void
 pass0_make_dst_reg(nvsPtr nvs, nvsRegister *reg,
                   struct prog_dst_register *dst)
 {
-   struct gl_program *mesa = (struct gl_program*)&nvs->mesa.vp;
-   nvsFixedReg sfr;
-
-   switch (dst->File) {
-   case PROGRAM_OUTPUT:
-      if (mesa->Target == GL_VERTEX_PROGRAM_ARB) {
-        sfr = (dst->Index < VERT_RESULT_MAX) ?
-           _tx_mesa_vp_dst_reg[dst->Index] : NVS_FR_UNKNOWN;
-      } else {
-        sfr = (dst->Index < FRAG_RESULT_MAX) ?
-           _tx_mesa_fp_dst_reg[dst->Index] : NVS_FR_UNKNOWN;
-      }
-      pass0_make_reg(nvs, reg, NVS_FILE_RESULT, sfr);
-      break;
-   case PROGRAM_TEMPORARY:
-      pass0_make_reg(nvs, reg, NVS_FILE_TEMP, dst->Index);
-      break;
-   case PROGRAM_ADDRESS:
-      pass0_make_reg(nvs, reg, NVS_FILE_ADDRESS, dst->Index);
-      break;
-   default:
-      fprintf(stderr, "Unknown dest file %d\n", dst->File);
-      assert(0);
-   }
+       struct gl_program *mesa = (struct gl_program*)&nvs->mesa.vp;
+       nvsFixedReg sfr;
+
+       switch (dst->File) {
+       case PROGRAM_OUTPUT:
+               if (mesa->Target == GL_VERTEX_PROGRAM_ARB) {
+                       sfr = (dst->Index < VERT_RESULT_MAX) ?
+                               _tx_mesa_vp_dst_reg[dst->Index] :
+                               NVS_FR_UNKNOWN;
+               } else {
+                       sfr = (dst->Index < FRAG_RESULT_MAX) ?
+                               _tx_mesa_fp_dst_reg[dst->Index] :
+                               NVS_FR_UNKNOWN;
+               }
+               pass0_make_reg(nvs, reg, NVS_FILE_RESULT, sfr);
+               break;
+       case PROGRAM_TEMPORARY:
+               pass0_make_reg(nvs, reg, NVS_FILE_TEMP, dst->Index);
+               break;
+       case PROGRAM_ADDRESS:
+               pass0_make_reg(nvs, reg, NVS_FILE_ADDRESS, dst->Index);
+               break;
+       default:
+               fprintf(stderr, "Unknown dest file %d\n", dst->File);
+               assert(0);
+       }
 }
 
 static void
 pass0_make_src_reg(nvsPtr nvs, nvsRegister *reg, struct prog_src_register *src)
 {
-   struct gl_program *mesa = (struct gl_program *)&nvs->mesa.vp.Base;
-   struct gl_program_parameter_list *p = mesa->Parameters;
-
-   *reg = nvr_unused;
-
-   switch (src->File) {
-   case PROGRAM_INPUT:
-      reg->file = NVS_FILE_ATTRIB;
-      if (mesa->Target == GL_VERTEX_PROGRAM_ARB) {
-        reg->index = (src->Index < VERT_ATTRIB_MAX) ?
-           _tx_mesa_vp_src_reg[src->Index] : NVS_FR_UNKNOWN;
-      } else {
-        reg->index = (src->Index < FRAG_ATTRIB_MAX) ?
-           _tx_mesa_fp_src_reg[src->Index] : NVS_FR_UNKNOWN;
-      }
-      break;
-   /* All const types seem to get shoved into here, not really sure why */
-   case PROGRAM_STATE_VAR:
-      switch (p->Parameters[src->Index].Type) {
-      case PROGRAM_NAMED_PARAM:
-      case PROGRAM_CONSTANT:
-        nvs->params[src->Index].source_val = NULL;
-        COPY_4V(nvs->params[src->Index].val, p->ParameterValues[src->Index]); 
-        break;
-      case PROGRAM_STATE_VAR:
-        nvs->params[src->Index].source_val = p->ParameterValues[src->Index];
-        break;
-      default:
-        fprintf(stderr, "Unknown parameter type %d\n",
-              p->Parameters[src->Index].Type);
-        assert(0);
-        break;
-      }
-
-      if (src->RelAddr) {
-        reg->indexed   = 1;
-        reg->addr_reg  = 0;
-        reg->addr_comp = NVS_SWZ_X;
-      } else
-        reg->indexed = 0;
-      reg->file  = NVS_FILE_CONST;
-      reg->index = src->Index;
-      break;
-   case PROGRAM_TEMPORARY:
-      reg->file  = NVS_FILE_TEMP;
-      reg->index = src->Index;
-      break;
-   default:
-      fprintf(stderr, "Unknown source type %d\n", src->File);
-      assert(0);
-   }
-
-   /* per-component negate handled elsewhere */
-   reg->negate = src->NegateBase != 0;
-   reg->abs    = src->Abs;
-   pass0_make_swizzle(reg->swizzle, src->Swizzle);
+       struct pass0_rec *rec = nvs->pass_rec;
+       struct gl_program *mesa = (struct gl_program *)&nvs->mesa.vp.Base;
+       int i;
+
+       *reg = nvr_unused;
+
+       switch (src->File) {
+       case PROGRAM_INPUT:
+               reg->file = NVS_FILE_ATTRIB;
+               if (mesa->Target == GL_VERTEX_PROGRAM_ARB) {
+                       for (i=0; i<NVS_MAX_ATTRIBS; i++) {
+                               if (nvs->vp_attrib_map[i] == src->Index) {
+                                       reg->index = i;
+                                       break;
+                               }
+                       }
+                       if (i==NVS_MAX_ATTRIBS)
+                               reg->index = NVS_FR_UNKNOWN;
+               } else {
+                       reg->index = (src->Index < FRAG_ATTRIB_MAX) ?
+                               _tx_mesa_fp_src_reg[src->Index] :
+                               NVS_FR_UNKNOWN;
+               }
+               break;
+       case PROGRAM_STATE_VAR:
+       case PROGRAM_NAMED_PARAM:
+       case PROGRAM_CONSTANT:
+               reg->file    = NVS_FILE_CONST;
+               reg->index   = src->Index + rec->mesa_const_base;
+               reg->indexed = src->RelAddr;
+               if (reg->indexed) {
+                       reg->addr_reg  = 0;
+                       reg->addr_comp = NVS_SWZ_X;
+               }
+               break;
+       case PROGRAM_TEMPORARY:
+               reg->file  = NVS_FILE_TEMP;
+               reg->index = src->Index;
+               break;
+       default:
+               fprintf(stderr, "Unknown source type %d\n", src->File);
+               assert(0);
+       }
+
+       /* per-component negate handled elsewhere */
+       reg->negate = src->NegateBase != 0;
+       reg->abs    = src->Abs;
+       pass0_make_swizzle(reg->swizzle, src->Swizzle);
 }
 
 static nvsInstruction *
-pass0_emit(nouveauShader *nvs, nvsOpcode op, nvsRegister dst,
-          unsigned int mask, int saturate,
+pass0_emit(nouveauShader *nvs, nvsFragmentHeader *parent, int fpos,
+          nvsOpcode op, nvsRegister dst,
+          unsigned int mask, int saturate,
           nvsRegister src0, nvsRegister src1, nvsRegister src2)
 {
-   struct pass0_rec *rec = nvs->pass_rec;
-   nvsInstruction *sif = NULL;
-
-   /* Seems mesa doesn't explicitly 0 this.. */
-   if (nvs->mesa.vp.Base.Target == GL_VERTEX_PROGRAM_ARB)
-      saturate = 0;
-
-   sif = calloc(1, sizeof(nvsInstruction));
-   if (sif) {
-      sif->header.type     = NVS_INSTRUCTION;
-      sif->header.position = rec->nvs_ipos++;
-      sif->op          = op;
-      sif->saturate    = saturate;
-      sif->dest                = dst;
-      sif->mask                = mask;
-      sif->src[0]      = src0;
-      sif->src[1]      = src1;
-      sif->src[2]      = src2;
-      sif->cond                = COND_TR;
-      sif->cond_reg    = 0;
-      sif->cond_test   = 0;
-      sif->cond_update = 0;
-      pass0_make_swizzle(sif->cond_swizzle, SWIZZLE_NOOP);
-      pass0_append_fragment(nvs, (nvsFragmentHeader *)sif);
-   }
-
-   return sif;
+       nvsInstruction *sif;
+
+       sif = CALLOC_STRUCT(nvs_instruction);
+       if (!sif)
+               return NULL;
+
+       /* Seems mesa doesn't explicitly 0 this.. */
+       if (nvs->mesa.vp.Base.Target == GL_VERTEX_PROGRAM_ARB)
+               saturate = 0;
+
+       sif->op         = op;
+       sif->saturate   = saturate;
+       sif->dest       = dst;
+       sif->mask       = mask;
+       sif->dest_scale = NVS_SCALE_1X;
+       sif->src[0]     = src0;
+       sif->src[1]     = src1;
+       sif->src[2]     = src2;
+       sif->cond       = COND_TR;
+       sif->cond_reg   = 0;
+       sif->cond_test  = 0;
+       sif->cond_update= 0;
+       pass0_make_swizzle(sif->cond_swizzle, SWIZZLE_NOOP);
+       pass0_append_fragment(parent, &sif->header, fpos);
+
+       return sif;
 }
 
 static void
-pass0_fixup_swizzle(nvsPtr nvs,
-                   struct prog_src_register *src,
+pass0_fixup_swizzle(nvsPtr nvs, nvsFragmentHeader *parent, int fpos,
+                   struct prog_src_register *src,
                    unsigned int sm1,
                    unsigned int sm2)
 {
-   static const float sc[4] = { 1.0, 0.0, -1.0, 0.0 };
-   struct pass0_rec *rec = nvs->pass_rec;
-   int fixup_1, fixup_2;
-   nvsRegister sr, dr = nvr_unused;
-   nvsRegister sm1const, sm2const;
-
-   if (!rec->swzconst_done) {
-      struct gl_program *prog = &nvs->mesa.vp.Base;
-      rec->swzconst_id = _mesa_add_unnamed_constant(prog->Parameters, sc, 4);
-      rec->swzconst_done = 1;
-      COPY_4V(nvs->params[rec->swzconst_id].val, sc);
-   }
-
-   fixup_1 = (sm1 != MAKE_SWIZZLE4(0,0,0,0) && sm2 != MAKE_SWIZZLE4(2,2,2,2));
-   fixup_2 = (sm2 != MAKE_SWIZZLE4(2,2,2,2));
-
-   if (src->File != PROGRAM_TEMPORARY && src->File != PROGRAM_INPUT) {
-      /* We can't use more than one const in an instruction, so move the const
-       * into a temp, and swizzle from there.
-       *TODO: should just emit the swizzled const, instead of swizzling it
-       *      in the shader.. would need to reswizzle any state params when they
-       *      change however..
-       */
-      pass0_make_reg(nvs, &dr, NVS_FILE_TEMP, -1);
-      pass0_make_src_reg(nvs, &sr, src);
-      pass0_emit(nvs, NVS_OP_MOV, dr, SMASK_ALL, 0, sr, nvr_unused, nvr_unused);
-      pass0_make_reg(nvs, &sr, NVS_FILE_TEMP, dr.index);
-   } else {
-      if (fixup_1)
-        src->NegateBase = 0;
-      pass0_make_src_reg(nvs, &sr, src);
-      pass0_make_reg(nvs, &dr, NVS_FILE_TEMP, -1);
-   }
-
-   pass0_make_reg(nvs, &sm1const, NVS_FILE_CONST, rec->swzconst_id);
-   pass0_make_swizzle(sm1const.swizzle, sm1);
-   if (fixup_1 && fixup_2) {
-      /* Any combination with SWIZZLE_ONE */
-      pass0_make_reg(nvs, &sm2const, NVS_FILE_CONST, rec->swzconst_id);
-      pass0_make_swizzle(sm2const.swizzle, sm2);
-      pass0_emit(nvs, NVS_OP_MAD, dr, SMASK_ALL, 0, sr, sm1const, sm2const);
-   } else {
-      /* SWIZZLE_ZERO || arbitrary negate */
-      pass0_emit(nvs, NVS_OP_MUL, dr, SMASK_ALL, 0, sr, sm1const, nvr_unused);
-   }
-
-   src->File   = PROGRAM_TEMPORARY;
-   src->Index  = dr.index;
-   src->Swizzle        = SWIZZLE_NOOP;
+       static const float sc[4] = { 1.0, 0.0, -1.0, 0.0 };
+       struct pass0_rec *rec = nvs->pass_rec;
+       int fixup_1, fixup_2;
+       nvsInstruction *nvsinst;
+       nvsRegister sr, dr = nvr_unused;
+       nvsRegister sm1const, sm2const;
+
+       if (!rec->swzconst_done) {
+               struct gl_program *prog = &nvs->mesa.vp.Base;
+                GLuint swizzle;
+               rec->swzconst_id = _mesa_add_unnamed_constant(prog->Parameters,
+                                                             sc, 4, &swizzle);
+                /* XXX what about swizzle? */
+               rec->swzconst_done = 1;
+               COPY_4V(nvs->params[rec->swzconst_id].val, sc);
+       }
+
+       fixup_1 = (sm1 != MAKE_SWIZZLE4(0,0,0,0) &&
+                       sm2 != MAKE_SWIZZLE4(2,2,2,2));
+       fixup_2 = (sm2 != MAKE_SWIZZLE4(2,2,2,2));
+
+       if (src->File != PROGRAM_TEMPORARY && src->File != PROGRAM_INPUT) {
+               /* We can't use more than one const in an instruction,
+                * so move the const into a temp, and swizzle from there.
+                *
+                * TODO: should just emit the swizzled const, instead of
+                *       swizzling it in the shader.. would need to reswizzle
+                *       any state params when they change however..
+                */
+               pass0_make_reg(nvs, &dr, NVS_FILE_TEMP, -1);
+               pass0_make_src_reg(nvs, &sr, src);
+               ARITHu(NVS_OP_MOV, dr, SMASK_ALL, 0,
+                                sr, nvr_unused, nvr_unused);
+               pass0_make_reg(nvs, &sr, NVS_FILE_TEMP, dr.index);
+       } else {
+               if (fixup_1)
+                       src->NegateBase = 0;
+               pass0_make_src_reg(nvs, &sr, src);
+               pass0_make_reg(nvs, &dr, NVS_FILE_TEMP, -1);
+       }
+
+       pass0_make_reg(nvs, &sm1const, NVS_FILE_CONST, rec->swzconst_id);
+       pass0_make_swizzle(sm1const.swizzle, sm1);
+       if (fixup_1 && fixup_2) {
+               /* Any combination with SWIZZLE_ONE */
+               pass0_make_reg(nvs, &sm2const,
+                                   NVS_FILE_CONST, rec->swzconst_id);
+               pass0_make_swizzle(sm2const.swizzle, sm2);
+               ARITHu(NVS_OP_MAD, dr, SMASK_ALL, 0, sr, sm1const, sm2const);
+       } else {
+               /* SWIZZLE_ZERO || arbitrary negate */
+               ARITHu(NVS_OP_MUL, dr, SMASK_ALL, 0, sr, sm1const, nvr_unused);
+       }
+
+       src->File       = PROGRAM_TEMPORARY;
+       src->Index      = dr.index;
+       src->Swizzle    = SWIZZLE_NOOP;
 }
 
 #define SET_SWZ(fs, cp, c) fs = (fs & ~(0x7<<(cp*3))) | (c<<(cp*3))
 static void
-pass0_check_sources(nvsPtr nvs, struct prog_instruction *inst)
+pass0_check_sources(nvsPtr nvs, nvsFragmentHeader *parent, int fpos,
+                   struct prog_instruction *inst)
 {
-   unsigned int insrc = -1, constsrc = -1;
-   int i;
-
-   for (i=0;i<_mesa_num_inst_src_regs(inst->Opcode);i++) {
-      struct prog_src_register *src = &inst->SrcReg[i];
-      unsigned int sm_1 = 0, sm_2 = 0;
-      nvsRegister sr, dr;
-      int do_mov = 0, c;
-
-      /* Build up swizzle masks as if we were going to use
-       * "MAD new, src, const1, const2" to support arbitrary negation
-       * and SWIZZLE_ZERO/SWIZZLE_ONE.
-       */
-      for (c=0;c<4;c++) {
-        if (GET_SWZ(src->Swizzle, c) == SWIZZLE_ZERO) {
-           SET_SWZ(sm_1, c, SWIZZLE_Y); /* 0.0 */
-           SET_SWZ(sm_2, c, SWIZZLE_Y);
-           SET_SWZ(src->Swizzle, c, SWIZZLE_X);
-        } else if (GET_SWZ(src->Swizzle, c) == SWIZZLE_ONE) {
-           SET_SWZ(sm_1, c, SWIZZLE_Y);
-           if (src->NegateBase & (1<<c))
-              SET_SWZ(sm_2, c, SWIZZLE_Z); /* -1.0 */
-           else
-              SET_SWZ(sm_2, c, SWIZZLE_X); /* 1.0 */
-           SET_SWZ(src->Swizzle, c, SWIZZLE_X);
-        } else {
-           if (src->NegateBase & (1<<c))
-              SET_SWZ(sm_1, c, SWIZZLE_Z); /* -[xyzw] */
-           else
-              SET_SWZ(sm_1, c, SWIZZLE_X); /* [xyzw] */
-           SET_SWZ(sm_2, c, SWIZZLE_Y);
-        }
-      }
-      /* Unless we're multiplying by 1.0 or -1.0 on all components, and we're
-       * adding nothing to any component we have to emulate the swizzle.
-       */
-      if ((sm_1 != MAKE_SWIZZLE4(0,0,0,0) && sm_1 != MAKE_SWIZZLE4(2,2,2,2)) ||
-              sm_2 != MAKE_SWIZZLE4(1,1,1,1)) {
-        pass0_fixup_swizzle(nvs, src, sm_1, sm_2);
-        /* The source is definitely in a temp now, so don't bother checking 
-         * for multiple ATTRIB/CONST regs.
-         */
-        continue;
-      }
-
-      /* HW can't use more than one ATTRIB or PARAM in a single instruction */
-      switch (src->File) {
-      case PROGRAM_INPUT:
-        if (insrc != -1 && insrc != src->Index) 
-           do_mov = 1;
-        else insrc = src->Index;
-        break;
-      case PROGRAM_STATE_VAR:
-        if (constsrc != -1 && constsrc != src->Index)
-           do_mov = 1;
-        else constsrc = src->Index;
-        break;
-      default:
-        break;
-      }
-
-      /* Emit any extra ATTRIB/CONST to a temp, and modify the Mesa instruction
-       * to point at the temp.
-       */
-      if (do_mov) {
-        pass0_make_src_reg(nvs, &sr, src);
-        pass0_make_reg(nvs, &dr, NVS_FILE_TEMP, -1);
-        pass0_emit(nvs, NVS_OP_MOV, dr, SMASK_ALL, 0,
-              sr, nvr_unused, nvr_unused);
-
-        src->File      = PROGRAM_TEMPORARY;
-        src->Index     = dr.index;
-        src->Swizzle= SWIZZLE_NOOP;
-      }
-   }
+       unsigned int insrc = -1, constsrc = -1;
+       int i;
+
+       for (i=0;i<_mesa_num_inst_src_regs(inst->Opcode);i++) {
+               struct prog_src_register *src = &inst->SrcReg[i];
+               unsigned int sm_1 = 0, sm_2 = 0;
+               nvsRegister sr, dr;
+               int do_mov = 0, c;
+
+               /* Build up swizzle masks as if we were going to use
+                * "MAD new, src, const1, const2" to support arbitrary negation
+                * and SWIZZLE_ZERO/SWIZZLE_ONE.
+                */
+               for (c=0;c<4;c++) {
+                       if (GET_SWZ(src->Swizzle, c) == SWIZZLE_ZERO) {
+                               SET_SWZ(sm_1, c, SWIZZLE_Y); /* 0.0 */
+                               SET_SWZ(sm_2, c, SWIZZLE_Y);
+                               SET_SWZ(src->Swizzle, c, SWIZZLE_X);
+                       } else if (GET_SWZ(src->Swizzle, c) == SWIZZLE_ONE) {
+                               SET_SWZ(sm_1, c, SWIZZLE_Y);
+                               if (src->NegateBase & (1<<c))
+                                       SET_SWZ(sm_2, c, SWIZZLE_Z); /* -1.0 */
+                               else
+                                       SET_SWZ(sm_2, c, SWIZZLE_X); /* 1.0 */
+                               SET_SWZ(src->Swizzle, c, SWIZZLE_X);
+                       } else {
+                               if (src->NegateBase & (1<<c))
+                                       SET_SWZ(sm_1, c, SWIZZLE_Z); /* -[xyzw] */
+                               else
+                                       SET_SWZ(sm_1, c, SWIZZLE_X); /*[xyzw]*/
+                               SET_SWZ(sm_2, c, SWIZZLE_Y);
+                       }
+               }
+
+               /* Unless we're multiplying by 1.0 or -1.0 on all components,
+                * and we're adding nothing to any component we have to
+                * emulate the swizzle.
+                */
+               if ((sm_1 != MAKE_SWIZZLE4(0,0,0,0) &&
+                                       sm_1 != MAKE_SWIZZLE4(2,2,2,2)) ||
+                               sm_2 != MAKE_SWIZZLE4(1,1,1,1)) {
+                       pass0_fixup_swizzle(nvs, parent, fpos, src, sm_1, sm_2);
+                       /* The source is definitely in a temp now, so don't
+                        * bother checking  for multiple ATTRIB/CONST regs.
+                        */
+                       continue;
+               }
+
+               /* HW can't use more than one ATTRIB or PARAM in a single
+                * instruction */
+               switch (src->File) {
+               case PROGRAM_INPUT:
+                       if (insrc != -1 && insrc != src->Index) 
+                               do_mov = 1;
+                       else insrc = src->Index;
+                       break;
+               case PROGRAM_STATE_VAR:
+                       if (constsrc != -1 && constsrc != src->Index)
+                               do_mov = 1;
+                       else constsrc = src->Index;
+                       break;
+               default:
+                       break;
+               }
+
+               /* Emit any extra ATTRIB/CONST to a temp, and modify the Mesa
+                * instruction to point at the temp.
+                */
+               if (do_mov) {
+                       pass0_make_src_reg(nvs, &sr, src);
+                       pass0_make_reg(nvs, &dr, NVS_FILE_TEMP, -1);
+                       pass0_emit(nvs, parent, fpos, NVS_OP_MOV,
+                                       dr, SMASK_ALL, 0,
+                                       sr, nvr_unused, nvr_unused);
+
+                       src->File       = PROGRAM_TEMPORARY;
+                       src->Index      = dr.index;
+                       src->Swizzle= SWIZZLE_NOOP;
+               }
+       }
 }
 
 static GLboolean
-pass0_emulate_instruction(nouveauShader *nvs, struct prog_instruction *inst)
+pass0_emulate_instruction(nouveauShader *nvs,
+                         nvsFragmentHeader *parent, int fpos,
+                         struct prog_instruction *inst)
+{
+       nvsFunc *shader = nvs->func;
+       nvsRegister src[3], dest, temp;
+       nvsInstruction *nvsinst;
+       unsigned int mask = pass0_make_mask(inst->DstReg.WriteMask);
+       int i, sat;
+
+       sat = (inst->SaturateMode == SATURATE_ZERO_ONE);
+
+       /* Build all the "real" regs for the instruction */
+       for (i=0; i<_mesa_num_inst_src_regs(inst->Opcode); i++)
+               pass0_make_src_reg(nvs, &src[i], &inst->SrcReg[i]);
+       if (inst->Opcode != OPCODE_KIL)
+               pass0_make_dst_reg(nvs, &dest, &inst->DstReg);
+
+       switch (inst->Opcode) {
+       case OPCODE_ABS:
+               if (shader->caps & SCAP_SRC_ABS)
+                       ARITH(NVS_OP_MOV, dest, mask, sat,
+                                       nvsAbs(src[0]), nvr_unused, nvr_unused);
+               else
+                       ARITH(NVS_OP_MAX, dest, mask, sat,
+                                       src[0], nvsNegate(src[0]), nvr_unused);
+               break;
+       case OPCODE_CMP:
+               /*XXX: this will clobber CC0... */
+               ARITH (NVS_OP_MOV, dest, mask, sat,
+                               src[2], nvr_unused, nvr_unused);
+               pass0_make_reg(nvs, &temp, NVS_FILE_TEMP, -1);
+               ARITHu(NVS_OP_MOV, temp, SMASK_ALL, 0,
+                               src[0], nvr_unused, nvr_unused);
+               nvsinst->cond_update = 1;
+               nvsinst->cond_reg    = 0;
+               ARITH (NVS_OP_MOV, dest, mask, sat,
+                               src[1], nvr_unused, nvr_unused);
+               nvsinst->cond      = COND_LT;
+               nvsinst->cond_reg  = 0;
+               nvsinst->cond_test = 1;
+               break;
+       case OPCODE_DPH:
+               pass0_make_reg(nvs, &temp, NVS_FILE_TEMP, -1);
+               ARITHu(NVS_OP_DP3, temp, SMASK_X, 0,
+                                src[0], src[1], nvr_unused);
+               ARITH (NVS_OP_ADD, dest, mask, sat,
+                                nvsSwizzle(temp, X, X, X, X),
+                                nvsSwizzle(src[1], W, W, W, W),
+                                nvr_unused);
+               break;
+       case OPCODE_KIL:
+               /* This is only in ARB shaders, so we don't have to worry
+                * about clobbering a CC reg as they aren't supported anyway.
+                *XXX: might have to worry with GLSL however...
+                */
+               /* MOVC0 temp, src */
+               pass0_make_reg(nvs, &temp, NVS_FILE_TEMP, -1);
+               ARITHu(NVS_OP_MOV, temp, SMASK_ALL, 0,
+                                src[0], nvr_unused, nvr_unused);
+               nvsinst->cond_update = 1;
+               nvsinst->cond_reg    = 0;
+               /* KIL_NV (LT0.xyzw) temp */
+               ARITHu(NVS_OP_KIL, nvr_unused, 0, 0,
+                                nvr_unused, nvr_unused, nvr_unused);
+               nvsinst->cond      = COND_LT;
+               nvsinst->cond_reg  = 0;
+               nvsinst->cond_test = 1;
+               pass0_make_swizzle(nvsinst->cond_swizzle, SWIZZLE_NOOP);
+               break;
+       case OPCODE_LRP:
+               pass0_make_reg(nvs, &temp, NVS_FILE_TEMP, -1);
+               ARITHu(NVS_OP_MAD, temp, mask, 0,
+                                nvsNegate(src[0]), src[2], src[2]);
+               ARITH (NVS_OP_MAD, dest, mask, sat, src[0], src[1], temp);
+               break;
+       case OPCODE_POW:
+               if (shader->SupportsOpcode(shader, NVS_OP_LG2) &&
+                               shader->SupportsOpcode(shader, NVS_OP_EX2)) {
+                       pass0_make_reg(nvs, &temp, NVS_FILE_TEMP, -1);
+                       /* LG2 temp.x, src0.c */
+                       ARITHu(NVS_OP_LG2, temp, SMASK_X, 0,
+                                        nvsSwizzle(src[0], X, X, X, X),
+                                        nvr_unused, nvr_unused);
+                       /* MUL temp.x, temp.x, src1.c */
+                       ARITHu(NVS_OP_MUL, temp, SMASK_X, 0,
+                                        nvsSwizzle(temp, X, X, X, X),
+                                        nvsSwizzle(src[1], X, X, X, X),
+                                        nvr_unused);
+                       /* EX2 dest, temp.x */
+                       ARITH (NVS_OP_EX2, dest, mask, sat,
+                                        nvsSwizzle(temp, X, X, X, X),
+                                        nvr_unused, nvr_unused);
+               } else {
+                       /* can we use EXP/LOG instead of EX2/LG2?? */
+                       fprintf(stderr, "Implement POW for NV20 vtxprog!\n");
+                       return GL_FALSE;
+               }
+               break;
+       case OPCODE_RSQ:
+               pass0_make_reg(nvs, &temp, NVS_FILE_TEMP, -1);
+               ARITHu(NVS_OP_LG2, temp, SMASK_X, 0,
+                                nvsAbs(nvsSwizzle(src[0], X, X, X, X)),
+                                nvr_unused, nvr_unused);
+               nvsinst->dest_scale = NVS_SCALE_INV_2X;
+               ARITH (NVS_OP_EX2, dest, mask, sat,
+                                nvsNegate(nvsSwizzle(temp, X, X, X, X)),
+                                nvr_unused, nvr_unused);
+               break;
+       case OPCODE_SCS:
+               if (mask & SMASK_X)
+                       ARITH(NVS_OP_COS, dest, SMASK_X, sat,
+                                       nvsSwizzle(src[0], X, X, X, X),
+                                       nvr_unused, nvr_unused);
+               if (mask & SMASK_Y)
+                       ARITH(NVS_OP_SIN, dest, SMASK_Y, sat,
+                                       nvsSwizzle(src[0], X, X, X, X),
+                                       nvr_unused, nvr_unused);
+               break;
+       case OPCODE_SUB:
+               ARITH(NVS_OP_ADD, dest, mask, sat,
+                               src[0], nvsNegate(src[1]), nvr_unused);
+               break;
+       case OPCODE_XPD:
+               pass0_make_reg(nvs, &temp, NVS_FILE_TEMP, -1);
+               ARITHu(NVS_OP_MUL, temp, SMASK_ALL, 0,
+                                nvsSwizzle(src[0], Z, X, Y, Y),
+                                nvsSwizzle(src[1], Y, Z, X, X),
+                                nvr_unused);
+               ARITH (NVS_OP_MAD, dest, (mask & ~SMASK_W), sat,
+                                nvsSwizzle(src[0], Y, Z, X, X),
+                                nvsSwizzle(src[1], Z, X, Y, Y),
+                                nvsNegate(temp));
+               break;
+       default:
+               WARN_ONCE("hw doesn't support opcode \"%s\","
+                         "and no emulation found\n",
+                         _mesa_opcode_string(inst->Opcode));
+               return GL_FALSE;
+       }
+
+       return GL_TRUE;
+}
+
+static GLboolean
+pass0_translate_arith(nouveauShader *nvs, struct gl_program *prog,
+                                         int ipos, int fpos,
+                                         nvsFragmentHeader *parent)
+{
+       struct prog_instruction *inst = &prog->Instructions[ipos];
+       nvsFunc *shader = nvs->func;
+       nvsInstruction *nvsinst;
+       GLboolean ret;
+
+       /* Deal with multiple ATTRIB/PARAM in a single instruction */
+       pass0_check_sources(nvs, parent, fpos, inst);
+
+       /* Now it's safe to do the prog_instruction->nvsInstruction
+        * conversion
+        */
+       if (shader->SupportsOpcode(shader,
+                                  pass0_make_opcode(inst->Opcode))) {
+               nvsRegister src[3], dest;
+               int i;
+
+               for (i=0; i<_mesa_num_inst_src_regs(inst->Opcode); i++)
+                       pass0_make_src_reg(nvs, &src[i], &inst->SrcReg[i]);
+               pass0_make_dst_reg(nvs, &dest, &inst->DstReg);
+
+               ARITH(pass0_make_opcode(inst->Opcode), dest,
+                               pass0_make_mask(inst->DstReg.WriteMask),
+                               (inst->SaturateMode != SATURATE_OFF),
+                               src[0], src[1], src[2]);
+               nvsinst->tex_unit   = inst->TexSrcUnit;
+               if (pass0_opcode_is_tex(inst->Opcode))
+                       nvsinst->tex_target =
+                               pass0_make_tex_target(inst->TexSrcTarget);
+               else
+                       nvsinst->tex_target = NVS_TEX_TARGET_UNKNOWN;
+
+               ret = GL_TRUE;
+       } else
+               ret = pass0_emulate_instruction(nvs, parent, fpos, inst);
+
+       return ret;
+}
+
+static GLboolean
+pass0_translate_instructions(nouveauShader *nvs, int ipos, int fpos,
+                                                nvsFragmentHeader *parent)
+{
+       struct gl_program *prog = (struct gl_program *)&nvs->mesa.vp;
+
+       while (1) {
+               struct prog_instruction *inst = &prog->Instructions[ipos];
+
+               switch (inst->Opcode) {
+               case OPCODE_END:
+                       return GL_TRUE;
+               case OPCODE_BRA:
+               case OPCODE_CAL:
+               case OPCODE_RET:
+               //case OPCODE_LOOP:
+               //case OPCODE_ENDLOOP:
+               //case OPCODE_IF:
+               //case OPCODE_ELSE:
+               //case OPCODE_ENDIF:
+                       WARN_ONCE("branch ops unimplemented\n");
+                       return GL_FALSE;
+                       break;
+               default:
+                       if (!pass0_translate_arith(nvs, prog,
+                                                  ipos, fpos, parent))
+                               return GL_FALSE;
+                       break;
+               }
+
+               ipos++;
+       }
+
+       return GL_TRUE;
+}
+
+static void
+pass0_build_attrib_map(nouveauShader *nvs, struct gl_vertex_program *vp)
+{
+       GLuint inputs_read = vp->Base.InputsRead;
+       GLuint input_alloc = ~0xFFFF;
+       int i;
+
+       for (i=0; i<NVS_MAX_ATTRIBS; i++)
+               nvs->vp_attrib_map[i] = -1;
+
+       while (inputs_read) {
+               int in = ffs(inputs_read) - 1;
+               int hw;
+               inputs_read &= ~(1<<in);
+
+               if (vp->IsNVProgram) {
+                       /* NVvp: must alias */
+                       if (in >= VERT_ATTRIB_GENERIC0)
+                               hw = in - VERT_ATTRIB_GENERIC0;
+                       else
+                               hw = in;
+               } else {
+                       /* ARBvp: may alias (but we won't)
+                        * GL2.0: must not alias
+                        */
+                       if (in >= VERT_ATTRIB_GENERIC0)
+                               hw = ffs(~input_alloc) - 1;
+                       else 
+                               hw = in;
+                       input_alloc |= (1<<hw);
+               }
+
+               nvs->vp_attrib_map[hw] = in;
+       }
+
+       if (NOUVEAU_DEBUG & DEBUG_SHADERS) {
+               printf("vtxprog attrib map:\n");
+               for (i=0; i<NVS_MAX_ATTRIBS; i++) {
+                       printf(" hw:%d = attrib:%d\n",
+                                       i, nvs->vp_attrib_map[i]);
+               }
+       }
+}
+
+static void
+pass0_vp_insert_ff_clip_planes(GLcontext *ctx, nouveauShader *nvs)
+{
+       struct gl_program *prog = &nvs->mesa.vp.Base;
+       nvsFragmentHeader *parent = nvs->program_tree;
+       nvsInstruction *nvsinst;
+       GLuint fpos = 0;
+       nvsRegister opos, epos, eqn, mv[4];
+       gl_state_index tokens[STATE_LENGTH]
+           = { STATE_MODELVIEW_MATRIX, 0, 0, 0, 0 };
+       GLint id;
+       int i;
+
+       /* modelview transform */
+       pass0_make_reg(nvs, &opos, NVS_FILE_ATTRIB, NVS_FR_POSITION);
+       pass0_make_reg(nvs, &epos, NVS_FILE_TEMP  , -1);
+       for (i=0; i<4; i++) {
+               tokens[2] = tokens[3] = i;
+               id = _mesa_add_state_reference(prog->Parameters, tokens);
+               pass0_make_reg(nvs, &mv[i], NVS_FILE_CONST, id);
+       }
+       ARITHu(NVS_OP_DP4, epos, SMASK_X, 0, opos, mv[0], nvr_unused);
+       ARITHu(NVS_OP_DP4, epos, SMASK_Y, 0, opos, mv[1], nvr_unused);
+       ARITHu(NVS_OP_DP4, epos, SMASK_Z, 0, opos, mv[2], nvr_unused);
+       ARITHu(NVS_OP_DP4, epos, SMASK_W, 0, opos, mv[3], nvr_unused);
+
+       /* Emit code to emulate fixed-function glClipPlane */
+       for (i=0; i<6; i++) {
+               GLuint clipmask = SMASK_X;
+               nvsRegister clip;
+
+               if (!(ctx->Transform.ClipPlanesEnabled & (1<<i)))
+                       continue;
+
+               /* Point a const at a user clipping plane */
+               tokens[0] = STATE_CLIPPLANE;
+               tokens[1] = i;
+               id = _mesa_add_state_reference(prog->Parameters, tokens);
+               pass0_make_reg(nvs, &eqn , NVS_FILE_CONST , id);
+               pass0_make_reg(nvs, &clip, NVS_FILE_RESULT, NVS_FR_CLIP0 + i);
+
+               /*XXX: something else needs to take care of modifying the
+                *     instructions to write to the correct hw clip register.
+                */
+               switch (i) {
+               case 0: case 3: clipmask = SMASK_Y; break;
+               case 1: case 4: clipmask = SMASK_Z; break;
+               case 2: case 5: clipmask = SMASK_W; break;
+               }
+
+               /* Emit transform */
+               ARITHu(NVS_OP_DP4, clip, clipmask, 0, epos, eqn, nvr_unused);
+       }
+}
+
+static void
+pass0_rebase_mesa_consts(nouveauShader *nvs)
 {
-   nvsFunc *shader = nvs->func;
-   nvsRegister src[3], dest, temp;
-   nvsInstruction *nvsinst;
-   struct pass0_rec *rec = nvs->pass_rec;
-   unsigned int mask = pass0_make_mask(inst->DstReg.WriteMask);
-   int i, sat;
-
-   sat = (inst->SaturateMode == SATURATE_ZERO_ONE);
-
-   /* Build all the "real" regs for the instruction */
-   for (i=0; i<_mesa_num_inst_src_regs(inst->Opcode); i++)
-      pass0_make_src_reg(nvs, &src[i], &inst->SrcReg[i]);
-   if (inst->Opcode != OPCODE_KIL)
-      pass0_make_dst_reg(nvs, &dest, &inst->DstReg);
-
-   switch (inst->Opcode) {
-   case OPCODE_ABS:
-      if (shader->caps & SCAP_SRC_ABS)
-        pass0_emit(nvs, NVS_OP_MOV, dest, mask, sat,
-                     nvsAbs(src[0]), nvr_unused, nvr_unused);
-      else
-        pass0_emit(nvs, NVS_OP_MAX, dest, mask, sat,
-                     src[0], nvsNegate(src[0]), nvr_unused);
-      break;
-   case OPCODE_KIL:
-      /* This is only in ARB shaders, so we don't have to worry
-       * about clobbering a CC reg as they aren't supported anyway.
-       */
-      /* MOVC0 temp, src */
-      pass0_make_reg(nvs, &temp, NVS_FILE_TEMP, -1);
-      nvsinst = pass0_emit(nvs, NVS_OP_MOV, temp, SMASK_ALL, 0,
-                          src[0], nvr_unused, nvr_unused);
-      nvsinst->cond_update = 1;
-      nvsinst->cond_reg    = 0;
-      /* KIL_NV (LT0.xyzw) temp */
-      nvsinst = pass0_emit(nvs, NVS_OP_KIL, nvr_unused, 0, 0,
-                          nvr_unused, nvr_unused, nvr_unused);
-      nvsinst->cond      = COND_LT;
-      nvsinst->cond_reg  = 0;
-      nvsinst->cond_test = 1;
-      pass0_make_swizzle(nvsinst->cond_swizzle, MAKE_SWIZZLE4(0,1,2,3));
-      break;
-   case OPCODE_LIT:
-      break;
-   case OPCODE_LRP:
-      pass0_make_reg(nvs, &temp, NVS_FILE_TEMP, -1);
-      pass0_emit(nvs, NVS_OP_MAD, temp, mask, 0,
-                nvsNegate(src[0]), src[2], src[2]);
-      pass0_emit(nvs, NVS_OP_MAD, dest, mask, sat,
-                src[0], src[1], temp);
-      break;
-   case OPCODE_POW:
-      if (shader->SupportsOpcode(shader, NVS_OP_LG2) &&
-           shader->SupportsOpcode(shader, NVS_OP_EX2)) {
-        pass0_make_reg(nvs, &temp, NVS_FILE_TEMP, -1);
-        /* LG2 temp.x, src0.c */
-        pass0_emit(nvs, NVS_OP_LG2, temp, SMASK_X, 0,
-                     nvsSwizzle(src[0], X, X, X, X),
-                     nvr_unused,
-                     nvr_unused);
-        /* MUL temp.x, temp.x, src1.c */
-        pass0_emit(nvs, NVS_OP_MUL, temp, SMASK_X, 0,
-                     nvsSwizzle(temp, X, X, X, X),
-                     nvsSwizzle(src[1], X, X, X, X),
-                     nvr_unused);
-        /* EX2 dest, temp.x */
-        pass0_emit(nvs, NVS_OP_EX2, dest, mask, sat,
-                     nvsSwizzle(temp, X, X, X, X),
-                     nvr_unused,
-                     nvr_unused);
-      } else {
-        /* can we use EXP/LOG instead of EX2/LG2?? */
-        fprintf(stderr, "Implement POW for NV20 vtxprog!\n");
-        return GL_FALSE;
-      }
-      break;
-   case OPCODE_RSQ:
-      if (rec->const_half.file != NVS_FILE_CONST) {
-        GLfloat const_half[4] = { 0.5, 0.0, 0.0, 0.0 };
-        pass0_make_reg(nvs, &rec->const_half, NVS_FILE_CONST,
-              _mesa_add_unnamed_constant(nvs->mesa.vp.Base.Parameters,
-                                         const_half, 4));
-        COPY_4V(nvs->params[rec->const_half.index].val, const_half);
-      }
-      pass0_make_reg(nvs, &temp, NVS_FILE_TEMP, -1);
-      pass0_emit(nvs, NVS_OP_LG2, temp, SMASK_X, 0,
-                nvsAbs(nvsSwizzle(src[0], X, X, X, X)),
-                nvr_unused,
-                nvr_unused);
-      pass0_emit(nvs, NVS_OP_MUL, temp, SMASK_X, 0,
-                nvsSwizzle(temp, X, X, X, X),
-                nvsNegate(rec->const_half),
-                nvr_unused);
-      pass0_emit(nvs, NVS_OP_EX2, dest, mask, sat,
-                nvsSwizzle(temp, X, X, X, X),
-                nvr_unused,
-                nvr_unused);
-      break;
-   case OPCODE_SCS:
-      if (mask & SMASK_X)
-        pass0_emit(nvs, NVS_OP_COS, dest, SMASK_X, sat,
-                     nvsSwizzle(src[0], X, X, X, X),
-                     nvr_unused,
-                     nvr_unused);
-      if (mask & SMASK_Y)
-        pass0_emit(nvs, NVS_OP_SIN, dest, SMASK_Y, sat,
-                     nvsSwizzle(src[0], X, X, X, X),
-                     nvr_unused,
-                     nvr_unused);
-      break;
-   case OPCODE_SUB:
-      pass0_emit(nvs, NVS_OP_ADD, dest, mask, sat,
-                src[0], nvsNegate(src[1]), nvr_unused);
-      break;
-   case OPCODE_XPD:
-      pass0_make_reg(nvs, &temp, NVS_FILE_TEMP, -1);
-      pass0_emit(nvs, NVS_OP_MUL, temp, SMASK_ALL, 0,
-                  nvsSwizzle(src[0], Z, X, Y, Y),
-                  nvsSwizzle(src[1], Y, Z, X, X),
-                  nvr_unused);
-      pass0_emit(nvs, NVS_OP_MAD, dest, (mask & ~SMASK_W), sat,
-                  nvsSwizzle(src[0], Y, Z, X, X),
-                  nvsSwizzle(src[1], Z, X, Y, Y),
-                  nvsNegate(temp));
-      break;
-   default:
-      fprintf(stderr, "hw doesn't support opcode \"%s\", and no emulation found\n",
-             _mesa_opcode_string(inst->Opcode));
-      return GL_FALSE;
-   }
-
-   return GL_TRUE;
+       struct pass0_rec *rec = nvs->pass_rec;
+       struct gl_program *prog = &nvs->mesa.vp.Base;
+       struct prog_instruction *inst = prog->Instructions;
+       int i;
+
+       /*XXX: not a good idea, params->hw_index is malloc'd */
+       memset(nvs->params, 0x00, sizeof(nvs->params));
+
+       /* When doing relative addressing on constants, the hardware needs us
+        * to fill the "const id" field with a positive value.  Determine the
+        * most negative index that is used so that all accesses to a
+        * mesa-provided constant can be rebased to a positive index.
+        */
+       while (inst->Opcode != OPCODE_END) {
+               for (i=0; i<_mesa_num_inst_src_regs(inst->Opcode); i++) {
+                       struct prog_src_register *src = &inst->SrcReg[i];
+
+                       switch (src->File) {
+                       case PROGRAM_STATE_VAR:
+                       case PROGRAM_CONSTANT:
+                       case PROGRAM_NAMED_PARAM:
+                               if (src->RelAddr && src->Index < 0) {
+                                       int base = src->Index * -1;
+                                       if (rec->mesa_const_base < base)
+                                               rec->mesa_const_base = base;
+                               }
+                               break;
+                       default:
+                               break;
+                       }
+               }
+
+               inst++;
+       }
 }
 
 static GLboolean
-pass0_translate_instructions(nouveauShader *nvs)
+pass0_resolve_mesa_consts(nouveauShader *nvs)
 {
-   struct gl_program *prog = (struct gl_program *)&nvs->mesa.vp;
-   nvsFunc *shader = nvs->func;
-   int ipos;
-
-   for (ipos=0; ipos<prog->NumInstructions; ipos++) {
-      struct prog_instruction *inst = &prog->Instructions[ipos];
-
-      if (inst->Opcode == OPCODE_END)
-        break;
-
-      /* Deal with multiple ATTRIB/PARAM in a single instruction */
-      pass0_check_sources(nvs, inst);
-      /* Now it's safe to do the prog_instruction->nvsInstruction conversion */
-      if (shader->SupportsOpcode(shader, pass0_make_opcode(inst->Opcode))) {
-        nvsInstruction *nvsinst;
-        nvsRegister src[3], dest;
-        int i;
-
-        for (i=0; i<_mesa_num_inst_src_regs(inst->Opcode); i++)
-           pass0_make_src_reg(nvs, &src[i], &inst->SrcReg[i]);
-        pass0_make_dst_reg(nvs, &dest, &inst->DstReg);
-
-        nvsinst = pass0_emit(nvs,
-                             pass0_make_opcode(inst->Opcode),
-                             dest,
-                             pass0_make_mask(inst->DstReg.WriteMask),
-                             (inst->SaturateMode != SATURATE_OFF),
-                             src[0], src[1], src[2]);
-        nvsinst->tex_unit   = inst->TexSrcUnit;
-        nvsinst->tex_target = pass0_make_tex_target(inst->TexSrcTarget);
-        /* TODO when NV_fp/vp is implemented */
-        nvsinst->cond       = COND_TR;
-      } else {
-        if (!pass0_emulate_instruction(nvs, inst))
-           return GL_FALSE;
-      }
-   }
-
-   return GL_TRUE;
+       struct pass0_rec *rec = nvs->pass_rec;
+       struct gl_program *prog = &nvs->mesa.vp.Base;
+       struct gl_program_parameter_list *plist = prog->Parameters;
+       int i;
+
+       /* Init all const tracking/alloc info from the parameter list, rather
+        * than doing it as we translate the program.  Otherwise:
+        *   1) we can't get at the correct constant info when relative
+        *      addressing is being used due to src->Index not pointing
+        *      at the exact const;
+        *   2) as we add extra consts to the program, mesa will call realloc()
+        *      and we get invalid pointers to the const data.
+        */
+       rec->mesa_const_last = plist->NumParameters + rec->mesa_const_base;
+       nvs->param_high = rec->mesa_const_last;
+       for (i=0; i<plist->NumParameters; i++) {
+               int hw = rec->mesa_const_base + i;
+
+               if (hw > NVS_MAX_CONSTS) {
+                       nvsProgramError(nvs, "hw = %d > NVS_MAX_CONSTS!\n", hw);
+                       return GL_FALSE;
+               }
+
+               switch (plist->Parameters[i].Type) {
+               case PROGRAM_NAMED_PARAM:
+               case PROGRAM_STATE_VAR:
+                       nvs->params[hw].in_use     = GL_TRUE;
+                       nvs->params[hw].source_val = plist->ParameterValues[i];
+                       COPY_4V(nvs->params[hw].val, plist->ParameterValues[i]);
+                       break;
+               case PROGRAM_CONSTANT:
+                       nvs->params[hw].in_use     = GL_TRUE;
+                       nvs->params[hw].source_val = NULL;
+                       COPY_4V(nvs->params[hw].val, plist->ParameterValues[i]);
+                       break;
+               default:
+                       nvsProgramError(nvs, "hit bad type=%d on param %d\n",
+                                       plist->Parameters[i].Type, i);
+                       return GL_FALSE;
+               }
+       }
+
+       return GL_TRUE;
 }
 
 GLboolean
 nouveau_shader_pass0(GLcontext *ctx, nouveauShader *nvs)
 {
-   nouveauContextPtr            nmesa  = NOUVEAU_CONTEXT(ctx);
-   struct gl_program           *prog   = (struct gl_program*)nvs;
-   struct gl_vertex_program    *vp     = (struct gl_vertex_program *)prog;
-   struct gl_fragment_program  *fp     = (struct gl_fragment_program *)prog;
-   struct pass0_rec *rec;
-   int ret;
-
-   switch (prog->Target) {
-   case GL_VERTEX_PROGRAM_ARB:
-      nvs->func = &nmesa->VPfunc;
-      if (vp->IsPositionInvariant)
-        _mesa_insert_mvp_code(ctx, vp);
-#if 0
-      if (IS_FIXEDFUNCTION_PROG && CLIP_PLANES_USED)
-        pass0_insert_ff_clip_planes();
-#endif
-      break;
-   case GL_FRAGMENT_PROGRAM_ARB:
-      nvs->func = &nmesa->FPfunc;
-      if (fp->FogOption != GL_NONE)
-        _mesa_append_fog_code(ctx, fp);
-      break;
-   default:
-      fprintf(stderr, "Unknown program type %d", prog->Target);
-      return GL_FALSE;
-   }
-
-   rec = calloc(1, sizeof(struct pass0_rec));
-   rec->next_temp = prog->NumTemporaries;
-   nvs->pass_rec = rec;
-
-   ret = pass0_translate_instructions(nvs);
-   if (!ret) {
-      /* DESTROY list */
-   }
-
-   free(nvs->pass_rec);
-   return ret;
+       nouveauContextPtr           nmesa = NOUVEAU_CONTEXT(ctx);
+       struct gl_program          *prog  = (struct gl_program*)nvs;
+       struct gl_vertex_program   *vp    = (struct gl_vertex_program *)prog;
+       struct gl_fragment_program *fp    = (struct gl_fragment_program *)prog;
+       struct pass0_rec *rec;
+       int ret = GL_FALSE;
+
+       NVSDBG("start: nvs=%p\n", nvs);
+
+       /* Previously detected an error, and haven't recieved new program
+        * string, so fail immediately.
+        */
+       if (nvs->error) {
+               NVSDBG("failed previous compile attempt, not retrying\n");
+               return GL_FALSE;
+       }
+
+       rec = CALLOC_STRUCT(pass0_rec);
+       if (!rec)
+               return GL_FALSE;
+
+       rec->next_temp = prog->NumTemporaries;
+       nvs->pass_rec  = rec;
+               
+       nvs->program_tree = (nvsFragmentHeader*)
+               pass0_create_subroutine(nvs, "program body");
+       if (!nvs->program_tree) {
+               FREE(rec);
+               return GL_FALSE;
+       }
+
+       switch (prog->Target) {
+       case GL_VERTEX_PROGRAM_ARB:
+               nvs->func = &nmesa->VPfunc;
+
+               if (vp->IsPositionInvariant)
+                       _mesa_insert_mvp_code(ctx, vp);
+               pass0_rebase_mesa_consts(nvs);
+
+               if (!prog->String && ctx->Transform.ClipPlanesEnabled)
+                       pass0_vp_insert_ff_clip_planes(ctx, nvs);
+
+               pass0_build_attrib_map(nvs, vp);
+               break;
+       case GL_FRAGMENT_PROGRAM_ARB:
+               nvs->func = &nmesa->FPfunc;
+
+               if (fp->FogOption != GL_NONE)
+                       _mesa_append_fog_code(ctx, fp);
+               pass0_rebase_mesa_consts(nvs);
+               break;
+       default:
+               fprintf(stderr, "Unknown program type %d", prog->Target);
+               FREE(rec);
+               /* DESTROY TREE!! */
+               return GL_FALSE;
+       }
+       nvs->func->card_priv = &nvs->card_priv;
+
+       ret = pass0_translate_instructions(nvs, 0, 0, nvs->program_tree);
+       if (ret)
+               ret = pass0_resolve_mesa_consts(nvs);   
+       
+       /*XXX: if (!ret) DESTROY TREE!!! */
+
+       FREE(rec);
+       return ret;
 }