fix several program-related bugs (bug 9136)
[mesa.git] / src / mesa / shader / program.c
index f6877bd142640b7230ed3c268eaec802f59d9f73..ddfad47b8949e2e1a3581348920943c6f5c294c7 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Mesa 3-D graphics library
- * Version:  6.5.1
+ * Version:  6.5.2
  *
  * Copyright (C) 1999-2006  Brian Paul   All Rights Reserved.
  *
@@ -45,7 +45,7 @@
 static const char *
 make_state_string(const GLint stateTokens[6]);
 
-static GLuint 
+static GLbitfield
 make_state_flags(const GLint state[]);
 
 
@@ -207,6 +207,7 @@ _mesa_init_program_struct( GLcontext *ctx, struct gl_program *prog,
       prog->Target = target;
       prog->Resident = GL_TRUE;
       prog->RefCount = 1;
+      prog->Format = GL_PROGRAM_FORMAT_ASCII_ARB;
    }
 
    return prog;
@@ -284,6 +285,9 @@ _mesa_delete_program(GLcontext *ctx, struct gl_program *prog)
    (void) ctx;
    ASSERT(prog);
 
+   if (prog == &_mesa_DummyProgram)
+      return;
+                 
    if (prog->String)
       _mesa_free(prog->String);
 
@@ -300,6 +304,13 @@ _mesa_delete_program(GLcontext *ctx, struct gl_program *prog)
       _mesa_free_parameter_list(prog->Parameters);
    }
 
+   /* XXX this is a little ugly */
+   if (prog->Target == GL_VERTEX_PROGRAM_ARB) {
+      struct gl_vertex_program *vprog = (struct gl_vertex_program *) prog;
+      if (vprog->TnlData)
+         _mesa_free(vprog->TnlData);
+   }
+
    _mesa_free(prog);
 }
 
@@ -423,14 +434,24 @@ _mesa_add_named_parameter(struct gl_program_parameter_list *paramList,
  * This will be used when the program contains something like this:
  *    PARAM myVals = { 0, 1, 2, 3 };
  *
- * \param paramList - the parameter list
- * \param values - four float values
- * \return index of the new parameter.
+ * \param paramList  the parameter list
+ * \param name  the name for the constant
+ * \param values  four float values
+ * \return index/position of the new parameter in the parameter list
  */
 GLint
 _mesa_add_named_constant(struct gl_program_parameter_list *paramList,
-                         const char *name, const GLfloat values[4])
+                         const char *name, const GLfloat values[4],
+                         GLuint size)
 {
+#if 0 /* disable this for now -- we need to save the name! */
+   GLuint pos, swizzle;
+   ASSERT(size == 4); /* XXX future feature */
+   /* check if we already have this constant */
+   if (_mesa_lookup_parameter_constant(paramList, values, 4, &pos, &swizzle)) {
+      return pos;
+   }
+#endif
    return add_parameter(paramList, name, values, PROGRAM_CONSTANT);
 }
 
@@ -440,14 +461,20 @@ _mesa_add_named_constant(struct gl_program_parameter_list *paramList,
  * This will be used when the program contains something like this:
  *    MOV r, { 0, 1, 2, 3 };
  *
- * \param paramList - the parameter list
- * \param values - four float values
- * \return index of the new parameter.
+ * \param paramList  the parameter list
+ * \param values  four float values
+ * \return index/position of the new parameter in the parameter list.
  */
 GLint
 _mesa_add_unnamed_constant(struct gl_program_parameter_list *paramList,
-                           const GLfloat values[4])
+                           const GLfloat values[4], GLuint size)
 {
+   GLuint pos, swizzle;
+   ASSERT(size == 4); /* XXX future feature */
+   /* check if we already have this constant */
+   if (_mesa_lookup_parameter_constant(paramList, values, 4, &pos, &swizzle)) {
+      return pos;
+   }
    return add_parameter(paramList, NULL, values, PROGRAM_CONSTANT);
 }
 
@@ -457,8 +484,8 @@ _mesa_add_unnamed_constant(struct gl_program_parameter_list *paramList,
  * This will be used when the program contains something like this:
  *    PARAM ambient = state.material.front.ambient;
  *
- * \param paramList - the parameter list
- * \param state     - an array of 6 state tokens
+ * \param paramList  the parameter list
+ * \param state  an array of 6 state tokens
  * \return index of the new parameter.
  */
 GLint
@@ -478,8 +505,7 @@ _mesa_add_state_reference(struct gl_program_parameter_list *paramList,
          paramList->Parameters[index].StateIndexes[i]
             = (enum state_index) stateTokens[i];
       }
-      paramList->StateFlags |= 
-           make_state_flags(stateTokens);
+      paramList->StateFlags |= make_state_flags(stateTokens);
    }
 
    /* free name string here since we duplicated it in add_parameter() */
@@ -494,7 +520,7 @@ _mesa_add_state_reference(struct gl_program_parameter_list *paramList,
  * \return pointer to the float[4] values.
  */
 GLfloat *
-_mesa_lookup_parameter_value(struct gl_program_parameter_list *paramList,
+_mesa_lookup_parameter_value(const struct gl_program_parameter_list *paramList,
                              GLsizei nameLen, const char *name)
 {
    GLuint i;
@@ -524,11 +550,15 @@ _mesa_lookup_parameter_value(struct gl_program_parameter_list *paramList,
 
 
 /**
- * Lookup a parameter index by name in the given parameter list.
+ * Given a program parameter name, find its position in the list of parameters.
+ * \param paramList  the parameter list to search
+ * \param nameLen  length of name (in chars).
+ *                 If length is negative, assume that name is null-terminated.
+ * \param name  the name to search for
  * \return index of parameter in the list.
  */
 GLint
-_mesa_lookup_parameter_index(struct gl_program_parameter_list *paramList,
+_mesa_lookup_parameter_index(const struct gl_program_parameter_list *paramList,
                              GLsizei nameLen, const char *name)
 {
    GLint i;
@@ -557,6 +587,61 @@ _mesa_lookup_parameter_index(struct gl_program_parameter_list *paramList,
 }
 
 
+/**
+ * Look for a float vector in the given parameter list.  The float vector
+ * may be of length 1, 2, 3 or 4.
+ * \param paramList  the parameter list to search
+ * \param v  the float vector to search for
+ * \param size  number of element in v
+ * \param posOut  returns the position of the constant, if found
+ * \param swizzleOut  returns a swizzle mask describing location of the
+ *                    vector elements if found
+ * \return GL_TRUE if found, GL_FALSE if not found
+ */
+GLboolean
+_mesa_lookup_parameter_constant(const struct gl_program_parameter_list *paramList,
+                                const GLfloat v[], GLsizei vSize,
+                                GLuint *posOut, GLuint *swizzleOut)
+{
+   GLuint i;
+
+   assert(vSize >= 1);
+   assert(vSize <= 4);
+
+   if (!paramList)
+      return -1;
+
+   for (i = 0; i < paramList->NumParameters; i++) {
+      if (paramList->Parameters[i].Type == PROGRAM_CONSTANT) {
+         const GLint maxShift = 4 - vSize;
+         GLint shift, j;
+         for (shift = 0; shift <= maxShift; shift++) {
+            GLint matched = 0;
+            GLuint swizzle[4];
+            swizzle[0] = swizzle[1] = swizzle[2] = swizzle[3] = 0;
+            /* XXX we could do out-of-order swizzle matches too, someday */
+            for (j = 0; j < vSize; j++) {
+               assert(shift + j < 4);
+               if (paramList->ParameterValues[i][shift + j] == v[j]) {
+                  matched++;
+                  swizzle[j] = shift + j;
+               }
+            }
+            if (matched == vSize) {
+               /* found! */
+               *posOut = i;
+               *swizzleOut = MAKE_SWIZZLE4(swizzle[0], swizzle[1],
+                                           swizzle[2], swizzle[3]);
+               return GL_TRUE;
+            }
+         }
+      }
+   }
+
+   return GL_FALSE;
+}
+
+
 /**
  * Use the list of tokens in the state[] array to find global GL state
  * and return it in <value>.  Usually, four values are returned in <value>
@@ -573,37 +658,29 @@ _mesa_fetch_state(GLcontext *ctx, const enum state_index state[],
       {
          /* state[1] is either 0=front or 1=back side */
          const GLuint face = (GLuint) state[1];
+         const struct gl_material *mat = &ctx->Light.Material;
+         ASSERT(face == 0 || face == 1);
+         /* we rely on tokens numbered so that _BACK_ == _FRONT_+ 1 */
+         ASSERT(MAT_ATTRIB_FRONT_AMBIENT + 1 == MAT_ATTRIB_BACK_AMBIENT);
+         /* XXX we could get rid of this switch entirely with a little
+          * work in arbprogparse.c's parse_state_single_item().
+          */
          /* state[2] is the material attribute */
          switch (state[2]) {
          case STATE_AMBIENT:
-            if (face == 0)
-               COPY_4V(value, ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_AMBIENT]);
-            else
-               COPY_4V(value, ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_AMBIENT]);
+            COPY_4V(value, mat->Attrib[MAT_ATTRIB_FRONT_AMBIENT + face]);
             return;
          case STATE_DIFFUSE:
-            if (face == 0)
-               COPY_4V(value, ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE]);
-            else
-               COPY_4V(value, ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_DIFFUSE]);
+            COPY_4V(value, mat->Attrib[MAT_ATTRIB_FRONT_DIFFUSE + face]);
             return;
          case STATE_SPECULAR:
-            if (face == 0)
-               COPY_4V(value, ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_SPECULAR]);
-            else
-               COPY_4V(value, ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_SPECULAR]);
+            COPY_4V(value, mat->Attrib[MAT_ATTRIB_FRONT_SPECULAR + face]);
             return;
          case STATE_EMISSION:
-            if (face == 0)
-               COPY_4V(value, ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_EMISSION]);
-            else
-               COPY_4V(value, ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_EMISSION]);
+            COPY_4V(value, mat->Attrib[MAT_ATTRIB_FRONT_EMISSION + face]);
             return;
          case STATE_SHININESS:
-            if (face == 0)
-               value[0] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_SHININESS][0];
-            else
-               value[0] = ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_SHININESS][0];
+            value[0] = mat->Attrib[MAT_ATTRIB_FRONT_SHININESS + face][0];
             value[1] = 0.0F;
             value[2] = 0.0F;
             value[3] = 1.0F;
@@ -910,8 +987,19 @@ _mesa_fetch_state(GLcontext *ctx, const enum state_index state[],
            case STATE_NORMAL_SCALE:
                ASSIGN_4V(value, ctx->_ModelViewInvScale, 0, 0, 1);
                break;
+           case STATE_TEXRECT_SCALE: {
+              const int unit = (int) state[2];
+              const struct gl_texture_object *texObj = ctx->Texture.Unit[unit]._Current;
+              if (texObj) {
+                 struct gl_texture_image *texImage = texObj->Image[0][0];
+                 ASSIGN_4V(value, 1.0 / texImage->Width, 1.0 / texImage->Height, 0, 1);
+              }
+               break;
+           }
            default:
-               _mesa_problem(ctx, "Bad state switch in _mesa_fetch_state()");
+              /* unknown state indexes are silently ignored
+              *  should be handled by the driver.
+              */
                return;
          }
       }
@@ -925,10 +1013,14 @@ _mesa_fetch_state(GLcontext *ctx, const enum state_index state[],
 
 
 /**
- * Return a bit mask of the Mesa state flags under which a parameter's
- * value might change.
+ * Return a bitmask of the Mesa state flags (_NEW_* values) which would
+ * indicate that the given context state may have changed.
+ * The bitmask is used during validation to determine if we need to update
+ * vertex/fragment program parameters (like "state.material.color") when
+ * some GL state has changed.
  */
-static GLuint make_state_flags(const GLint state[])
+static GLbitfield
+make_state_flags(const GLint state[])
 {
    switch (state[0]) {
    case STATE_MATERIAL:
@@ -981,8 +1073,12 @@ static GLuint make_state_flags(const GLint state[])
       switch (state[1]) {
       case STATE_NORMAL_SCALE:
         return _NEW_MODELVIEW;
+      case STATE_TEXRECT_SCALE:
+        return _NEW_TEXTURE;
       default:
-         _mesa_problem(NULL, "unexpected int. state in make_state_flags()");
+         /* unknown state indexes are silently ignored and
+         *  no flag set, since it is handled by the driver.
+         */
         return 0;
       }
 
@@ -1254,7 +1350,7 @@ make_state_string(const GLint state[6])
    case STATE_INTERNAL:
       break;
    default:
-      _mesa_problem(NULL, "Invalid state in maka_state_string");
+      _mesa_problem(NULL, "Invalid state in make_state_string");
       break;
    }
 
@@ -1289,26 +1385,45 @@ _mesa_load_state_parameters(GLcontext *ctx,
 
 /**
  * Initialize program instruction fields to defaults.
+ * \param inst  first instruction to initialize
+ * \param count  number of instructions to initialize
  */
 void
-_mesa_init_instruction(struct prog_instruction *inst)
+_mesa_init_instructions(struct prog_instruction *inst, GLuint count)
 {
-   _mesa_bzero(inst, sizeof(struct prog_instruction));
-
-   inst->SrcReg[0].File = PROGRAM_UNDEFINED;
-   inst->SrcReg[0].Swizzle = SWIZZLE_NOOP;
-   inst->SrcReg[1].File = PROGRAM_UNDEFINED;
-   inst->SrcReg[1].Swizzle = SWIZZLE_NOOP;
-   inst->SrcReg[2].File = PROGRAM_UNDEFINED;
-   inst->SrcReg[2].Swizzle = SWIZZLE_NOOP;
-
-   inst->DstReg.File = PROGRAM_UNDEFINED;
-   inst->DstReg.WriteMask = WRITEMASK_XYZW;
-   inst->DstReg.CondMask = COND_TR;
-   inst->DstReg.CondSwizzle = SWIZZLE_NOOP;
-
-   inst->SaturateMode = SATURATE_OFF;
-   inst->Precision = FLOAT32;
+   GLuint i;
+
+   _mesa_bzero(inst, count * sizeof(struct prog_instruction));
+
+   for (i = 0; i < count; i++) {
+      inst[i].SrcReg[0].File = PROGRAM_UNDEFINED;
+      inst[i].SrcReg[0].Swizzle = SWIZZLE_NOOP;
+      inst[i].SrcReg[1].File = PROGRAM_UNDEFINED;
+      inst[i].SrcReg[1].Swizzle = SWIZZLE_NOOP;
+      inst[i].SrcReg[2].File = PROGRAM_UNDEFINED;
+      inst[i].SrcReg[2].Swizzle = SWIZZLE_NOOP;
+
+      inst[i].DstReg.File = PROGRAM_UNDEFINED;
+      inst[i].DstReg.WriteMask = WRITEMASK_XYZW;
+      inst[i].DstReg.CondMask = COND_TR;
+      inst[i].DstReg.CondSwizzle = SWIZZLE_NOOP;
+
+      inst[i].SaturateMode = SATURATE_OFF;
+      inst[i].Precision = FLOAT32;
+   }
+}
+
+
+/**
+ * Allocate an array of program instructions.
+ * \param numInst  number of instructions
+ * \return pointer to instruction memory
+ */
+struct prog_instruction *
+_mesa_alloc_instructions(GLuint numInst)
+{
+   return (struct prog_instruction *)
+      _mesa_calloc(numInst * sizeof(struct prog_instruction));
 }
 
 
@@ -1430,19 +1545,8 @@ static const struct instruction_info InstInfo[MAX_OPCODE] = {
 GLuint
 _mesa_num_inst_src_regs(enum prog_opcode opcode)
 {
-   GLuint i;
-#ifdef DEBUG
-   for (i = 0; i < MAX_OPCODE; i++) {
-      ASSERT(i == InstInfo[i].Opcode);
-   }
-#endif
-   for (i = 0; i < MAX_OPCODE; i++) {
-      if (InstInfo[i].Opcode == opcode) {
-         return InstInfo[i].NumSrcRegs;
-      }
-   }
-   _mesa_problem(NULL, "invalid opcode in _mesa_num_inst_src_regs");
-   return 0;
+   ASSERT(opcode == InstInfo[opcode].Opcode);
+   return InstInfo[opcode].NumSrcRegs;
 }
 
 
@@ -1581,6 +1685,38 @@ print_src_reg(const struct prog_src_register *srcReg)
                                srcReg->NegateBase, GL_FALSE));
 }
 
+void
+_mesa_print_alu_instruction(const struct prog_instruction *inst,
+                           const char *opcode_string, 
+                           GLuint numRegs)
+{
+   GLuint j;
+
+   _mesa_printf("%s", opcode_string);
+
+   /* frag prog only */
+   if (inst->SaturateMode == SATURATE_ZERO_ONE)
+      _mesa_printf("_SAT");
+
+   if (inst->DstReg.File != PROGRAM_UNDEFINED) {
+      _mesa_printf(" %s[%d]%s",
+                  program_file_string((enum register_file) inst->DstReg.File),
+                  inst->DstReg.Index,
+                  writemask_string(inst->DstReg.WriteMask));
+   }
+
+   if (numRegs > 0)
+      _mesa_printf(", ");
+
+   for (j = 0; j < numRegs; j++) {
+      print_src_reg(inst->SrcReg + j);
+      if (j + 1 < numRegs)
+        _mesa_printf(", ");
+   }
+
+   _mesa_printf(";\n");
+}
+
 
 /**
  * Print a single vertex/fragment program instruction.
@@ -1639,37 +1775,16 @@ _mesa_print_instruction(const struct prog_instruction *inst)
       print_src_reg(&inst->SrcReg[0]);
       _mesa_printf(";\n");
       break;
+   case OPCODE_END:
+      _mesa_printf("END;\n");
+      break;
    /* XXX may need for other special-case instructions */
    default:
       /* typical alu instruction */
-      {
-         const GLuint numRegs = _mesa_num_inst_src_regs(inst->Opcode);
-         GLuint j;
-
-         _mesa_printf("%s", _mesa_opcode_string(inst->Opcode));
-
-         /* frag prog only */
-         if (inst->SaturateMode == SATURATE_ZERO_ONE)
-            _mesa_printf("_SAT");
-
-         if (inst->DstReg.File != PROGRAM_UNDEFINED) {
-            _mesa_printf(" %s[%d]%s",
-                         program_file_string((enum register_file) inst->DstReg.File),
-                         inst->DstReg.Index,
-                         writemask_string(inst->DstReg.WriteMask));
-         }
-
-         if (numRegs > 0)
-            _mesa_printf(", ");
-
-         for (j = 0; j < numRegs; j++) {
-            print_src_reg(inst->SrcReg + j);
-            if (j + 1 < numRegs)
-               _mesa_printf(", ");
-         }
-
-         _mesa_printf(";\n");
-      }
+      _mesa_print_alu_instruction(inst,
+                                 _mesa_opcode_string(inst->Opcode),
+                                 _mesa_num_inst_src_regs(inst->Opcode));
+      break;
    }
 }
 
@@ -1757,103 +1872,95 @@ compatible_program_targets(GLenum t1, GLenum t2)
 void GLAPIENTRY
 _mesa_BindProgram(GLenum target, GLuint id)
 {
-   struct gl_program *prog;
+   struct gl_program *curProg, *newProg;
    GET_CURRENT_CONTEXT(ctx);
    ASSERT_OUTSIDE_BEGIN_END(ctx);
 
    FLUSH_VERTICES(ctx, _NEW_PROGRAM);
 
+   /* Error-check target and get curProg */
    if ((target == GL_VERTEX_PROGRAM_ARB) && /* == GL_VERTEX_PROGRAM_NV */
         (ctx->Extensions.NV_vertex_program ||
          ctx->Extensions.ARB_vertex_program)) {
-      /*** Vertex program binding ***/
-      struct gl_vertex_program *curProg = ctx->VertexProgram.Current;
-      if (curProg->Base.Id == id) {
-         /* binding same program - no change */
-         return;
-      }
-      if (curProg->Base.Id != 0) {
-         /* decrement refcount on previously bound vertex program */
-         curProg->Base.RefCount--;
-         /* and delete if refcount goes below one */
-         if (curProg->Base.RefCount <= 0) {
-            /* the program ID was already removed from the hash table */
-            ctx->Driver.DeleteProgram(ctx, &(curProg->Base));
-         }
-      }
+      curProg = &ctx->VertexProgram.Current->Base;
    }
    else if ((target == GL_FRAGMENT_PROGRAM_NV
              && ctx->Extensions.NV_fragment_program) ||
             (target == GL_FRAGMENT_PROGRAM_ARB
              && ctx->Extensions.ARB_fragment_program)) {
-      /*** Fragment program binding ***/
-      struct gl_fragment_program *curProg = ctx->FragmentProgram.Current;
-      if (curProg->Base.Id == id) {
-         /* binding same program - no change */
-         return;
-      }
-      if (curProg->Base.Id != 0) {
-         /* decrement refcount on previously bound fragment program */
-         curProg->Base.RefCount--;
-         /* and delete if refcount goes below one */
-         if (curProg->Base.RefCount <= 0) {
-            /* the program ID was already removed from the hash table */
-            ctx->Driver.DeleteProgram(ctx, &(curProg->Base));
-         }
-      }
+      curProg = &ctx->FragmentProgram.Current->Base;
    }
    else {
       _mesa_error(ctx, GL_INVALID_ENUM, "glBindProgramNV/ARB(target)");
       return;
    }
 
-   /* NOTE: binding to a non-existant program is not an error.
+   /*
+    * Get pointer to new program to bind.
+    * NOTE: binding to a non-existant program is not an error.
     * That's supposed to be caught in glBegin.
     */
    if (id == 0) {
-      /* Bind default program */
-      prog = NULL;
+      /* Bind default program */
+      newProg = NULL;
       if (target == GL_VERTEX_PROGRAM_ARB) /* == GL_VERTEX_PROGRAM_NV */
-         prog = ctx->Shared->DefaultVertexProgram;
+         newProg = ctx->Shared->DefaultVertexProgram;
       else
-         prog = ctx->Shared->DefaultFragmentProgram;
+         newProg = ctx->Shared->DefaultFragmentProgram;
    }
    else {
-      /* Bind user program */
-      prog = _mesa_lookup_program(ctx, id);
-      if (!prog || prog == &_mesa_DummyProgram) {
+      /* Bind user program */
+      newProg = _mesa_lookup_program(ctx, id);
+      if (!newProg || newProg == &_mesa_DummyProgram) {
          /* allocate a new program now */
-         prog = ctx->Driver.NewProgram(ctx, target, id);
-         if (!prog) {
+         newProg = ctx->Driver.NewProgram(ctx, target, id);
+         if (!newProg) {
             _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindProgramNV/ARB");
             return;
          }
-         _mesa_HashInsert(ctx->Shared->Programs, id, prog);
+         _mesa_HashInsert(ctx->Shared->Programs, id, newProg);
       }
-      else if (!compatible_program_targets(prog->Target, target)) {
+      else if (!compatible_program_targets(newProg->Target, target)) {
          _mesa_error(ctx, GL_INVALID_OPERATION,
                      "glBindProgramNV/ARB(target mismatch)");
          return;
       }
    }
 
-   /* bind now */
+   /** All error checking is complete now **/
+
+   if (curProg->Id == id) {
+      /* binding same program - no change */
+      return;
+   }
+
+   /* unbind/delete oldProg */
+   if (curProg->Id != 0) {
+      /* decrement refcount on previously bound fragment program */
+      curProg->RefCount--;
+      /* and delete if refcount goes below one */
+      if (curProg->RefCount <= 0) {
+         /* the program ID was already removed from the hash table */
+         ctx->Driver.DeleteProgram(ctx, curProg);
+      }
+   }
+
+   /* bind newProg */
    if (target == GL_VERTEX_PROGRAM_ARB) { /* == GL_VERTEX_PROGRAM_NV */
-      ctx->VertexProgram.Current = (struct gl_vertex_program *) prog;
+      ctx->VertexProgram.Current = (struct gl_vertex_program *) newProg;
    }
-   else if (target == GL_FRAGMENT_PROGRAM_NV || target == GL_FRAGMENT_PROGRAM_ARB) {
-      ctx->FragmentProgram.Current = (struct gl_fragment_program *) prog;
+   else if (target == GL_FRAGMENT_PROGRAM_NV ||
+            target == GL_FRAGMENT_PROGRAM_ARB) {
+      ctx->FragmentProgram.Current = (struct gl_fragment_program *) newProg;
    }
+   newProg->RefCount++;
 
    /* Never null pointers */
    ASSERT(ctx->VertexProgram.Current);
    ASSERT(ctx->FragmentProgram.Current);
 
-   if (prog)
-      prog->RefCount++;
-
    if (ctx->Driver.BindProgram)
-      ctx->Driver.BindProgram(ctx, target, prog);
+      ctx->Driver.BindProgram(ctx, target, newProg);
 }
 
 
@@ -1949,30 +2056,6 @@ _mesa_GenPrograms(GLsizei n, GLuint *ids)
 }
 
 
-/**
- * Determine if id names a vertex or fragment program.
- * \note Not compiled into display lists.
- * \note Called from both glIsProgramNV and glIsProgramARB.
- * \param id is the program identifier
- * \return GL_TRUE if id is a program, else GL_FALSE.
- */
-GLboolean GLAPIENTRY
-_mesa_IsProgram(GLuint id)
-{
-   GET_CURRENT_CONTEXT(ctx);
-   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
-
-   if (id == 0)
-      return GL_FALSE;
-
-   if (_mesa_lookup_program(ctx, id))
-      return GL_TRUE;
-   else
-      return GL_FALSE;
-}
-
-
-
 /**********************************************************************/
 /* GL_MESA_program_debug extension                                    */
 /**********************************************************************/
@@ -2079,7 +2162,9 @@ _mesa_GetProgramRegisterfvMESA(GLenum target,
                            "glGetProgramRegisterfvMESA(registerName)");
                return;
             }
-            COPY_4V(v, ctx->VertexProgram.Temporaries[i]);
+#if 0 /* FIX ME */
+            ctx->Driver.GetVertexProgramRegister(ctx, PROGRAM_TEMPORARY, i, v);
+#endif
          }
          else if (reg[0] == 'v' && reg[1] == '[') {
             /* Vertex Input attribute */
@@ -2090,7 +2175,10 @@ _mesa_GetProgramRegisterfvMESA(GLenum target,
                _mesa_sprintf(number, "%d", i);
                if (_mesa_strncmp(reg + 2, name, 4) == 0 ||
                    _mesa_strncmp(reg + 2, number, _mesa_strlen(number)) == 0) {
-                  COPY_4V(v, ctx->VertexProgram.Inputs[i]);
+#if 0 /* FIX ME */
+                  ctx->Driver.GetVertexProgramRegister(ctx, PROGRAM_INPUT,
+                                                       i, v);
+#endif
                   return;
                }
             }
@@ -2143,7 +2231,8 @@ _mesa_GetProgramRegisterfvMESA(GLenum target,
                            "glGetProgramRegisterfvMESA(registerName)");
                return;
             }
-            COPY_4V(v, ctx->FragmentProgram.Machine.Temporaries[i]);
+            ctx->Driver.GetFragmentProgramRegister(ctx, PROGRAM_TEMPORARY,
+                                                   i, v);
          }
          else if (reg[0] == 'f' && reg[1] == '[') {
             /* Fragment input attribute */
@@ -2151,7 +2240,8 @@ _mesa_GetProgramRegisterfvMESA(GLenum target,
             for (i = 0; i < ctx->Const.FragmentProgram.MaxAttribs; i++) {
                const char *name = _mesa_nv_fragment_input_register_name(i);
                if (_mesa_strncmp(reg + 2, name, 4) == 0) {
-                  COPY_4V(v, ctx->FragmentProgram.Machine.Inputs[i]);
+                  ctx->Driver.GetFragmentProgramRegister(ctx,
+                                                         PROGRAM_INPUT, i, v);
                   return;
                }
             }
@@ -2161,15 +2251,18 @@ _mesa_GetProgramRegisterfvMESA(GLenum target,
          }
          else if (_mesa_strcmp(reg, "o[COLR]") == 0) {
             /* Fragment output color */
-            COPY_4V(v, ctx->FragmentProgram.Machine.Outputs[FRAG_RESULT_COLR]);
+            ctx->Driver.GetFragmentProgramRegister(ctx, PROGRAM_OUTPUT,
+                                                   FRAG_RESULT_COLR, v);
          }
          else if (_mesa_strcmp(reg, "o[COLH]") == 0) {
             /* Fragment output color */
-            COPY_4V(v, ctx->FragmentProgram.Machine.Outputs[FRAG_RESULT_COLH]);
+            ctx->Driver.GetFragmentProgramRegister(ctx, PROGRAM_OUTPUT,
+                                                   FRAG_RESULT_COLH, v);
          }
          else if (_mesa_strcmp(reg, "o[DEPR]") == 0) {
             /* Fragment output depth */
-            COPY_4V(v, ctx->FragmentProgram.Machine.Outputs[FRAG_RESULT_DEPR]);
+            ctx->Driver.GetFragmentProgramRegister(ctx, PROGRAM_OUTPUT,
+                                                   FRAG_RESULT_DEPR, v);
          }
          else {
             /* try user-defined identifiers */
@@ -2190,5 +2283,4 @@ _mesa_GetProgramRegisterfvMESA(GLenum target,
                      "glGetProgramRegisterfvMESA(target)");
          return;
    }
-
 }