meta: use non-ARB shader/program create/delete functions
[mesa.git] / src / mesa / drivers / common / meta.c
index 60157af98c53e747ce8e138bffdbdc2b11590534..fe353ec2a06b236adcf629a5757dde41553472b7 100644 (file)
@@ -51,6 +51,8 @@
 #include "main/macros.h"
 #include "main/matrix.h"
 #include "main/mipmap.h"
+#include "main/multisample.h"
+#include "main/objectlabel.h"
 #include "main/pixel.h"
 #include "main/pbo.h"
 #include "main/polygon.h"
 /** Return offset in bytes of the field within a vertex struct */
 #define OFFSET(FIELD) ((void *) offsetof(struct vertex, FIELD))
 
-/**
- * State which we may save/restore across meta ops.
- * XXX this may be incomplete...
- */
-struct save_state
-{
-   GLbitfield SavedState;  /**< bitmask of MESA_META_* flags */
-
-   /** MESA_META_CLEAR (and others?) */
-   struct gl_query_object *CurrentOcclusionObject;
-
-   /** MESA_META_ALPHA_TEST */
-   GLboolean AlphaEnabled;
-   GLenum AlphaFunc;
-   GLclampf AlphaRef;
-
-   /** MESA_META_BLEND */
-   GLbitfield BlendEnabled;
-   GLboolean ColorLogicOpEnabled;
-
-   /** MESA_META_COLOR_MASK */
-   GLubyte ColorMask[MAX_DRAW_BUFFERS][4];
-
-   /** MESA_META_DEPTH_TEST */
-   struct gl_depthbuffer_attrib Depth;
-
-   /** MESA_META_FOG */
-   GLboolean Fog;
-
-   /** MESA_META_PIXEL_STORE */
-   struct gl_pixelstore_attrib Pack, Unpack;
-
-   /** MESA_META_PIXEL_TRANSFER */
-   GLfloat RedBias, RedScale;
-   GLfloat GreenBias, GreenScale;
-   GLfloat BlueBias, BlueScale;
-   GLfloat AlphaBias, AlphaScale;
-   GLfloat DepthBias, DepthScale;
-   GLboolean MapColorFlag;
-
-   /** MESA_META_RASTERIZATION */
-   GLenum FrontPolygonMode, BackPolygonMode;
-   GLboolean PolygonOffset;
-   GLboolean PolygonSmooth;
-   GLboolean PolygonStipple;
-   GLboolean PolygonCull;
-
-   /** MESA_META_SCISSOR */
-   struct gl_scissor_attrib Scissor;
-
-   /** MESA_META_SHADER */
-   GLboolean VertexProgramEnabled;
-   struct gl_vertex_program *VertexProgram;
-   GLboolean FragmentProgramEnabled;
-   struct gl_fragment_program *FragmentProgram;
-   GLboolean ATIFragmentShaderEnabled;
-   struct gl_shader_program *VertexShader;
-   struct gl_shader_program *GeometryShader;
-   struct gl_shader_program *FragmentShader;
-   struct gl_shader_program *ActiveShader;
-
-   /** MESA_META_STENCIL_TEST */
-   struct gl_stencil_attrib Stencil;
-
-   /** MESA_META_TRANSFORM */
-   GLenum MatrixMode;
-   GLfloat ModelviewMatrix[16];
-   GLfloat ProjectionMatrix[16];
-   GLfloat TextureMatrix[16];
-
-   /** MESA_META_CLIP */
-   GLbitfield ClipPlanesEnabled;
-
-   /** MESA_META_TEXTURE */
-   GLuint ActiveUnit;
-   GLuint ClientActiveUnit;
-   /** for unit[0] only */
-   struct gl_texture_object *CurrentTexture[NUM_TEXTURE_TARGETS];
-   /** mask of TEXTURE_2D_BIT, etc */
-   GLbitfield TexEnabled[MAX_TEXTURE_UNITS];
-   GLbitfield TexGenEnabled[MAX_TEXTURE_UNITS];
-   GLuint EnvMode;  /* unit[0] only */
-
-   /** MESA_META_VERTEX */
-   struct gl_array_object *ArrayObj;
-   struct gl_buffer_object *ArrayBufferObj;
-
-   /** MESA_META_VIEWPORT */
-   GLint ViewportX, ViewportY, ViewportW, ViewportH;
-   GLclampd DepthNear, DepthFar;
-
-   /** MESA_META_CLAMP_FRAGMENT_COLOR */
-   GLenum ClampFragmentColor;
-
-   /** MESA_META_CLAMP_VERTEX_COLOR */
-   GLenum ClampVertexColor;
-
-   /** MESA_META_CONDITIONAL_RENDER */
-   struct gl_query_object *CondRenderQuery;
-   GLenum CondRenderMode;
-
-   /** MESA_META_SELECT_FEEDBACK */
-   GLenum RenderMode;
-   struct gl_selection Select;
-   struct gl_feedback Feedback;
-
-   /** MESA_META_MULTISAMPLE */
-   GLboolean MultisampleEnabled;
-
-   /** MESA_META_FRAMEBUFFER_SRGB */
-   GLboolean sRGBEnabled;
-
-   /** Miscellaneous (always disabled) */
-   GLboolean Lighting;
-   GLboolean RasterDiscard;
-   GLboolean TransformFeedbackNeedsResume;
-};
-
-/**
- * Temporary texture used for glBlitFramebuffer, glDrawPixels, etc.
- * This is currently shared by all the meta ops.  But we could create a
- * separate one for each of glDrawPixel, glBlitFramebuffer, glCopyPixels, etc.
- */
-struct temp_texture
-{
-   GLuint TexObj;
-   GLenum Target;         /**< GL_TEXTURE_2D or GL_TEXTURE_RECTANGLE */
-   GLsizei MinSize;       /**< Min texture size to allocate */
-   GLsizei MaxSize;       /**< Max possible texture size */
-   GLboolean NPOT;        /**< Non-power of two size OK? */
-   GLsizei Width, Height; /**< Current texture size */
-   GLenum IntFormat;
-   GLfloat Sright, Ttop;  /**< right, top texcoords */
-};
-
-
-/**
- * State for glBlitFramebufer()
- */
-struct blit_state
-{
-   GLuint ArrayObj;
-   GLuint VBO;
-   GLuint DepthFP;
-   GLuint ShaderProg;
-   GLuint RectShaderProg;
-   struct temp_texture depthTex;
-};
-
-
-/**
- * State for glClear()
- */
-struct clear_state
-{
-   GLuint ArrayObj;
-   GLuint VBO;
-   GLuint ShaderProg;
-   GLint ColorLocation;
-
-   GLuint IntegerShaderProg;
-   GLint IntegerColorLocation;
-};
-
-
-/**
- * State for glCopyPixels()
- */
-struct copypix_state
-{
-   GLuint ArrayObj;
-   GLuint VBO;
-};
-
-
-/**
- * State for glDrawPixels()
- */
-struct drawpix_state
-{
-   GLuint ArrayObj;
-
-   GLuint StencilFP;  /**< Fragment program for drawing stencil images */
-   GLuint DepthFP;  /**< Fragment program for drawing depth images */
-};
-
-
-/**
- * State for glBitmap()
- */
-struct bitmap_state
-{
-   GLuint ArrayObj;
-   GLuint VBO;
-   struct temp_texture Tex;  /**< separate texture from other meta ops */
-};
-
-/**
- * State for GLSL texture sampler which is used to generate fragment
- * shader in _mesa_meta_generate_mipmap().
- */
-struct glsl_sampler {
-   const char *type;
-   const char *func;
-   const char *texcoords;
-   GLuint shader_prog;
-};
-
-/**
- * State for _mesa_meta_generate_mipmap()
- */
-struct gen_mipmap_state
-{
-   GLuint ArrayObj;
-   GLuint VBO;
-   GLuint FBO;
-   GLuint Sampler;
-   GLuint ShaderProg;
-   struct glsl_sampler sampler_1d;
-   struct glsl_sampler sampler_2d;
-   struct glsl_sampler sampler_3d;
-   struct glsl_sampler sampler_cubemap;
-   struct glsl_sampler sampler_1d_array;
-   struct glsl_sampler sampler_2d_array;
-};
-
-/**
- * State for texture decompression
- */
-struct decompress_state
-{
-   GLuint ArrayObj;
-   GLuint VBO, FBO, RBO, Sampler;
-   GLint Width, Height;
-};
+static struct blit_shader *
+choose_blit_shader(GLenum target, struct blit_shader_table *table);
 
-/**
- * State for glDrawTex()
- */
-struct drawtex_state
-{
-   GLuint ArrayObj;
-   GLuint VBO;
-};
+static void cleanup_temp_texture(struct temp_texture *tex);
+static void meta_glsl_clear_cleanup(struct clear_state *clear);
+static void meta_decompress_cleanup(struct decompress_state *decompress);
+static void meta_drawpix_cleanup(struct drawpix_state *drawpix);
 
-#define MAX_META_OPS_DEPTH      8
-/**
- * All per-context meta state.
- */
-struct gl_meta_state
-{
-   /** Stack of state saved during meta-ops */
-   struct save_state Save[MAX_META_OPS_DEPTH];
-   /** Save stack depth */
-   GLuint SaveStackDepth;
-
-   struct temp_texture TempTex;
-
-   struct blit_state Blit;    /**< For _mesa_meta_BlitFramebuffer() */
-   struct clear_state Clear;  /**< For _mesa_meta_Clear() */
-   struct copypix_state CopyPix;  /**< For _mesa_meta_CopyPixels() */
-   struct drawpix_state DrawPix;  /**< For _mesa_meta_DrawPixels() */
-   struct bitmap_state Bitmap;    /**< For _mesa_meta_Bitmap() */
-   struct gen_mipmap_state Mipmap;    /**< For _mesa_meta_GenerateMipmap() */
-   struct decompress_state Decompress;  /**< For texture decompression */
-   struct drawtex_state DrawTex;  /**< For _mesa_meta_DrawTex() */
-};
-
-static void meta_glsl_blit_cleanup(struct gl_context *ctx, struct blit_state *blit);
-static void cleanup_temp_texture(struct gl_context *ctx, struct temp_texture *tex);
-static void meta_glsl_clear_cleanup(struct gl_context *ctx, struct clear_state *clear);
-static void meta_glsl_generate_mipmap_cleanup(struct gl_context *ctx,
-                                              struct gen_mipmap_state *mipmap);
-
-static GLuint
-compile_shader_with_debug(struct gl_context *ctx, GLenum target, const GLcharARB *source)
+GLuint
+_mesa_meta_compile_shader_with_debug(struct gl_context *ctx, GLenum target,
+                                     const GLcharARB *source)
 {
    GLuint shader;
    GLint ok, size;
    GLchar *info;
 
-   shader = _mesa_CreateShaderObjectARB(target);
+   shader = _mesa_CreateShader(target);
    _mesa_ShaderSource(shader, 1, &source, NULL);
    _mesa_CompileShader(shader);
 
@@ -373,30 +110,30 @@ compile_shader_with_debug(struct gl_context *ctx, GLenum target, const GLcharARB
 
    _mesa_GetShaderiv(shader, GL_INFO_LOG_LENGTH, &size);
    if (size == 0) {
-      _mesa_DeleteObjectARB(shader);
+      _mesa_DeleteShader(shader);
       return 0;
    }
 
    info = malloc(size);
    if (!info) {
-      _mesa_DeleteObjectARB(shader);
+      _mesa_DeleteShader(shader);
       return 0;
    }
 
-   _mesa_GetProgramInfoLog(shader, size, NULL, info);
+   _mesa_GetShaderInfoLog(shader, size, NULL, info);
    _mesa_problem(ctx,
                 "meta program compile failed:\n%s\n"
                 "source:\n%s\n",
                 info, source);
 
    free(info);
-   _mesa_DeleteObjectARB(shader);
+   _mesa_DeleteShader(shader);
 
    return 0;
 }
 
-static GLuint
-link_program_with_debug(struct gl_context *ctx, GLuint program)
+GLuint
+_mesa_meta_link_program_with_debug(struct gl_context *ctx, GLuint program)
 {
    GLint ok, size;
    GLchar *info;
@@ -423,6 +160,182 @@ link_program_with_debug(struct gl_context *ctx, GLuint program)
    return 0;
 }
 
+/**
+ * Generate a generic shader to blit from a texture to a framebuffer
+ *
+ * \param ctx       Current GL context
+ * \param texTarget Texture target that will be the source of the blit
+ *
+ * \returns a handle to a shader program on success or zero on failure.
+ */
+void
+_mesa_meta_setup_blit_shader(struct gl_context *ctx,
+                             GLenum target,
+                             struct blit_shader_table *table)
+{
+   const char *vs_source;
+   char *fs_source;
+   GLuint vs, fs;
+   void *const mem_ctx = ralloc_context(NULL);
+   struct blit_shader *shader = choose_blit_shader(target, table);
+   char *name;
+
+   assert(shader != NULL);
+
+   if (shader->shader_prog != 0) {
+      _mesa_UseProgram(shader->shader_prog);
+      return;
+   }
+
+   if (ctx->Const.GLSLVersion < 130) {
+      vs_source =
+         "attribute vec2 position;\n"
+         "attribute vec4 textureCoords;\n"
+         "varying vec4 texCoords;\n"
+         "void main()\n"
+         "{\n"
+         "   texCoords = textureCoords;\n"
+         "   gl_Position = vec4(position, 0.0, 1.0);\n"
+         "}\n";
+
+      fs_source = ralloc_asprintf(mem_ctx,
+                                  "#extension GL_EXT_texture_array : enable\n"
+                                  "#extension GL_ARB_texture_cube_map_array: enable\n"
+                                  "uniform %s texSampler;\n"
+                                  "varying vec4 texCoords;\n"
+                                  "void main()\n"
+                                  "{\n"
+                                  "   gl_FragColor = %s(texSampler, %s);\n"
+                                  "   gl_FragDepth = gl_FragColor.x;\n"
+                                  "}\n",
+                                  shader->type,
+                                  shader->func, shader->texcoords);
+   }
+   else {
+      vs_source = ralloc_asprintf(mem_ctx,
+                                  "#version 130\n"
+                                  "in vec2 position;\n"
+                                  "in vec4 textureCoords;\n"
+                                  "out vec4 texCoords;\n"
+                                  "void main()\n"
+                                  "{\n"
+                                  "   texCoords = textureCoords;\n"
+                                  "   gl_Position = vec4(position, 0.0, 1.0);\n"
+                                  "}\n");
+      fs_source = ralloc_asprintf(mem_ctx,
+                                  "#version 130\n"
+                                  "#extension GL_ARB_texture_cube_map_array: enable\n"
+                                  "uniform %s texSampler;\n"
+                                  "in vec4 texCoords;\n"
+                                  "out vec4 out_color;\n"
+                                  "\n"
+                                  "void main()\n"
+                                  "{\n"
+                                  "   out_color = texture(texSampler, %s);\n"
+                                  "   gl_FragDepth = out_color.x;\n"
+                                  "}\n",
+                                  shader->type,
+                                  shader->texcoords);
+   }
+
+   vs = _mesa_meta_compile_shader_with_debug(ctx, GL_VERTEX_SHADER, vs_source);
+   fs = _mesa_meta_compile_shader_with_debug(ctx, GL_FRAGMENT_SHADER, fs_source);
+
+   shader->shader_prog = _mesa_CreateProgram();
+   _mesa_AttachShader(shader->shader_prog, fs);
+   _mesa_DeleteShader(fs);
+   _mesa_AttachShader(shader->shader_prog, vs);
+   _mesa_DeleteShader(vs);
+   _mesa_BindAttribLocation(shader->shader_prog, 0, "position");
+   _mesa_BindAttribLocation(shader->shader_prog, 1, "texcoords");
+   _mesa_meta_link_program_with_debug(ctx, shader->shader_prog);
+   name = ralloc_asprintf(mem_ctx, "%s blit", shader->type);
+   _mesa_ObjectLabel(GL_PROGRAM, shader->shader_prog, -1, name);
+   ralloc_free(mem_ctx);
+
+   _mesa_UseProgram(shader->shader_prog);
+}
+
+/**
+ * Configure vertex buffer and vertex array objects for tests
+ *
+ * Regardless of whether a new VAO and new VBO are created, the objects
+ * referenced by \c VAO and \c VBO will be bound into the GL state vector
+ * when this function terminates.
+ *
+ * \param VAO       Storage for vertex array object handle.  If 0, a new VAO
+ *                  will be created.
+ * \param VBO       Storage for vertex buffer object handle.  If 0, a new VBO
+ *                  will be created.  The new VBO will have storage for 4
+ *                  \c vertex structures.
+ * \param use_generic_attributes  Should generic attributes 0 and 1 be used,
+ *                  or should traditional, fixed-function color and texture
+ *                  coordinate be used?
+ * \param vertex_size  Number of components for attribute 0 / vertex.
+ * \param texcoord_size  Number of components for attribute 1 / texture
+ *                  coordinate.  If this is 0, attribute 1 will not be set or
+ *                  enabled.
+ * \param color_size  Number of components for attribute 1 / primary color.
+ *                  If this is 0, attribute 1 will not be set or enabled.
+ *
+ * \note If \c use_generic_attributes is \c true, \c color_size must be zero.
+ * Use \c texcoord_size instead.
+ */
+void
+_mesa_meta_setup_vertex_objects(GLuint *VAO, GLuint *VBO,
+                                bool use_generic_attributes,
+                                unsigned vertex_size, unsigned texcoord_size,
+                                unsigned color_size)
+{
+   if (*VAO == 0) {
+      assert(*VBO == 0);
+
+      /* create vertex array object */
+      _mesa_GenVertexArrays(1, VAO);
+      _mesa_BindVertexArray(*VAO);
+
+      /* create vertex array buffer */
+      _mesa_GenBuffers(1, VBO);
+      _mesa_BindBuffer(GL_ARRAY_BUFFER, *VBO);
+      _mesa_BufferData(GL_ARRAY_BUFFER, 4 * sizeof(struct vertex), NULL,
+                       GL_DYNAMIC_DRAW);
+
+      /* setup vertex arrays */
+      if (use_generic_attributes) {
+         assert(color_size == 0);
+
+         _mesa_VertexAttribPointer(0, vertex_size, GL_FLOAT, GL_FALSE,
+                                   sizeof(struct vertex), OFFSET(x));
+         _mesa_EnableVertexAttribArray(0);
+
+         if (texcoord_size > 0) {
+            _mesa_VertexAttribPointer(1, texcoord_size, GL_FLOAT, GL_FALSE,
+                                      sizeof(struct vertex), OFFSET(tex));
+            _mesa_EnableVertexAttribArray(1);
+         }
+      } else {
+         _mesa_VertexPointer(vertex_size, GL_FLOAT, sizeof(struct vertex),
+                             OFFSET(x));
+         _mesa_EnableClientState(GL_VERTEX_ARRAY);
+
+         if (texcoord_size > 0) {
+            _mesa_TexCoordPointer(texcoord_size, GL_FLOAT,
+                                  sizeof(struct vertex), OFFSET(tex));
+            _mesa_EnableClientState(GL_TEXTURE_COORD_ARRAY);
+         }
+
+         if (color_size > 0) {
+            _mesa_ColorPointer(color_size, GL_FLOAT,
+                               sizeof(struct vertex), OFFSET(r));
+            _mesa_EnableClientState(GL_COLOR_ARRAY);
+         }
+      }
+   } else {
+      _mesa_BindVertexArray(*VAO);
+      _mesa_BindBuffer(GL_ARRAY_BUFFER, *VBO);
+   }
+}
+
 /**
  * Initialize meta-ops for a context.
  * To be called once during context creation.
@@ -445,10 +358,12 @@ _mesa_meta_free(struct gl_context *ctx)
 {
    GET_CURRENT_CONTEXT(old_context);
    _mesa_make_current(ctx, NULL, NULL);
-   meta_glsl_blit_cleanup(ctx, &ctx->Meta->Blit);
-   meta_glsl_clear_cleanup(ctx, &ctx->Meta->Clear);
-   meta_glsl_generate_mipmap_cleanup(ctx, &ctx->Meta->Mipmap);
-   cleanup_temp_texture(ctx, &ctx->Meta->TempTex);
+   _mesa_meta_glsl_blit_cleanup(&ctx->Meta->Blit);
+   meta_glsl_clear_cleanup(&ctx->Meta->Clear);
+   _mesa_meta_glsl_generate_mipmap_cleanup(&ctx->Meta->Mipmap);
+   cleanup_temp_texture(&ctx->Meta->TempTex);
+   meta_decompress_cleanup(&ctx->Meta->Decompress);
+   meta_drawpix_cleanup(&ctx->Meta->DrawPix);
    if (old_context)
       _mesa_make_current(old_context, old_context->WinSysDrawBuffer, old_context->WinSysReadBuffer);
    else
@@ -477,6 +392,13 @@ _mesa_meta_begin(struct gl_context *ctx, GLbitfield state)
    memset(save, 0, sizeof(*save));
    save->SavedState = state;
 
+   /* We always push into desktop GL mode and pop out at the end.  No sense in
+    * writing our shaders varying based on the user's context choice, when
+    * Mesa can handle either.
+    */
+   save->API = ctx->API;
+   ctx->API = API_OPENGL_COMPAT;
+
    /* Pausing transform feedback needs to be done early, or else we won't be
     * able to change other state.
     */
@@ -536,9 +458,7 @@ _mesa_meta_begin(struct gl_context *ctx, GLbitfield state)
          _mesa_set_enable(ctx, GL_DEPTH_TEST, GL_FALSE);
    }
 
-   if ((state & MESA_META_FOG)
-       && ctx->API != API_OPENGL_CORE
-       && ctx->API != API_OPENGLES2) {
+   if (state & MESA_META_FOG) {
       save->Fog = ctx->Fog.Enabled;
       if (ctx->Fog.Enabled)
          _mesa_set_enable(ctx, GL_FOG, GL_FALSE);
@@ -583,10 +503,8 @@ _mesa_meta_begin(struct gl_context *ctx, GLbitfield state)
       save->PolygonCull = ctx->Polygon.CullFlag;
       _mesa_PolygonMode(GL_FRONT_AND_BACK, GL_FILL);
       _mesa_set_enable(ctx, GL_POLYGON_OFFSET_FILL, GL_FALSE);
-      if (ctx->API == API_OPENGL_COMPAT) {
-         _mesa_set_enable(ctx, GL_POLYGON_SMOOTH, GL_FALSE);
-         _mesa_set_enable(ctx, GL_POLYGON_STIPPLE, GL_FALSE);
-      }
+      _mesa_set_enable(ctx, GL_POLYGON_SMOOTH, GL_FALSE);
+      _mesa_set_enable(ctx, GL_POLYGON_STIPPLE, GL_FALSE);
       _mesa_set_enable(ctx, GL_CULL_FACE, GL_FALSE);
    }
 
@@ -596,31 +514,31 @@ _mesa_meta_begin(struct gl_context *ctx, GLbitfield state)
    }
 
    if (state & MESA_META_SHADER) {
-      if (ctx->API == API_OPENGL_COMPAT && ctx->Extensions.ARB_vertex_program) {
+      int i;
+
+      if (ctx->Extensions.ARB_vertex_program) {
          save->VertexProgramEnabled = ctx->VertexProgram.Enabled;
          _mesa_reference_vertprog(ctx, &save->VertexProgram,
                                  ctx->VertexProgram.Current);
          _mesa_set_enable(ctx, GL_VERTEX_PROGRAM_ARB, GL_FALSE);
       }
 
-      if (ctx->API == API_OPENGL_COMPAT && ctx->Extensions.ARB_fragment_program) {
+      if (ctx->Extensions.ARB_fragment_program) {
          save->FragmentProgramEnabled = ctx->FragmentProgram.Enabled;
          _mesa_reference_fragprog(ctx, &save->FragmentProgram,
                                  ctx->FragmentProgram.Current);
          _mesa_set_enable(ctx, GL_FRAGMENT_PROGRAM_ARB, GL_FALSE);
       }
 
-      if (ctx->API == API_OPENGL_COMPAT && ctx->Extensions.ATI_fragment_shader) {
+      if (ctx->Extensions.ATI_fragment_shader) {
          save->ATIFragmentShaderEnabled = ctx->ATIFragmentShader.Enabled;
          _mesa_set_enable(ctx, GL_FRAGMENT_SHADER_ATI, GL_FALSE);
       }
 
-      _mesa_reference_shader_program(ctx, &save->VertexShader,
-                                     ctx->Shader.CurrentVertexProgram);
-      _mesa_reference_shader_program(ctx, &save->GeometryShader,
-                                     ctx->Shader.CurrentGeometryProgram);
-      _mesa_reference_shader_program(ctx, &save->FragmentShader,
-                                     ctx->Shader.CurrentFragmentProgram);
+      for (i = 0; i < MESA_SHADER_STAGES; i++) {
+         _mesa_reference_shader_program(ctx, &save->Shader[i],
+                                     ctx->Shader.CurrentProgram[i]);
+      }
       _mesa_reference_shader_program(ctx, &save->ActiveShader,
                                      ctx->Shader.ActiveProgram);
 
@@ -642,33 +560,24 @@ _mesa_meta_begin(struct gl_context *ctx, GLbitfield state)
       save->EnvMode = ctx->Texture.Unit[0].EnvMode;
 
       /* Disable all texture units */
-      if (ctx->API == API_OPENGL_COMPAT || ctx->API == API_OPENGLES) {
-         for (u = 0; u < ctx->Const.MaxTextureUnits; u++) {
-            save->TexEnabled[u] = ctx->Texture.Unit[u].Enabled;
-            save->TexGenEnabled[u] = ctx->Texture.Unit[u].TexGenEnabled;
-            if (ctx->Texture.Unit[u].Enabled ||
-                ctx->Texture.Unit[u].TexGenEnabled) {
-               _mesa_ActiveTexture(GL_TEXTURE0 + u);
-               _mesa_set_enable(ctx, GL_TEXTURE_2D, GL_FALSE);
-               if (ctx->Extensions.ARB_texture_cube_map)
-                  _mesa_set_enable(ctx, GL_TEXTURE_CUBE_MAP, GL_FALSE);
-               if (_mesa_is_gles(ctx) &&
-                   ctx->Extensions.OES_EGL_image_external)
-                  _mesa_set_enable(ctx, GL_TEXTURE_EXTERNAL_OES, GL_FALSE);
-
-               if (ctx->API == API_OPENGL_COMPAT) {
-                  _mesa_set_enable(ctx, GL_TEXTURE_1D, GL_FALSE);
-                  _mesa_set_enable(ctx, GL_TEXTURE_3D, GL_FALSE);
-                  if (ctx->Extensions.NV_texture_rectangle)
-                     _mesa_set_enable(ctx, GL_TEXTURE_RECTANGLE, GL_FALSE);
-                  _mesa_set_enable(ctx, GL_TEXTURE_GEN_S, GL_FALSE);
-                  _mesa_set_enable(ctx, GL_TEXTURE_GEN_T, GL_FALSE);
-                  _mesa_set_enable(ctx, GL_TEXTURE_GEN_R, GL_FALSE);
-                  _mesa_set_enable(ctx, GL_TEXTURE_GEN_Q, GL_FALSE);
-               } else {
-                  _mesa_set_enable(ctx, GL_TEXTURE_GEN_STR_OES, GL_FALSE);
-               }
-            }
+      for (u = 0; u < ctx->Const.MaxTextureUnits; u++) {
+         save->TexEnabled[u] = ctx->Texture.Unit[u].Enabled;
+         save->TexGenEnabled[u] = ctx->Texture.Unit[u].TexGenEnabled;
+         if (ctx->Texture.Unit[u].Enabled ||
+             ctx->Texture.Unit[u].TexGenEnabled) {
+            _mesa_ActiveTexture(GL_TEXTURE0 + u);
+            _mesa_set_enable(ctx, GL_TEXTURE_2D, GL_FALSE);
+            if (ctx->Extensions.ARB_texture_cube_map)
+               _mesa_set_enable(ctx, GL_TEXTURE_CUBE_MAP, GL_FALSE);
+
+            _mesa_set_enable(ctx, GL_TEXTURE_1D, GL_FALSE);
+            _mesa_set_enable(ctx, GL_TEXTURE_3D, GL_FALSE);
+            if (ctx->Extensions.NV_texture_rectangle)
+               _mesa_set_enable(ctx, GL_TEXTURE_RECTANGLE, GL_FALSE);
+            _mesa_set_enable(ctx, GL_TEXTURE_GEN_S, GL_FALSE);
+            _mesa_set_enable(ctx, GL_TEXTURE_GEN_T, GL_FALSE);
+            _mesa_set_enable(ctx, GL_TEXTURE_GEN_R, GL_FALSE);
+            _mesa_set_enable(ctx, GL_TEXTURE_GEN_Q, GL_FALSE);
          }
       }
 
@@ -681,9 +590,7 @@ _mesa_meta_begin(struct gl_context *ctx, GLbitfield state)
       /* set defaults for unit[0] */
       _mesa_ActiveTexture(GL_TEXTURE0);
       _mesa_ClientActiveTexture(GL_TEXTURE0);
-      if (ctx->API == API_OPENGL_COMPAT || ctx->API == API_OPENGLES) {
-         _mesa_TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
-      }
+      _mesa_TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
    }
 
    if (state & MESA_META_TRANSFORM) {
@@ -726,8 +633,8 @@ _mesa_meta_begin(struct gl_context *ctx, GLbitfield state)
 
    if (state & MESA_META_VERTEX) {
       /* save vertex array object state */
-      _mesa_reference_array_object(ctx, &save->ArrayObj,
-                                   ctx->Array.ArrayObj);
+      _mesa_reference_vao(ctx, &save->VAO,
+                                   ctx->Array.VAO);
       _mesa_reference_buffer_object(ctx, &save->ArrayBufferObj,
                                     ctx->Array.ArrayBufferObj);
       /* set some default state? */
@@ -735,21 +642,21 @@ _mesa_meta_begin(struct gl_context *ctx, GLbitfield state)
 
    if (state & MESA_META_VIEWPORT) {
       /* save viewport state */
-      save->ViewportX = ctx->Viewport.X;
-      save->ViewportY = ctx->Viewport.Y;
-      save->ViewportW = ctx->Viewport.Width;
-      save->ViewportH = ctx->Viewport.Height;
+      save->ViewportX = ctx->ViewportArray[0].X;
+      save->ViewportY = ctx->ViewportArray[0].Y;
+      save->ViewportW = ctx->ViewportArray[0].Width;
+      save->ViewportH = ctx->ViewportArray[0].Height;
       /* set viewport to match window size */
-      if (ctx->Viewport.X != 0 ||
-          ctx->Viewport.Y != 0 ||
-          ctx->Viewport.Width != ctx->DrawBuffer->Width ||
-          ctx->Viewport.Height != ctx->DrawBuffer->Height) {
-         _mesa_set_viewport(ctx, 0, 0,
+      if (ctx->ViewportArray[0].X != 0 ||
+          ctx->ViewportArray[0].Y != 0 ||
+          ctx->ViewportArray[0].Width != (float) ctx->DrawBuffer->Width ||
+          ctx->ViewportArray[0].Height != (float) ctx->DrawBuffer->Height) {
+         _mesa_set_viewport(ctx, 0, 0, 0,
                             ctx->DrawBuffer->Width, ctx->DrawBuffer->Height);
       }
       /* save depth range state */
-      save->DepthNear = ctx->Viewport.Near;
-      save->DepthFar = ctx->Viewport.Far;
+      save->DepthNear = ctx->ViewportArray[0].Near;
+      save->DepthFar = ctx->ViewportArray[0].Far;
       /* set depth range to default */
       _mesa_DepthRange(0.0, 1.0);
    }
@@ -796,9 +703,20 @@ _mesa_meta_begin(struct gl_context *ctx, GLbitfield state)
    }
 
    if (state & MESA_META_MULTISAMPLE) {
-      save->MultisampleEnabled = ctx->Multisample.Enabled;
+      save->Multisample = ctx->Multisample; /* struct copy */
+
       if (ctx->Multisample.Enabled)
          _mesa_set_multisample(ctx, GL_FALSE);
+      if (ctx->Multisample.SampleCoverage)
+         _mesa_set_enable(ctx, GL_SAMPLE_COVERAGE, GL_FALSE);
+      if (ctx->Multisample.SampleAlphaToCoverage)
+         _mesa_set_enable(ctx, GL_SAMPLE_ALPHA_TO_COVERAGE, GL_FALSE);
+      if (ctx->Multisample.SampleAlphaToOne)
+         _mesa_set_enable(ctx, GL_SAMPLE_ALPHA_TO_ONE, GL_FALSE);
+      if (ctx->Multisample.SampleShading)
+         _mesa_set_enable(ctx, GL_SAMPLE_SHADING, GL_FALSE);
+      if (ctx->Multisample.SampleMask)
+         _mesa_set_enable(ctx, GL_SAMPLE_MASK, GL_FALSE);
    }
 
    if (state & MESA_META_FRAMEBUFFER_SRGB) {
@@ -827,6 +745,7 @@ _mesa_meta_end(struct gl_context *ctx)
 {
    struct save_state *save = &ctx->Meta->Save[ctx->Meta->SaveStackDepth - 1];
    const GLbitfield state = save->SavedState;
+   int i;
 
    /* After starting a new occlusion query, initialize the results to the
     * values saved previously. The driver will then continue to increment
@@ -888,9 +807,7 @@ _mesa_meta_end(struct gl_context *ctx)
       _mesa_DepthMask(save->Depth.Mask);
    }
 
-   if ((state & MESA_META_FOG)
-       && ctx->API != API_OPENGL_CORE
-       && ctx->API != API_OPENGLES2) {
+   if (state & MESA_META_FOG) {
       _mesa_set_enable(ctx, GL_FOG, save->Fog);
    }
 
@@ -914,30 +831,30 @@ _mesa_meta_end(struct gl_context *ctx)
    }
 
    if (state & MESA_META_RASTERIZATION) {
-      /* Core context requires that front and back mode be the same.
-       */
-      if (ctx->API == API_OPENGL_CORE) {
-         _mesa_PolygonMode(GL_FRONT_AND_BACK, save->FrontPolygonMode);
-      } else {
-         _mesa_PolygonMode(GL_FRONT, save->FrontPolygonMode);
-         _mesa_PolygonMode(GL_BACK, save->BackPolygonMode);
-      }
-      if (ctx->API == API_OPENGL_COMPAT) {
-         _mesa_set_enable(ctx, GL_POLYGON_STIPPLE, save->PolygonStipple);
-         _mesa_set_enable(ctx, GL_POLYGON_SMOOTH, save->PolygonSmooth);
-      }
+      _mesa_PolygonMode(GL_FRONT, save->FrontPolygonMode);
+      _mesa_PolygonMode(GL_BACK, save->BackPolygonMode);
+      _mesa_set_enable(ctx, GL_POLYGON_STIPPLE, save->PolygonStipple);
+      _mesa_set_enable(ctx, GL_POLYGON_SMOOTH, save->PolygonSmooth);
       _mesa_set_enable(ctx, GL_POLYGON_OFFSET_FILL, save->PolygonOffset);
       _mesa_set_enable(ctx, GL_CULL_FACE, save->PolygonCull);
    }
 
    if (state & MESA_META_SCISSOR) {
-      _mesa_set_enable(ctx, GL_SCISSOR_TEST, save->Scissor.Enabled);
-      _mesa_Scissor(save->Scissor.X, save->Scissor.Y,
-                    save->Scissor.Width, save->Scissor.Height);
+      unsigned i;
+
+      for (i = 0; i < ctx->Const.MaxViewports; i++) {
+         _mesa_set_scissor(ctx, i,
+                           save->Scissor.ScissorArray[i].X,
+                           save->Scissor.ScissorArray[i].Y,
+                           save->Scissor.ScissorArray[i].Width,
+                           save->Scissor.ScissorArray[i].Height);
+         _mesa_set_enablei(ctx, GL_SCISSOR_TEST, i,
+                           (save->Scissor.EnableFlags >> i) & 1);
+      }
    }
 
    if (state & MESA_META_SHADER) {
-      if (ctx->API == API_OPENGL_COMPAT && ctx->Extensions.ARB_vertex_program) {
+      if (ctx->Extensions.ARB_vertex_program) {
          _mesa_set_enable(ctx, GL_VERTEX_PROGRAM_ARB,
                           save->VertexProgramEnabled);
          _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current, 
@@ -945,7 +862,7 @@ _mesa_meta_end(struct gl_context *ctx)
         _mesa_reference_vertprog(ctx, &save->VertexProgram, NULL);
       }
 
-      if (ctx->API == API_OPENGL_COMPAT && ctx->Extensions.ARB_fragment_program) {
+      if (ctx->Extensions.ARB_fragment_program) {
          _mesa_set_enable(ctx, GL_FRAGMENT_PROGRAM_ARB,
                           save->FragmentProgramEnabled);
          _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current,
@@ -953,28 +870,29 @@ _mesa_meta_end(struct gl_context *ctx)
         _mesa_reference_fragprog(ctx, &save->FragmentProgram, NULL);
       }
 
-      if (ctx->API == API_OPENGL_COMPAT && ctx->Extensions.ATI_fragment_shader) {
+      if (ctx->Extensions.ATI_fragment_shader) {
          _mesa_set_enable(ctx, GL_FRAGMENT_SHADER_ATI,
                           save->ATIFragmentShaderEnabled);
       }
 
-      if (ctx->Extensions.ARB_vertex_shader)
-        _mesa_use_shader_program(ctx, GL_VERTEX_SHADER, save->VertexShader);
+      if (ctx->Extensions.ARB_vertex_shader) {
+        _mesa_use_shader_program(ctx, GL_VERTEX_SHADER,
+                                  save->Shader[MESA_SHADER_VERTEX]);
+      }
 
       if (_mesa_has_geometry_shaders(ctx))
         _mesa_use_shader_program(ctx, GL_GEOMETRY_SHADER_ARB,
-                                 save->GeometryShader);
+                                 save->Shader[MESA_SHADER_GEOMETRY]);
 
       if (ctx->Extensions.ARB_fragment_shader)
         _mesa_use_shader_program(ctx, GL_FRAGMENT_SHADER,
-                                 save->FragmentShader);
+                                 save->Shader[MESA_SHADER_FRAGMENT]);
 
       _mesa_reference_shader_program(ctx, &ctx->Shader.ActiveProgram,
                                     save->ActiveShader);
 
-      _mesa_reference_shader_program(ctx, &save->VertexShader, NULL);
-      _mesa_reference_shader_program(ctx, &save->GeometryShader, NULL);
-      _mesa_reference_shader_program(ctx, &save->FragmentShader, NULL);
+      for (i = 0; i < MESA_SHADER_STAGES; i++)
+         _mesa_reference_shader_program(ctx, &save->Shader[i], NULL);
       _mesa_reference_shader_program(ctx, &save->ActiveShader, NULL);
    }
 
@@ -983,7 +901,7 @@ _mesa_meta_end(struct gl_context *ctx)
 
       _mesa_set_enable(ctx, GL_STENCIL_TEST, stencil->Enabled);
       _mesa_ClearStencil(stencil->Clear);
-      if (ctx->API == API_OPENGL_COMPAT && ctx->Extensions.EXT_stencil_two_side) {
+      if (ctx->Extensions.EXT_stencil_two_side) {
          _mesa_set_enable(ctx, GL_STENCIL_TEST_TWO_SIDE_EXT,
                           stencil->TestTwoSide);
          _mesa_ActiveStencilFaceEXT(stencil->ActiveFace
@@ -1015,9 +933,7 @@ _mesa_meta_end(struct gl_context *ctx)
       ASSERT(ctx->Texture.CurrentUnit == 0);
 
       /* restore texenv for unit[0] */
-      if (ctx->API == API_OPENGL_COMPAT || ctx->API == API_OPENGLES) {
-         _mesa_TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, save->EnvMode);
-      }
+      _mesa_TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, save->EnvMode);
 
       /* restore texture objects for unit[0] only */
       for (tgt = 0; tgt < NUM_TEXTURE_TARGETS; tgt++) {
@@ -1030,17 +946,15 @@ _mesa_meta_end(struct gl_context *ctx)
       }
 
       /* Restore fixed function texture enables, texgen */
-      if (ctx->API == API_OPENGL_COMPAT || ctx->API == API_OPENGLES) {
-         for (u = 0; u < ctx->Const.MaxTextureUnits; u++) {
-            if (ctx->Texture.Unit[u].Enabled != save->TexEnabled[u]) {
-               FLUSH_VERTICES(ctx, _NEW_TEXTURE);
-               ctx->Texture.Unit[u].Enabled = save->TexEnabled[u];
-            }
+      for (u = 0; u < ctx->Const.MaxTextureUnits; u++) {
+         if (ctx->Texture.Unit[u].Enabled != save->TexEnabled[u]) {
+            FLUSH_VERTICES(ctx, _NEW_TEXTURE);
+            ctx->Texture.Unit[u].Enabled = save->TexEnabled[u];
+         }
 
-            if (ctx->Texture.Unit[u].TexGenEnabled != save->TexGenEnabled[u]) {
-               FLUSH_VERTICES(ctx, _NEW_TEXTURE);
-               ctx->Texture.Unit[u].TexGenEnabled = save->TexGenEnabled[u];
-            }
+         if (ctx->Texture.Unit[u].TexGenEnabled != save->TexGenEnabled[u]) {
+            FLUSH_VERTICES(ctx, _NEW_TEXTURE);
+            ctx->Texture.Unit[u].TexGenEnabled = save->TexGenEnabled[u];
          }
       }
 
@@ -1082,16 +996,16 @@ _mesa_meta_end(struct gl_context *ctx)
       _mesa_reference_buffer_object(ctx, &save->ArrayBufferObj, NULL);
 
       /* restore vertex array object */
-      _mesa_BindVertexArray(save->ArrayObj->Name);
-      _mesa_reference_array_object(ctx, &save->ArrayObj, NULL);
+      _mesa_BindVertexArray(save->VAO->Name);
+      _mesa_reference_vao(ctx, &save->VAO, NULL);
    }
 
    if (state & MESA_META_VIEWPORT) {
-      if (save->ViewportX != ctx->Viewport.X ||
-          save->ViewportY != ctx->Viewport.Y ||
-          save->ViewportW != ctx->Viewport.Width ||
-          save->ViewportH != ctx->Viewport.Height) {
-         _mesa_set_viewport(ctx, save->ViewportX, save->ViewportY,
+      if (save->ViewportX != ctx->ViewportArray[0].X ||
+          save->ViewportY != ctx->ViewportArray[0].Y ||
+          save->ViewportW != ctx->ViewportArray[0].Width ||
+          save->ViewportH != ctx->ViewportArray[0].Height) {
+         _mesa_set_viewport(ctx, 0, save->ViewportX, save->ViewportY,
                             save->ViewportW, save->ViewportH);
       }
       _mesa_DepthRange(save->DepthNear, save->DepthFar);
@@ -1124,8 +1038,30 @@ _mesa_meta_end(struct gl_context *ctx)
    }
 
    if (state & MESA_META_MULTISAMPLE) {
-      if (ctx->Multisample.Enabled != save->MultisampleEnabled)
-         _mesa_set_multisample(ctx, save->MultisampleEnabled);
+      struct gl_multisample_attrib *ctx_ms = &ctx->Multisample;
+      struct gl_multisample_attrib *save_ms = &save->Multisample;
+
+      if (ctx_ms->Enabled != save_ms->Enabled)
+         _mesa_set_multisample(ctx, save_ms->Enabled);
+      if (ctx_ms->SampleCoverage != save_ms->SampleCoverage)
+         _mesa_set_enable(ctx, GL_SAMPLE_COVERAGE, save_ms->SampleCoverage);
+      if (ctx_ms->SampleAlphaToCoverage != save_ms->SampleAlphaToCoverage)
+         _mesa_set_enable(ctx, GL_SAMPLE_ALPHA_TO_COVERAGE, save_ms->SampleAlphaToCoverage);
+      if (ctx_ms->SampleAlphaToOne != save_ms->SampleAlphaToOne)
+         _mesa_set_enable(ctx, GL_SAMPLE_ALPHA_TO_ONE, save_ms->SampleAlphaToOne);
+      if (ctx_ms->SampleCoverageValue != save_ms->SampleCoverageValue ||
+          ctx_ms->SampleCoverageInvert != save_ms->SampleCoverageInvert) {
+         _mesa_SampleCoverage(save_ms->SampleCoverageValue,
+                              save_ms->SampleCoverageInvert);
+      }
+      if (ctx_ms->SampleShading != save_ms->SampleShading)
+         _mesa_set_enable(ctx, GL_SAMPLE_SHADING, save_ms->SampleShading);
+      if (ctx_ms->SampleMask != save_ms->SampleMask)
+         _mesa_set_enable(ctx, GL_SAMPLE_MASK, save_ms->SampleMask);
+      if (ctx_ms->SampleMaskValue != save_ms->SampleMaskValue)
+         _mesa_SampleMaski(0, save_ms->SampleMaskValue);
+      if (ctx_ms->MinSampleShadingValue != save_ms->MinSampleShadingValue)
+         _mesa_MinSampleShading(save_ms->MinSampleShadingValue);
    }
 
    if (state & MESA_META_FRAMEBUFFER_SRGB) {
@@ -1144,6 +1080,8 @@ _mesa_meta_end(struct gl_context *ctx)
       _mesa_ResumeTransformFeedback();
 
    ctx->Meta->SaveStackDepth--;
+
+   ctx->API = save->API;
 }
 
 
@@ -1198,7 +1136,7 @@ init_temp_texture(struct gl_context *ctx, struct temp_texture *tex)
 }
 
 static void
-cleanup_temp_texture(struct gl_context *ctx, struct temp_texture *tex)
+cleanup_temp_texture(struct temp_texture *tex)
 {
    if (!tex->TexObj)
      return;
@@ -1211,8 +1149,8 @@ cleanup_temp_texture(struct gl_context *ctx, struct temp_texture *tex)
  * Return pointer to temp_texture info for non-bitmap ops.
  * This does some one-time init if needed.
  */
-static struct temp_texture *
-get_temp_texture(struct gl_context *ctx)
+struct temp_texture *
+_mesa_meta_get_temp_texture(struct gl_context *ctx)
 {
    struct temp_texture *tex = &ctx->Meta->TempTex;
 
@@ -1245,8 +1183,8 @@ get_bitmap_temp_texture(struct gl_context *ctx)
  * Return pointer to depth temp_texture.
  * This does some one-time init if needed.
  */
-static struct temp_texture *
-get_temp_depth_texture(struct gl_context *ctx)
+struct temp_texture *
+_mesa_meta_get_temp_depth_texture(struct gl_context *ctx)
 {
    struct temp_texture *tex = &ctx->Meta->Blit.depthTex;
 
@@ -1266,9 +1204,9 @@ get_temp_depth_texture(struct gl_context *ctx)
  *
  * \return GL_TRUE if new texture is needed, GL_FALSE otherwise
  */
-static GLboolean
-alloc_texture(struct temp_texture *tex,
-              GLsizei width, GLsizei height, GLenum intFormat)
+GLboolean
+_mesa_meta_alloc_texture(struct temp_texture *tex,
+                         GLsizei width, GLsizei height, GLenum intFormat)
 {
    GLboolean newTex = GL_FALSE;
 
@@ -1319,19 +1257,22 @@ alloc_texture(struct temp_texture *tex,
 /**
  * Setup/load texture for glCopyPixels or glBlitFramebuffer.
  */
-static void
-setup_copypix_texture(struct gl_context *ctx,
-                      struct temp_texture *tex,
-                      GLboolean newTex,
-                      GLint srcX, GLint srcY,
-                      GLsizei width, GLsizei height, GLenum intFormat,
-                      GLenum filter)
+void
+_mesa_meta_setup_copypix_texture(struct gl_context *ctx,
+                                 struct temp_texture *tex,
+                                 GLint srcX, GLint srcY,
+                                 GLsizei width, GLsizei height,
+                                 GLenum intFormat,
+                                 GLenum filter)
 {
+   bool newTex;
+
    _mesa_BindTexture(tex->Target, tex->TexObj);
    _mesa_TexParameteri(tex->Target, GL_TEXTURE_MIN_FILTER, filter);
    _mesa_TexParameteri(tex->Target, GL_TEXTURE_MAG_FILTER, filter);
-   if (ctx->API == API_OPENGL_COMPAT || ctx->API == API_OPENGLES)
-      _mesa_TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+   _mesa_TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+
+   newTex = _mesa_meta_alloc_texture(tex, width, height, intFormat);
 
    /* copy framebuffer image to texture */
    if (newTex) {
@@ -1362,20 +1303,18 @@ setup_copypix_texture(struct gl_context *ctx,
 /**
  * Setup/load texture for glDrawPixels.
  */
-static void
-setup_drawpix_texture(struct gl_context *ctx,
-                     struct temp_texture *tex,
-                      GLboolean newTex,
-                      GLenum texIntFormat,
-                      GLsizei width, GLsizei height,
-                      GLenum format, GLenum type,
-                      const GLvoid *pixels)
+void
+_mesa_meta_setup_drawpix_texture(struct gl_context *ctx,
+                                 struct temp_texture *tex,
+                                 GLboolean newTex,
+                                 GLsizei width, GLsizei height,
+                                 GLenum format, GLenum type,
+                                 const GLvoid *pixels)
 {
    _mesa_BindTexture(tex->Target, tex->TexObj);
    _mesa_TexParameteri(tex->Target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    _mesa_TexParameteri(tex->Target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-   if (ctx->API == API_OPENGL_COMPAT || ctx->API == API_OPENGLES)
-      _mesa_TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+   _mesa_TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
 
    /* copy pixel data to texture */
    if (newTex) {
@@ -1409,660 +1348,53 @@ setup_drawpix_texture(struct gl_context *ctx,
    }
 }
 
-
-
-/**
- * One-time init for drawing depth pixels.
- */
-static void
-init_blit_depth_pixels(struct gl_context *ctx)
-{
-   static const char *program =
-      "!!ARBfp1.0\n"
-      "TEX result.depth, fragment.texcoord[0], texture[0], %s; \n"
-      "END \n";
-   char program2[200];
-   struct blit_state *blit = &ctx->Meta->Blit;
-   struct temp_texture *tex = get_temp_texture(ctx);
-   const char *texTarget;
-
-   assert(blit->DepthFP == 0);
-
-   /* replace %s with "RECT" or "2D" */
-   assert(strlen(program) + 4 < sizeof(program2));
-   if (tex->Target == GL_TEXTURE_RECTANGLE)
-      texTarget = "RECT";
-   else
-      texTarget = "2D";
-   _mesa_snprintf(program2, sizeof(program2), program, texTarget);
-
-   _mesa_GenProgramsARB(1, &blit->DepthFP);
-   _mesa_BindProgramARB(GL_FRAGMENT_PROGRAM_ARB, blit->DepthFP);
-   _mesa_ProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB,
-                          strlen(program2), (const GLubyte *) program2);
-}
-
-static void
-setup_ff_blit_framebuffer(struct gl_context *ctx,
-                          struct blit_state *blit)
+void
+_mesa_meta_setup_ff_tnl_for_blit(GLuint *VAO, GLuint *VBO,
+                                 unsigned texcoord_size)
 {
-   struct vertex {
-      GLfloat x, y, s, t;
-   };
-   struct vertex verts[4];
-
-   if (blit->ArrayObj == 0) {
-      /* one-time setup */
-
-      /* create vertex array object */
-      _mesa_GenVertexArrays(1, &blit->ArrayObj);
-      _mesa_BindVertexArray(blit->ArrayObj);
-
-      /* create vertex array buffer */
-      _mesa_GenBuffers(1, &blit->VBO);
-      _mesa_BindBuffer(GL_ARRAY_BUFFER_ARB, blit->VBO);
-      _mesa_BufferData(GL_ARRAY_BUFFER_ARB, sizeof(verts),
-                          NULL, GL_DYNAMIC_DRAW_ARB);
-
-      /* setup vertex arrays */
-      _mesa_VertexPointer(2, GL_FLOAT, sizeof(struct vertex), OFFSET(x));
-      _mesa_TexCoordPointer(2, GL_FLOAT, sizeof(struct vertex), OFFSET(s));
-      _mesa_EnableClientState(GL_VERTEX_ARRAY);
-      _mesa_EnableClientState(GL_TEXTURE_COORD_ARRAY);
-   }
+   _mesa_meta_setup_vertex_objects(VAO, VBO, false, 2, texcoord_size, 0);
 
    /* setup projection matrix */
    _mesa_MatrixMode(GL_PROJECTION);
    _mesa_LoadIdentity();
-   _mesa_Ortho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
-
 }
 
-static void
-setup_glsl_blit_framebuffer(struct gl_context *ctx,
-                            struct blit_state *blit,
-                            GLenum target)
+/**
+ * Meta implementation of ctx->Driver.Clear() in terms of polygon rendering.
+ */
+void
+_mesa_meta_Clear(struct gl_context *ctx, GLbitfield buffers)
 {
-   struct vertex {
-      GLfloat x, y, s, t;
-   };
+   struct clear_state *clear = &ctx->Meta->Clear;
    struct vertex verts[4];
-   const char *vs_source;
-   char *fs_source;
-   GLuint vs, fs;
-   void *mem_ctx;
-   GLuint ShaderProg;
-   GLboolean texture_2d = (target == GL_TEXTURE_2D);
+   /* save all state but scissor, pixel pack/unpack */
+   GLbitfield metaSave = (MESA_META_ALL -
+                         MESA_META_SCISSOR -
+                         MESA_META_PIXEL_STORE -
+                         MESA_META_CONDITIONAL_RENDER -
+                          MESA_META_FRAMEBUFFER_SRGB);
+   const GLuint stencilMax = (1 << ctx->DrawBuffer->Visual.stencilBits) - 1;
 
-   /* target = GL_TEXTURE_RECTANGLE is not supported in GLES 3.0 */
-   assert(_mesa_is_desktop_gl(ctx) || texture_2d);
+   if (buffers & BUFFER_BITS_COLOR) {
+      /* if clearing color buffers, don't save/restore colormask */
+      metaSave -= MESA_META_COLOR_MASK;
+   }
 
-   /* Check if already initialized */
-   if (blit->ArrayObj == 0) {
+   _mesa_meta_begin(ctx, metaSave);
 
-      /* create vertex array object */
-      _mesa_GenVertexArrays(1, &blit->ArrayObj);
-      _mesa_BindVertexArray(blit->ArrayObj);
+   _mesa_meta_setup_vertex_objects(&clear->VAO, &clear->VBO, false, 3, 0, 4);
 
-      /* create vertex array buffer */
-      _mesa_GenBuffers(1, &blit->VBO);
-      _mesa_BindBuffer(GL_ARRAY_BUFFER_ARB, blit->VBO);
-      _mesa_BufferData(GL_ARRAY_BUFFER_ARB, sizeof(verts),
-                          NULL, GL_DYNAMIC_DRAW_ARB);
+   /* GL_COLOR_BUFFER_BIT */
+   if (buffers & BUFFER_BITS_COLOR) {
+      /* leave colormask, glDrawBuffer state as-is */
 
-      /* setup vertex arrays */
-      _mesa_VertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE,
-                                   sizeof(struct vertex), OFFSET(x));
-      _mesa_VertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE,
-                                   sizeof(struct vertex), OFFSET(s));
+      /* Clears never have the color clamped. */
+      if (ctx->Extensions.ARB_color_buffer_float)
+         _mesa_ClampColor(GL_CLAMP_FRAGMENT_COLOR, GL_FALSE);
    }
-
-   /* Generate a relevant fragment shader program for the texture target */
-   if ((target == GL_TEXTURE_2D && blit->ShaderProg != 0) ||
-       (target == GL_TEXTURE_RECTANGLE && blit->RectShaderProg != 0)) {
-      return;
-   }
-
-   mem_ctx = ralloc_context(NULL);
-
-   if (ctx->Const.GLSLVersion < 130) {
-      vs_source =
-         "attribute vec2 position;\n"
-         "attribute vec2 textureCoords;\n"
-         "varying vec2 texCoords;\n"
-         "void main()\n"
-         "{\n"
-         "   texCoords = textureCoords;\n"
-         "   gl_Position = vec4(position, 0.0, 1.0);\n"
-         "}\n";
-
-      fs_source = ralloc_asprintf(mem_ctx,
-                                  "uniform %s texSampler;\n"
-                                  "varying vec2 texCoords;\n"
-                                  "void main()\n"
-                                  "{\n"
-                                  "   gl_FragColor = %s(texSampler, texCoords);\n"
-                                  "   gl_FragDepth = gl_FragColor.r;\n"
-                                  "}\n",
-                                  texture_2d ? "sampler2D" : "sampler2DRect",
-                                  texture_2d ? "texture2D" : "texture2DRect");
-   }
-   else {
-      vs_source = ralloc_asprintf(mem_ctx,
-                                  "#version %s\n"
-                                  "in vec2 position;\n"
-                                  "in vec2 textureCoords;\n"
-                                  "out vec2 texCoords;\n"
-                                  "void main()\n"
-                                  "{\n"
-                                  "   texCoords = textureCoords;\n"
-                                  "   gl_Position = vec4(position, 0.0, 1.0);\n"
-                                  "}\n",
-                                  _mesa_is_desktop_gl(ctx) ? "130" : "300 es");
-      fs_source = ralloc_asprintf(mem_ctx,
-                                  "#version %s\n"
-                                  "uniform %s texSampler;\n"
-                                  "in vec2 texCoords;\n"
-                                  "out vec4 out_color;\n"
-                                  "\n"
-                                  "void main()\n"
-                                  "{\n"
-                                  "   out_color = %s(texSampler, texCoords);\n"
-                                  "   gl_FragDepth = out_color.r;\n"
-                                  "}\n",
-                                  _mesa_is_desktop_gl(ctx) ? "130" : "300 es",
-                                  texture_2d ? "sampler2D" : "sampler2DRect",
-                                  texture_2d ? "texture" : "texture2DRect");
-   }
-
-   vs = compile_shader_with_debug(ctx, GL_VERTEX_SHADER, vs_source);
-   fs = compile_shader_with_debug(ctx, GL_FRAGMENT_SHADER, fs_source);
-
-   ShaderProg = _mesa_CreateProgramObjectARB();
-   _mesa_AttachShader(ShaderProg, fs);
-   _mesa_DeleteObjectARB(fs);
-   _mesa_AttachShader(ShaderProg, vs);
-   _mesa_DeleteObjectARB(vs);
-   _mesa_BindAttribLocation(ShaderProg, 0, "position");
-   _mesa_BindAttribLocation(ShaderProg, 1, "texcoords");
-   _mesa_EnableVertexAttribArray(0);
-   _mesa_EnableVertexAttribArray(1);
-   link_program_with_debug(ctx, ShaderProg);
-   ralloc_free(mem_ctx);
-   if (texture_2d)
-      blit->ShaderProg = ShaderProg;
-   else
-      blit->RectShaderProg = ShaderProg;
-}
-
-/**
- * Try to do a glBlitFramebuffer using no-copy texturing.
- * We can do this when the src renderbuffer is actually a texture.
- * But if the src buffer == dst buffer we cannot do this.
- *
- * \return new buffer mask indicating the buffers left to blit using the
- *         normal path.
- */
-static GLbitfield
-blitframebuffer_texture(struct gl_context *ctx,
-                        GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
-                        GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
-                        GLbitfield mask, GLenum filter, GLint flipX,
-                        GLint flipY, GLboolean glsl_version)
-{
-   if (mask & GL_COLOR_BUFFER_BIT) {
-      const struct gl_framebuffer *drawFb = ctx->DrawBuffer;
-      const struct gl_framebuffer *readFb = ctx->ReadBuffer;
-      const struct gl_renderbuffer_attachment *drawAtt;
-      const struct gl_renderbuffer_attachment *readAtt =
-         &readFb->Attachment[readFb->_ColorReadBufferIndex];
-
-      if (readAtt && readAtt->Texture) {
-         struct blit_state *blit = &ctx->Meta->Blit;
-         const GLint dstX = MIN2(dstX0, dstX1);
-         const GLint dstY = MIN2(dstY0, dstY1);
-         const GLint dstW = abs(dstX1 - dstX0);
-         const GLint dstH = abs(dstY1 - dstY0);
-         const struct gl_texture_object *texObj = readAtt->Texture;
-         const GLuint srcLevel = readAtt->TextureLevel;
-         const GLint baseLevelSave = texObj->BaseLevel;
-         const GLint maxLevelSave = texObj->MaxLevel;
-         const GLenum target = texObj->Target;
-         GLuint sampler, samplerSave =
-            ctx->Texture.Unit[ctx->Texture.CurrentUnit].Sampler ?
-            ctx->Texture.Unit[ctx->Texture.CurrentUnit].Sampler->Name : 0;
-         int i;
-
-         /* Iterate through all draw buffers */
-         for (i = 0; i < ctx->DrawBuffer->_NumColorDrawBuffers; i++) {
-            int idx = ctx->DrawBuffer->_ColorDrawBufferIndexes[i];
-            if (idx == -1)
-               continue;
-            drawAtt = &drawFb->Attachment[idx];
-
-            if (drawAtt->Texture == readAtt->Texture) {
-               /* Can't use same texture as both the source and dest.  We need
-                * to handle overlapping blits and besides, some hw may not
-                * support this.
-                */
-               return mask;
-            }
-         }
-
-         if (target != GL_TEXTURE_2D && target != GL_TEXTURE_RECTANGLE_ARB) {
-            /* Can't handle other texture types at this time */
-            return mask;
-         }
-
-         /* Choose between glsl version and fixed function version of
-          * BlitFramebuffer function.
-          */
-         if (glsl_version) {
-            setup_glsl_blit_framebuffer(ctx, blit, target);
-            if (target == GL_TEXTURE_2D)
-               _mesa_UseProgram(blit->ShaderProg);
-            else
-               _mesa_UseProgram(blit->RectShaderProg);
-         }
-         else {
-            setup_ff_blit_framebuffer(ctx, &ctx->Meta->Blit);
-         }
-
-         _mesa_BindVertexArray(blit->ArrayObj);
-         _mesa_BindBuffer(GL_ARRAY_BUFFER_ARB, blit->VBO);
-
-         _mesa_GenSamplers(1, &sampler);
-         _mesa_BindSampler(ctx->Texture.CurrentUnit, sampler);
-
-         /*
-         printf("Blit from texture!\n");
-         printf("  srcAtt %p  dstAtt %p\n", readAtt, drawAtt);
-         printf("  srcTex %p  dstText %p\n", texObj, drawAtt->Texture);
-         */
-
-         /* Prepare src texture state */
-         _mesa_BindTexture(target, texObj->Name);
-         _mesa_SamplerParameteri(sampler, GL_TEXTURE_MIN_FILTER, filter);
-         _mesa_SamplerParameteri(sampler, GL_TEXTURE_MAG_FILTER, filter);
-         if (target != GL_TEXTURE_RECTANGLE_ARB) {
-            _mesa_TexParameteri(target, GL_TEXTURE_BASE_LEVEL, srcLevel);
-            _mesa_TexParameteri(target, GL_TEXTURE_MAX_LEVEL, srcLevel);
-         }
-         _mesa_SamplerParameteri(sampler, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-         _mesa_SamplerParameteri(sampler, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-
-        /* Always do our blits with no sRGB decode or encode.  Note that
-          * GL_FRAMEBUFFER_SRGB has already been disabled by
-          * _mesa_meta_begin().
-          */
-        if (ctx->Extensions.EXT_texture_sRGB_decode) {
-           _mesa_SamplerParameteri(sampler, GL_TEXTURE_SRGB_DECODE_EXT,
-                               GL_SKIP_DECODE_EXT);
-        }
-
-         if (ctx->API == API_OPENGL_COMPAT || ctx->API == API_OPENGLES) {
-            _mesa_TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
-            _mesa_set_enable(ctx, target, GL_TRUE);
-        }
-
-         /* Prepare vertex data (the VBO was previously created and bound) */
-         {
-            struct vertex {
-               GLfloat x, y, s, t;
-            };
-            struct vertex verts[4];
-            GLfloat s0, t0, s1, t1;
-
-            if (target == GL_TEXTURE_2D) {
-               const struct gl_texture_image *texImage
-                   = _mesa_select_tex_image(ctx, texObj, target, srcLevel);
-               s0 = srcX0 / (float) texImage->Width;
-               s1 = srcX1 / (float) texImage->Width;
-               t0 = srcY0 / (float) texImage->Height;
-               t1 = srcY1 / (float) texImage->Height;
-            }
-            else {
-               assert(target == GL_TEXTURE_RECTANGLE_ARB);
-               s0 = srcX0;
-               s1 = srcX1;
-               t0 = srcY0;
-               t1 = srcY1;
-            }
-
-            /* setup vertex positions */
-            verts[0].x = -1.0F * flipX;
-            verts[0].y = -1.0F * flipY;
-            verts[1].x =  1.0F * flipX;
-            verts[1].y = -1.0F * flipY;
-            verts[2].x =  1.0F * flipX;
-            verts[2].y =  1.0F * flipY;
-            verts[3].x = -1.0F * flipX;
-            verts[3].y =  1.0F * flipY;
-
-            verts[0].s = s0;
-            verts[0].t = t0;
-            verts[1].s = s1;
-            verts[1].t = t0;
-            verts[2].s = s1;
-            verts[2].t = t1;
-            verts[3].s = s0;
-            verts[3].t = t1;
-
-            _mesa_BufferSubData(GL_ARRAY_BUFFER_ARB, 0, sizeof(verts), verts);
-         }
-
-         /* setup viewport */
-         _mesa_set_viewport(ctx, dstX, dstY, dstW, dstH);
-         _mesa_ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
-         _mesa_DepthMask(GL_FALSE);
-         _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4);
-
-         /* Restore texture object state, the texture binding will
-          * be restored by _mesa_meta_end().
-          */
-         if (target != GL_TEXTURE_RECTANGLE_ARB) {
-            _mesa_TexParameteri(target, GL_TEXTURE_BASE_LEVEL, baseLevelSave);
-            _mesa_TexParameteri(target, GL_TEXTURE_MAX_LEVEL, maxLevelSave);
-         }
-
-         _mesa_BindSampler(ctx->Texture.CurrentUnit, samplerSave);
-         _mesa_DeleteSamplers(1, &sampler);
-
-         /* Done with color buffer */
-         mask &= ~GL_COLOR_BUFFER_BIT;
-      }
-   }
-
-   return mask;
-}
-
-
-/**
- * Meta implementation of ctx->Driver.BlitFramebuffer() in terms
- * of texture mapping and polygon rendering.
- */
-void
-_mesa_meta_BlitFramebuffer(struct gl_context *ctx,
-                           GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
-                           GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
-                           GLbitfield mask, GLenum filter)
-{
-   struct blit_state *blit = &ctx->Meta->Blit;
-   struct temp_texture *tex = get_temp_texture(ctx);
-   struct temp_texture *depthTex = get_temp_depth_texture(ctx);
-   const GLsizei maxTexSize = tex->MaxSize;
-   const GLint srcX = MIN2(srcX0, srcX1);
-   const GLint srcY = MIN2(srcY0, srcY1);
-   const GLint srcW = abs(srcX1 - srcX0);
-   const GLint srcH = abs(srcY1 - srcY0);
-   const GLint dstX = MIN2(dstX0, dstX1);
-   const GLint dstY = MIN2(dstY0, dstY1);
-   const GLint dstW = abs(dstX1 - dstX0);
-   const GLint dstH = abs(dstY1 - dstY0);
-   const GLint srcFlipX = (srcX1 - srcX0) / srcW;
-   const GLint srcFlipY = (srcY1 - srcY0) / srcH;
-   const GLint dstFlipX = (dstX1 - dstX0) / dstW;
-   const GLint dstFlipY = (dstY1 - dstY0) / dstH;
-   const GLint flipX = srcFlipX * dstFlipX;
-   const GLint flipY = srcFlipY * dstFlipY;
-
-   struct vertex {
-      GLfloat x, y, s, t;
-   };
-   struct vertex verts[4];
-   GLboolean newTex;
-   const GLboolean use_glsl_version = ctx->Extensions.ARB_vertex_shader &&
-                                      ctx->Extensions.ARB_fragment_shader &&
-                                      (ctx->API != API_OPENGLES);
-
-   /* In addition to falling back if the blit size is larger than the maximum
-    * texture size, fallback if the source is multisampled.  This fallback can
-    * be removed once Mesa gets support ARB_texture_multisample.
-    */
-   if (srcW > maxTexSize || srcH > maxTexSize
-       || ctx->ReadBuffer->Visual.samples > 0) {
-      /* XXX avoid this fallback */
-      _swrast_BlitFramebuffer(ctx, srcX0, srcY0, srcX1, srcY1,
-                              dstX0, dstY0, dstX1, dstY1, mask, filter);
-      return;
-   }
-
-   /* only scissor effects blit so save/clear all other relevant state */
-   _mesa_meta_begin(ctx, ~MESA_META_SCISSOR);
-
-   /* Try faster, direct texture approach first */
-   mask = blitframebuffer_texture(ctx, srcX0, srcY0, srcX1, srcY1,
-                                  dstX0, dstY0, dstX1, dstY1, mask, filter,
-                                  dstFlipX, dstFlipY, use_glsl_version);
-   if (mask == 0x0) {
-      _mesa_meta_end(ctx);
-      return;
-   }
-
-   /* Choose between glsl version and fixed function version of
-    * BlitFramebuffer function.
-    */
-   if (use_glsl_version) {
-      setup_glsl_blit_framebuffer(ctx, blit, tex->Target);
-      if (tex->Target == GL_TEXTURE_2D)
-         _mesa_UseProgram(blit->ShaderProg);
-      else
-         _mesa_UseProgram(blit->RectShaderProg);
-   }
-   else {
-      setup_ff_blit_framebuffer(ctx, blit);
-   }
-
-   _mesa_BindVertexArray(blit->ArrayObj);
-   _mesa_BindBuffer(GL_ARRAY_BUFFER_ARB, blit->VBO);
-
-   /* Continue with "normal" approach which involves copying the src rect
-    * into a temporary texture and is "blitted" by drawing a textured quad.
-    */
-   {
-      /* setup vertex positions */
-      verts[0].x = -1.0F * flipX;
-      verts[0].y = -1.0F * flipY;
-      verts[1].x =  1.0F * flipX;
-      verts[1].y = -1.0F * flipY;
-      verts[2].x =  1.0F * flipX;
-      verts[2].y =  1.0F * flipY;
-      verts[3].x = -1.0F * flipX;
-      verts[3].y =  1.0F * flipY;
-
-   }
-
-   /* glEnable() in gles2 and gles3 doesn't allow GL_TEXTURE_{1D, 2D, etc.}
-    * tokens.
-    */
-   if (_mesa_is_desktop_gl(ctx) || ctx->API == API_OPENGLES)
-      _mesa_set_enable(ctx, tex->Target, GL_TRUE);
-
-   if (mask & GL_COLOR_BUFFER_BIT) {
-      const struct gl_framebuffer *readFb = ctx->ReadBuffer;
-      const struct gl_renderbuffer *colorReadRb = readFb->_ColorReadBuffer;
-      const GLenum rb_base_format =
-         _mesa_base_tex_format(ctx, colorReadRb->InternalFormat);
-
-      /* Using  the exact source rectangle to create the texture does incorrect
-       * linear filtering along the edges. So, allocate the texture extended along
-       * edges by one pixel in x, y directions.
-       */
-      newTex = alloc_texture(tex, srcW + 2, srcH + 2, rb_base_format);
-      setup_copypix_texture(ctx, tex, newTex,
-                            srcX - 1, srcY - 1, srcW + 2, srcH + 2,
-                            rb_base_format, filter);
-      /* texcoords (after texture allocation!) */
-      {
-         verts[0].s = 1.0F;
-         verts[0].t = 1.0F;
-         verts[1].s = tex->Sright - 1.0F;
-         verts[1].t = 1.0F;
-         verts[2].s = tex->Sright - 1.0F;
-         verts[2].t = tex->Ttop - 1.0F;
-         verts[3].s = 1.0F;
-         verts[3].t = tex->Ttop - 1.0F;
-
-         /* upload new vertex data */
-         _mesa_BufferSubData(GL_ARRAY_BUFFER_ARB, 0, sizeof(verts), verts);
-      }
-
-      _mesa_set_viewport(ctx, dstX, dstY, dstW, dstH);
-      _mesa_ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
-      _mesa_set_enable(ctx, GL_DEPTH_TEST, GL_FALSE);
-      _mesa_DepthMask(GL_FALSE);
-      _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4);
-      mask &= ~GL_COLOR_BUFFER_BIT;
-   }
-
-   if ((mask & GL_DEPTH_BUFFER_BIT) &&
-       _mesa_is_desktop_gl(ctx) &&
-       ctx->Extensions.ARB_depth_texture &&
-       ctx->Extensions.ARB_fragment_program) {
-
-      GLuint *tmp = malloc(srcW * srcH * sizeof(GLuint));
-
-      if (tmp) {
-
-         newTex = alloc_texture(depthTex, srcW, srcH, GL_DEPTH_COMPONENT);
-         _mesa_ReadPixels(srcX, srcY, srcW, srcH, GL_DEPTH_COMPONENT,
-                          GL_UNSIGNED_INT, tmp);
-         setup_drawpix_texture(ctx, depthTex, newTex, GL_DEPTH_COMPONENT,
-                               srcW, srcH, GL_DEPTH_COMPONENT,
-                               GL_UNSIGNED_INT, tmp);
-
-         /* texcoords (after texture allocation!) */
-         {
-            verts[0].s = 0.0F;
-            verts[0].t = 0.0F;
-            verts[1].s = depthTex->Sright;
-            verts[1].t = 0.0F;
-            verts[2].s = depthTex->Sright;
-            verts[2].t = depthTex->Ttop;
-            verts[3].s = 0.0F;
-            verts[3].t = depthTex->Ttop;
-
-            /* upload new vertex data */
-            _mesa_BufferSubData(GL_ARRAY_BUFFER_ARB, 0, sizeof(verts), verts);
-         }
-
-         if (!blit->DepthFP)
-            init_blit_depth_pixels(ctx);
-
-         _mesa_BindProgramARB(GL_FRAGMENT_PROGRAM_ARB, blit->DepthFP);
-         _mesa_set_enable(ctx, GL_FRAGMENT_PROGRAM_ARB, GL_TRUE);
-         _mesa_ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
-         _mesa_set_enable(ctx, GL_DEPTH_TEST, GL_TRUE);
-         _mesa_DepthFunc(GL_ALWAYS);
-         _mesa_DepthMask(GL_TRUE);
-
-         _mesa_set_viewport(ctx, dstX, dstY, dstW, dstH);
-         _mesa_BufferSubData(GL_ARRAY_BUFFER_ARB, 0, sizeof(verts), verts);
-         _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4);
-         mask &= ~GL_DEPTH_BUFFER_BIT;
-
-         free(tmp);
-      }
-   }
-
-   if (mask & GL_STENCIL_BUFFER_BIT) {
-      /* XXX can't easily do stencil */
-   }
-
-   if (_mesa_is_desktop_gl(ctx) || ctx->API == API_OPENGLES)
-      _mesa_set_enable(ctx, tex->Target, GL_FALSE);
-
-   _mesa_meta_end(ctx);
-
-   if (mask) {
-      _swrast_BlitFramebuffer(ctx, srcX0, srcY0, srcX1, srcY1,
-                              dstX0, dstY0, dstX1, dstY1, mask, filter);
-   }
-}
-
-static void
-meta_glsl_blit_cleanup(struct gl_context *ctx, struct blit_state *blit)
-{
-   if (blit->ArrayObj) {
-      _mesa_DeleteVertexArrays(1, &blit->ArrayObj);
-      blit->ArrayObj = 0;
-      _mesa_DeleteBuffers(1, &blit->VBO);
-      blit->VBO = 0;
-   }
-   if (blit->DepthFP) {
-      _mesa_DeleteProgramsARB(1, &blit->DepthFP);
-      blit->DepthFP = 0;
-   }
-
-   _mesa_DeleteObjectARB(blit->ShaderProg);
-   blit->ShaderProg = 0;
-   _mesa_DeleteObjectARB(blit->RectShaderProg);
-   blit->RectShaderProg = 0;
-
-   _mesa_DeleteTextures(1, &blit->depthTex.TexObj);
-   blit->depthTex.TexObj = 0;
-}
-
-
-/**
- * Meta implementation of ctx->Driver.Clear() in terms of polygon rendering.
- */
-void
-_mesa_meta_Clear(struct gl_context *ctx, GLbitfield buffers)
-{
-   struct clear_state *clear = &ctx->Meta->Clear;
-   struct vertex {
-      GLfloat x, y, z, r, g, b, a;
-   };
-   struct vertex verts[4];
-   /* save all state but scissor, pixel pack/unpack */
-   GLbitfield metaSave = (MESA_META_ALL -
-                         MESA_META_SCISSOR -
-                         MESA_META_PIXEL_STORE -
-                         MESA_META_CONDITIONAL_RENDER -
-                          MESA_META_FRAMEBUFFER_SRGB);
-   const GLuint stencilMax = (1 << ctx->DrawBuffer->Visual.stencilBits) - 1;
-
-   if (buffers & BUFFER_BITS_COLOR) {
-      /* if clearing color buffers, don't save/restore colormask */
-      metaSave -= MESA_META_COLOR_MASK;
-   }
-
-   _mesa_meta_begin(ctx, metaSave);
-
-   if (clear->ArrayObj == 0) {
-      /* one-time setup */
-
-      /* create vertex array object */
-      _mesa_GenVertexArrays(1, &clear->ArrayObj);
-      _mesa_BindVertexArray(clear->ArrayObj);
-
-      /* create vertex array buffer */
-      _mesa_GenBuffers(1, &clear->VBO);
-      _mesa_BindBuffer(GL_ARRAY_BUFFER_ARB, clear->VBO);
-
-      /* setup vertex arrays */
-      _mesa_VertexPointer(3, GL_FLOAT, sizeof(struct vertex), OFFSET(x));
-      _mesa_ColorPointer(4, GL_FLOAT, sizeof(struct vertex), OFFSET(r));
-      _mesa_EnableClientState(GL_VERTEX_ARRAY);
-      _mesa_EnableClientState(GL_COLOR_ARRAY);
-   }
-   else {
-      _mesa_BindVertexArray(clear->ArrayObj);
-      _mesa_BindBuffer(GL_ARRAY_BUFFER_ARB, clear->VBO);
-   }
-
-   /* GL_COLOR_BUFFER_BIT */
-   if (buffers & BUFFER_BITS_COLOR) {
-      /* leave colormask, glDrawBuffer state as-is */
-
-      /* Clears never have the color clamped. */
-      if (ctx->Extensions.ARB_color_buffer_float)
-         _mesa_ClampColor(GL_CLAMP_FRAGMENT_COLOR, GL_FALSE);
-   }
-   else {
-      ASSERT(metaSave & MESA_META_COLOR_MASK);
-      _mesa_ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
+   else {
+      ASSERT(metaSave & MESA_META_COLOR_MASK);
+      _mesa_ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
    }
 
    /* GL_DEPTH_BUFFER_BIT */
@@ -2138,48 +1470,63 @@ meta_glsl_clear_init(struct gl_context *ctx, struct clear_state *clear)
       "{\n"
       "   gl_Position = position;\n"
       "}\n";
+   const char *gs_source =
+      "#version 150\n"
+      "layout(triangles) in;\n"
+      "layout(triangle_strip, max_vertices = 4) out;\n"
+      "uniform int layer;\n"
+      "void main()\n"
+      "{\n"
+      "  for (int i = 0; i < 3; i++) {\n"
+      "    gl_Layer = layer;\n"
+      "    gl_Position = gl_in[i].gl_Position;\n"
+      "    EmitVertex();\n"
+      "  }\n"
+      "}\n";
    const char *fs_source =
       "uniform vec4 color;\n"
       "void main()\n"
       "{\n"
       "   gl_FragColor = color;\n"
       "}\n";
-   GLuint vs, fs;
+   GLuint vs, gs = 0, fs;
    bool has_integer_textures;
 
-   if (clear->ArrayObj != 0)
-      return;
-
-   /* create vertex array object */
-   _mesa_GenVertexArrays(1, &clear->ArrayObj);
-   _mesa_BindVertexArray(clear->ArrayObj);
+   _mesa_meta_setup_vertex_objects(&clear->VAO, &clear->VBO, true, 3, 0, 0);
 
-   /* create vertex array buffer */
-   _mesa_GenBuffers(1, &clear->VBO);
-   _mesa_BindBuffer(GL_ARRAY_BUFFER_ARB, clear->VBO);
-
-   /* setup vertex arrays */
-   _mesa_VertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void *)0);
-   _mesa_EnableVertexAttribArray(0);
+   if (clear->ShaderProg != 0)
+      return;
 
-   vs = _mesa_CreateShaderObjectARB(GL_VERTEX_SHADER);
+   vs = _mesa_CreateShader(GL_VERTEX_SHADER);
    _mesa_ShaderSource(vs, 1, &vs_source, NULL);
    _mesa_CompileShader(vs);
 
-   fs = _mesa_CreateShaderObjectARB(GL_FRAGMENT_SHADER);
+   if (_mesa_has_geometry_shaders(ctx)) {
+      gs = _mesa_CreateShader(GL_GEOMETRY_SHADER);
+      _mesa_ShaderSource(gs, 1, &gs_source, NULL);
+      _mesa_CompileShader(gs);
+   }
+
+   fs = _mesa_CreateShader(GL_FRAGMENT_SHADER);
    _mesa_ShaderSource(fs, 1, &fs_source, NULL);
    _mesa_CompileShader(fs);
 
-   clear->ShaderProg = _mesa_CreateProgramObjectARB();
+   clear->ShaderProg = _mesa_CreateProgram();
    _mesa_AttachShader(clear->ShaderProg, fs);
-   _mesa_DeleteObjectARB(fs);
+   _mesa_DeleteShader(fs);
+   if (gs != 0)
+      _mesa_AttachShader(clear->ShaderProg, gs);
    _mesa_AttachShader(clear->ShaderProg, vs);
-   _mesa_DeleteObjectARB(vs);
+   _mesa_DeleteShader(vs);
    _mesa_BindAttribLocation(clear->ShaderProg, 0, "position");
    _mesa_LinkProgram(clear->ShaderProg);
 
    clear->ColorLocation = _mesa_GetUniformLocation(clear->ShaderProg,
                                                      "color");
+   if (gs != 0) {
+      clear->LayerLocation = _mesa_GetUniformLocation(clear->ShaderProg,
+                                                     "layer");
+   }
 
    has_integer_textures = _mesa_is_gles3(ctx) ||
       (_mesa_is_desktop_gl(ctx) && ctx->Const.GLSLVersion >= 130);
@@ -2188,34 +1535,36 @@ meta_glsl_clear_init(struct gl_context *ctx, struct clear_state *clear)
       void *shader_source_mem_ctx = ralloc_context(NULL);
       const char *vs_int_source =
          ralloc_asprintf(shader_source_mem_ctx,
-                         "#version %s\n"
+                         "#version 130\n"
                          "in vec4 position;\n"
                          "void main()\n"
                          "{\n"
                          "   gl_Position = position;\n"
-                         "}\n",
-                         _mesa_is_desktop_gl(ctx) ? "130" : "300 es");
+                         "}\n");
       const char *fs_int_source =
          ralloc_asprintf(shader_source_mem_ctx,
-                         "#version %s\n"
+                         "#version 130\n"
                          "uniform ivec4 color;\n"
                          "out ivec4 out_color;\n"
                          "\n"
                          "void main()\n"
                          "{\n"
                          "   out_color = color;\n"
-                         "}\n",
-                         _mesa_is_desktop_gl(ctx) ? "130" : "300 es");
+                         "}\n");
 
-      vs = compile_shader_with_debug(ctx, GL_VERTEX_SHADER, vs_int_source);
-      fs = compile_shader_with_debug(ctx, GL_FRAGMENT_SHADER, fs_int_source);
+      vs = _mesa_meta_compile_shader_with_debug(ctx, GL_VERTEX_SHADER,
+                                                vs_int_source);
+      fs = _mesa_meta_compile_shader_with_debug(ctx, GL_FRAGMENT_SHADER,
+                                                fs_int_source);
       ralloc_free(shader_source_mem_ctx);
 
-      clear->IntegerShaderProg = _mesa_CreateProgramObjectARB();
+      clear->IntegerShaderProg = _mesa_CreateProgram();
       _mesa_AttachShader(clear->IntegerShaderProg, fs);
-      _mesa_DeleteObjectARB(fs);
+      _mesa_DeleteShader(fs);
+      if (gs != 0)
+         _mesa_AttachShader(clear->IntegerShaderProg, gs);
       _mesa_AttachShader(clear->IntegerShaderProg, vs);
-      _mesa_DeleteObjectARB(vs);
+      _mesa_DeleteShader(vs);
       _mesa_BindAttribLocation(clear->IntegerShaderProg, 0, "position");
 
       /* Note that user-defined out attributes get automatically assigned
@@ -2223,27 +1572,35 @@ meta_glsl_clear_init(struct gl_context *ctx, struct clear_state *clear)
        * BindFragDataLocation to 0.
        */
 
-      link_program_with_debug(ctx, clear->IntegerShaderProg);
+      _mesa_ObjectLabel(GL_PROGRAM, clear->IntegerShaderProg, -1,
+                        "integer clear");
+      _mesa_meta_link_program_with_debug(ctx, clear->IntegerShaderProg);
 
       clear->IntegerColorLocation =
         _mesa_GetUniformLocation(clear->IntegerShaderProg, "color");
+      if (gs != 0) {
+         clear->IntegerLayerLocation =
+            _mesa_GetUniformLocation(clear->IntegerShaderProg, "layer");
+      }
    }
+   if (gs != 0)
+      _mesa_DeleteShader(gs);
 }
 
 static void
-meta_glsl_clear_cleanup(struct gl_context *ctx, struct clear_state *clear)
+meta_glsl_clear_cleanup(struct clear_state *clear)
 {
-   if (clear->ArrayObj == 0)
+   if (clear->VAO == 0)
       return;
-   _mesa_DeleteVertexArrays(1, &clear->ArrayObj);
-   clear->ArrayObj = 0;
+   _mesa_DeleteVertexArrays(1, &clear->VAO);
+   clear->VAO = 0;
    _mesa_DeleteBuffers(1, &clear->VBO);
    clear->VBO = 0;
-   _mesa_DeleteObjectARB(clear->ShaderProg);
+   _mesa_DeleteProgram(clear->ShaderProg);
    clear->ShaderProg = 0;
 
    if (clear->IntegerShaderProg) {
-      _mesa_DeleteObjectARB(clear->IntegerShaderProg);
+      _mesa_DeleteProgram(clear->IntegerShaderProg);
       clear->IntegerShaderProg = 0;
    }
 }
@@ -2263,9 +1620,7 @@ _mesa_meta_glsl_Clear(struct gl_context *ctx, GLbitfield buffers)
    const float x1 = ((float)fb->_Xmax / fb->Width)  * 2.0f - 1.0f;
    const float y1 = ((float)fb->_Ymax / fb->Height) * 2.0f - 1.0f;
    const float z = -invert_z(ctx->Depth.Clear);
-   struct vertex {
-      GLfloat x, y, z;
-   } verts[4];
+   struct vertex verts[4];
 
    metaSave = (MESA_META_ALPHA_TEST |
               MESA_META_BLEND |
@@ -2301,9 +1656,6 @@ _mesa_meta_glsl_Clear(struct gl_context *ctx, GLbitfield buffers)
                          ctx->Color.ClearColor.f);
    }
 
-   _mesa_BindVertexArray(clear->ArrayObj);
-   _mesa_BindBuffer(GL_ARRAY_BUFFER_ARB, clear->VBO);
-
    /* GL_COLOR_BUFFER_BIT */
    if (buffers & BUFFER_BITS_COLOR) {
       /* leave colormask, glDrawBuffer state as-is */
@@ -2358,8 +1710,19 @@ _mesa_meta_glsl_Clear(struct gl_context *ctx, GLbitfield buffers)
    _mesa_BufferData(GL_ARRAY_BUFFER_ARB, sizeof(verts), verts,
                       GL_DYNAMIC_DRAW_ARB);
 
-   /* draw quad */
-   _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4);
+   /* draw quad(s) */
+   if (fb->MaxNumLayers > 0) {
+      unsigned layer;
+      for (layer = 0; layer < fb->MaxNumLayers; layer++) {
+         if (fb->_IntegerColor)
+            _mesa_Uniform1i(clear->IntegerLayerLocation, layer);
+         else
+            _mesa_Uniform1i(clear->LayerLocation, layer);
+         _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4);
+      }
+   } else {
+      _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4);
+   }
 
    _mesa_meta_end(ctx);
 }
@@ -2374,13 +1737,8 @@ _mesa_meta_CopyPixels(struct gl_context *ctx, GLint srcX, GLint srcY,
                       GLint dstX, GLint dstY, GLenum type)
 {
    struct copypix_state *copypix = &ctx->Meta->CopyPix;
-   struct temp_texture *tex = get_temp_texture(ctx);
-   struct vertex {
-      GLfloat x, y, z, s, t;
-   };
+   struct temp_texture *tex = _mesa_meta_get_temp_texture(ctx);
    struct vertex verts[4];
-   GLboolean newTex;
-   GLenum intFormat = GL_RGBA;
 
    if (type != GL_COLOR ||
        ctx->_ImageTransferState ||
@@ -2403,31 +1761,15 @@ _mesa_meta_CopyPixels(struct gl_context *ctx, GLint srcX, GLint srcY,
                           MESA_META_VERTEX |
                           MESA_META_VIEWPORT));
 
-   if (copypix->ArrayObj == 0) {
-      /* one-time setup */
-
-      /* create vertex array object */
-      _mesa_GenVertexArrays(1, &copypix->ArrayObj);
-      _mesa_BindVertexArray(copypix->ArrayObj);
+   _mesa_meta_setup_vertex_objects(&copypix->VAO, &copypix->VBO, false,
+                                   3, 2, 0);
 
-      /* create vertex array buffer */
-      _mesa_GenBuffers(1, &copypix->VBO);
-      _mesa_BindBuffer(GL_ARRAY_BUFFER_ARB, copypix->VBO);
-      _mesa_BufferData(GL_ARRAY_BUFFER_ARB, sizeof(verts),
-                          NULL, GL_DYNAMIC_DRAW_ARB);
+   /* Silence valgrind warnings about reading uninitialized stack. */
+   memset(verts, 0, sizeof(verts));
 
-      /* setup vertex arrays */
-      _mesa_VertexPointer(3, GL_FLOAT, sizeof(struct vertex), OFFSET(x));
-      _mesa_TexCoordPointer(2, GL_FLOAT, sizeof(struct vertex), OFFSET(s));
-      _mesa_EnableClientState(GL_VERTEX_ARRAY);
-      _mesa_EnableClientState(GL_TEXTURE_COORD_ARRAY);
-   }
-   else {
-      _mesa_BindVertexArray(copypix->ArrayObj);
-      _mesa_BindBuffer(GL_ARRAY_BUFFER_ARB, copypix->VBO);
-   }
-
-   newTex = alloc_texture(tex, width, height, intFormat);
+   /* Alloc/setup texture */
+   _mesa_meta_setup_copypix_texture(ctx, tex, srcX, srcY, width, height,
+                                    GL_RGBA, GL_NEAREST);
 
    /* vertex positions, texcoords (after texture allocation!) */
    {
@@ -2440,32 +1782,28 @@ _mesa_meta_CopyPixels(struct gl_context *ctx, GLint srcX, GLint srcY,
       verts[0].x = dstX0;
       verts[0].y = dstY0;
       verts[0].z = z;
-      verts[0].s = 0.0F;
-      verts[0].t = 0.0F;
+      verts[0].tex[0] = 0.0F;
+      verts[0].tex[1] = 0.0F;
       verts[1].x = dstX1;
       verts[1].y = dstY0;
       verts[1].z = z;
-      verts[1].s = tex->Sright;
-      verts[1].t = 0.0F;
+      verts[1].tex[0] = tex->Sright;
+      verts[1].tex[1] = 0.0F;
       verts[2].x = dstX1;
       verts[2].y = dstY1;
       verts[2].z = z;
-      verts[2].s = tex->Sright;
-      verts[2].t = tex->Ttop;
+      verts[2].tex[0] = tex->Sright;
+      verts[2].tex[1] = tex->Ttop;
       verts[3].x = dstX0;
       verts[3].y = dstY1;
       verts[3].z = z;
-      verts[3].s = 0.0F;
-      verts[3].t = tex->Ttop;
+      verts[3].tex[0] = 0.0F;
+      verts[3].tex[1] = tex->Ttop;
 
       /* upload new vertex data */
       _mesa_BufferSubData(GL_ARRAY_BUFFER_ARB, 0, sizeof(verts), verts);
    }
 
-   /* Alloc/setup texture */
-   setup_copypix_texture(ctx, tex, newTex, srcX, srcY, width, height,
-                         GL_RGBA, GL_NEAREST);
-
    _mesa_set_enable(ctx, tex->Target, GL_TRUE);
 
    /* draw textured quad */
@@ -2476,7 +1814,27 @@ _mesa_meta_CopyPixels(struct gl_context *ctx, GLint srcX, GLint srcY,
    _mesa_meta_end(ctx);
 }
 
+static void
+meta_drawpix_cleanup(struct drawpix_state *drawpix)
+{
+   if (drawpix->VAO != 0) {
+      _mesa_DeleteVertexArrays(1, &drawpix->VAO);
+      drawpix->VAO = 0;
+
+      _mesa_DeleteBuffers(1, &drawpix->VBO);
+      drawpix->VBO = 0;
+   }
+
+   if (drawpix->StencilFP != 0) {
+      _mesa_DeleteProgramsARB(1, &drawpix->StencilFP);
+      drawpix->StencilFP = 0;
+   }
 
+   if (drawpix->DepthFP != 0) {
+      _mesa_DeleteProgramsARB(1, &drawpix->DepthFP);
+      drawpix->DepthFP = 0;
+   }
+}
 
 /**
  * When the glDrawPixels() image size is greater than the max rectangle
@@ -2560,7 +1918,7 @@ init_draw_stencil_pixels(struct gl_context *ctx)
       "END \n";
    char program2[1000];
    struct drawpix_state *drawpix = &ctx->Meta->DrawPix;
-   struct temp_texture *tex = get_temp_texture(ctx);
+   struct temp_texture *tex = _mesa_meta_get_temp_texture(ctx);
    const char *texTarget;
 
    assert(drawpix->StencilFP == 0);
@@ -2594,7 +1952,7 @@ init_draw_depth_pixels(struct gl_context *ctx)
       "END \n";
    char program2[200];
    struct drawpix_state *drawpix = &ctx->Meta->DrawPix;
-   struct temp_texture *tex = get_temp_texture(ctx);
+   struct temp_texture *tex = _mesa_meta_get_temp_texture(ctx);
    const char *texTarget;
 
    assert(drawpix->DepthFP == 0);
@@ -2626,17 +1984,13 @@ _mesa_meta_DrawPixels(struct gl_context *ctx,
                       const GLvoid *pixels)
 {
    struct drawpix_state *drawpix = &ctx->Meta->DrawPix;
-   struct temp_texture *tex = get_temp_texture(ctx);
+   struct temp_texture *tex = _mesa_meta_get_temp_texture(ctx);
    const struct gl_pixelstore_attrib unpackSave = ctx->Unpack;
    const GLuint origStencilMask = ctx->Stencil.WriteMask[0];
-   struct vertex {
-      GLfloat x, y, z, s, t;
-   };
    struct vertex verts[4];
    GLenum texIntFormat;
    GLboolean fallback, newTex;
    GLbitfield metaExtraSave = 0x0;
-   GLuint vbo;
 
    /*
     * Determine if we can do the glDrawPixels with texture mapping.
@@ -2726,7 +2080,13 @@ _mesa_meta_DrawPixels(struct gl_context *ctx,
                           MESA_META_VIEWPORT |
                           metaExtraSave));
 
-   newTex = alloc_texture(tex, width, height, texIntFormat);
+   newTex = _mesa_meta_alloc_texture(tex, width, height, texIntFormat);
+
+   _mesa_meta_setup_vertex_objects(&drawpix->VAO, &drawpix->VBO, false,
+                                   3, 2, 0);
+
+   /* Silence valgrind warnings about reading uninitialized stack. */
+   memset(verts, 0, sizeof(verts));
 
    /* vertex positions, texcoords (after texture allocation!) */
    {
@@ -2739,43 +2099,29 @@ _mesa_meta_DrawPixels(struct gl_context *ctx,
       verts[0].x = x0;
       verts[0].y = y0;
       verts[0].z = z;
-      verts[0].s = 0.0F;
-      verts[0].t = 0.0F;
+      verts[0].tex[0] = 0.0F;
+      verts[0].tex[1] = 0.0F;
       verts[1].x = x1;
       verts[1].y = y0;
       verts[1].z = z;
-      verts[1].s = tex->Sright;
-      verts[1].t = 0.0F;
+      verts[1].tex[0] = tex->Sright;
+      verts[1].tex[1] = 0.0F;
       verts[2].x = x1;
       verts[2].y = y1;
       verts[2].z = z;
-      verts[2].s = tex->Sright;
-      verts[2].t = tex->Ttop;
+      verts[2].tex[0] = tex->Sright;
+      verts[2].tex[1] = tex->Ttop;
       verts[3].x = x0;
       verts[3].y = y1;
       verts[3].z = z;
-      verts[3].s = 0.0F;
-      verts[3].t = tex->Ttop;
-   }
-
-   if (drawpix->ArrayObj == 0) {
-      /* one-time setup: create vertex array object */
-      _mesa_GenVertexArrays(1, &drawpix->ArrayObj);
+      verts[3].tex[0] = 0.0F;
+      verts[3].tex[1] = tex->Ttop;
    }
-   _mesa_BindVertexArray(drawpix->ArrayObj);
 
-   /* create vertex array buffer */
-   _mesa_GenBuffers(1, &vbo);
-   _mesa_BindBuffer(GL_ARRAY_BUFFER_ARB, vbo);
+   /* upload new vertex data */
    _mesa_BufferData(GL_ARRAY_BUFFER_ARB, sizeof(verts),
                        verts, GL_DYNAMIC_DRAW_ARB);
 
-   /* setup vertex arrays */
-   _mesa_VertexPointer(3, GL_FLOAT, sizeof(struct vertex), OFFSET(x));
-   _mesa_TexCoordPointer(2, GL_FLOAT, sizeof(struct vertex), OFFSET(s));
-   _mesa_EnableClientState(GL_VERTEX_ARRAY);
-   _mesa_EnableClientState(GL_TEXTURE_COORD_ARRAY);
-
    /* set given unpack params */
    ctx->Unpack = *unpack;
 
@@ -2788,8 +2134,8 @@ _mesa_meta_DrawPixels(struct gl_context *ctx,
       if (!drawpix->StencilFP)
          init_draw_stencil_pixels(ctx);
 
-      setup_drawpix_texture(ctx, tex, newTex, texIntFormat, width, height,
-                            GL_ALPHA, type, pixels);
+      _mesa_meta_setup_drawpix_texture(ctx, tex, newTex, width, height,
+                                       GL_ALPHA, type, pixels);
 
       _mesa_ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
 
@@ -2813,7 +2159,7 @@ _mesa_meta_DrawPixels(struct gl_context *ctx,
             _mesa_StencilMask(mask);
 
             _mesa_ProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 0,
-                                             255.0 / mask, 0.5, 0.0, 0.0);
+                                             255.0f / mask, 0.5f, 0.0f, 0.0f);
 
             _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4);
          }
@@ -2831,22 +2177,20 @@ _mesa_meta_DrawPixels(struct gl_context *ctx,
       _mesa_ProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, 0,
                                         ctx->Current.RasterColor);
 
-      setup_drawpix_texture(ctx, tex, newTex, texIntFormat, width, height,
-                            format, type, pixels);
+      _mesa_meta_setup_drawpix_texture(ctx, tex, newTex, width, height,
+                                       format, type, pixels);
 
       _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4);
    }
    else {
       /* Drawing RGBA */
-      setup_drawpix_texture(ctx, tex, newTex, texIntFormat, width, height,
-                            format, type, pixels);
+      _mesa_meta_setup_drawpix_texture(ctx, tex, newTex, width, height,
+                                       format, type, pixels);
       _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4);
    }
 
    _mesa_set_enable(ctx, tex->Target, GL_FALSE);
 
-   _mesa_DeleteBuffers(1, &vbo);
-
    /* restore unpack params */
    ctx->Unpack = unpackSave;
 
@@ -2898,9 +2242,6 @@ _mesa_meta_Bitmap(struct gl_context *ctx,
    const GLenum texIntFormat = GL_ALPHA;
    const struct gl_pixelstore_attrib unpackSave = *unpack;
    GLubyte fg, bg;
-   struct vertex {
-      GLfloat x, y, z, s, t, r, g, b, a;
-   };
    struct vertex verts[4];
    GLboolean newTex;
    GLubyte *bitmap8;
@@ -2934,33 +2275,12 @@ _mesa_meta_Bitmap(struct gl_context *ctx,
                           MESA_META_VERTEX |
                           MESA_META_VIEWPORT));
 
-   if (bitmap->ArrayObj == 0) {
-      /* one-time setup */
-
-      /* create vertex array object */
-      _mesa_GenVertexArraysAPPLE(1, &bitmap->ArrayObj);
-      _mesa_BindVertexArrayAPPLE(bitmap->ArrayObj);
-
-      /* create vertex array buffer */
-      _mesa_GenBuffers(1, &bitmap->VBO);
-      _mesa_BindBuffer(GL_ARRAY_BUFFER_ARB, bitmap->VBO);
-      _mesa_BufferData(GL_ARRAY_BUFFER_ARB, sizeof(verts),
-                          NULL, GL_DYNAMIC_DRAW_ARB);
+   _mesa_meta_setup_vertex_objects(&bitmap->VAO, &bitmap->VBO, false, 3, 2, 4);
 
-      /* setup vertex arrays */
-      _mesa_VertexPointer(3, GL_FLOAT, sizeof(struct vertex), OFFSET(x));
-      _mesa_TexCoordPointer(2, GL_FLOAT, sizeof(struct vertex), OFFSET(s));
-      _mesa_ColorPointer(4, GL_FLOAT, sizeof(struct vertex), OFFSET(r));
-      _mesa_EnableClientState(GL_VERTEX_ARRAY);
-      _mesa_EnableClientState(GL_TEXTURE_COORD_ARRAY);
-      _mesa_EnableClientState(GL_COLOR_ARRAY);
-   }
-   else {
-      _mesa_BindVertexArray(bitmap->ArrayObj);
-      _mesa_BindBuffer(GL_ARRAY_BUFFER_ARB, bitmap->VBO);
-   }
+   newTex = _mesa_meta_alloc_texture(tex, width, height, texIntFormat);
 
-   newTex = alloc_texture(tex, width, height, texIntFormat);
+   /* Silence valgrind warnings about reading uninitialized stack. */
+   memset(verts, 0, sizeof(verts));
 
    /* vertex positions, texcoords, colors (after texture allocation!) */
    {
@@ -2974,23 +2294,23 @@ _mesa_meta_Bitmap(struct gl_context *ctx,
       verts[0].x = x0;
       verts[0].y = y0;
       verts[0].z = z;
-      verts[0].s = 0.0F;
-      verts[0].t = 0.0F;
+      verts[0].tex[0] = 0.0F;
+      verts[0].tex[1] = 0.0F;
       verts[1].x = x1;
       verts[1].y = y0;
       verts[1].z = z;
-      verts[1].s = tex->Sright;
-      verts[1].t = 0.0F;
+      verts[1].tex[0] = tex->Sright;
+      verts[1].tex[1] = 0.0F;
       verts[2].x = x1;
       verts[2].y = y1;
       verts[2].z = z;
-      verts[2].s = tex->Sright;
-      verts[2].t = tex->Ttop;
+      verts[2].tex[0] = tex->Sright;
+      verts[2].tex[1] = tex->Ttop;
       verts[3].x = x0;
       verts[3].y = y1;
       verts[3].z = z;
-      verts[3].s = 0.0F;
-      verts[3].t = tex->Ttop;
+      verts[3].tex[0] = 0.0F;
+      verts[3].tex[1] = tex->Ttop;
 
       for (i = 0; i < 4; i++) {
          verts[i].r = ctx->Current.RasterColor[0];
@@ -3024,8 +2344,8 @@ _mesa_meta_Bitmap(struct gl_context *ctx,
       _mesa_set_enable(ctx, GL_ALPHA_TEST, GL_TRUE);
       _mesa_AlphaFunc(GL_NOTEQUAL, UBYTE_TO_FLOAT(bg));
 
-      setup_drawpix_texture(ctx, tex, newTex, texIntFormat, width, height,
-                            GL_ALPHA, GL_UNSIGNED_BYTE, bitmap8);
+      _mesa_meta_setup_drawpix_texture(ctx, tex, newTex, width, height,
+                                       GL_ALPHA, GL_UNSIGNED_BYTE, bitmap8);
 
       _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4);
 
@@ -3039,102 +2359,6 @@ _mesa_meta_Bitmap(struct gl_context *ctx,
    _mesa_meta_end(ctx);
 }
 
-
-/**
- * Check if the call to _mesa_meta_GenerateMipmap() will require a
- * software fallback.  The fallback path will require that the texture
- * images are mapped.
- * \return GL_TRUE if a fallback is needed, GL_FALSE otherwise
- */
-GLboolean
-_mesa_meta_check_generate_mipmap_fallback(struct gl_context *ctx, GLenum target,
-                                          struct gl_texture_object *texObj)
-{
-   const GLuint fboSave = ctx->DrawBuffer->Name;
-   struct gen_mipmap_state *mipmap = &ctx->Meta->Mipmap;
-   struct gl_texture_image *baseImage;
-   GLuint srcLevel;
-   GLenum status;
-
-   /* check for fallbacks */
-   if (target == GL_TEXTURE_3D ||
-       target == GL_TEXTURE_1D_ARRAY ||
-       target == GL_TEXTURE_2D_ARRAY) {
-      _mesa_perf_debug(ctx, MESA_DEBUG_SEVERITY_HIGH,
-                       "glGenerateMipmap() to %s target\n",
-                       _mesa_lookup_enum_by_nr(target));
-      return GL_TRUE;
-   }
-
-   srcLevel = texObj->BaseLevel;
-   baseImage = _mesa_select_tex_image(ctx, texObj, target, srcLevel);
-   if (!baseImage) {
-      _mesa_perf_debug(ctx, MESA_DEBUG_SEVERITY_HIGH,
-                       "glGenerateMipmap() couldn't find base teximage\n");
-      return GL_TRUE;
-   }
-
-   if (_mesa_is_format_compressed(baseImage->TexFormat)) {
-      _mesa_perf_debug(ctx, MESA_DEBUG_SEVERITY_HIGH,
-                       "glGenerateMipmap() with %s format\n",
-                       _mesa_get_format_name(baseImage->TexFormat));
-      return GL_TRUE;
-   }
-
-   if (_mesa_get_format_color_encoding(baseImage->TexFormat) == GL_SRGB &&
-       !ctx->Extensions.EXT_texture_sRGB_decode) {
-      /* The texture format is sRGB but we can't turn off sRGB->linear
-       * texture sample conversion.  So we won't be able to generate the
-       * right colors when rendering.  Need to use a fallback.
-       */
-      _mesa_perf_debug(ctx, MESA_DEBUG_SEVERITY_HIGH,
-                       "glGenerateMipmap() of sRGB texture without "
-                       "sRGB decode\n");
-      return GL_TRUE;
-   }
-
-   /*
-    * Test that we can actually render in the texture's format.
-    */
-   if (!mipmap->FBO)
-      _mesa_GenFramebuffers(1, &mipmap->FBO);
-   _mesa_BindFramebuffer(GL_FRAMEBUFFER_EXT, mipmap->FBO);
-
-   if (target == GL_TEXTURE_1D) {
-      _mesa_FramebufferTexture1D(GL_FRAMEBUFFER_EXT,
-                                    GL_COLOR_ATTACHMENT0_EXT,
-                                    target, texObj->Name, srcLevel);
-   }
-#if 0
-   /* other work is needed to enable 3D mipmap generation */
-   else if (target == GL_TEXTURE_3D) {
-      GLint zoffset = 0;
-      _mesa_FramebufferTexture3D(GL_FRAMEBUFFER_EXT,
-                                    GL_COLOR_ATTACHMENT0_EXT,
-                                    target, texObj->Name, srcLevel, zoffset);
-   }
-#endif
-   else {
-      /* 2D / cube */
-      _mesa_FramebufferTexture2D(GL_FRAMEBUFFER_EXT,
-                                    GL_COLOR_ATTACHMENT0_EXT,
-                                    target, texObj->Name, srcLevel);
-   }
-
-   status = _mesa_CheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
-
-   _mesa_BindFramebuffer(GL_FRAMEBUFFER_EXT, fboSave);
-
-   if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
-      _mesa_perf_debug(ctx, MESA_DEBUG_SEVERITY_HIGH,
-                       "glGenerateMipmap() got incomplete FBO\n");
-      return GL_TRUE;
-   }
-
-   return GL_FALSE;
-}
-
-
 /**
  * Compute the texture coordinates for the four vertices of a quad for
  * drawing a 2D texture image or slice of a cube/3D texture.
@@ -3144,16 +2368,16 @@ _mesa_meta_check_generate_mipmap_fallback(struct gl_context *ctx, GLenum target,
  * \param height  height of the texture image
  * \param coords0/1/2/3  returns the computed texcoords
  */
-static void
-setup_texture_coords(GLenum faceTarget,
-                     GLint slice,
-                     GLint width,
-                     GLint height,
-                     GLint depth,
-                     GLfloat coords0[3],
-                     GLfloat coords1[3],
-                     GLfloat coords2[3],
-                     GLfloat coords3[3])
+void
+_mesa_meta_setup_texture_coords(GLenum faceTarget,
+                                GLint slice,
+                                GLint width,
+                                GLint height,
+                                GLint depth,
+                                GLfloat coords0[4],
+                                GLfloat coords1[4],
+                                GLfloat coords2[4],
+                                GLfloat coords3[4])
 {
    static const GLfloat st[4][2] = {
       {0.0f, 0.0f}, {1.0f, 0.0f}, {1.0f, 1.0f}, {0.0f, 1.0f}
@@ -3161,6 +2385,13 @@ setup_texture_coords(GLenum faceTarget,
    GLuint i;
    GLfloat r;
 
+   /* Currently all texture targets want the W component to be 1.0.
+    */
+   coords0[3] = 1.0F;
+   coords1[3] = 1.0F;
+   coords2[3] = 1.0F;
+   coords3[3] = 1.0F;
+
    switch (faceTarget) {
    case GL_TEXTURE_1D:
    case GL_TEXTURE_2D:
@@ -3172,7 +2403,7 @@ setup_texture_coords(GLenum faceTarget,
          r = (slice + 0.5f) / depth;
       }
       else if (faceTarget == GL_TEXTURE_2D_ARRAY)
-         r = slice;
+         r = (float) slice;
       else
          r = 0.0F;
       coords0[0] = 0.0F; /* s */
@@ -3192,28 +2423,28 @@ setup_texture_coords(GLenum faceTarget,
       coords0[0] = 0.0F; /* s */
       coords0[1] = 0.0F; /* t */
       coords0[2] = 0.0F; /* r */
-      coords1[0] = width;
+      coords1[0] = (float) width;
       coords1[1] = 0.0F;
       coords1[2] = 0.0F;
-      coords2[0] = width;
-      coords2[1] = height;
+      coords2[0] = (float) width;
+      coords2[1] = (float) height;
       coords2[2] = 0.0F;
       coords3[0] = 0.0F;
-      coords3[1] = height;
+      coords3[1] = (float) height;
       coords3[2] = 0.0F;
       break;
    case GL_TEXTURE_1D_ARRAY:
       coords0[0] = 0.0F; /* s */
-      coords0[1] = slice; /* t */
+      coords0[1] = (float) slice; /* t */
       coords0[2] = 0.0F; /* r */
       coords1[0] = 1.0f;
-      coords1[1] = slice;
+      coords1[1] = (float) slice;
       coords1[2] = 0.0F;
       coords2[0] = 1.0F;
-      coords2[1] = slice;
+      coords2[1] = (float) slice;
       coords2[2] = 0.0F;
       coords3[0] = 0.0F;
-      coords3[1] = slice;
+      coords3[1] = (float) slice;
       coords3[2] = 0.0F;
       break;
 
@@ -3251,6 +2482,8 @@ setup_texture_coords(GLenum faceTarget,
             assert(0);
          }
 
+         coord[3] = (float) (slice / 6);
+
          switch (faceTarget) {
          case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
             coord[0] = 1.0f;
@@ -3288,79 +2521,57 @@ setup_texture_coords(GLenum faceTarget,
       }
       break;
    default:
-      assert(0 && "unexpected target in meta setup_texture_coords()");
-   }
-}
-
-
-static void
-setup_ff_generate_mipmap(struct gl_context *ctx,
-                         struct gen_mipmap_state *mipmap)
-{
-   struct vertex {
-      GLfloat x, y, tex[3];
-   };
-
-   if (mipmap->ArrayObj == 0) {
-      /* one-time setup */
-      /* create vertex array object */
-      _mesa_GenVertexArraysAPPLE(1, &mipmap->ArrayObj);
-      _mesa_BindVertexArrayAPPLE(mipmap->ArrayObj);
-
-      /* create vertex array buffer */
-      _mesa_GenBuffers(1, &mipmap->VBO);
-      _mesa_BindBuffer(GL_ARRAY_BUFFER_ARB, mipmap->VBO);
-      /* setup vertex arrays */
-      _mesa_VertexPointer(2, GL_FLOAT, sizeof(struct vertex), OFFSET(x));
-      _mesa_TexCoordPointer(3, GL_FLOAT, sizeof(struct vertex), OFFSET(tex));
-      _mesa_EnableClientState(GL_VERTEX_ARRAY);
-      _mesa_EnableClientState(GL_TEXTURE_COORD_ARRAY);
+      assert(!"unexpected target in _mesa_meta_setup_texture_coords()");
    }
-
-   /* setup projection matrix */
-   _mesa_MatrixMode(GL_PROJECTION);
-   _mesa_LoadIdentity();
-   _mesa_Ortho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
 }
 
-
-static struct glsl_sampler *
-setup_texture_sampler(GLenum target, struct gen_mipmap_state *mipmap)
+static struct blit_shader *
+choose_blit_shader(GLenum target, struct blit_shader_table *table)
 {
    switch(target) {
    case GL_TEXTURE_1D:
-      mipmap->sampler_1d.type = "sampler1D";
-      mipmap->sampler_1d.func = "texture1D";
-      mipmap->sampler_1d.texcoords = "texCoords.x";
-      return &mipmap->sampler_1d;
+      table->sampler_1d.type = "sampler1D";
+      table->sampler_1d.func = "texture1D";
+      table->sampler_1d.texcoords = "texCoords.x";
+      return &table->sampler_1d;
    case GL_TEXTURE_2D:
-      mipmap->sampler_2d.type = "sampler2D";
-      mipmap->sampler_2d.func = "texture2D";
-      mipmap->sampler_2d.texcoords = "texCoords.xy";
-      return &mipmap->sampler_2d;
+      table->sampler_2d.type = "sampler2D";
+      table->sampler_2d.func = "texture2D";
+      table->sampler_2d.texcoords = "texCoords.xy";
+      return &table->sampler_2d;
+   case GL_TEXTURE_RECTANGLE:
+      table->sampler_rect.type = "sampler2DRect";
+      table->sampler_rect.func = "texture2DRect";
+      table->sampler_rect.texcoords = "texCoords.xy";
+      return &table->sampler_rect;
    case GL_TEXTURE_3D:
       /* Code for mipmap generation with 3D textures is not used yet.
        * It's a sw fallback.
        */
-      mipmap->sampler_3d.type = "sampler3D";
-      mipmap->sampler_3d.func = "texture3D";
-      mipmap->sampler_3d.texcoords = "texCoords";
-      return &mipmap->sampler_3d;
+      table->sampler_3d.type = "sampler3D";
+      table->sampler_3d.func = "texture3D";
+      table->sampler_3d.texcoords = "texCoords.xyz";
+      return &table->sampler_3d;
    case GL_TEXTURE_CUBE_MAP:
-      mipmap->sampler_cubemap.type = "samplerCube";
-      mipmap->sampler_cubemap.func = "textureCube";
-      mipmap->sampler_cubemap.texcoords = "texCoords";
-      return &mipmap->sampler_cubemap;
+      table->sampler_cubemap.type = "samplerCube";
+      table->sampler_cubemap.func = "textureCube";
+      table->sampler_cubemap.texcoords = "texCoords.xyz";
+      return &table->sampler_cubemap;
    case GL_TEXTURE_1D_ARRAY:
-      mipmap->sampler_1d_array.type = "sampler1DArray";
-      mipmap->sampler_1d_array.func = "texture1DArray";
-      mipmap->sampler_1d_array.texcoords = "texCoords.xy";
-      return &mipmap->sampler_1d_array;
+      table->sampler_1d_array.type = "sampler1DArray";
+      table->sampler_1d_array.func = "texture1DArray";
+      table->sampler_1d_array.texcoords = "texCoords.xy";
+      return &table->sampler_1d_array;
    case GL_TEXTURE_2D_ARRAY:
-      mipmap->sampler_2d_array.type = "sampler2DArray";
-      mipmap->sampler_2d_array.func = "texture2DArray";
-      mipmap->sampler_2d_array.texcoords = "texCoords";
-      return &mipmap->sampler_2d_array;
+      table->sampler_2d_array.type = "sampler2DArray";
+      table->sampler_2d_array.func = "texture2DArray";
+      table->sampler_2d_array.texcoords = "texCoords.xyz";
+      return &table->sampler_2d_array;
+   case GL_TEXTURE_CUBE_MAP_ARRAY:
+      table->sampler_cubemap_array.type = "samplerCubeArray";
+      table->sampler_cubemap_array.func = "textureCubeArray";
+      table->sampler_cubemap_array.texcoords = "texCoords.xyzw";
+      return &table->sampler_cubemap_array;
    default:
       _mesa_problem(NULL, "Unexpected texture target 0x%x in"
                     " setup_texture_sampler()\n", target);
@@ -3368,380 +2579,34 @@ setup_texture_sampler(GLenum target, struct gen_mipmap_state *mipmap)
    }
 }
 
-
-static void
-setup_glsl_generate_mipmap(struct gl_context *ctx,
-                           struct gen_mipmap_state *mipmap,
-                           GLenum target)
-{
-   struct vertex {
-      GLfloat x, y, tex[3];
-   };
-   struct glsl_sampler *sampler;
-   const char *vs_source;
-   char *fs_source;
-   GLuint vs, fs;
-   void *mem_ctx;
-
-   /* Check if already initialized */
-   if (mipmap->ArrayObj == 0) {
-
-      /* create vertex array object */
-      _mesa_GenVertexArrays(1, &mipmap->ArrayObj);
-      _mesa_BindVertexArray(mipmap->ArrayObj);
-
-      /* create vertex array buffer */
-      _mesa_GenBuffers(1, &mipmap->VBO);
-      _mesa_BindBuffer(GL_ARRAY_BUFFER_ARB, mipmap->VBO);
-
-      /* setup vertex arrays */
-      _mesa_VertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE,
-                                   sizeof(struct vertex), OFFSET(x));
-      _mesa_VertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE,
-                                   sizeof(struct vertex), OFFSET(tex));
-      _mesa_EnableVertexAttribArray(0);
-      _mesa_EnableVertexAttribArray(1);
-   }
-
-   /* Generate a fragment shader program appropriate for the texture target */
-   sampler = setup_texture_sampler(target, mipmap);
-   assert(sampler != NULL);
-   if (sampler->shader_prog != 0) {
-      mipmap->ShaderProg = sampler->shader_prog;
-      return;
-   }
-
-   mem_ctx = ralloc_context(NULL);
-
-   if (ctx->API == API_OPENGLES2 || ctx->Const.GLSLVersion < 130) {
-      vs_source =
-         "attribute vec2 position;\n"
-         "attribute vec3 textureCoords;\n"
-         "varying vec3 texCoords;\n"
-         "void main()\n"
-         "{\n"
-         "   texCoords = textureCoords;\n"
-         "   gl_Position = vec4(position, 0.0, 1.0);\n"
-         "}\n";
-
-      fs_source = ralloc_asprintf(mem_ctx,
-                                  "#extension GL_EXT_texture_array : enable\n"
-                                  "uniform %s texSampler;\n"
-                                  "varying vec3 texCoords;\n"
-                                  "void main()\n"
-                                  "{\n"
-                                  "   gl_FragColor = %s(texSampler, %s);\n"
-                                  "}\n",
-                                  sampler->type,
-                                  sampler->func, sampler->texcoords);
-   }
-   else {
-      vs_source = ralloc_asprintf(mem_ctx,
-                                  "#version %s\n"
-                                  "in vec2 position;\n"
-                                  "in vec3 textureCoords;\n"
-                                  "out vec3 texCoords;\n"
-                                  "void main()\n"
-                                  "{\n"
-                                  "   texCoords = textureCoords;\n"
-                                  "   gl_Position = vec4(position, 0.0, 1.0);\n"
-                                  "}\n",
-                                  _mesa_is_desktop_gl(ctx) ? "130" : "300 es");
-      fs_source = ralloc_asprintf(mem_ctx,
-                                  "#version %s\n"
-                                  "uniform %s texSampler;\n"
-                                  "in vec3 texCoords;\n"
-                                  "out vec4 out_color;\n"
-                                  "\n"
-                                  "void main()\n"
-                                  "{\n"
-                                  "   out_color = texture(texSampler, %s);\n"
-                                  "}\n",
-                                  _mesa_is_desktop_gl(ctx) ? "130" : "300 es",
-                                  sampler->type,
-                                  sampler->texcoords);
-   }
-
-   vs = compile_shader_with_debug(ctx, GL_VERTEX_SHADER, vs_source);
-   fs = compile_shader_with_debug(ctx, GL_FRAGMENT_SHADER, fs_source);
-
-   mipmap->ShaderProg = _mesa_CreateProgramObjectARB();
-   _mesa_AttachShader(mipmap->ShaderProg, fs);
-   _mesa_DeleteObjectARB(fs);
-   _mesa_AttachShader(mipmap->ShaderProg, vs);
-   _mesa_DeleteObjectARB(vs);
-   _mesa_BindAttribLocation(mipmap->ShaderProg, 0, "position");
-   _mesa_BindAttribLocation(mipmap->ShaderProg, 1, "texcoords");
-   link_program_with_debug(ctx, mipmap->ShaderProg);
-   sampler->shader_prog = mipmap->ShaderProg;
-   ralloc_free(mem_ctx);
-}
-
-
-static void
-meta_glsl_generate_mipmap_cleanup(struct gl_context *ctx,
-                                 struct gen_mipmap_state *mipmap)
-{
-   if (mipmap->ArrayObj == 0)
-      return;
-   _mesa_DeleteVertexArrays(1, &mipmap->ArrayObj);
-   mipmap->ArrayObj = 0;
-   _mesa_DeleteBuffers(1, &mipmap->VBO);
-   mipmap->VBO = 0;
-
-   _mesa_DeleteObjectARB(mipmap->sampler_1d.shader_prog);
-   _mesa_DeleteObjectARB(mipmap->sampler_2d.shader_prog);
-   _mesa_DeleteObjectARB(mipmap->sampler_3d.shader_prog);
-   _mesa_DeleteObjectARB(mipmap->sampler_cubemap.shader_prog);
-   _mesa_DeleteObjectARB(mipmap->sampler_1d_array.shader_prog);
-   _mesa_DeleteObjectARB(mipmap->sampler_2d_array.shader_prog);
-
-   mipmap->sampler_1d.shader_prog = 0;
-   mipmap->sampler_2d.shader_prog = 0;
-   mipmap->sampler_3d.shader_prog = 0;
-   mipmap->sampler_cubemap.shader_prog = 0;
-   mipmap->sampler_1d_array.shader_prog = 0;
-   mipmap->sampler_2d_array.shader_prog = 0;
-}
-
-
-/**
- * Called via ctx->Driver.GenerateMipmap()
- * Note: We don't yet support 3D textures, 1D/2D array textures or texture
- * borders.
- */
 void
-_mesa_meta_GenerateMipmap(struct gl_context *ctx, GLenum target,
-                          struct gl_texture_object *texObj)
+_mesa_meta_blit_shader_table_cleanup(struct blit_shader_table *table)
 {
-   struct gen_mipmap_state *mipmap = &ctx->Meta->Mipmap;
-   struct vertex {
-      GLfloat x, y, tex[3];
-   };
-   struct vertex verts[4];
-   const GLuint baseLevel = texObj->BaseLevel;
-   const GLuint maxLevel = texObj->MaxLevel;
-   const GLint maxLevelSave = texObj->MaxLevel;
-   const GLboolean genMipmapSave = texObj->GenerateMipmap;
-   const GLuint fboSave = ctx->DrawBuffer->Name;
-   const GLuint currentTexUnitSave = ctx->Texture.CurrentUnit;
-   const GLboolean use_glsl_version = ctx->Extensions.ARB_vertex_shader &&
-                                      ctx->Extensions.ARB_fragment_shader &&
-                                     (ctx->API != API_OPENGLES);
-   GLenum faceTarget;
-   GLuint dstLevel;
-   const GLint slice = 0;
-   GLuint samplerSave;
-
-   if (_mesa_meta_check_generate_mipmap_fallback(ctx, target, texObj)) {
-      _mesa_generate_mipmap(ctx, target, texObj);
-      return;
-   }
-
-   if (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X &&
-       target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z) {
-      faceTarget = target;
-      target = GL_TEXTURE_CUBE_MAP;
-   }
-   else {
-      faceTarget = target;
-   }
-
-   _mesa_meta_begin(ctx, MESA_META_ALL);
-
-   /* Choose between glsl version and fixed function version of
-    * GenerateMipmap function.
-    */
-   if (use_glsl_version) {
-      setup_glsl_generate_mipmap(ctx, mipmap, target);
-      _mesa_UseProgram(mipmap->ShaderProg);
-   }
-   else {
-      setup_ff_generate_mipmap(ctx, mipmap);
-      _mesa_set_enable(ctx, target, GL_TRUE);
-   }
-
-   _mesa_BindVertexArray(mipmap->ArrayObj);
-   _mesa_BindBuffer(GL_ARRAY_BUFFER_ARB, mipmap->VBO);
-
-   samplerSave = ctx->Texture.Unit[ctx->Texture.CurrentUnit].Sampler ?
-      ctx->Texture.Unit[ctx->Texture.CurrentUnit].Sampler->Name : 0;
-
-   if (currentTexUnitSave != 0)
-      _mesa_BindTexture(target, texObj->Name);
-
-   if (!mipmap->FBO) {
-      _mesa_GenFramebuffers(1, &mipmap->FBO);
-   }
-
-   if (!mipmap->Sampler) {
-      _mesa_GenSamplers(1, &mipmap->Sampler);
-      _mesa_BindSampler(ctx->Texture.CurrentUnit, mipmap->Sampler);
-
-      _mesa_SamplerParameteri(mipmap->Sampler,
-                              GL_TEXTURE_MIN_FILTER,
-                              GL_LINEAR_MIPMAP_LINEAR);
-      _mesa_SamplerParameteri(mipmap->Sampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-      _mesa_SamplerParameteri(mipmap->Sampler, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-      _mesa_SamplerParameteri(mipmap->Sampler, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-      _mesa_SamplerParameteri(mipmap->Sampler, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
-
-      /* We don't want to encode or decode sRGB values; treat them as linear.
-       * This is not technically correct for GLES3 but we don't get any API
-       * error at the moment.
-       */
-      if (ctx->Extensions.EXT_texture_sRGB_decode) {
-         _mesa_SamplerParameteri(mipmap->Sampler, GL_TEXTURE_SRGB_DECODE_EXT,
-               GL_SKIP_DECODE_EXT);
-      }
-
-   } else {
-      _mesa_BindSampler(ctx->Texture.CurrentUnit, mipmap->Sampler);
-   }
-
-   _mesa_BindFramebuffer(GL_FRAMEBUFFER_EXT, mipmap->FBO);
-
-   if (ctx->API == API_OPENGL_COMPAT || ctx->API == API_OPENGLES)
-      _mesa_TexParameteri(target, GL_GENERATE_MIPMAP, GL_FALSE);
-   else
-      assert(!genMipmapSave);
-
-   /* Setup texture coordinates */
-   setup_texture_coords(faceTarget,
-                        slice,
-                        0, 0, 1, /* width, height never used here */
-                        verts[0].tex,
-                        verts[1].tex,
-                        verts[2].tex,
-                        verts[3].tex);
-
-   /* setup vertex positions */
-   verts[0].x = -1.0F;
-   verts[0].y = -1.0F;
-   verts[1].x =  1.0F;
-   verts[1].y = -1.0F;
-   verts[2].x =  1.0F;
-   verts[2].y =  1.0F;
-   verts[3].x = -1.0F;
-   verts[3].y =  1.0F;
-
-   /* upload vertex data */
-   _mesa_BufferData(GL_ARRAY_BUFFER_ARB, sizeof(verts),
-                       verts, GL_DYNAMIC_DRAW_ARB);
-
-   /* texture is already locked, unlock now */
-   _mesa_unlock_texture(ctx, texObj);
-
-   for (dstLevel = baseLevel + 1; dstLevel <= maxLevel; dstLevel++) {
-      const struct gl_texture_image *srcImage;
-      const GLuint srcLevel = dstLevel - 1;
-      GLsizei srcWidth, srcHeight, srcDepth;
-      GLsizei dstWidth, dstHeight, dstDepth;
-      GLenum status;
-
-      srcImage = _mesa_select_tex_image(ctx, texObj, faceTarget, srcLevel);
-      assert(srcImage->Border == 0);
-
-      /* src size */
-      srcWidth = srcImage->Width;
-      srcHeight = srcImage->Height;
-      srcDepth = srcImage->Depth;
-
-      /* new dst size */
-      dstWidth = MAX2(1, srcWidth / 2);
-      dstHeight = MAX2(1, srcHeight / 2);
-      dstDepth = MAX2(1, srcDepth / 2);
-
-      if (dstWidth == srcImage->Width &&
-          dstHeight == srcImage->Height &&
-          dstDepth == srcImage->Depth) {
-         /* all done */
-         break;
-      }
-
-      /* Allocate storage for the destination mipmap image(s) */
-
-      /* Set MaxLevel large enough to hold the new level when we allocate it */
-      _mesa_TexParameteri(target, GL_TEXTURE_MAX_LEVEL, dstLevel);
-
-      if (!_mesa_prepare_mipmap_level(ctx, texObj, dstLevel,
-                                      dstWidth, dstHeight, dstDepth,
-                                      srcImage->Border,
-                                      srcImage->InternalFormat,
-                                      srcImage->TexFormat)) {
-         /* All done.  We either ran out of memory or we would go beyond the
-          * last valid level of an immutable texture if we continued.
-          */
-         break;
-      }
-
-      /* limit minification to src level */
-      _mesa_TexParameteri(target, GL_TEXTURE_MAX_LEVEL, srcLevel);
-
-      /* Set to draw into the current dstLevel */
-      if (target == GL_TEXTURE_1D) {
-         _mesa_FramebufferTexture1D(GL_FRAMEBUFFER_EXT,
-                                       GL_COLOR_ATTACHMENT0_EXT,
-                                       target,
-                                       texObj->Name,
-                                       dstLevel);
-      }
-      else if (target == GL_TEXTURE_3D) {
-         GLint zoffset = 0; /* XXX unfinished */
-         _mesa_FramebufferTexture3D(GL_FRAMEBUFFER_EXT,
-                                       GL_COLOR_ATTACHMENT0_EXT,
-                                       target,
-                                       texObj->Name,
-                                       dstLevel, zoffset);
-      }
-      else {
-         /* 2D / cube */
-         _mesa_FramebufferTexture2D(GL_FRAMEBUFFER_EXT,
-                                       GL_COLOR_ATTACHMENT0_EXT,
-                                       faceTarget,
-                                       texObj->Name,
-                                       dstLevel);
-      }
-
-      _mesa_DrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
-
-      /* sanity check */
-      status = _mesa_CheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
-      if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
-         _mesa_problem(ctx, "Unexpected incomplete framebuffer in "
-                       "_mesa_meta_GenerateMipmap()");
-         break;
-      }
-
-      assert(dstWidth == ctx->DrawBuffer->Width);
-      assert(dstHeight == ctx->DrawBuffer->Height);
-
-      /* setup viewport */
-      _mesa_set_viewport(ctx, 0, 0, dstWidth, dstHeight);
-
-      _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4);
-   }
-
-   _mesa_lock_texture(ctx, texObj); /* relock */
-
-   _mesa_BindSampler(ctx->Texture.CurrentUnit, samplerSave);
-
-   _mesa_meta_end(ctx);
-
-   _mesa_TexParameteri(target, GL_TEXTURE_MAX_LEVEL, maxLevelSave);
-   if (genMipmapSave)
-      _mesa_TexParameteri(target, GL_GENERATE_MIPMAP, genMipmapSave);
-
-   _mesa_BindFramebuffer(GL_FRAMEBUFFER_EXT, fboSave);
+   _mesa_DeleteProgram(table->sampler_1d.shader_prog);
+   _mesa_DeleteProgram(table->sampler_2d.shader_prog);
+   _mesa_DeleteProgram(table->sampler_3d.shader_prog);
+   _mesa_DeleteProgram(table->sampler_rect.shader_prog);
+   _mesa_DeleteProgram(table->sampler_cubemap.shader_prog);
+   _mesa_DeleteProgram(table->sampler_1d_array.shader_prog);
+   _mesa_DeleteProgram(table->sampler_2d_array.shader_prog);
+   _mesa_DeleteProgram(table->sampler_cubemap_array.shader_prog);
+
+   table->sampler_1d.shader_prog = 0;
+   table->sampler_2d.shader_prog = 0;
+   table->sampler_3d.shader_prog = 0;
+   table->sampler_rect.shader_prog = 0;
+   table->sampler_cubemap.shader_prog = 0;
+   table->sampler_1d_array.shader_prog = 0;
+   table->sampler_2d_array.shader_prog = 0;
+   table->sampler_cubemap_array.shader_prog = 0;
 }
 
-
 /**
  * Determine the GL data type to use for the temporary image read with
  * ReadPixels() and passed to Tex[Sub]Image().
  */
 static GLenum
-get_temp_image_type(struct gl_context *ctx, gl_format format)
+get_temp_image_type(struct gl_context *ctx, mesa_format format)
 {
    GLenum baseFormat;
 
@@ -3805,6 +2670,12 @@ _mesa_meta_CopyTexSubImage(struct gl_context *ctx, GLuint dims,
    GLint bpp;
    void *buf;
 
+   /* The gl_renderbuffer is part of the interface for
+    * dd_function_table::CopyTexSubImage, but this implementation does not use
+    * it.
+    */
+   (void) rb;
+
    /* Choose format/type for temporary image buffer */
    format = _mesa_get_format_base_format(texImage->TexFormat);
    if (format == GL_LUMINANCE ||
@@ -3872,6 +2743,25 @@ _mesa_meta_CopyTexSubImage(struct gl_context *ctx, GLuint dims,
 }
 
 
+static void
+meta_decompress_cleanup(struct decompress_state *decompress)
+{
+   if (decompress->FBO != 0) {
+      _mesa_DeleteFramebuffers(1, &decompress->FBO);
+      _mesa_DeleteRenderbuffers(1, &decompress->RBO);
+   }
+
+   if (decompress->VAO != 0) {
+      _mesa_DeleteVertexArrays(1, &decompress->VAO);
+      _mesa_DeleteBuffers(1, &decompress->VBO);
+   }
+
+   if (decompress->Sampler != 0)
+      _mesa_DeleteSamplers(1, &decompress->Sampler);
+
+   memset(decompress, 0, sizeof(*decompress));
+}
+
 /**
  * Decompress a texture image by drawing a quad with the compressed
  * texture and reading the pixels out of the color buffer.
@@ -3895,24 +2785,40 @@ decompress_texture_image(struct gl_context *ctx,
    const GLint depth = texImage->Height;
    const GLenum target = texObj->Target;
    GLenum faceTarget;
-   struct vertex {
-      GLfloat x, y, tex[3];
-   };
    struct vertex verts[4];
    GLuint fboDrawSave, fboReadSave;
    GLuint rbSave;
    GLuint samplerSave;
+   const bool use_glsl_version = ctx->Extensions.ARB_vertex_shader &&
+                                      ctx->Extensions.ARB_fragment_shader;
 
    if (slice > 0) {
       assert(target == GL_TEXTURE_3D ||
-             target == GL_TEXTURE_2D_ARRAY);
+             target == GL_TEXTURE_2D_ARRAY ||
+             target == GL_TEXTURE_CUBE_MAP_ARRAY);
    }
 
-   if (target == GL_TEXTURE_CUBE_MAP) {
+   switch (target) {
+   case GL_TEXTURE_1D:
+   case GL_TEXTURE_1D_ARRAY:
+      assert(!"No compressed 1D textures.");
+      return;
+
+   case GL_TEXTURE_3D:
+      assert(!"No compressed 3D textures.");
+      return;
+
+   case GL_TEXTURE_CUBE_MAP_ARRAY:
+      faceTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + (slice % 6);
+      break;
+
+   case GL_TEXTURE_CUBE_MAP:
       faceTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + texImage->Face;
-   }
-   else {
+      break;
+
+   default:
       faceTarget = target;
+      break;
    }
 
    /* save fbo bindings (not saved by _mesa_meta_begin()) */
@@ -3949,27 +2855,13 @@ decompress_texture_image(struct gl_context *ctx,
       decompress->Height = height;
    }
 
-   /* setup VBO data */
-   if (decompress->ArrayObj == 0) {
-      /* create vertex array object */
-      _mesa_GenVertexArrays(1, &decompress->ArrayObj);
-      _mesa_BindVertexArray(decompress->ArrayObj);
-
-      /* create vertex array buffer */
-      _mesa_GenBuffers(1, &decompress->VBO);
-      _mesa_BindBuffer(GL_ARRAY_BUFFER_ARB, decompress->VBO);
-      _mesa_BufferData(GL_ARRAY_BUFFER_ARB, sizeof(verts),
-                          NULL, GL_DYNAMIC_DRAW_ARB);
+   if (use_glsl_version) {
+      _mesa_meta_setup_vertex_objects(&decompress->VAO, &decompress->VBO, true,
+                                      2, 4, 0);
 
-      /* setup vertex arrays */
-      _mesa_VertexPointer(2, GL_FLOAT, sizeof(struct vertex), OFFSET(x));
-      _mesa_TexCoordPointer(3, GL_FLOAT, sizeof(struct vertex), OFFSET(tex));
-      _mesa_EnableClientState(GL_VERTEX_ARRAY);
-      _mesa_EnableClientState(GL_TEXTURE_COORD_ARRAY);
-   }
-   else {
-      _mesa_BindVertexArray(decompress->ArrayObj);
-      _mesa_BindBuffer(GL_ARRAY_BUFFER_ARB, decompress->VBO);
+      _mesa_meta_setup_blit_shader(ctx, target, &decompress->shaders);
+   } else {
+      _mesa_meta_setup_ff_tnl_for_blit(&decompress->VAO, &decompress->VBO, 3);
    }
 
    if (!decompress->Sampler) {
@@ -3988,28 +2880,35 @@ decompress_texture_image(struct gl_context *ctx,
       _mesa_BindSampler(ctx->Texture.CurrentUnit, decompress->Sampler);
    }
 
-   setup_texture_coords(faceTarget, slice, width, height, depth,
-                        verts[0].tex,
-                        verts[1].tex,
-                        verts[2].tex,
-                        verts[3].tex);
+   /* Silence valgrind warnings about reading uninitialized stack. */
+   memset(verts, 0, sizeof(verts));
+
+   _mesa_meta_setup_texture_coords(faceTarget, slice, width, height, depth,
+                                   verts[0].tex,
+                                   verts[1].tex,
+                                   verts[2].tex,
+                                   verts[3].tex);
 
    /* setup vertex positions */
-   verts[0].x = 0.0F;
-   verts[0].y = 0.0F;
-   verts[1].x = width;
-   verts[1].y = 0.0F;
-   verts[2].x = width;
-   verts[2].y = height;
-   verts[3].x = 0.0F;
-   verts[3].y = height;
+   verts[0].x = -1.0F;
+   verts[0].y = -1.0F;
+   verts[1].x =  1.0F;
+   verts[1].y = -1.0F;
+   verts[2].x =  1.0F;
+   verts[2].y =  1.0F;
+   verts[3].x = -1.0F;
+   verts[3].y =  1.0F;
+
+   _mesa_set_viewport(ctx, 0, 0, 0, width, height);
 
    /* upload new vertex data */
    _mesa_BufferSubData(GL_ARRAY_BUFFER_ARB, 0, sizeof(verts), verts);
 
    /* setup texture state */
    _mesa_BindTexture(target, texObj->Name);
-   _mesa_set_enable(ctx, target, GL_TRUE);
+
+   if (!use_glsl_version)
+      _mesa_set_enable(ctx, target, GL_TRUE);
 
    {
       /* save texture object state */
@@ -4069,7 +2968,8 @@ decompress_texture_image(struct gl_context *ctx,
    }
 
    /* disable texture unit */
-   _mesa_set_enable(ctx, target, GL_FALSE);
+   if (!use_glsl_version)
+      _mesa_set_enable(ctx, target, GL_FALSE);
 
    _mesa_BindSampler(ctx->Texture.CurrentUnit, samplerSave);
 
@@ -4110,7 +3010,8 @@ _mesa_meta_GetTexImage(struct gl_context *ctx,
       _mesa_unlock_texture(ctx, texObj);
       for (slice = 0; slice < texImage->Depth; slice++) {
          void *dst;
-         if (texImage->TexObject->Target == GL_TEXTURE_2D_ARRAY) {
+         if (texImage->TexObject->Target == GL_TEXTURE_2D_ARRAY
+             || texImage->TexObject->Target == GL_TEXTURE_CUBE_MAP_ARRAY) {
             /* Setup pixel packing.  SkipPixels and SkipRows will be applied
              * in the decompress_texture_image() function's call to
              * glReadPixels but we need to compute the dest slice's address
@@ -4158,13 +3059,13 @@ _mesa_meta_DrawTex(struct gl_context *ctx, GLfloat x, GLfloat y, GLfloat z,
                           MESA_META_VERTEX |
                           MESA_META_VIEWPORT));
 
-   if (drawtex->ArrayObj == 0) {
+   if (drawtex->VAO == 0) {
       /* one-time setup */
       GLint active_texture;
 
       /* create vertex array object */
-      _mesa_GenVertexArrays(1, &drawtex->ArrayObj);
-      _mesa_BindVertexArray(drawtex->ArrayObj);
+      _mesa_GenVertexArrays(1, &drawtex->VAO);
+      _mesa_BindVertexArray(drawtex->VAO);
 
       /* create vertex array buffer */
       _mesa_GenBuffers(1, &drawtex->VBO);
@@ -4188,7 +3089,7 @@ _mesa_meta_DrawTex(struct gl_context *ctx, GLfloat x, GLfloat y, GLfloat z,
       _mesa_ClientActiveTexture(GL_TEXTURE0 + active_texture);
    }
    else {
-      _mesa_BindVertexArray(drawtex->ArrayObj);
+      _mesa_BindVertexArray(drawtex->VAO);
       _mesa_BindBuffer(GL_ARRAY_BUFFER_ARB, drawtex->VBO);
    }