mesa/version: only enable GL4.1 with correct limits.
[mesa.git] / src / mesa / main / atifragshader.c
index 550f50b7a00fbe5fabbb8cfb6b8dc38acb560a74..44f6bb46484293c5f44fed89b52e09593ccf1a9d 100644 (file)
 #include "main/glheader.h"
 #include "main/context.h"
 #include "main/hash.h"
-#include "main/imports.h"
+
 #include "main/macros.h"
 #include "main/enums.h"
 #include "main/mtypes.h"
-#include "main/dispatch.h"
 #include "main/atifragshader.h"
-
-#if FEATURE_ATI_fragment_shader
+#include "program/program.h"
+#include "util/u_memory.h"
 
 #define MESA_DEBUG_ATI_FS 0
 
 static struct ati_fragment_shader DummyShader;
 
 
-void
-_mesa_init_ati_fragment_shader_dispatch(struct _glapi_table *disp)
-{
-   SET_GenFragmentShadersATI(disp, _mesa_GenFragmentShadersATI);
-   SET_BindFragmentShaderATI(disp, _mesa_BindFragmentShaderATI);
-   SET_DeleteFragmentShaderATI(disp, _mesa_DeleteFragmentShaderATI);
-   SET_BeginFragmentShaderATI(disp, _mesa_BeginFragmentShaderATI);
-   SET_EndFragmentShaderATI(disp, _mesa_EndFragmentShaderATI);
-   SET_PassTexCoordATI(disp, _mesa_PassTexCoordATI);
-   SET_SampleMapATI(disp, _mesa_SampleMapATI);
-   SET_ColorFragmentOp1ATI(disp, _mesa_ColorFragmentOp1ATI);
-   SET_ColorFragmentOp2ATI(disp, _mesa_ColorFragmentOp2ATI);
-   SET_ColorFragmentOp3ATI(disp, _mesa_ColorFragmentOp3ATI);
-   SET_AlphaFragmentOp1ATI(disp, _mesa_AlphaFragmentOp1ATI);
-   SET_AlphaFragmentOp2ATI(disp, _mesa_AlphaFragmentOp2ATI);
-   SET_AlphaFragmentOp3ATI(disp, _mesa_AlphaFragmentOp3ATI);
-   SET_SetFragmentShaderConstantATI(disp, _mesa_SetFragmentShaderConstantATI);
-}
-
-
 /**
  * Allocate and initialize a new ATI fragment shader object.
  */
 struct ati_fragment_shader *
-_mesa_new_ati_fragment_shader(GLcontext *ctx, GLuint id)
+_mesa_new_ati_fragment_shader(struct gl_context *ctx, GLuint id)
 {
    struct ati_fragment_shader *s = CALLOC_STRUCT(ati_fragment_shader);
    (void) ctx;
@@ -78,38 +57,26 @@ _mesa_new_ati_fragment_shader(GLcontext *ctx, GLuint id)
  * Delete the given ati fragment shader
  */
 void
-_mesa_delete_ati_fragment_shader(GLcontext *ctx, struct ati_fragment_shader *s)
+_mesa_delete_ati_fragment_shader(struct gl_context *ctx, struct ati_fragment_shader *s)
 {
    GLuint i;
+
+   if (s == &DummyShader)
+      return;
+
    for (i = 0; i < MAX_NUM_PASSES_ATI; i++) {
-      if (s->Instructions[i])
-         free(s->Instructions[i]);
-      if (s->SetupInst[i])
-         free(s->SetupInst[i]);
+      free(s->Instructions[i]);
+      free(s->SetupInst[i]);
    }
+   _mesa_reference_program(ctx, &s->Program, NULL);
    free(s);
 }
 
 
-
-static void
-new_arith_inst(struct ati_fragment_shader *prog)
-{
-/* set "default" instruction as not all may get defined.
-   there is no specified way to express a nop with ati fragment shaders we use
-   GL_NONE as the op enum and just set some params to 0 - so nothing to do here */
-   prog->numArithInstr[prog->cur_pass >> 1]++;
-}
-
-static void
-new_tex_inst(struct ati_fragment_shader *prog)
-{
-}
-
 static void match_pair_inst(struct ati_fragment_shader *curProg, GLuint optype)
 {
    if (optype == curProg->last_optype) {
-      curProg->last_optype = 1;
+      curProg->last_optype = ATI_FRAGMENT_SHADER_ALPHA_OP;
    }
 }
 
@@ -143,7 +110,7 @@ create_dst_mod_str(GLuint mod)
    return ret_str;
 }
 
-static char *atifs_ops[] = {"ColorFragmentOp1ATI", "ColorFragmentOp2ATI", "ColorFragmentOp3ATI", 
+static char *atifs_ops[] = {"ColorFragmentOp1ATI", "ColorFragmentOp2ATI", "ColorFragmentOp3ATI",
                            "AlphaFragmentOp1ATI", "AlphaFragmentOp2ATI", "AlphaFragmentOp3ATI" };
 
 static void debug_op(GLint optype, GLuint arg_count, GLenum op, GLuint dst,
@@ -155,30 +122,30 @@ static void debug_op(GLint optype, GLuint arg_count, GLenum op, GLuint dst,
   char *op_name;
 
   op_name = atifs_ops[(arg_count-1)+(optype?3:0)];
-  
-  fprintf(stderr, "%s(%s, %s", op_name, _mesa_lookup_enum_by_nr(op),
-             _mesa_lookup_enum_by_nr(dst));
-  if (!optype)
+
+  fprintf(stderr, "%s(%s, %s", op_name, _mesa_enum_to_string(op),
+             _mesa_enum_to_string(dst));
+  if (optype == ATI_FRAGMENT_SHADER_COLOR_OP)
     fprintf(stderr, ", %d", dstMask);
-  
+
   fprintf(stderr, ", %s", create_dst_mod_str(dstMod));
-  
-  fprintf(stderr, ", %s, %s, %d", _mesa_lookup_enum_by_nr(arg1),
-             _mesa_lookup_enum_by_nr(arg1Rep), arg1Mod);
+
+  fprintf(stderr, ", %s, %s, %d", _mesa_enum_to_string(arg1),
+             _mesa_enum_to_string(arg1Rep), arg1Mod);
   if (arg_count>1)
-    fprintf(stderr, ", %s, %s, %d", _mesa_lookup_enum_by_nr(arg2),
-             _mesa_lookup_enum_by_nr(arg2Rep), arg2Mod);
+    fprintf(stderr, ", %s, %s, %d", _mesa_enum_to_string(arg2),
+             _mesa_enum_to_string(arg2Rep), arg2Mod);
   if (arg_count>2)
-    fprintf(stderr, ", %s, %s, %d", _mesa_lookup_enum_by_nr(arg3),
-             _mesa_lookup_enum_by_nr(arg3Rep), arg3Mod);
+    fprintf(stderr, ", %s, %s, %d", _mesa_enum_to_string(arg3),
+             _mesa_enum_to_string(arg3Rep), arg3Mod);
 
   fprintf(stderr,")\n");
 
 }
 #endif
 
-static int check_arith_arg(struct ati_fragment_shader *curProg,
-                       GLuint optype, GLuint arg, GLuint argRep)
+static int
+check_arith_arg(GLuint optype, GLuint arg, GLuint argRep)
 {
    GET_CURRENT_CONTEXT(ctx);
 
@@ -189,23 +156,34 @@ static int check_arith_arg(struct ati_fragment_shader *curProg,
       _mesa_error(ctx, GL_INVALID_ENUM, "C/AFragmentOpATI(arg)");
       return 0;
    }
-   if ((arg == GL_SECONDARY_INTERPOLATOR_ATI) && (((optype == 0) && (argRep == GL_ALPHA)) ||
-      ((optype == 1) && ((arg == GL_ALPHA) || (argRep == GL_NONE))))) {
-      _mesa_error(ctx, GL_INVALID_OPERATION, "C/AFragmentOpATI(sec_interp)");
-      return 0;
-   }
-   if ((arg == GL_SECONDARY_INTERPOLATOR_ATI) && (((optype == 0) && (argRep == GL_ALPHA)) ||
-      ((optype == 1) && ((arg == GL_ALPHA) || (argRep == GL_NONE))))) {
-      _mesa_error(ctx, GL_INVALID_OPERATION, "C/AFragmentOpATI(sec_interp)");
-      return 0;
-   }
-   if ((curProg->cur_pass == 1) &&
-      ((arg == GL_PRIMARY_COLOR_ARB) || (arg == GL_SECONDARY_INTERPOLATOR_ATI))) {
-      curProg->interpinp1 = GL_TRUE;
+   /* The ATI_fragment_shader spec says:
+    *
+    *        The error INVALID_OPERATION is generated by
+    *        ColorFragmentOp[1..3]ATI if <argN> is SECONDARY_INTERPOLATOR_ATI
+    *        and <argNRep> is ALPHA, or by AlphaFragmentOp[1..3]ATI if <argN>
+    *        is SECONDARY_INTERPOLATOR_ATI and <argNRep> is ALPHA or NONE, ...
+    */
+   if (arg == GL_SECONDARY_INTERPOLATOR_ATI) {
+      if (optype == ATI_FRAGMENT_SHADER_COLOR_OP && argRep == GL_ALPHA) {
+         _mesa_error(ctx, GL_INVALID_OPERATION, "CFragmentOpATI(sec_interp)");
+         return 0;
+      } else if (optype == ATI_FRAGMENT_SHADER_ALPHA_OP &&
+                 (argRep == GL_ALPHA || argRep == GL_NONE)) {
+         _mesa_error(ctx, GL_INVALID_OPERATION, "AFragmentOpATI(sec_interp)");
+         return 0;
+      }
    }
    return 1;
 }
 
+static GLboolean
+check_arg_color(GLubyte pass, GLuint arg)
+{
+   if (pass == 1 && (arg == GL_PRIMARY_COLOR_ARB || arg == GL_SECONDARY_INTERPOLATOR_ATI))
+         return GL_TRUE;
+   return GL_FALSE;
+}
+
 GLuint GLAPIENTRY
 _mesa_GenFragmentShadersATI(GLuint range)
 {
@@ -223,11 +201,15 @@ _mesa_GenFragmentShadersATI(GLuint range)
       return 0;
    }
 
+   _mesa_HashLockMutex(ctx->Shared->ATIShaders);
+
    first = _mesa_HashFindFreeKeyBlock(ctx->Shared->ATIShaders, range);
    for (i = 0; i < range; i++) {
-      _mesa_HashInsert(ctx->Shared->ATIShaders, first + i, &DummyShader);
+      _mesa_HashInsertLocked(ctx->Shared->ATIShaders, first + i, &DummyShader);
    }
 
+   _mesa_HashUnlockMutex(ctx->Shared->ATIShaders);
+
    return first;
 }
 
@@ -279,12 +261,9 @@ _mesa_BindFragmentShaderATI(GLuint id)
    /* do actual bind */
    ctx->ATIFragmentShader.Current = newProg;
 
-   ASSERT(ctx->ATIFragmentShader.Current);
+   assert(ctx->ATIFragmentShader.Current);
    if (newProg)
       newProg->RefCount++;
-
-   /*if (ctx->Driver.BindProgram)
-      ctx->Driver.BindProgram(ctx, target, prog); */
 }
 
 void GLAPIENTRY
@@ -316,7 +295,7 @@ _mesa_DeleteFragmentShaderATI(GLuint id)
       if (prog) {
         prog->RefCount--;
         if (prog->RefCount <= 0) {
-           free(prog);
+            _mesa_delete_ati_fragment_shader(ctx, prog);
         }
       }
    }
@@ -340,23 +319,21 @@ _mesa_BeginFragmentShaderATI(void)
       (or, could use the same mem but would need to reinitialize) */
    /* no idea if it's allowed to redefine a shader */
    for (i = 0; i < MAX_NUM_PASSES_ATI; i++) {
-         if (ctx->ATIFragmentShader.Current->Instructions[i])
-            free(ctx->ATIFragmentShader.Current->Instructions[i]);
-         if (ctx->ATIFragmentShader.Current->SetupInst[i])
-            free(ctx->ATIFragmentShader.Current->SetupInst[i]);
+         free(ctx->ATIFragmentShader.Current->Instructions[i]);
+         free(ctx->ATIFragmentShader.Current->SetupInst[i]);
    }
 
+   _mesa_reference_program(ctx, &ctx->ATIFragmentShader.Current->Program, NULL);
+
    /* malloc the instructions here - not sure if the best place but its
       a start */
    for (i = 0; i < MAX_NUM_PASSES_ATI; i++) {
       ctx->ATIFragmentShader.Current->Instructions[i] =
-        (struct atifs_instruction *)
-        calloc(1, sizeof(struct atifs_instruction) *
-                  (MAX_NUM_INSTRUCTIONS_PER_PASS_ATI));
+        calloc(sizeof(struct atifs_instruction),
+                MAX_NUM_INSTRUCTIONS_PER_PASS_ATI);
       ctx->ATIFragmentShader.Current->SetupInst[i] =
-        (struct atifs_setupinst *)
-        calloc(1, sizeof(struct atifs_setupinst) *
-                  (MAX_NUM_FRAGMENT_REGISTERS_ATI));
+        calloc(sizeof(struct atifs_setupinst),
+                MAX_NUM_FRAGMENT_REGISTERS_ATI);
    }
 
 /* can't rely on calloc for initialization as it's possible to redefine a shader (?) */
@@ -372,6 +349,9 @@ _mesa_BeginFragmentShaderATI(void)
    ctx->ATIFragmentShader.Current->isValid = GL_FALSE;
    ctx->ATIFragmentShader.Current->swizzlerq = 0;
    ctx->ATIFragmentShader.Compiling = 1;
+#if MESA_DEBUG_ATI_FS
+   _mesa_debug(ctx, "%s %u\n", __func__, ctx->ATIFragmentShader.Current->Id);
+#endif
 }
 
 void GLAPIENTRY
@@ -410,7 +390,7 @@ _mesa_EndFragmentShaderATI(void)
    for (j = 0; j < MAX_NUM_PASSES_ATI; j++) {
       for (i = 0; i < MAX_NUM_FRAGMENT_REGISTERS_ATI; i++) {
         GLuint op = curProg->SetupInst[j][i].Opcode;
-        const char *op_enum = op > 5 ? _mesa_lookup_enum_by_nr(op) : "0";
+        const char *op_enum = op > 5 ? _mesa_enum_to_string(op) : "0";
         GLuint src = curProg->SetupInst[j][i].src;
         GLuint swizzle = curProg->SetupInst[j][i].swizzle;
         fprintf(stderr, "%2d %04X %s %d %04X\n", i, op, op_enum, src,
@@ -419,8 +399,8 @@ _mesa_EndFragmentShaderATI(void)
       for (i = 0; i < curProg->numArithInstr[j]; i++) {
         GLuint op0 = curProg->Instructions[j][i].Opcode[0];
         GLuint op1 = curProg->Instructions[j][i].Opcode[1];
-        const char *op0_enum = op0 > 5 ? _mesa_lookup_enum_by_nr(op0) : "0";
-        const char *op1_enum = op1 > 5 ? _mesa_lookup_enum_by_nr(op1) : "0";
+        const char *op0_enum = op0 > 5 ? _mesa_enum_to_string(op0) : "0";
+        const char *op1_enum = op1 > 5 ? _mesa_enum_to_string(op1) : "0";
         GLuint count0 = curProg->Instructions[j][i].ArgCount[0];
         GLuint count1 = curProg->Instructions[j][i].ArgCount[1];
         fprintf(stderr, "%2d %04X %s %d %04X %s %d\n", i, op0, op0_enum, count0,
@@ -429,7 +409,17 @@ _mesa_EndFragmentShaderATI(void)
    }
 #endif
 
-   if (!ctx->Driver.ProgramStringNotify(ctx, GL_FRAGMENT_SHADER_ATI, NULL)) {
+   if (ctx->Driver.NewATIfs) {
+      struct gl_program *prog = ctx->Driver.NewATIfs(ctx,
+                                                     ctx->ATIFragmentShader.Current);
+      _mesa_reference_program(ctx, &ctx->ATIFragmentShader.Current->Program,
+                                   NULL);
+      /* Don't use _mesa_reference_program(), just take ownership */
+      ctx->ATIFragmentShader.Current->Program = prog;
+   }
+
+   if (!ctx->Driver.ProgramStringNotify(ctx, GL_FRAGMENT_SHADER_ATI,
+                                        curProg->Program)) {
       ctx->ATIFragmentShader.Current->isValid = GL_FALSE;
       /* XXX is this the right error? */
       _mesa_error(ctx, GL_INVALID_OPERATION,
@@ -443,18 +433,17 @@ _mesa_PassTexCoordATI(GLuint dst, GLuint coord, GLenum swizzle)
    GET_CURRENT_CONTEXT(ctx);
    struct ati_fragment_shader *curProg = ctx->ATIFragmentShader.Current;
    struct atifs_setupinst *curI;
+   GLubyte new_pass = curProg->cur_pass;
 
    if (!ctx->ATIFragmentShader.Compiling) {
       _mesa_error(ctx, GL_INVALID_OPERATION, "glPassTexCoordATI(outsideShader)");
       return;
    }
 
-   if (curProg->cur_pass == 1) {
-      match_pair_inst(curProg, 0);
-      curProg->cur_pass = 2;
-   }
-   if ((curProg->cur_pass > 2) ||
-      ((1 << (dst - GL_REG_0_ATI)) & curProg->regsAssigned[curProg->cur_pass >> 1])) {
+   if (curProg->cur_pass == 1)
+      new_pass = 2;
+   if ((new_pass > 2) ||
+      ((1 << (dst - GL_REG_0_ATI)) & curProg->regsAssigned[new_pass >> 1])) {
       _mesa_error(ctx, GL_INVALID_OPERATION, "glPassTexCoord(pass)");
       return;
    }
@@ -469,7 +458,7 @@ _mesa_PassTexCoordATI(GLuint dst, GLuint coord, GLenum swizzle)
       _mesa_error(ctx, GL_INVALID_ENUM, "glPassTexCoordATI(coord)");
       return;
    }
-   if ((curProg->cur_pass == 0) && (coord >= GL_REG_0_ATI)) {
+   if ((new_pass == 0) && (coord >= GL_REG_0_ATI)) {
       _mesa_error(ctx, GL_INVALID_OPERATION, "glPassTexCoordATI(coord)");
       return;
    }
@@ -492,8 +481,10 @@ _mesa_PassTexCoordATI(GLuint dst, GLuint coord, GLenum swizzle)
       }
    }
 
-   curProg->regsAssigned[curProg->cur_pass >> 1] |=  1 << (dst - GL_REG_0_ATI);
-   new_tex_inst(curProg);
+   if (curProg->cur_pass == 1)
+      match_pair_inst(curProg, 0);
+   curProg->cur_pass = new_pass;
+   curProg->regsAssigned[curProg->cur_pass >> 1] |= 1 << (dst - GL_REG_0_ATI);
 
    /* add the instructions */
    curI = &curProg->SetupInst[curProg->cur_pass >> 1][dst - GL_REG_0_ATI];
@@ -503,9 +494,9 @@ _mesa_PassTexCoordATI(GLuint dst, GLuint coord, GLenum swizzle)
    curI->swizzle = swizzle;
 
 #if MESA_DEBUG_ATI_FS
-   _mesa_debug(ctx, "%s(%s, %s, %s)\n", __FUNCTION__,
-              _mesa_lookup_enum_by_nr(dst), _mesa_lookup_enum_by_nr(coord),
-              _mesa_lookup_enum_by_nr(swizzle));
+   _mesa_debug(ctx, "%s(%s, %s, %s)\n", __func__,
+              _mesa_enum_to_string(dst), _mesa_enum_to_string(coord),
+              _mesa_enum_to_string(swizzle));
 #endif
 }
 
@@ -515,18 +506,17 @@ _mesa_SampleMapATI(GLuint dst, GLuint interp, GLenum swizzle)
    GET_CURRENT_CONTEXT(ctx);
    struct ati_fragment_shader *curProg = ctx->ATIFragmentShader.Current;
    struct atifs_setupinst *curI;
+   GLubyte new_pass = curProg->cur_pass;
 
    if (!ctx->ATIFragmentShader.Compiling) {
       _mesa_error(ctx, GL_INVALID_OPERATION, "glSampleMapATI(outsideShader)");
       return;
    }
 
-   if (curProg->cur_pass == 1) {
-      match_pair_inst(curProg, 0);
-      curProg->cur_pass = 2;
-   }
-   if ((curProg->cur_pass > 2) ||
-      ((1 << (dst - GL_REG_0_ATI)) & curProg->regsAssigned[curProg->cur_pass >> 1])) {
+   if (curProg->cur_pass == 1)
+      new_pass = 2;
+   if ((new_pass > 2) ||
+      ((1 << (dst - GL_REG_0_ATI)) & curProg->regsAssigned[new_pass >> 1])) {
       _mesa_error(ctx, GL_INVALID_OPERATION, "glSampleMapATI(pass)");
       return;
    }
@@ -542,7 +532,7 @@ _mesa_SampleMapATI(GLuint dst, GLuint interp, GLenum swizzle)
       _mesa_error(ctx, GL_INVALID_ENUM, "glSampleMapATI(interp)");
       return;
    }
-   if ((curProg->cur_pass == 0) && (interp >= GL_REG_0_ATI)) {
+   if ((new_pass == 0) && (interp >= GL_REG_0_ATI)) {
       _mesa_error(ctx, GL_INVALID_OPERATION, "glSampleMapATI(interp)");
       return;
    }
@@ -565,8 +555,10 @@ _mesa_SampleMapATI(GLuint dst, GLuint interp, GLenum swizzle)
       }
    }
 
-   curProg->regsAssigned[curProg->cur_pass >> 1] |=  1 << (dst - GL_REG_0_ATI);
-   new_tex_inst(curProg);
+   if (curProg->cur_pass == 1)
+      match_pair_inst(curProg, 0);
+   curProg->cur_pass = new_pass;
+   curProg->regsAssigned[curProg->cur_pass >> 1] |= 1 << (dst - GL_REG_0_ATI);
 
    /* add the instructions */
    curI = &curProg->SetupInst[curProg->cur_pass >> 1][dst - GL_REG_0_ATI];
@@ -576,9 +568,9 @@ _mesa_SampleMapATI(GLuint dst, GLuint interp, GLenum swizzle)
    curI->swizzle = swizzle;
 
 #if MESA_DEBUG_ATI_FS
-   _mesa_debug(ctx, "%s(%s, %s, %s)\n", __FUNCTION__,
-              _mesa_lookup_enum_by_nr(dst), _mesa_lookup_enum_by_nr(interp),
-              _mesa_lookup_enum_by_nr(swizzle));
+   _mesa_debug(ctx, "%s(%s, %s, %s)\n", __func__,
+              _mesa_enum_to_string(dst), _mesa_enum_to_string(interp),
+              _mesa_enum_to_string(swizzle));
 #endif
 }
 
@@ -594,34 +586,36 @@ _mesa_FragmentOpXATI(GLint optype, GLuint arg_count, GLenum op, GLuint dst,
    GLint ci;
    struct atifs_instruction *curI;
    GLuint modtemp = dstMod & ~GL_SATURATE_BIT_ATI;
+   GLubyte new_pass = curProg->cur_pass;
+   GLubyte numArithInstr;
 
    if (!ctx->ATIFragmentShader.Compiling) {
       _mesa_error(ctx, GL_INVALID_OPERATION, "C/AFragmentOpATI(outsideShader)");
       return;
    }
 
-   if (curProg->cur_pass==0)
-      curProg->cur_pass=1;
+   if (curProg->cur_pass == 0)
+      new_pass = 1;
+   else if (curProg->cur_pass == 2)
+      new_pass = 3;
 
-   else if (curProg->cur_pass==2)
-      curProg->cur_pass=3;
+   numArithInstr = curProg->numArithInstr[new_pass >> 1];
 
-   /* decide whether this is a new instruction or not ... all color instructions are new,
-      and alpha instructions might also be new if there was no preceding color inst */
-   if ((optype == 0) || (curProg->last_optype == optype)) {
-      if (curProg->numArithInstr[curProg->cur_pass >> 1] > 7) {
+   /* Decide whether this is a new instruction or not. All color instructions
+    * are new, and alpha instructions might also be new if there was no
+    * preceding color inst. This may also be the first inst of the pass
+    */
+   if (optype == ATI_FRAGMENT_SHADER_COLOR_OP ||
+       curProg->last_optype == optype ||
+       curProg->numArithInstr[new_pass >> 1] == 0) {
+      if (curProg->numArithInstr[new_pass >> 1] > 7) {
         _mesa_error(ctx, GL_INVALID_OPERATION, "C/AFragmentOpATI(instrCount)");
         return;
       }
-      /* easier to do that here slight side effect invalid instr will still be inserted as nops */
-      match_pair_inst(curProg, optype);
-      new_arith_inst(curProg);
+      numArithInstr++;
    }
-   curProg->last_optype = optype;
-   ci = curProg->numArithInstr[curProg->cur_pass >> 1] - 1;
-
-   /* add the instructions */
-   curI = &curProg->Instructions[curProg->cur_pass >> 1][ci];
+   ci = numArithInstr - 1;
+   curI = &curProg->Instructions[new_pass >> 1][ci];
 
    /* error checking */
    if ((dst < GL_REG_0_ATI) || (dst > GL_REG_5_ATI)) {
@@ -630,7 +624,7 @@ _mesa_FragmentOpXATI(GLint optype, GLuint arg_count, GLenum op, GLuint dst,
    }
    if ((modtemp != GL_NONE) && (modtemp != GL_2X_BIT_ATI) &&
       (modtemp != GL_4X_BIT_ATI) && (modtemp != GL_8X_BIT_ATI) &&
-      (modtemp != GL_HALF_BIT_ATI) && !(modtemp != GL_QUARTER_BIT_ATI) &&
+      (modtemp != GL_HALF_BIT_ATI) && (modtemp != GL_QUARTER_BIT_ATI) &&
       (modtemp != GL_EIGHTH_BIT_ATI)) {
       _mesa_error(ctx, GL_INVALID_ENUM, "C/AFragmentOpATI(dstMod)%x", modtemp);
       return;
@@ -640,7 +634,7 @@ _mesa_FragmentOpXATI(GLint optype, GLuint arg_count, GLenum op, GLuint dst,
       _mesa_error(ctx, GL_INVALID_ENUM, "C/AFragmentOpATI(op)");
       return;
    }
-   if (optype == 1) {
+   if (optype == ATI_FRAGMENT_SHADER_ALPHA_OP) {
       if (((op == GL_DOT2_ADD_ATI) && (curI->Opcode[0] != GL_DOT2_ADD_ATI)) ||
         ((op == GL_DOT3_ATI) && (curI->Opcode[0] != GL_DOT3_ATI)) ||
         ((op == GL_DOT4_ATI) && (curI->Opcode[0] != GL_DOT4_ATI)) ||
@@ -649,22 +643,29 @@ _mesa_FragmentOpXATI(GLint optype, GLuint arg_count, GLenum op, GLuint dst,
         return;
       }
    }
-   if ((op == GL_DOT4_ATI) &&
-      (((arg1 == GL_SECONDARY_INTERPOLATOR_ATI) && ((arg1Rep == GL_ALPHA) || (arg1Rep == GL_NONE))) ||
-      (((arg2 == GL_SECONDARY_INTERPOLATOR_ATI) && ((arg2Rep == GL_ALPHA) || (arg2Rep == GL_NONE)))))) {
-      _mesa_error(ctx, GL_INVALID_OPERATION, "C/AFragmentOpATI(sec_interp)");
+   /* The ATI_fragment_shader spec says:
+    *
+    *        The error INVALID_OPERATION is generated by... ColorFragmentOp2ATI
+    *        if <op> is DOT4_ATI and <argN> is SECONDARY_INTERPOLATOR_ATI and
+    *        <argNRep> is ALPHA or NONE.
+    */
+   if (optype == ATI_FRAGMENT_SHADER_COLOR_OP && op == GL_DOT4_ATI &&
+       ((arg1 == GL_SECONDARY_INTERPOLATOR_ATI && (arg1Rep == GL_ALPHA || arg1Rep == GL_NONE)) ||
+       (arg2 == GL_SECONDARY_INTERPOLATOR_ATI && (arg2Rep == GL_ALPHA || arg2Rep == GL_NONE)))) {
+      _mesa_error(ctx, GL_INVALID_OPERATION, "C/AFragmentOpATI(sec_interpDOT4)");
+      return;
    }
 
-   if (!check_arith_arg(curProg, optype, arg1, arg1Rep)) {
+   if (!check_arith_arg(optype, arg1, arg1Rep)) {
       return;
    }
    if (arg2) {
-      if (!check_arith_arg(curProg, optype, arg2, arg2Rep)) {
+      if (!check_arith_arg(optype, arg2, arg2Rep)) {
         return;
       }
    }
    if (arg3) {
-      if (!check_arith_arg(curProg, optype, arg3, arg3Rep)) {
+      if (!check_arith_arg(optype, arg3, arg3Rep)) {
         return;
       }
       if ((arg1 >= GL_CON_0_ATI) && (arg1 <= GL_CON_7_ATI) &&
@@ -678,6 +679,16 @@ _mesa_FragmentOpXATI(GLint optype, GLuint arg_count, GLenum op, GLuint dst,
 
    /* all ok - not all fully validated though (e.g. argNMod - spec doesn't say anything) */
 
+   curProg->interpinp1 |= check_arg_color(new_pass, arg1);
+   if (arg2)
+      curProg->interpinp1 |= check_arg_color(new_pass, arg2);
+   if (arg3)
+      curProg->interpinp1 |= check_arg_color(new_pass, arg3);
+
+   curProg->numArithInstr[new_pass >> 1] = numArithInstr;
+   curProg->last_optype = optype;
+   curProg->cur_pass = new_pass;
+
    curI->Opcode[optype] = op;
    curI->SrcReg[optype][0].Index = arg1;
    curI->SrcReg[optype][0].argRep = arg1Rep;
@@ -790,5 +801,3 @@ _mesa_SetFragmentShaderConstantATI(GLuint dst, const GLfloat * value)
       COPY_4V(ctx->ATIFragmentShader.GlobalConstants[dstindex], value);
    }
 }
-
-#endif /* FEATURE_ATI_fragment_shader */