_mesa_reference_pipeline_object(ctx, &save->Pipeline, NULL);
       }
+
+      _mesa_update_vertex_processing_mode(ctx);
    }
 
    if (state & MESA_META_STENCIL_TEST) {
 
 #include "main/mtypes.h"
 #include "main/arbprogram.h"
 #include "main/shaderapi.h"
+#include "main/state.h"
 #include "program/arbprogparse.h"
 #include "program/program.h"
 #include "program/prog_print.h"
       _mesa_reference_program(ctx, &ctx->FragmentProgram.Current, newProg);
    }
 
+   _mesa_update_vertex_processing_mode(ctx);
+
    /* Never null pointers */
    assert(ctx->VertexProgram.Current);
    assert(ctx->FragmentProgram.Current);
       }
    }
 
+   _mesa_update_vertex_processing_mode(ctx);
+
    if (ctx->_Shader->Flags & GLSL_DUMP) {
       const char *shader_type =
          target == GL_FRAGMENT_PROGRAM_ARB ? "fragment" : "vertex";
 
 #include "shared.h"
 #include "shaderobj.h"
 #include "shaderimage.h"
+#include "state.h"
 #include "util/debug.h"
 #include "util/disk_cache.h"
 #include "util/strtod.h"
 
    check_context_limits(ctx);
 
+   _mesa_update_vertex_processing_mode(ctx);
+
    /* According to GL_MESA_configless_context the default value of
     * glDrawBuffers depends on the config of the first surface it is bound to.
     * For GLES it is always GL_BACK which has a magic interpretation.
 
 #include "light.h"
 #include "mtypes.h"
 #include "enums.h"
+#include "state.h"
 #include "texstate.h"
 #include "varray.h"
 
             return;
          FLUSH_VERTICES(ctx, _NEW_PROGRAM);
          ctx->VertexProgram.Enabled = state;
+         _mesa_update_vertex_processing_mode(ctx);
          break;
       case GL_VERTEX_PROGRAM_POINT_SIZE_ARB:
          /* This was added with ARB_vertex_program, but it is also used with
 
 } gl_register_file;
 
 
+/**
+ * Current vertex processing mode: fixed function vs. shader.
+ * In reality, fixed function is probably implemented by a shader but that's
+ * not what we care about here.
+ */
+typedef enum
+{
+   VP_MODE_FF,     /**< legacy / fixed function */
+   VP_MODE_SHADER, /**< ARB vertex program or GLSL vertex shader */
+   VP_MODE_MAX     /**< for sizing arrays */
+} gl_vertex_processing_mode;
+
+
 /**
  * Base class for any kind of program object
  */
    struct gl_program_cache *Cache;
 
    GLboolean _Overriden;
+
+   /**
+    * If we have a vertex program, a TNL program or no program at all.
+    * Note that this value should be kept up to date all the time,
+    * nevertheless its correctness is asserted in _mesa_update_state.
+    * The reason is to avoid calling _mesa_update_state twice we need
+    * this value on draw *before* actually calling _mesa_update_state.
+    * Also it should need to get recomputed only on changes to the
+    * vertex program which are heavyweight already.
+    */
+   gl_vertex_processing_mode _VPMode;
 };
 
 /**
 
 #include "main/pipelineobj.h"
 #include "main/shaderapi.h"
 #include "main/shaderobj.h"
+#include "main/state.h"
 #include "main/transformfeedback.h"
 #include "main/uniforms.h"
 #include "compiler/glsl/glsl_parser_extras.h"
             _mesa_program_init_subroutine_defaults(ctx, prog);
          }
       }
+
+      _mesa_update_vertex_processing_mode(ctx);
    }
 }
 
 
 #include "main/program_binary.h"
 #include "main/shaderapi.h"
 #include "main/shaderobj.h"
+#include "main/state.h"
 #include "main/transformfeedback.h"
 #include "main/uniforms.h"
 #include "compiler/glsl/glsl_parser_extras.h"
                   shProg->Name, shProg->data->InfoLog);
    }
 
+   _mesa_update_vertex_processing_mode(ctx);
+
    /* debug code */
    if (0) {
       GLuint i;
                                      &shTarget->ReferencedPrograms[stage],
                                      shProg);
       _mesa_reference_program(ctx, target, prog);
+      if (stage == MESA_SHADER_VERTEX)
+         _mesa_update_vertex_processing_mode(ctx);
       return;
    }
 
 
     */
    if (vsProg) {
       /* Use GLSL vertex shader */
+      assert(VP_MODE_SHADER == ctx->VertexProgram._VPMode);
       _mesa_reference_program(ctx, &ctx->VertexProgram._Current, vsProg);
    }
    else if (_mesa_arb_vertex_program_enabled(ctx)) {
       /* Use user-defined vertex program */
+      assert(VP_MODE_SHADER == ctx->VertexProgram._VPMode);
       _mesa_reference_program(ctx, &ctx->VertexProgram._Current,
                               ctx->VertexProgram.Current);
    }
    else if (ctx->VertexProgram._MaintainTnlProgram) {
       /* Use vertex program generated from fixed-function state */
+      assert(VP_MODE_FF == ctx->VertexProgram._VPMode);
       _mesa_reference_program(ctx, &ctx->VertexProgram._Current,
                               _mesa_get_fixed_func_vertex_program(ctx));
       _mesa_reference_program(ctx, &ctx->VertexProgram._TnlProgram,
    }
    else {
       /* no vertex program */
+      assert(VP_MODE_FF == ctx->VertexProgram._VPMode);
       _mesa_reference_program(ctx, &ctx->VertexProgram._Current, NULL);
    }
 
       ctx->NewState |= _NEW_PROGRAM;
    }
 }
+
+
+/**
+ * Update ctx->VertexProgram._VPMode.
+ * This is to distinguish whether we're running
+ *   a vertex program/shader,
+ *   a fixed-function TNL program or
+ *   a fixed function vertex transformation without any program.
+ */
+void
+_mesa_update_vertex_processing_mode(struct gl_context *ctx)
+{
+   if (ctx->_Shader->CurrentProgram[MESA_SHADER_VERTEX])
+      ctx->VertexProgram._VPMode = VP_MODE_SHADER;
+   else if (_mesa_arb_vertex_program_enabled(ctx))
+      ctx->VertexProgram._VPMode = VP_MODE_SHADER;
+   else
+      ctx->VertexProgram._VPMode = VP_MODE_FF;
+}
 
 _mesa_set_vp_override(struct gl_context *ctx, GLboolean flag);
 
 
+/**
+ * Update ctx->VertexProgram._VertexProgramMode.
+ */
+extern void
+_mesa_update_vertex_processing_mode(struct gl_context *ctx);
+
+
 static inline bool
 _mesa_ati_fragment_shader_enabled(const struct gl_context *ctx)
 {
 
                            ctx->Shared->DefaultFragmentProgram);
    assert(ctx->FragmentProgram.Current);
    ctx->FragmentProgram.Cache = _mesa_new_program_cache();
+   ctx->VertexProgram._VPMode = VP_MODE_FF;
 
    /* XXX probably move this stuff */
    ctx->ATIFragmentShader.Enabled = GL_FALSE;