radeon/r200: drop legacy texture heap code
[mesa.git] / src / mesa / drivers / dri / r200 / r200_vertprog.c
index dfacdc88cc4e58b8811694e10d7b7a05d5e90629..888f91db73d21149a9f5c936e44b9ef6cc2b640a 100644 (file)
@@ -28,18 +28,35 @@ USE OR OTHER DEALINGS IN THE SOFTWARE.
 /*
  * Authors:
  *   Aapo Tahkola <aet@rasterburn.org>
+ *   Roland Scheidegger <rscheidegger_lists@hispeed.ch>
  */
-#include "glheader.h"
-#include "macros.h"
-#include "enums.h"
-#include "program.h"
+#include "main/glheader.h"
+#include "main/macros.h"
+#include "main/enums.h"
+#include "shader/program.h"
+#include "shader/prog_instruction.h"
+#include "shader/prog_parameter.h"
+#include "shader/prog_statevars.h"
+#include "shader/programopt.h"
+#include "tnl/tnl.h"
 
 #include "r200_context.h"
 #include "r200_vertprog.h"
 #include "r200_ioctl.h"
 #include "r200_tcl.h"
-#include "program_instruction.h"
-#include "tnl/tnl.h"
+
+#if SWIZZLE_X != VSF_IN_COMPONENT_X || \
+    SWIZZLE_Y != VSF_IN_COMPONENT_Y || \
+    SWIZZLE_Z != VSF_IN_COMPONENT_Z || \
+    SWIZZLE_W != VSF_IN_COMPONENT_W || \
+    SWIZZLE_ZERO != VSF_IN_COMPONENT_ZERO || \
+    SWIZZLE_ONE != VSF_IN_COMPONENT_ONE || \
+    WRITEMASK_X != VSF_FLAG_X || \
+    WRITEMASK_Y != VSF_FLAG_Y || \
+    WRITEMASK_Z != VSF_FLAG_Z || \
+    WRITEMASK_W != VSF_FLAG_W
+#error Cannot change these!
+#endif
 
 #define SCALAR_FLAG (1<<31)
 #define FLAG_MASK (1<<31)
@@ -88,8 +105,8 @@ static GLboolean r200VertexProgUpdateParams(GLcontext *ctx, struct r200_vertex_p
    r200ContextPtr rmesa = R200_CONTEXT( ctx );
    GLfloat *fcmd = (GLfloat *)&rmesa->hw.vpp[0].cmd[VPP_CMD_0 + 1];
    int pi;
-   struct vertex_program *mesa_vp = (void *)vp;
-   struct program_parameter_list *paramList;
+   struct gl_vertex_program *mesa_vp = &vp->mesa_program;
+   struct gl_program_parameter_list *paramList;
    drm_radeon_cmd_header_t tmp;
 
    R200_STATECHANGE( rmesa, vpp[0] );
@@ -119,7 +136,7 @@ static GLboolean r200VertexProgUpdateParams(GLcontext *ctx, struct r200_vertex_p
         break;
       }
       if (pi == 95) {
-        fcmd = (GLfloat *)rmesa->hw.vpp[1].cmd[VPP_CMD_0 + 1];
+        fcmd = (GLfloat *)&rmesa->hw.vpp[1].cmd[VPP_CMD_0 + 1];
       }
    }
    /* hack up the cmd_size so not the whole state atom is emitted always. */
@@ -137,16 +154,10 @@ static GLboolean r200VertexProgUpdateParams(GLcontext *ctx, struct r200_vertex_p
    return GL_TRUE;
 }
 
-static unsigned long t_dst_mask(GLuint mask)
+static INLINE unsigned long t_dst_mask(GLuint mask)
 {
-   unsigned long flags = 0;
-
-   if(mask & WRITEMASK_X) flags |= VSF_FLAG_X;
-   if(mask & WRITEMASK_Y) flags |= VSF_FLAG_Y;
-   if(mask & WRITEMASK_Z) flags |= VSF_FLAG_Z;
-   if(mask & WRITEMASK_W) flags |= VSF_FLAG_W;
-
-   return flags;
+   /* WRITEMASK_* is equivalent to VSF_FLAG_* */
+   return mask & VSF_FLAG_ALL;
 }
 
 static unsigned long t_dst(struct prog_dst_register *dst)
@@ -204,6 +215,7 @@ static unsigned long t_src_class(enum register_file file)
    case PROGRAM_LOCAL_PARAM:
    case PROGRAM_ENV_PARAM:
    case PROGRAM_NAMED_PARAM:
+   case PROGRAM_CONSTANT:
    case PROGRAM_STATE_VAR:
       return VSF_IN_CLASS_PARAM;
    /*
@@ -217,22 +229,9 @@ static unsigned long t_src_class(enum register_file file)
    }
 }
 
-static __inline unsigned long t_swizzle(GLubyte swizzle)
+static INLINE unsigned long t_swizzle(GLubyte swizzle)
 {
 /* this is in fact a NOP as the Mesa SWIZZLE_* are all identical to VSF_IN_COMPONENT_* */
-/*
-   switch(swizzle){
-   case SWIZZLE_X: return VSF_IN_COMPONENT_X;
-   case SWIZZLE_Y: return VSF_IN_COMPONENT_Y;
-   case SWIZZLE_Z: return VSF_IN_COMPONENT_Z;
-   case SWIZZLE_W: return VSF_IN_COMPONENT_W;
-   case SWIZZLE_ZERO: return VSF_IN_COMPONENT_ZERO;
-   case SWIZZLE_ONE: return VSF_IN_COMPONENT_ONE;
-   default:
-      fprintf(stderr, "problem in %s", __FUNCTION__);
-      exit(0);
-   }
-*/
    return swizzle;
 }
 
@@ -311,6 +310,10 @@ static unsigned long t_opcode(enum prog_opcode opcode)
 
    switch(opcode){
    case OPCODE_ADD: return R200_VPI_OUT_OP_ADD;
+   /* FIXME: ARL works fine, but negative offsets won't work - fglrx just
+    * seems to ignore neg offsets which isn't quite correct...
+    */
+   case OPCODE_ARL: return R200_VPI_OUT_OP_ARL;
    case OPCODE_DP4: return R200_VPI_OUT_OP_DOT;
    case OPCODE_DST: return R200_VPI_OUT_OP_DST;
    case OPCODE_EX2: return R200_VPI_OUT_OP_EX2;
@@ -388,21 +391,34 @@ static unsigned long op_operands(enum prog_opcode opcode)
 #define UNUSED_SRC_2 ((o_inst->src2 & ~15) | 9)
 
 
-/* DP4 version seems to trigger some hw peculiarity - fglrx does this on r200 however */
-#define PREFER_DP4
-
-static GLboolean r200_translate_vertex_program(struct r200_vertex_program *vp)
+/**
+ * Generate an R200 vertex program from Mesa's internal representation.
+ *
+ * \return  GL_TRUE for success, GL_FALSE for failure.
+ */
+static GLboolean r200_translate_vertex_program(GLcontext *ctx, struct r200_vertex_program *vp)
 {
-   struct vertex_program *mesa_vp = (void *)vp;
+   struct gl_vertex_program *mesa_vp = &vp->mesa_program;
    struct prog_instruction *vpi;
    int i;
    VERTEX_SHADER_INSTRUCTION *o_inst;
    unsigned long operands;
    int are_srcs_scalar;
    unsigned long hw_op;
+   int dofogfix = 0;
+   int fog_temp_i = 0;
+   int free_inputs;
+   int array_count = 0;
+   int u_temp_used;
 
    vp->native = GL_FALSE;
+   vp->translated = GL_TRUE;
+   vp->fogmode = ctx->Fog.Mode;
+
+   if (mesa_vp->Base.NumInstructions == 0)
+      return GL_FALSE;
 
+#if 0
    if ((mesa_vp->Base.InputsRead &
       ~(VERT_BIT_POS | VERT_BIT_NORMAL | VERT_BIT_COLOR0 | VERT_BIT_COLOR1 |
       VERT_BIT_FOG | VERT_BIT_TEX0 | VERT_BIT_TEX1 | VERT_BIT_TEX2 |
@@ -413,193 +429,206 @@ static GLboolean r200_translate_vertex_program(struct r200_vertex_program *vp)
       }
       return GL_FALSE;
    }
+#endif
 
+   if ((mesa_vp->Base.OutputsWritten &
+      ~((1 << VERT_RESULT_HPOS) | (1 << VERT_RESULT_COL0) | (1 << VERT_RESULT_COL1) |
+      (1 << VERT_RESULT_FOGC) | (1 << VERT_RESULT_TEX0) | (1 << VERT_RESULT_TEX1) |
+      (1 << VERT_RESULT_TEX2) | (1 << VERT_RESULT_TEX3) | (1 << VERT_RESULT_TEX4) |
+      (1 << VERT_RESULT_TEX5) | (1 << VERT_RESULT_PSIZ))) != 0) {
+      if (R200_DEBUG & DEBUG_FALLBACKS) {
+        fprintf(stderr, "can't handle vert prog outputs 0x%x\n",
+           mesa_vp->Base.OutputsWritten);
+      }
+      return GL_FALSE;
+   }
+
+   if (mesa_vp->IsNVProgram) {
+   /* subtle differences in spec like guaranteed initialized regs could cause
+      headaches. Might want to remove the driconf option to enable it completely */
+      return GL_FALSE;
+   }
    /* Initial value should be last tmp reg that hw supports.
       Strangely enough r300 doesnt mind even though these would be out of range.
       Smart enough to realize that it doesnt need it? */
    int u_temp_i = R200_VSF_MAX_TEMPS - 1;
    struct prog_src_register src[3];
+   struct prog_dst_register dst;
 
-/*   if (getenv("R300_VP_SAFETY")) {
-      WARN_ONCE("R300_VP_SAFETY enabled.\n");
-
-      vpi = malloc((mesa_vp->Base.NumInstructions + VSF_MAX_FRAGMENT_TEMPS) * sizeof(struct prog_instruction));
-      memset(vpi, 0, VSF_MAX_FRAGMENT_TEMPS * sizeof(struct prog_instruction));
-
-      for (i=0; i < VSF_MAX_FRAGMENT_TEMPS; i++) {
-        vpi[i].Opcode = OPCODE_MOV;
-        vpi[i].StringPos = 0;
-        vpi[i].Data = 0;
-
-        vpi[i].DstReg.File = PROGRAM_TEMPORARY;
-        vpi[i].DstReg.Index = i;
-        vpi[i].DstReg.WriteMask = WRITEMASK_XYZW;
-        vpi[i].DstReg.CondMask = COND_TR;
-
-        vpi[i].SrcReg[0].File = PROGRAM_STATE_VAR;
-        vpi[i].SrcReg[0].Index = 0;
-        vpi[i].SrcReg[0].Swizzle = MAKE_SWIZZLE4(SWIZZLE_ONE, SWIZZLE_ONE, SWIZZLE_ONE, SWIZZLE_ONE);
-      }
-
-      memcpy(&vpi[i], mesa_vp->Base.Instructions, mesa_vp->Base.NumInstructions * sizeof(struct prog_instruction));
-
-      free(mesa_vp->Base.Instructions);
-
-      mesa_vp->Base.Instructions = vpi;
-
-      mesa_vp->Base.NumInstructions += VSF_MAX_FRAGMENT_TEMPS;
-      vpi = &mesa_vp->Base.Instructions[mesa_vp->Base.NumInstructions-1];
-
-      assert(vpi->Opcode == OPCODE_END);
-   }*/
 /* FIXME: is changing the prog safe to do here? */
-   if (mesa_vp->IsPositionInvariant) {
-      struct program_parameter_list *paramList;
-      GLint tokens[6] = { STATE_MATRIX, STATE_MVP, 0, 0, 0, STATE_MATRIX };
-
-#ifdef PREFER_DP4
-      tokens[5] = STATE_MATRIX;
-#else
-      tokens[5] = STATE_MATRIX_TRANSPOSE;
-#endif
-      paramList = mesa_vp->Base.Parameters;
-
-      vpi = malloc((mesa_vp->Base.NumInstructions + 4) * sizeof(struct prog_instruction));
-      memset(vpi, 0, 4 * sizeof(struct prog_instruction));
-
-      for (i=0; i < 4; i++) {
-        GLint idx;
-        tokens[3] = tokens[4] = i;
-        idx = _mesa_add_state_reference(paramList, tokens);
-#ifdef PREFER_DP4
-        vpi[i].Opcode = OPCODE_DP4;
-        vpi[i].StringPos = 0;
-        vpi[i].Data = 0;
-
-        vpi[i].DstReg.File = PROGRAM_OUTPUT;
-        vpi[i].DstReg.Index = VERT_RESULT_HPOS;
-        vpi[i].DstReg.WriteMask = 1 << i;
-        vpi[i].DstReg.CondMask = COND_TR;
-
-        vpi[i].SrcReg[0].File = PROGRAM_STATE_VAR;
-        vpi[i].SrcReg[0].Index = idx;
-        vpi[i].SrcReg[0].Swizzle = MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_W);
-
-        vpi[i].SrcReg[1].File = PROGRAM_INPUT;
-        vpi[i].SrcReg[1].Index = VERT_ATTRIB_POS;
-        vpi[i].SrcReg[1].Swizzle = MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_W);
-#else
-        if (i == 0)
-           vpi[i].Opcode = OPCODE_MUL;
-        else
-           vpi[i].Opcode = OPCODE_MAD;
-
-        vpi[i].StringPos = 0;
-        vpi[i].Data = 0;
-
-        if (i == 3)
-           vpi[i].DstReg.File = PROGRAM_OUTPUT;
-        else
-           vpi[i].DstReg.File = PROGRAM_TEMPORARY;
-        vpi[i].DstReg.Index = 0;
-        vpi[i].DstReg.WriteMask = 0xf;
-        vpi[i].DstReg.CondMask = COND_TR;
-
-        vpi[i].SrcReg[0].File = PROGRAM_STATE_VAR;
-        vpi[i].SrcReg[0].Index = idx;
-        vpi[i].SrcReg[0].Swizzle = MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_W);
-
-        vpi[i].SrcReg[1].File = PROGRAM_INPUT;
-        vpi[i].SrcReg[1].Index = VERT_ATTRIB_POS;
-        vpi[i].SrcReg[1].Swizzle = MAKE_SWIZZLE4(i, i, i, i);
-
-        if (i > 0) {
-           vpi[i].SrcReg[2].File = PROGRAM_TEMPORARY;
-           vpi[i].SrcReg[2].Index = 0;
-           vpi[i].SrcReg[2].Swizzle = MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_W);
-        }
-#endif 
+   if (mesa_vp->IsPositionInvariant &&
+      /* make sure we only do this once */
+       !(mesa_vp->Base.OutputsWritten & (1 << VERT_RESULT_HPOS))) {
+        _mesa_insert_mvp_code(ctx, mesa_vp);
       }
 
-      memcpy(&vpi[i], mesa_vp->Base.Instructions, mesa_vp->Base.NumInstructions * sizeof(struct prog_instruction));
-
-      free(mesa_vp->Base.Instructions);
-
-      mesa_vp->Base.Instructions = vpi;
-
-      mesa_vp->Base.NumInstructions += 4;
-      vpi = &mesa_vp->Base.Instructions[mesa_vp->Base.NumInstructions-1];
-
-      assert(vpi->Opcode == OPCODE_END);
-
-      mesa_vp->Base.InputsRead |= (1 << VERT_ATTRIB_POS);
-      mesa_vp->Base.OutputsWritten |= (1 << VERT_RESULT_HPOS);
-
-      //fprintf(stderr, "IsPositionInvariant is set!\n");
-      //_mesa_print_program(&mesa_vp->Base);
+   /* for fogc, can't change mesa_vp, as it would hose swtnl, and exp with
+      base e isn't directly available neither. */
+   if ((mesa_vp->Base.OutputsWritten & (1 << VERT_RESULT_FOGC)) && !vp->fogpidx) {
+      struct gl_program_parameter_list *paramList;
+      gl_state_index tokens[STATE_LENGTH] = { STATE_FOG_PARAMS, 0, 0, 0, 0 };
+      paramList = mesa_vp->Base.Parameters;
+      vp->fogpidx = _mesa_add_state_reference(paramList, tokens);
    }
 
    vp->pos_end = 0;
    mesa_vp->Base.NumNativeInstructions = 0;
-   mesa_vp->Base.NumNativeParameters = mesa_vp->Base.Parameters->NumParameters;
+   if (mesa_vp->Base.Parameters)
+      mesa_vp->Base.NumNativeParameters = mesa_vp->Base.Parameters->NumParameters;
+   else
+      mesa_vp->Base.NumNativeParameters = 0;
 
-   for(i=0; i < VERT_ATTRIB_MAX; i++)
+   for(i = 0; i < VERT_ATTRIB_MAX; i++)
       vp->inputs[i] = -1;
+   for(i = 0; i < 15; i++)
+      vp->inputmap_rev[i] = 255;
+   free_inputs = 0x2ffd;
+
 /* fglrx uses fixed inputs as follows for conventional attribs.
-   generic attribs use non-fixed assignment, fglrx will always use the lowest attrib values available.
-   There are 12 generic attribs possible, corresponding to attrib 0, 2-11 and 13 in a hw vertex prog.
-   attr 1 and 12 are not available for generic attribs as those cannot be made vec4 (correspond to
-   vertex normal/weight)
+   generic attribs use non-fixed assignment, fglrx will always use the
+   lowest attrib values available. We'll just do the same.
+   There are 12 generic attribs possible, corresponding to attrib 0, 2-11
+   and 13 in a hw vertex prog.
+   attr 1 and 12 aren't used for generic attribs as those cannot be made vec4
+   (correspond to vertex normal/weight - maybe weight actually could be made vec4).
+   Additionally, not more than 12 arrays in total are possible I think.
    attr 0 is pos, R200_VTX_XY1|R200_VTX_Z1|R200_VTX_W1 in R200_SE_VTX_FMT_0
    attr 2-5 use colors 0-3 (R200_VTX_FP_RGBA << R200_VTX_COLOR_0/1/2/3_SHIFT in R200_SE_VTX_FMT_0)
    attr 6-11 use tex 0-5 (4 << R200_VTX_TEX0/1/2/3/4/5_COMP_CNT_SHIFT in R200_SE_VTX_FMT_1)
    attr 13 uses vtx1 pos (R200_VTX_XY1|R200_VTX_Z1|R200_VTX_W1 in R200_SE_VTX_FMT_0)
-   generic attribs would require some more work (dma regions, renaming). */
+*/
 
-/* may look different when using idx buf / input_route instead of se_vtx_fmt? */
-   vp->inputs[VERT_ATTRIB_POS] = 0;
-   vp->inputs[VERT_ATTRIB_WEIGHT] = 12;
-   vp->inputs[VERT_ATTRIB_NORMAL] = 1;
-   vp->inputs[VERT_ATTRIB_COLOR0] = 2;
-   vp->inputs[VERT_ATTRIB_COLOR1] = 3;
-   vp->inputs[VERT_ATTRIB_FOG] = 15;
-   vp->inputs[VERT_ATTRIB_TEX0] = 6;
-   vp->inputs[VERT_ATTRIB_TEX1] = 7;
-   vp->inputs[VERT_ATTRIB_TEX2] = 8;
-   vp->inputs[VERT_ATTRIB_TEX3] = 9;
-   vp->inputs[VERT_ATTRIB_TEX4] = 10;
-   vp->inputs[VERT_ATTRIB_TEX5] = 11;
 /* attr 4,5 and 13 are only used with generic attribs.
    Haven't seen attr 14 used, maybe that's for the hw pointsize vec1 (which is
    not possibe to use with vertex progs as it is lacking in vert prog specification) */
-
-   assert(mesa_vp->Base.OutputsWritten & (1 << VERT_RESULT_HPOS));
-
-   vp->translated = GL_TRUE;
-
-   o_inst = vp->instr;
-   for(vpi = mesa_vp->Base.Instructions; vpi->Opcode != OPCODE_END; vpi++, o_inst++){
-      if (u_temp_i < mesa_vp->Base.NumTemporaries) {
-        if (R200_DEBUG & DEBUG_FALLBACKS) {
-           fprintf(stderr, "Ran out of temps, num temps %d, us %d\n", mesa_vp->Base.NumTemporaries, u_temp_i);
-        }
-        return GL_FALSE;
+/* may look different when using idx buf / input_route instead of se_vtx_fmt? */
+   if (mesa_vp->Base.InputsRead & VERT_BIT_POS) {
+      vp->inputs[VERT_ATTRIB_POS] = 0;
+      vp->inputmap_rev[0] = VERT_ATTRIB_POS;
+      free_inputs &= ~(1 << 0);
+      array_count++;
+   }
+   if (mesa_vp->Base.InputsRead & VERT_BIT_WEIGHT) {
+      vp->inputs[VERT_ATTRIB_WEIGHT] = 12;
+      vp->inputmap_rev[1] = VERT_ATTRIB_WEIGHT;
+      array_count++;
+   }
+   if (mesa_vp->Base.InputsRead & VERT_BIT_NORMAL) {
+      vp->inputs[VERT_ATTRIB_NORMAL] = 1;
+      vp->inputmap_rev[2] = VERT_ATTRIB_NORMAL;
+      array_count++;
+   }
+   if (mesa_vp->Base.InputsRead & VERT_BIT_COLOR0) {
+      vp->inputs[VERT_ATTRIB_COLOR0] = 2;
+      vp->inputmap_rev[4] = VERT_ATTRIB_COLOR0;
+      free_inputs &= ~(1 << 2);
+      array_count++;
+   }
+   if (mesa_vp->Base.InputsRead & VERT_BIT_COLOR1) {
+      vp->inputs[VERT_ATTRIB_COLOR1] = 3;
+      vp->inputmap_rev[5] = VERT_ATTRIB_COLOR1;
+      free_inputs &= ~(1 << 3);
+      array_count++;
+   }
+   if (mesa_vp->Base.InputsRead & VERT_BIT_FOG) {
+      vp->inputs[VERT_ATTRIB_FOG] = 15; array_count++;
+      vp->inputmap_rev[3] = VERT_ATTRIB_FOG;
+      array_count++;
+   }
+   for (i = VERT_ATTRIB_TEX0; i <= VERT_ATTRIB_TEX5; i++) {
+      if (mesa_vp->Base.InputsRead & (1 << i)) {
+        vp->inputs[i] = i - VERT_ATTRIB_TEX0 + 6;
+        vp->inputmap_rev[8 + i - VERT_ATTRIB_TEX0] = i;
+        free_inputs &= ~(1 << (i - VERT_ATTRIB_TEX0 + 6));
+        array_count++;
       }
-      u_temp_i = R200_VSF_MAX_TEMPS - 1;
-      if(o_inst - vp->instr >= R200_VSF_MAX_INST) {
-        mesa_vp->Base.NumNativeInstructions = 129;
-        if (R200_DEBUG & DEBUG_FALLBACKS) {
-           fprintf(stderr, "more than 128 native instructions\n");
+   }
+   /* using VERT_ATTRIB_TEX6/7 would be illegal */
+   /* completely ignore aliasing? */
+   for (i = VERT_ATTRIB_GENERIC0; i < VERT_ATTRIB_MAX; i++) {
+      int j;
+   /* completely ignore aliasing? */
+      if (mesa_vp->Base.InputsRead & (1 << i)) {
+        array_count++;
+        if (array_count > 12) {
+           if (R200_DEBUG & DEBUG_FALLBACKS) {
+              fprintf(stderr, "more than 12 attribs used in vert prog\n");
+           }
+           return GL_FALSE;
         }
-        return GL_FALSE;
+        for (j = 0; j < 14; j++) {
+           /* will always find one due to limited array_count */
+           if (free_inputs & (1 << j)) {
+              free_inputs &= ~(1 << j);
+              vp->inputs[i] = j;
+              if (j == 0) vp->inputmap_rev[j] = i; /* mapped to pos */
+              else if (j < 12) vp->inputmap_rev[j + 2] = i; /* mapped to col/tex */
+              else vp->inputmap_rev[j + 1] = i; /* mapped to pos1 */
+              break;
+           }
+        }
+      }
+   }
+
+   if (!(mesa_vp->Base.OutputsWritten & (1 << VERT_RESULT_HPOS))) {
+      if (R200_DEBUG & DEBUG_FALLBACKS) {
+        fprintf(stderr, "can't handle vert prog without position output\n");
       }
+      return GL_FALSE;
+   }
+   if (free_inputs & 1) {
+      if (R200_DEBUG & DEBUG_FALLBACKS) {
+        fprintf(stderr, "can't handle vert prog without position input\n");
+      }
+      return GL_FALSE;
+   }
 
+   o_inst = vp->instr;
+   for (vpi = mesa_vp->Base.Instructions; vpi->Opcode != OPCODE_END; vpi++, o_inst++){
       operands = op_operands(vpi->Opcode);
       are_srcs_scalar = operands & SCALAR_FLAG;
       operands &= OP_MASK;
 
-      for(i = 0; i < operands; i++)
+      for(i = 0; i < operands; i++) {
         src[i] = vpi->SrcReg[i];
+        /* hack up default attrib values as per spec as swizzling.
+           normal, fog, secondary color. Crazy?
+           May need more if we don't submit vec4 elements? */
+        if (src[i].File == PROGRAM_INPUT) {
+           if (src[i].Index == VERT_ATTRIB_NORMAL) {
+              int j;
+              for (j = 0; j < 4; j++) {
+                 if (GET_SWZ(src[i].Swizzle, j) == SWIZZLE_W) {
+                    src[i].Swizzle &= ~(SWIZZLE_W << (j*3));
+                    src[i].Swizzle |= SWIZZLE_ONE << (j*3);
+                 }
+              }
+           }
+           else if (src[i].Index == VERT_ATTRIB_COLOR1) {
+              int j;
+              for (j = 0; j < 4; j++) {
+                 if (GET_SWZ(src[i].Swizzle, j) == SWIZZLE_W) {
+                    src[i].Swizzle &= ~(SWIZZLE_W << (j*3));
+                    src[i].Swizzle |= SWIZZLE_ZERO << (j*3);
+                 }
+              }
+           }
+           else if (src[i].Index == VERT_ATTRIB_FOG) {
+              int j;
+              for (j = 0; j < 4; j++) {
+                 if (GET_SWZ(src[i].Swizzle, j) == SWIZZLE_W) {
+                    src[i].Swizzle &= ~(SWIZZLE_W << (j*3));
+                    src[i].Swizzle |= SWIZZLE_ONE << (j*3);
+                 }
+                 else if ((GET_SWZ(src[i].Swizzle, j) == SWIZZLE_Y) ||
+                           GET_SWZ(src[i].Swizzle, j) == SWIZZLE_Z) {
+                    src[i].Swizzle &= ~(SWIZZLE_W << (j*3));
+                    src[i].Swizzle |= SWIZZLE_ZERO << (j*3);
+                 }
+              }
+           }
+        }
+      }
 
       if(operands == 3){
         if( CMP_SRCS(src[1], src[2]) || CMP_SRCS(src[0], src[2]) ){
@@ -645,25 +674,26 @@ static GLboolean r200_translate_vertex_program(struct r200_vertex_program *vp)
         }
       }
 
+      dst = vpi->DstReg;
+      if (dst.File == PROGRAM_OUTPUT &&
+         dst.Index == VERT_RESULT_FOGC &&
+         dst.WriteMask & WRITEMASK_X) {
+         fog_temp_i = u_temp_i;
+         dst.File = PROGRAM_TEMPORARY;
+         dst.Index = fog_temp_i;
+         dofogfix = 1;
+         u_temp_i--;
+      }
+
       /* These ops need special handling. */
       switch(vpi->Opcode){
-      /* FIXME: ARL works fine, but negative offsets won't work - fglrx just sems to ignore neg offsets
-        which isn't quite correct... */
-      case OPCODE_ARL:
-        o_inst->op = MAKE_VSF_OP(R200_VPI_OUT_OP_ARL, t_dst(&vpi->DstReg),
-               t_dst_mask(vpi->DstReg.WriteMask));
-        o_inst->src0 = t_src_scalar(vp, &src[0]);
-        o_inst->src1 = UNUSED_SRC_0;
-        o_inst->src2 = UNUSED_SRC_1;
-        goto next;
-
       case OPCODE_POW:
 /* pow takes only one argument, first scalar is in slot x, 2nd in slot z (other slots don't matter).
    So may need to insert additional instruction */
         if ((src[0].File == src[1].File) &&
             (src[0].Index == src[1].Index)) {
-           o_inst->op = MAKE_VSF_OP(R200_VPI_OUT_OP_POW, t_dst(&vpi->DstReg),
-                  t_dst_mask(vpi->DstReg.WriteMask));
+           o_inst->op = MAKE_VSF_OP(R200_VPI_OUT_OP_POW, t_dst(&dst),
+                  t_dst_mask(dst.WriteMask));
            o_inst->src0 = MAKE_VSF_SOURCE(t_src_index(vp, &src[0]),
                   t_swizzle(GET_SWZ(src[0].Swizzle, 0)),
                   SWIZZLE_ZERO,
@@ -691,8 +721,8 @@ static GLboolean r200_translate_vertex_program(struct r200_vertex_program *vp)
            o_inst->src2 = UNUSED_SRC_1;
            o_inst++;
 
-           o_inst->op = MAKE_VSF_OP(R200_VPI_OUT_OP_POW, t_dst(&vpi->DstReg),
-                  t_dst_mask(vpi->DstReg.WriteMask));
+           o_inst->op = MAKE_VSF_OP(R200_VPI_OUT_OP_POW, t_dst(&dst),
+                  t_dst_mask(dst.WriteMask));
            o_inst->src0 = MAKE_VSF_SOURCE(u_temp_i,
                   VSF_IN_COMPONENT_X,
                   VSF_IN_COMPONENT_Y,
@@ -708,20 +738,27 @@ static GLboolean r200_translate_vertex_program(struct r200_vertex_program *vp)
 
       case OPCODE_MOV://ADD RESULT 1.X Y Z W PARAM 0{} {X Y Z W} PARAM 0{} {ZERO ZERO ZERO ZERO} 
       case OPCODE_SWZ:
-        o_inst->op = MAKE_VSF_OP(R200_VPI_OUT_OP_ADD, t_dst(&vpi->DstReg),
-               t_dst_mask(vpi->DstReg.WriteMask));
+        o_inst->op = MAKE_VSF_OP(R200_VPI_OUT_OP_ADD, t_dst(&dst),
+               t_dst_mask(dst.WriteMask));
         o_inst->src0 = t_src(vp, &src[0]);
         o_inst->src1 = ZERO_SRC_0;
         o_inst->src2 = UNUSED_SRC_1;
         goto next;
-      
+
       case OPCODE_MAD:
+        /* only 2 read ports into temp memory thus may need the macro op MAD_2
+           instead (requiring 2 clocks) if all inputs are in temp memory
+           (and, only if they actually reference 3 distinct temps) */
         hw_op=(src[0].File == PROGRAM_TEMPORARY &&
            src[1].File == PROGRAM_TEMPORARY &&
-           src[2].File == PROGRAM_TEMPORARY) ? R200_VPI_OUT_OP_MAD_2 : R200_VPI_OUT_OP_MAD;
-
-        o_inst->op = MAKE_VSF_OP(hw_op, t_dst(&vpi->DstReg),
-           t_dst_mask(vpi->DstReg.WriteMask));
+           src[2].File == PROGRAM_TEMPORARY &&
+           (((src[0].RelAddr << 8) | src[0].Index) != ((src[1].RelAddr << 8) | src[1].Index)) &&
+           (((src[0].RelAddr << 8) | src[0].Index) != ((src[2].RelAddr << 8) | src[2].Index)) &&
+           (((src[1].RelAddr << 8) | src[1].Index) != ((src[2].RelAddr << 8) | src[2].Index))) ?
+           R200_VPI_OUT_OP_MAD_2 : R200_VPI_OUT_OP_MAD;
+
+        o_inst->op = MAKE_VSF_OP(hw_op, t_dst(&dst),
+           t_dst_mask(dst.WriteMask));
         o_inst->src0 = t_src(vp, &src[0]);
 #if 0
 if ((o_inst - vp->instr) == 31) {
@@ -746,8 +783,8 @@ else {
         goto next;
 
       case OPCODE_DP3://DOT RESULT 1.X Y Z W PARAM 0{} {X Y Z ZERO} PARAM 0{} {X Y Z ZERO} 
-        o_inst->op = MAKE_VSF_OP(R200_VPI_OUT_OP_DOT, t_dst(&vpi->DstReg),
-               t_dst_mask(vpi->DstReg.WriteMask));
+        o_inst->op = MAKE_VSF_OP(R200_VPI_OUT_OP_DOT, t_dst(&dst),
+               t_dst_mask(dst.WriteMask));
 
         o_inst->src0 = MAKE_VSF_SOURCE(t_src_index(vp, &src[0]),
                t_swizzle(GET_SWZ(src[0].Swizzle, 0)),
@@ -769,8 +806,8 @@ else {
         goto next;
 
       case OPCODE_DPH://DOT RESULT 1.X Y Z W PARAM 0{} {X Y Z ONE} PARAM 0{} {X Y Z W} 
-        o_inst->op = MAKE_VSF_OP(R200_VPI_OUT_OP_DOT, t_dst(&vpi->DstReg),
-               t_dst_mask(vpi->DstReg.WriteMask));
+        o_inst->op = MAKE_VSF_OP(R200_VPI_OUT_OP_DOT, t_dst(&dst),
+               t_dst_mask(dst.WriteMask));
 
         o_inst->src0 = MAKE_VSF_SOURCE(t_src_index(vp, &src[0]),
                t_swizzle(GET_SWZ(src[0].Swizzle, 0)),
@@ -784,8 +821,8 @@ else {
         goto next;
 
       case OPCODE_SUB://ADD RESULT 1.X Y Z W TMP 0{} {X Y Z W} PARAM 1{X Y Z W } {X Y Z W} neg Xneg Yneg Zneg W
-        o_inst->op = MAKE_VSF_OP(R200_VPI_OUT_OP_ADD, t_dst(&vpi->DstReg),
-               t_dst_mask(vpi->DstReg.WriteMask));
+        o_inst->op = MAKE_VSF_OP(R200_VPI_OUT_OP_ADD, t_dst(&dst),
+               t_dst_mask(dst.WriteMask));
 
         o_inst->src0 = t_src(vp, &src[0]);
         o_inst->src1 = MAKE_VSF_SOURCE(t_src_index(vp, &src[1]),
@@ -799,8 +836,8 @@ else {
         goto next;
 
       case OPCODE_ABS://MAX RESULT 1.X Y Z W PARAM 0{} {X Y Z W} PARAM 0{X Y Z W } {X Y Z W} neg Xneg Yneg Zneg W
-        o_inst->op=MAKE_VSF_OP(R200_VPI_OUT_OP_MAX, t_dst(&vpi->DstReg),
-               t_dst_mask(vpi->DstReg.WriteMask));
+        o_inst->op=MAKE_VSF_OP(R200_VPI_OUT_OP_MAX, t_dst(&dst),
+               t_dst_mask(dst.WriteMask));
 
         o_inst->src0=t_src(vp, &src[0]);
         o_inst->src1=MAKE_VSF_SOURCE(t_src_index(vp, &src[0]),
@@ -819,15 +856,15 @@ else {
 
         o_inst->op = MAKE_VSF_OP(R200_VPI_OUT_OP_FRC,
            (u_temp_i << R200_VPI_OUT_REG_INDEX_SHIFT) | R200_VSF_OUT_CLASS_TMP,
-           t_dst_mask(vpi->DstReg.WriteMask));
+           t_dst_mask(dst.WriteMask));
 
         o_inst->src0 = t_src(vp, &src[0]);
         o_inst->src1 = UNUSED_SRC_0;
         o_inst->src2 = UNUSED_SRC_1;
         o_inst++;
 
-        o_inst->op = MAKE_VSF_OP(R200_VPI_OUT_OP_ADD, t_dst(&vpi->DstReg),
-               t_dst_mask(vpi->DstReg.WriteMask));
+        o_inst->op = MAKE_VSF_OP(R200_VPI_OUT_OP_ADD, t_dst(&dst),
+               t_dst_mask(dst.WriteMask));
 
         o_inst->src0 = t_src(vp, &src[0]);
         o_inst->src1 = MAKE_VSF_SOURCE(u_temp_i,
@@ -846,12 +883,15 @@ else {
       case OPCODE_XPD:
         /* mul r0, r1.yzxw, r2.zxyw
            mad r0, -r2.yzxw, r1.zxyw, r0
-           NOTE: might need MAD_2
          */
+        hw_op=(src[0].File == PROGRAM_TEMPORARY &&
+           src[1].File == PROGRAM_TEMPORARY &&
+           (((src[0].RelAddr << 8) | src[0].Index) != ((src[1].RelAddr << 8) | src[1].Index))) ?
+           R200_VPI_OUT_OP_MAD_2 : R200_VPI_OUT_OP_MAD;
 
         o_inst->op = MAKE_VSF_OP(R200_VPI_OUT_OP_MUL,
            (u_temp_i << R200_VPI_OUT_REG_INDEX_SHIFT) | R200_VSF_OUT_CLASS_TMP,
-           t_dst_mask(vpi->DstReg.WriteMask));
+           t_dst_mask(dst.WriteMask));
 
         o_inst->src0 = MAKE_VSF_SOURCE(t_src_index(vp, &src[0]),
                t_swizzle(GET_SWZ(src[0].Swizzle, 1)), // y
@@ -873,8 +913,8 @@ else {
         o_inst++;
         u_temp_i--;
 
-        o_inst->op = MAKE_VSF_OP(R200_VPI_OUT_OP_MAD, t_dst(&vpi->DstReg),
-               t_dst_mask(vpi->DstReg.WriteMask));
+        o_inst->op = MAKE_VSF_OP(hw_op, t_dst(&dst),
+               t_dst_mask(dst.WriteMask));
 
         o_inst->src0 = MAKE_VSF_SOURCE(t_src_index(vp, &src[1]),
                t_swizzle(GET_SWZ(src[1].Swizzle, 1)), // y
@@ -902,13 +942,13 @@ else {
         goto next;
 
       case OPCODE_END:
-        break;
+        assert(0);
       default:
         break;
       }
 
-      o_inst->op = MAKE_VSF_OP(t_opcode(vpi->Opcode), t_dst(&vpi->DstReg),
-           t_dst_mask(vpi->DstReg.WriteMask));
+      o_inst->op = MAKE_VSF_OP(t_opcode(vpi->Opcode), t_dst(&dst),
+           t_dst_mask(dst.WriteMask));
 
       if(are_srcs_scalar){
         switch(operands){
@@ -962,19 +1002,92 @@ else {
         }
       }
       next:
+
+      if (dofogfix) {
+        o_inst++;
+        if (vp->fogmode == GL_EXP) {
+           o_inst->op = MAKE_VSF_OP(R200_VPI_OUT_OP_MUL,
+               (fog_temp_i << R200_VPI_OUT_REG_INDEX_SHIFT) | R200_VSF_OUT_CLASS_TMP,
+               VSF_FLAG_X);
+           o_inst->src0 = EASY_VSF_SOURCE(fog_temp_i, X, X, X, X, TMP, NONE);
+           o_inst->src1 = EASY_VSF_SOURCE(vp->fogpidx, X, X, X, X, PARAM, NONE);
+           o_inst->src2 = UNUSED_SRC_1;
+           o_inst++;
+           o_inst->op = MAKE_VSF_OP(R200_VPI_OUT_OP_EXP_E,
+               R200_VSF_OUT_CLASS_RESULT_FOGC,
+               VSF_FLAG_X);
+           o_inst->src0 = EASY_VSF_SOURCE(fog_temp_i, X, X, X, X, TMP, ALL);
+           o_inst->src1 = UNUSED_SRC_0;
+           o_inst->src2 = UNUSED_SRC_1;
+        }
+        else if (vp->fogmode == GL_EXP2) {
+           o_inst->op = MAKE_VSF_OP(R200_VPI_OUT_OP_MUL,
+               (fog_temp_i << R200_VPI_OUT_REG_INDEX_SHIFT) | R200_VSF_OUT_CLASS_TMP,
+               VSF_FLAG_X);
+           o_inst->src0 = EASY_VSF_SOURCE(fog_temp_i, X, X, X, X, TMP, NONE);
+           o_inst->src1 = EASY_VSF_SOURCE(vp->fogpidx, X, X, X, X, PARAM, NONE);
+           o_inst->src2 = UNUSED_SRC_1;
+           o_inst++;
+           o_inst->op = MAKE_VSF_OP(R200_VPI_OUT_OP_MUL,
+               (fog_temp_i << R200_VPI_OUT_REG_INDEX_SHIFT) | R200_VSF_OUT_CLASS_TMP,
+               VSF_FLAG_X);
+           o_inst->src0 = EASY_VSF_SOURCE(fog_temp_i, X, X, X, X, TMP, NONE);
+           o_inst->src1 = EASY_VSF_SOURCE(fog_temp_i, X, X, X, X, TMP, NONE);
+           o_inst->src2 = UNUSED_SRC_1;
+           o_inst++;
+           o_inst->op = MAKE_VSF_OP(R200_VPI_OUT_OP_EXP_E,
+               R200_VSF_OUT_CLASS_RESULT_FOGC,
+               VSF_FLAG_X);
+           o_inst->src0 = EASY_VSF_SOURCE(fog_temp_i, X, X, X, X, TMP, ALL);
+           o_inst->src1 = UNUSED_SRC_0;
+           o_inst->src2 = UNUSED_SRC_1;
+        }
+        else { /* fogmode == GL_LINEAR */
+               /* could do that with single op (dot) if using params like
+                  with fixed function pipeline fog */
+           o_inst->op = MAKE_VSF_OP(R200_VPI_OUT_OP_ADD,
+               (fog_temp_i << R200_VPI_OUT_REG_INDEX_SHIFT) | R200_VSF_OUT_CLASS_TMP,
+               VSF_FLAG_X);
+           o_inst->src0 = EASY_VSF_SOURCE(fog_temp_i, X, X, X, X, TMP, ALL);
+           o_inst->src1 = EASY_VSF_SOURCE(vp->fogpidx, Z, Z, Z, Z, PARAM, NONE);
+           o_inst->src2 = UNUSED_SRC_1;
+           o_inst++;
+           o_inst->op = MAKE_VSF_OP(R200_VPI_OUT_OP_MUL,
+               R200_VSF_OUT_CLASS_RESULT_FOGC,
+               VSF_FLAG_X);
+           o_inst->src0 = EASY_VSF_SOURCE(fog_temp_i, X, X, X, X, TMP, NONE);
+           o_inst->src1 = EASY_VSF_SOURCE(vp->fogpidx, W, W, W, W, PARAM, NONE);
+           o_inst->src2 = UNUSED_SRC_1;
+
+        }
+         dofogfix = 0;
+      }
+
+      u_temp_used = (R200_VSF_MAX_TEMPS - 1) - u_temp_i;
+      if (mesa_vp->Base.NumNativeTemporaries <
+        (mesa_vp->Base.NumTemporaries + u_temp_used)) {
+        mesa_vp->Base.NumNativeTemporaries =
+           mesa_vp->Base.NumTemporaries + u_temp_used;
+      }
+      if ((mesa_vp->Base.NumTemporaries + u_temp_used) > R200_VSF_MAX_TEMPS) {
+        if (R200_DEBUG & DEBUG_FALLBACKS) {
+           fprintf(stderr, "Ran out of temps, num temps %d, us %d\n", mesa_vp->Base.NumTemporaries, u_temp_used);
+        }
+        return GL_FALSE;
+      }
+      u_temp_i = R200_VSF_MAX_TEMPS - 1;
+      if(o_inst - vp->instr >= R200_VSF_MAX_INST) {
+        mesa_vp->Base.NumNativeInstructions = 129;
+        if (R200_DEBUG & DEBUG_FALLBACKS) {
+           fprintf(stderr, "more than 128 native instructions\n");
+        }
+        return GL_FALSE;
+      }
       if ((o_inst->op & R200_VSF_OUT_CLASS_MASK) == R200_VSF_OUT_CLASS_RESULT_POS) {
         vp->pos_end = (o_inst - vp->instr);
       }
    }
 
-   /* need to test again since some instructions require more than one (up to 3) native inst */
-   if(o_inst - vp->instr > R200_VSF_MAX_INST) {
-      mesa_vp->Base.NumNativeInstructions = 129;
-      if (R200_DEBUG & DEBUG_FALLBACKS) {
-        fprintf(stderr, "more than 128 native instructions\n");
-      }
-      return GL_FALSE;
-   }
    vp->native = GL_TRUE;
    mesa_vp->Base.NumNativeInstructions = (o_inst - vp->instr);
 #if 0
@@ -991,15 +1104,20 @@ void r200SetupVertexProg( GLcontext *ctx ) {
    GLboolean fallback;
    GLint i;
 
-   if (!vp->translated) {
+   if (!vp->translated || (ctx->Fog.Enabled && ctx->Fog.Mode != vp->fogmode)) {
       rmesa->curr_vp_hw = NULL;
-      r200_translate_vertex_program(vp);
+      r200_translate_vertex_program(ctx, vp);
    }
    /* could optimize setting up vertex progs away for non-tcl hw */
    fallback = !(vp->native && r200VertexProgUpdateParams(ctx, vp) &&
-      rmesa->r200Screen->drmSupportsVertexProgram);
+      rmesa->radeon.radeonScreen->drmSupportsVertexProgram);
    TCL_FALLBACK(ctx, R200_TCL_FALLBACK_VERTEX_PROGRAM, fallback);
-   if (fallback) return;
+   if (rmesa->radeon.TclFallback) return;
+
+   R200_STATECHANGE( rmesa, vap );
+   /* FIXME: fglrx sets R200_VAP_SINGLE_BUF_STATE_ENABLE too. Do we need it?
+             maybe only when using more than 64 inst / 96 param? */
+   rmesa->hw.vap.cmd[VAP_SE_VAP_CNTL] |= R200_VAP_PROG_VTX_SHADER_ENABLE /*| R200_VAP_SINGLE_BUF_STATE_ENABLE*/;
 
    R200_STATECHANGE( rmesa, pvs );
 
@@ -1060,7 +1178,8 @@ void r200SetupVertexProg( GLcontext *ctx ) {
 }
 
 
-static void r200BindProgram(GLcontext *ctx, GLenum target, struct program *prog)
+static void
+r200BindProgram(GLcontext *ctx, GLenum target, struct gl_program *prog)
 {
    r200ContextPtr rmesa = R200_CONTEXT(ctx);
 
@@ -1074,7 +1193,8 @@ static void r200BindProgram(GLcontext *ctx, GLenum target, struct program *prog)
    }
 }
 
-static struct program *r200NewProgram(GLcontext *ctx, GLenum target, GLuint id)
+static struct gl_program *
+r200NewProgram(GLcontext *ctx, GLenum target, GLuint id)
 {
    struct r200_vertex_program *vp;
 
@@ -1084,7 +1204,7 @@ static struct program *r200NewProgram(GLcontext *ctx, GLenum target, GLuint id)
       return _mesa_init_vertex_program(ctx, &vp->mesa_program, target, id);
    case GL_FRAGMENT_PROGRAM_ARB:
    case GL_FRAGMENT_PROGRAM_NV:
-      return _mesa_init_fragment_program( ctx, CALLOC_STRUCT(fragment_program), target, id );
+      return _mesa_init_fragment_program( ctx, CALLOC_STRUCT(gl_fragment_program), target, id );
    default:
       _mesa_problem(ctx, "Bad target in r200NewProgram");
    }
@@ -1092,27 +1212,36 @@ static struct program *r200NewProgram(GLcontext *ctx, GLenum target, GLuint id)
 }
 
 
-static void r200DeleteProgram(GLcontext *ctx, struct program *prog)
+static void
+r200DeleteProgram(GLcontext *ctx, struct gl_program *prog)
 {
    _mesa_delete_program(ctx, prog);
 }
 
-static void r200ProgramStringNotify(GLcontext *ctx, GLenum target, struct program *prog)
+static void
+r200ProgramStringNotify(GLcontext *ctx, GLenum target, struct gl_program *prog)
 {
    struct r200_vertex_program *vp = (void *)prog;
+   r200ContextPtr rmesa = R200_CONTEXT(ctx);
 
    switch(target) {
    case GL_VERTEX_PROGRAM_ARB:
       vp->translated = GL_FALSE;
-      memset(&vp->translated, 0, sizeof(struct r200_vertex_program) - sizeof(struct vertex_program));
-      /*r200_translate_vertex_shader(vp);*/
+      vp->fogpidx = 0;
+/*      memset(&vp->translated, 0, sizeof(struct r200_vertex_program) - sizeof(struct gl_vertex_program));*/
+      r200_translate_vertex_program(ctx, vp);
+      rmesa->curr_vp_hw = NULL;
+      break;
+   case GL_FRAGMENT_SHADER_ATI:
+      rmesa->afs_loaded = NULL;
       break;
    }
    /* need this for tcl fallbacks */
    _tnl_program_string(ctx, target, prog);
 }
 
-static GLboolean r200IsProgramNative(GLcontext *ctx, GLenum target, struct program *prog)
+static GLboolean
+r200IsProgramNative(GLcontext *ctx, GLenum target, struct gl_program *prog)
 {
    struct r200_vertex_program *vp = (void *)prog;
 
@@ -1120,7 +1249,7 @@ static GLboolean r200IsProgramNative(GLcontext *ctx, GLenum target, struct progr
    case GL_VERTEX_STATE_PROGRAM_NV:
    case GL_VERTEX_PROGRAM_ARB:
       if (!vp->translated) {
-        r200_translate_vertex_program(vp);
+        r200_translate_vertex_program(ctx, vp);
       }
      /* does not take parameters etc. into account */
       return vp->native;