i965/gen6_surface_state.c: Remove (gen < 6) code path
[mesa.git] / src / mesa / drivers / common / meta.c
index 44fafac6cbb32f8f47b99a57ba4d77925d75f139..485128696c5ae476f2ca7f4ce7a2c610210c5520 100644 (file)
 #include "main/arbprogram.h"
 #include "main/arrayobj.h"
 #include "main/blend.h"
+#include "main/blit.h"
 #include "main/bufferobj.h"
 #include "main/buffers.h"
+#include "main/clear.h"
 #include "main/colortab.h"
 #include "main/condrender.h"
 #include "main/depth.h"
 #include "main/fbobject.h"
 #include "main/feedback.h"
 #include "main/formats.h"
+#include "main/format_unpack.h"
 #include "main/glformats.h"
 #include "main/image.h"
 #include "main/macros.h"
 #include "main/matrix.h"
 #include "main/mipmap.h"
+#include "main/multisample.h"
+#include "main/objectlabel.h"
+#include "main/pipelineobj.h"
 #include "main/pixel.h"
 #include "main/pbo.h"
 #include "main/polygon.h"
@@ -67,6 +73,7 @@
 #include "main/teximage.h"
 #include "main/texparam.h"
 #include "main/texstate.h"
+#include "main/texstore.h"
 #include "main/transformfeedback.h"
 #include "main/uniforms.h"
 #include "main/varray.h"
 #include "drivers/common/meta.h"
 #include "main/enums.h"
 #include "main/glformats.h"
-#include "../glsl/ralloc.h"
+#include "util/ralloc.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 *Shader[MESA_SHADER_STAGES];
-   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 */
-   GLfloat 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;
-   GLint LayerLocation;
-
-   GLuint IntegerShaderProg;
-   GLint IntegerColorLocation;
-   GLint IntegerLayerLocation;
-};
-
-
-/**
- * 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 */
-};
-
+static void
+meta_clear(struct gl_context *ctx, GLbitfield buffers, bool glsl);
 
-/**
- * State for glBitmap()
- */
-struct bitmap_state
-{
-   GLuint ArrayObj;
-   GLuint VBO;
-   struct temp_texture Tex;  /**< separate texture from other meta ops */
-};
+static struct blit_shader *
+choose_blit_shader(GLenum target, struct blit_shader_table *table);
 
-/**
- * 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;
-};
+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);
 
-/**
- * State for _mesa_meta_generate_mipmap()
- */
-struct gen_mipmap_state
+void
+_mesa_meta_bind_fbo_image(GLenum fboTarget, GLenum attachment,
+                          struct gl_texture_image *texImage, GLuint layer)
 {
-   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;
-};
+   struct gl_texture_object *texObj = texImage->TexObject;
+   int level = texImage->Level;
+   GLenum texTarget = texObj->Target;
 
-/**
- * State for texture decompression
- */
-struct decompress_state
-{
-   GLuint ArrayObj;
-   GLuint VBO, FBO, RBO, Sampler;
-   GLint Width, Height;
-};
+   switch (texTarget) {
+   case GL_TEXTURE_1D:
+      _mesa_FramebufferTexture1D(fboTarget,
+                                 attachment,
+                                 texTarget,
+                                 texObj->Name,
+                                 level);
+      break;
+   case GL_TEXTURE_1D_ARRAY:
+   case GL_TEXTURE_2D_ARRAY:
+   case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
+   case GL_TEXTURE_CUBE_MAP_ARRAY:
+   case GL_TEXTURE_3D:
+      _mesa_FramebufferTextureLayer(fboTarget,
+                                    attachment,
+                                    texObj->Name,
+                                    level,
+                                    layer);
+      break;
+   default: /* 2D / cube */
+      if (texTarget == GL_TEXTURE_CUBE_MAP)
+         texTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + texImage->Face;
 
-/**
- * State for glDrawTex()
- */
-struct drawtex_state
-{
-   GLuint ArrayObj;
-   GLuint VBO;
-};
+      _mesa_FramebufferTexture2D(fboTarget,
+                                 attachment,
+                                 texTarget,
+                                 texObj->Name,
+                                 level);
+   }
+}
 
-#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 +157,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 +207,183 @@ link_program_with_debug(struct gl_context *ctx, GLuint program)
    return 0;
 }
 
+void
+_mesa_meta_compile_and_link_program(struct gl_context *ctx,
+                                    const char *vs_source,
+                                    const char *fs_source,
+                                    const char *name,
+                                    GLuint *program)
+{
+   GLuint vs = _mesa_meta_compile_shader_with_debug(ctx, GL_VERTEX_SHADER,
+                                                    vs_source);
+   GLuint fs = _mesa_meta_compile_shader_with_debug(ctx, GL_FRAGMENT_SHADER,
+                                                    fs_source);
+
+   *program = _mesa_CreateProgram();
+   _mesa_ObjectLabel(GL_PROGRAM, *program, -1, name);
+   _mesa_AttachShader(*program, fs);
+   _mesa_DeleteShader(fs);
+   _mesa_AttachShader(*program, vs);
+   _mesa_DeleteShader(vs);
+   _mesa_BindAttribLocation(*program, 0, "position");
+   _mesa_BindAttribLocation(*program, 1, "texcoords");
+   _mesa_meta_link_program_with_debug(ctx, *program);
+
+   _mesa_UseProgram(*program);
+}
+
+/**
+ * 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)
+{
+   char *vs_source, *fs_source;
+   void *const mem_ctx = ralloc_context(NULL);
+   struct blit_shader *shader = choose_blit_shader(target, table);
+   const char *vs_input, *vs_output, *fs_input, *vs_preprocess, *fs_preprocess;
+
+   if (ctx->Const.GLSLVersion < 130) {
+      vs_preprocess = "";
+      vs_input = "attribute";
+      vs_output = "varying";
+      fs_preprocess = "#extension GL_EXT_texture_array : enable";
+      fs_input = "varying";
+   } else {
+      vs_preprocess = "#version 130";
+      vs_input = "in";
+      vs_output = "out";
+      fs_preprocess = "#version 130";
+      fs_input = "in";
+      shader->func = "texture";
+   }
+
+   assert(shader != NULL);
+
+   if (shader->shader_prog != 0) {
+      _mesa_UseProgram(shader->shader_prog);
+      return;
+   }
+
+   vs_source = ralloc_asprintf(mem_ctx,
+                "%s\n"
+                "%s vec2 position;\n"
+                "%s vec4 textureCoords;\n"
+                "%s vec4 texCoords;\n"
+                "void main()\n"
+                "{\n"
+                "   texCoords = textureCoords;\n"
+                "   gl_Position = vec4(position, 0.0, 1.0);\n"
+                "}\n",
+                vs_preprocess, vs_input, vs_input, vs_output);
+
+   fs_source = ralloc_asprintf(mem_ctx,
+                "%s\n"
+                "#extension GL_ARB_texture_cube_map_array: enable\n"
+                "uniform %s texSampler;\n"
+                "%s vec4 texCoords;\n"
+                "void main()\n"
+                "{\n"
+                "   gl_FragColor = %s(texSampler, %s);\n"
+                "   gl_FragDepth = gl_FragColor.x;\n"
+                "}\n",
+                fs_preprocess, shader->type, fs_input,
+                shader->func, shader->texcoords);
+
+   _mesa_meta_compile_and_link_program(ctx, vs_source, fs_source,
+                                       ralloc_asprintf(mem_ctx, "%s blit",
+                                                       shader->type),
+                                       &shader->shader_prog);
+   ralloc_free(mem_ctx);
+}
+
+/**
+ * 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.
@@ -435,6 +396,24 @@ _mesa_meta_init(struct gl_context *ctx)
    ctx->Meta = CALLOC_STRUCT(gl_meta_state);
 }
 
+static GLenum
+gl_buffer_index_to_drawbuffers_enum(gl_buffer_index bufindex)
+{
+   assert(bufindex < BUFFER_COUNT);
+
+   if (bufindex >= BUFFER_COLOR0)
+      return GL_COLOR_ATTACHMENT0 + bufindex - BUFFER_COLOR0;
+   else if (bufindex == BUFFER_FRONT_LEFT)
+      return GL_FRONT_LEFT;
+   else if (bufindex == BUFFER_FRONT_RIGHT)
+      return GL_FRONT_RIGHT;
+   else if (bufindex == BUFFER_BACK_LEFT)
+      return GL_BACK_LEFT;
+   else if (bufindex == BUFFER_BACK_RIGHT)
+      return GL_BACK_RIGHT;
+
+   return GL_NONE;
+}
 
 /**
  * Free context meta-op state.
@@ -445,10 +424,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 +458,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.
     */
@@ -520,6 +508,11 @@ _mesa_meta_begin(struct gl_context *ctx, GLbitfield state)
          _mesa_set_enable(ctx, GL_COLOR_LOGIC_OP, GL_FALSE);
    }
 
+   if (state & MESA_META_DITHER) {
+      save->DitherFlag = ctx->Color.DitherFlag;
+      _mesa_set_enable(ctx, GL_DITHER, GL_TRUE);
+   }
+
    if (state & MESA_META_COLOR_MASK) {
       memcpy(save->ColorMask, ctx->Color.ColorMask,
              sizeof(ctx->Color.ColorMask));
@@ -536,9 +529,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 +574,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,28 +585,39 @@ _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);
       }
 
-      for (int i = 0; i < MESA_SHADER_STAGES; i++) {
+      if (ctx->Pipeline.Current) {
+         _mesa_reference_pipeline_object(ctx, &save->Pipeline,
+                                         ctx->Pipeline.Current);
+         _mesa_BindProgramPipeline(0);
+      }
+
+      /* Save the shader state from ctx->Shader (instead of ctx->_Shader) so
+       * that we don't have to worry about the current pipeline state.
+       */
+      for (i = 0; i <= MESA_SHADER_FRAGMENT; i++) {
          _mesa_reference_shader_program(ctx, &save->Shader[i],
-                                     ctx->Shader.CurrentProgram[i]);
+                                        ctx->Shader.CurrentProgram[i]);
       }
       _mesa_reference_shader_program(ctx, &save->ActiveShader,
                                      ctx->Shader.ActiveProgram);
@@ -640,33 +640,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);
          }
       }
 
@@ -679,9 +670,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) {
@@ -724,8 +713,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? */
@@ -794,9 +783,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) {
@@ -805,6 +805,23 @@ _mesa_meta_begin(struct gl_context *ctx, GLbitfield state)
          _mesa_set_framebuffer_srgb(ctx, GL_FALSE);
    }
 
+   if (state & MESA_META_DRAW_BUFFERS) {
+      int buf, real_color_buffers = 0;
+      memset(save->ColorDrawBuffers, 0, sizeof(save->ColorDrawBuffers));
+
+      for (buf = 0; buf < ctx->Const.MaxDrawBuffers; buf++) {
+         int buf_index = ctx->DrawBuffer->_ColorDrawBufferIndexes[buf];
+         if (buf_index == -1)
+            continue;
+
+         save->ColorDrawBuffers[buf] =
+            gl_buffer_index_to_drawbuffers_enum(buf_index);
+
+         if (++real_color_buffers >= ctx->DrawBuffer->_NumColorDrawBuffers)
+            break;
+      }
+   }
+
    /* misc */
    {
       save->Lighting = ctx->Light.Enabled;
@@ -813,6 +830,11 @@ _mesa_meta_begin(struct gl_context *ctx, GLbitfield state)
       save->RasterDiscard = ctx->RasterDiscard;
       if (ctx->RasterDiscard)
          _mesa_set_enable(ctx, GL_RASTERIZER_DISCARD, GL_FALSE);
+
+      save->DrawBufferName = ctx->DrawBuffer->Name;
+      save->ReadBufferName = ctx->ReadBuffer->Name;
+      save->RenderbufferName = (ctx->CurrentRenderbuffer ?
+                                ctx->CurrentRenderbuffer->Name : 0);
    }
 }
 
@@ -861,6 +883,9 @@ _mesa_meta_end(struct gl_context *ctx)
          _mesa_set_enable(ctx, GL_COLOR_LOGIC_OP, save->ColorLogicOpEnabled);
    }
 
+   if (state & MESA_META_DITHER)
+      _mesa_set_enable(ctx, GL_DITHER, save->DitherFlag);
+
    if (state & MESA_META_COLOR_MASK) {
       GLuint i;
       for (i = 0; i < ctx->Const.MaxDrawBuffers; i++) {
@@ -887,9 +912,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);
    }
 
@@ -913,18 +936,10 @@ _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);
    }
@@ -944,7 +959,15 @@ _mesa_meta_end(struct gl_context *ctx)
    }
 
    if (state & MESA_META_SHADER) {
-      if (ctx->API == API_OPENGL_COMPAT && ctx->Extensions.ARB_vertex_program) {
+      static const GLenum targets[] = {
+         GL_VERTEX_SHADER,
+         GL_GEOMETRY_SHADER,
+         GL_FRAGMENT_SHADER,
+      };
+
+      bool any_shader;
+
+      if (ctx->Extensions.ARB_vertex_program) {
          _mesa_set_enable(ctx, GL_VERTEX_PROGRAM_ARB,
                           save->VertexProgramEnabled);
          _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current, 
@@ -952,7 +975,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,
@@ -960,30 +983,51 @@ _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->Shader[MESA_SHADER_VERTEX]);
-      }
+      any_shader = false;
+      for (i = 0; i <= MESA_SHADER_FRAGMENT; i++) {
+         /* It is safe to call _mesa_use_shader_program even if the extension
+          * necessary for that program state is not supported.  In that case,
+          * the saved program object must be NULL and the currently bound
+          * program object must be NULL.  _mesa_use_shader_program is a no-op
+          * in that case.
+          */
+         _mesa_use_shader_program(ctx, targets[i],
+                                  save->Shader[i],
+                                  &ctx->Shader);
 
-      if (_mesa_has_geometry_shaders(ctx))
-        _mesa_use_shader_program(ctx, GL_GEOMETRY_SHADER_ARB,
-                                 save->Shader[MESA_SHADER_GEOMETRY]);
+         /* Do this *before* killing the reference. :)
+          */
+         if (save->Shader[i] != NULL)
+            any_shader = true;
 
-      if (ctx->Extensions.ARB_fragment_shader)
-        _mesa_use_shader_program(ctx, GL_FRAGMENT_SHADER,
-                                 save->Shader[MESA_SHADER_FRAGMENT]);
+         _mesa_reference_shader_program(ctx, &save->Shader[i], NULL);
+      }
 
       _mesa_reference_shader_program(ctx, &ctx->Shader.ActiveProgram,
-                                    save->ActiveShader);
-
-      for (i = 0; i < MESA_SHADER_STAGES; i++)
-         _mesa_reference_shader_program(ctx, &save->Shader[i], NULL);
+                                     save->ActiveShader);
       _mesa_reference_shader_program(ctx, &save->ActiveShader, NULL);
+
+      /* If there were any stages set with programs, use ctx->Shader as the
+       * current shader state.  Otherwise, use Pipeline.Default.  The pipeline
+       * hasn't been restored yet, and that may modify ctx->_Shader further.
+       */
+      if (any_shader)
+         _mesa_reference_pipeline_object(ctx, &ctx->_Shader,
+                                         &ctx->Shader);
+      else
+         _mesa_reference_pipeline_object(ctx, &ctx->_Shader,
+                                         ctx->Pipeline.Default);
+
+      if (save->Pipeline) {
+         _mesa_bind_pipeline(ctx, save->Pipeline);
+
+         _mesa_reference_pipeline_object(ctx, &save->Pipeline, NULL);
+      }
    }
 
    if (state & MESA_META_STENCIL_TEST) {
@@ -991,7 +1035,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
@@ -1023,9 +1067,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++) {
@@ -1038,17 +1080,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];
          }
       }
 
@@ -1090,8 +1130,8 @@ _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) {
@@ -1132,8 +1172,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) {
@@ -1151,7 +1213,23 @@ _mesa_meta_end(struct gl_context *ctx)
    if (save->TransformFeedbackNeedsResume)
       _mesa_ResumeTransformFeedback();
 
+   if (ctx->DrawBuffer->Name != save->DrawBufferName)
+      _mesa_BindFramebuffer(GL_DRAW_FRAMEBUFFER, save->DrawBufferName);
+
+   if (ctx->ReadBuffer->Name != save->ReadBufferName)
+      _mesa_BindFramebuffer(GL_READ_FRAMEBUFFER, save->ReadBufferName);
+
+   if (!ctx->CurrentRenderbuffer ||
+       ctx->CurrentRenderbuffer->Name != save->RenderbufferName)
+      _mesa_BindRenderbuffer(GL_RENDERBUFFER, save->RenderbufferName);
+
+   if (state & MESA_META_DRAW_BUFFERS) {
+      _mesa_DrawBuffers(ctx->Const.MaxDrawBuffers, save->ColorDrawBuffers);
+   }
+
    ctx->Meta->SaveStackDepth--;
+
+   ctx->API = save->API;
 }
 
 
@@ -1206,7 +1284,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;
@@ -1219,8 +1297,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;
 
@@ -1253,8 +1331,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;
 
@@ -1274,9 +1352,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;
 
@@ -1327,19 +1405,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) {
@@ -1370,20 +1451,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) {
@@ -1417,812 +1496,78 @@ setup_drawpix_texture(struct gl_context *ctx,
    }
 }
 
+void
+_mesa_meta_setup_ff_tnl_for_blit(GLuint *VAO, GLuint *VBO,
+                                 unsigned texcoord_size)
+{
+   _mesa_meta_setup_vertex_objects(VAO, VBO, false, 2, texcoord_size, 0);
 
+   /* setup projection matrix */
+   _mesa_MatrixMode(GL_PROJECTION);
+   _mesa_LoadIdentity();
+}
 
 /**
- * One-time init for drawing depth pixels.
+ * Meta implementation of ctx->Driver.Clear() in terms of polygon rendering.
  */
-static void
-init_blit_depth_pixels(struct gl_context *ctx)
+void
+_mesa_meta_Clear(struct gl_context *ctx, GLbitfield buffers)
 {
-   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);
+   meta_clear(ctx, buffers, false);
 }
 
-static void
-setup_ff_blit_framebuffer(struct gl_context *ctx,
-                          struct blit_state *blit)
+void
+_mesa_meta_glsl_Clear(struct gl_context *ctx, GLbitfield buffers)
 {
-   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);
-   }
-
-   /* setup projection matrix */
-   _mesa_MatrixMode(GL_PROJECTION);
-   _mesa_LoadIdentity();
-   _mesa_Ortho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
-
+   meta_clear(ctx, buffers, true);
 }
 
 static void
-setup_glsl_blit_framebuffer(struct gl_context *ctx,
-                            struct blit_state *blit,
-                            GLenum target)
+meta_glsl_clear_init(struct gl_context *ctx, struct clear_state *clear)
 {
-   struct vertex {
-      GLfloat x, y, s, t;
-   };
-   struct vertex verts[4];
-   const char *vs_source;
-   char *fs_source;
+   const char *vs_source =
+      "#extension GL_AMD_vertex_shader_layer : enable\n"
+      "#extension GL_ARB_draw_instanced : enable\n"
+      "attribute vec4 position;\n"
+      "void main()\n"
+      "{\n"
+      "#ifdef GL_AMD_vertex_shader_layer\n"
+      "   gl_Layer = gl_InstanceID;\n"
+      "#endif\n"
+      "   gl_Position = position;\n"
+      "}\n";
+   const char *fs_source =
+      "uniform vec4 color;\n"
+      "void main()\n"
+      "{\n"
+      "   gl_FragColor = color;\n"
+      "}\n";
    GLuint vs, fs;
-   void *mem_ctx;
-   GLuint ShaderProg;
-   GLboolean texture_2d = (target == GL_TEXTURE_2D);
+   bool has_integer_textures;
 
-   /* target = GL_TEXTURE_RECTANGLE is not supported in GLES 3.0 */
-   assert(_mesa_is_desktop_gl(ctx) || texture_2d);
+   _mesa_meta_setup_vertex_objects(&clear->VAO, &clear->VBO, true, 3, 0, 0);
 
-   /* Check if already initialized */
-   if (blit->ArrayObj == 0) {
+   if (clear->ShaderProg != 0)
+      return;
 
-      /* create vertex array object */
-      _mesa_GenVertexArrays(1, &blit->ArrayObj);
-      _mesa_BindVertexArray(blit->ArrayObj);
+   vs = _mesa_CreateShader(GL_VERTEX_SHADER);
+   _mesa_ShaderSource(vs, 1, &vs_source, NULL);
+   _mesa_CompileShader(vs);
 
-      /* 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);
+   fs = _mesa_CreateShader(GL_FRAGMENT_SHADER);
+   _mesa_ShaderSource(fs, 1, &fs_source, NULL);
+   _mesa_CompileShader(fs);
 
-      /* 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));
-
-      _mesa_EnableVertexAttribArray(0);
-      _mesa_EnableVertexAttribArray(1);
-   }
-
-   /* 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,
-                                  "#ifdef GL_ES\n"
-                                  "precision highp float;\n"
-                                  "#endif\n"
-                                  "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"
-                                  "#ifdef GL_ES\n"
-                                  "precision highp float;\n"
-                                  "#endif\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");
-   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 = (float) srcX0;
-               s1 = (float) srcX1;
-               t0 = (float) srcY0;
-               t1 = (float) 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, 0, 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, 0, 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, 0, 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);
-   }
-
-   /* GL_DEPTH_BUFFER_BIT */
-   if (buffers & BUFFER_BIT_DEPTH) {
-      _mesa_set_enable(ctx, GL_DEPTH_TEST, GL_TRUE);
-      _mesa_DepthFunc(GL_ALWAYS);
-      _mesa_DepthMask(GL_TRUE);
-   }
-   else {
-      assert(!ctx->Depth.Test);
-   }
-
-   /* GL_STENCIL_BUFFER_BIT */
-   if (buffers & BUFFER_BIT_STENCIL) {
-      _mesa_set_enable(ctx, GL_STENCIL_TEST, GL_TRUE);
-      _mesa_StencilOpSeparate(GL_FRONT_AND_BACK,
-                              GL_REPLACE, GL_REPLACE, GL_REPLACE);
-      _mesa_StencilFuncSeparate(GL_FRONT_AND_BACK, GL_ALWAYS,
-                                ctx->Stencil.Clear & stencilMax,
-                                ctx->Stencil.WriteMask[0]);
-   }
-   else {
-      assert(!ctx->Stencil.Enabled);
-   }
-
-   /* vertex positions/colors */
-   {
-      const GLfloat x0 = (GLfloat) ctx->DrawBuffer->_Xmin;
-      const GLfloat y0 = (GLfloat) ctx->DrawBuffer->_Ymin;
-      const GLfloat x1 = (GLfloat) ctx->DrawBuffer->_Xmax;
-      const GLfloat y1 = (GLfloat) ctx->DrawBuffer->_Ymax;
-      const GLfloat z = invert_z(ctx->Depth.Clear);
-      GLuint i;
-
-      verts[0].x = x0;
-      verts[0].y = y0;
-      verts[0].z = z;
-      verts[1].x = x1;
-      verts[1].y = y0;
-      verts[1].z = z;
-      verts[2].x = x1;
-      verts[2].y = y1;
-      verts[2].z = z;
-      verts[3].x = x0;
-      verts[3].y = y1;
-      verts[3].z = z;
-
-      /* vertex colors */
-      for (i = 0; i < 4; i++) {
-         verts[i].r = ctx->Color.ClearColor.f[0];
-         verts[i].g = ctx->Color.ClearColor.f[1];
-         verts[i].b = ctx->Color.ClearColor.f[2];
-         verts[i].a = ctx->Color.ClearColor.f[3];
-      }
-
-      /* upload new vertex data */
-      _mesa_BufferData(GL_ARRAY_BUFFER_ARB, sizeof(verts), verts,
-                         GL_DYNAMIC_DRAW_ARB);
-   }
-
-   /* draw quad */
-   _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4);
-
-   _mesa_meta_end(ctx);
-}
-
-static void
-meta_glsl_clear_init(struct gl_context *ctx, struct clear_state *clear)
-{
-   const char *vs_source =
-      "attribute vec4 position;\n"
-      "void main()\n"
-      "{\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 =
-      "#ifdef GL_ES\n"
-      "precision highp float;\n"
-      "#endif\n"
-      "uniform vec4 color;\n"
-      "void main()\n"
-      "{\n"
-      "   gl_FragColor = color;\n"
-      "}\n";
-   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);
-
-   /* 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);
-
-   vs = _mesa_CreateShaderObjectARB(GL_VERTEX_SHADER);
-   _mesa_ShaderSource(vs, 1, &vs_source, NULL);
-   _mesa_CompileShader(vs);
-
-   if (_mesa_has_geometry_shaders(ctx)) {
-      gs = _mesa_CreateShaderObjectARB(GL_GEOMETRY_SHADER);
-      _mesa_ShaderSource(gs, 1, &gs_source, NULL);
-      _mesa_CompileShader(gs);
-   }
-
-   fs = _mesa_CreateShaderObjectARB(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);
-   if (gs != 0)
-      _mesa_AttachShader(clear->ShaderProg, gs);
+   _mesa_DeleteShader(fs);
    _mesa_AttachShader(clear->ShaderProg, vs);
-   _mesa_DeleteObjectARB(vs);
+   _mesa_DeleteShader(vs);
    _mesa_BindAttribLocation(clear->ShaderProg, 0, "position");
+   _mesa_ObjectLabel(GL_PROGRAM, clear->ShaderProg, -1, "meta clear");
    _mesa_LinkProgram(clear->ShaderProg);
 
-   clear->ColorLocation = _mesa_GetUniformLocation(clear->ShaderProg,
-                                                     "color");
-   if (gs != 0) {
-      clear->LayerLocation = _mesa_GetUniformLocation(clear->ShaderProg,
-                                                     "layer");
-   }
+   clear->ColorLocation = _mesa_GetUniformLocation(clear->ShaderProg, "color");
 
    has_integer_textures = _mesa_is_gles3(ctx) ||
       (_mesa_is_desktop_gl(ctx) && ctx->Const.GLSLVersion >= 130);
@@ -2231,39 +1576,39 @@ 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"
+                         "#extension GL_AMD_vertex_shader_layer : enable\n"
+                         "#extension GL_ARB_draw_instanced : enable\n"
                          "in vec4 position;\n"
                          "void main()\n"
                          "{\n"
+                         "#ifdef GL_AMD_vertex_shader_layer\n"
+                         "   gl_Layer = gl_InstanceID;\n"
+                         "#endif\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"
-                         "#ifdef GL_ES\n"
-                         "precision highp float;\n"
-                         "#endif\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);
-      if (gs != 0)
-         _mesa_AttachShader(clear->IntegerShaderProg, gs);
+      _mesa_DeleteShader(fs);
       _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
@@ -2271,55 +1616,88 @@ 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_DeleteObjectARB(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;
    }
 }
 
 /**
- * Meta implementation of ctx->Driver.Clear() in terms of polygon rendering.
+ * Given a bitfield of BUFFER_BIT_x draw buffers, call glDrawBuffers to
+ * set GL to only draw to those buffers.
+ *
+ * Since the bitfield has no associated order, the assignment of draw buffer
+ * indices to color attachment indices is rather arbitrary.
  */
 void
-_mesa_meta_glsl_Clear(struct gl_context *ctx, GLbitfield buffers)
+_mesa_meta_drawbuffers_from_bitfield(GLbitfield bits)
+{
+   GLenum enums[MAX_DRAW_BUFFERS];
+   int i = 0;
+   int n;
+
+   /* This function is only legal for color buffer bitfields. */
+   assert((bits & ~BUFFER_BITS_COLOR) == 0);
+
+   /* Make sure we don't overflow any arrays. */
+   assert(_mesa_bitcount(bits) <= MAX_DRAW_BUFFERS);
+
+   enums[0] = GL_NONE;
+
+   if (bits & BUFFER_BIT_FRONT_LEFT)
+      enums[i++] = GL_FRONT_LEFT;
+
+   if (bits & BUFFER_BIT_FRONT_RIGHT)
+      enums[i++] = GL_FRONT_RIGHT;
+
+   if (bits & BUFFER_BIT_BACK_LEFT)
+      enums[i++] = GL_BACK_LEFT;
+
+   if (bits & BUFFER_BIT_BACK_RIGHT)
+      enums[i++] = GL_BACK_RIGHT;
+
+   for (n = 0; n < MAX_COLOR_ATTACHMENTS; n++) {
+      if (bits & (1 << (BUFFER_COLOR0 + n)))
+         enums[i++] = GL_COLOR_ATTACHMENT0 + n;
+   }
+
+   _mesa_DrawBuffers(i, enums);
+}
+
+/**
+ * Meta implementation of ctx->Driver.Clear() in terms of polygon rendering.
+ */
+static void
+meta_clear(struct gl_context *ctx, GLbitfield buffers, bool glsl)
 {
    struct clear_state *clear = &ctx->Meta->Clear;
    GLbitfield metaSave;
    const GLuint stencilMax = (1 << ctx->DrawBuffer->Visual.stencilBits) - 1;
    struct gl_framebuffer *fb = ctx->DrawBuffer;
-   const float x0 = ((float)fb->_Xmin / fb->Width)  * 2.0f - 1.0f;
-   const float y0 = ((float)fb->_Ymin / fb->Height) * 2.0f - 1.0f;
-   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];
+   float x0, y0, x1, y1, z;
+   struct vertex verts[4];
+   int i;
 
    metaSave = (MESA_META_ALPHA_TEST |
               MESA_META_BLEND |
@@ -2334,7 +1712,18 @@ _mesa_meta_glsl_Clear(struct gl_context *ctx, GLbitfield buffers)
                MESA_META_MULTISAMPLE |
                MESA_META_OCCLUSION_QUERY);
 
-   if (!(buffers & BUFFER_BITS_COLOR)) {
+   if (!glsl) {
+      metaSave |= MESA_META_FOG |
+                  MESA_META_PIXEL_TRANSFER |
+                  MESA_META_TRANSFORM |
+                  MESA_META_TEXTURE |
+                  MESA_META_CLAMP_VERTEX_COLOR |
+                  MESA_META_SELECT_FEEDBACK;
+   }
+
+   if (buffers & BUFFER_BITS_COLOR) {
+      metaSave |= MESA_META_DRAW_BUFFERS;
+   } else {
       /* We'll use colormask to disable color writes.  Otherwise,
        * respect color mask
        */
@@ -2343,24 +1732,41 @@ _mesa_meta_glsl_Clear(struct gl_context *ctx, GLbitfield buffers)
 
    _mesa_meta_begin(ctx, metaSave);
 
-   meta_glsl_clear_init(ctx, clear);
+   if (glsl) {
+      meta_glsl_clear_init(ctx, clear);
+
+      x0 = ((float) fb->_Xmin / fb->Width)  * 2.0f - 1.0f;
+      y0 = ((float) fb->_Ymin / fb->Height) * 2.0f - 1.0f;
+      x1 = ((float) fb->_Xmax / fb->Width)  * 2.0f - 1.0f;
+      y1 = ((float) fb->_Ymax / fb->Height) * 2.0f - 1.0f;
+      z = -invert_z(ctx->Depth.Clear);
+   } else {
+      _mesa_meta_setup_vertex_objects(&clear->VAO, &clear->VBO, false, 3, 0, 4);
+
+      x0 = (float) fb->_Xmin;
+      y0 = (float) fb->_Ymin;
+      x1 = (float) fb->_Xmax;
+      y1 = (float) fb->_Ymax;
+      z = invert_z(ctx->Depth.Clear);
+   }
 
    if (fb->_IntegerColor) {
+      assert(glsl);
       _mesa_UseProgram(clear->IntegerShaderProg);
       _mesa_Uniform4iv(clear->IntegerColorLocation, 1,
                          ctx->Color.ClearColor.i);
-   } else {
+   } else if (glsl) {
       _mesa_UseProgram(clear->ShaderProg);
       _mesa_Uniform4fv(clear->ColorLocation, 1,
                          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 */
+      /* Only draw to the buffers we were asked to clear. */
+      _mesa_meta_drawbuffers_from_bitfield(buffers & BUFFER_BITS_COLOR);
+
+      /* leave colormask state as-is */
 
       /* Clears never have the color clamped. */
       if (ctx->Extensions.ARB_color_buffer_float)
@@ -2408,20 +1814,22 @@ _mesa_meta_glsl_Clear(struct gl_context *ctx, GLbitfield buffers)
    verts[3].y = y1;
    verts[3].z = z;
 
+   if (!glsl) {
+      for (i = 0; i < 4; i++) {
+         verts[i].r = ctx->Color.ClearColor.f[0];
+         verts[i].g = ctx->Color.ClearColor.f[1];
+         verts[i].b = ctx->Color.ClearColor.f[2];
+         verts[i].a = ctx->Color.ClearColor.f[3];
+      }
+   }
+
    /* upload new vertex data */
    _mesa_BufferData(GL_ARRAY_BUFFER_ARB, sizeof(verts), verts,
                       GL_DYNAMIC_DRAW_ARB);
 
    /* 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);
-      }
+      _mesa_DrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, fb->MaxNumLayers);
    } else {
       _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4);
    }
@@ -2439,13 +1847,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 ||
@@ -2468,31 +1871,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);
-
-      /* 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);
-   }
+   /* Silence valgrind warnings about reading uninitialized stack. */
+   memset(verts, 0, sizeof(verts));
 
-   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!) */
    {
@@ -2505,32 +1892,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 */
@@ -2541,7 +1924,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
@@ -2625,7 +2028,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);
@@ -2659,7 +2062,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);
@@ -2691,17 +2094,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.
@@ -2791,7 +2190,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!) */
    {
@@ -2804,43 +2209,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;
+      verts[3].tex[0] = 0.0F;
+      verts[3].tex[1] = tex->Ttop;
    }
 
-   if (drawpix->ArrayObj == 0) {
-      /* one-time setup: create vertex array object */
-      _mesa_GenVertexArrays(1, &drawpix->ArrayObj);
-   }
-   _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;
 
@@ -2853,8 +2244,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);
 
@@ -2896,22 +2287,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;
 
@@ -2963,9 +2352,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;
@@ -2976,7 +2362,7 @@ _mesa_meta_Bitmap(struct gl_context *ctx,
    if (ctx->_ImageTransferState ||
        ctx->FragmentProgram._Enabled ||
        ctx->Fog.Enabled ||
-       ctx->Texture._EnabledUnits ||
+       ctx->Texture._MaxEnabledTexImageUnit != -1 ||
        width > tex->MaxSize ||
        height > tex->MaxSize) {
       _swrast_Bitmap(ctx, x, y, width, height, unpack, bitmap1);
@@ -2999,33 +2385,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);
-
-      /* 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);
-   }
+   _mesa_meta_setup_vertex_objects(&bitmap->VAO, &bitmap->VBO, false, 3, 2, 4);
 
-   newTex = alloc_texture(tex, width, height, texIntFormat);
+   newTex = _mesa_meta_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!) */
    {
@@ -3039,23 +2404,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];
@@ -3089,8 +2454,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);
 
@@ -3104,102 +2469,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.
@@ -3209,16 +2478,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}
@@ -3226,6 +2495,16 @@ setup_texture_coords(GLenum faceTarget,
    GLuint i;
    GLfloat r;
 
+   if (faceTarget == GL_TEXTURE_CUBE_MAP_ARRAY)
+      faceTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + slice % 6;
+
+   /* 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:
@@ -3291,532 +2570,160 @@ setup_texture_coords(GLenum faceTarget,
       /* loop over quad verts */
       for (i = 0; i < 4; i++) {
          /* Compute sc = +/-scale and tc = +/-scale.
-          * Not +/-1 to avoid cube face selection ambiguity near the edges,
-          * though that can still sometimes happen with this scale factor...
-          */
-         const GLfloat scale = 0.9999f;
-         const GLfloat sc = (2.0f * st[i][0] - 1.0f) * scale;
-         const GLfloat tc = (2.0f * st[i][1] - 1.0f) * scale;
-         GLfloat *coord;
-
-         switch (i) {
-         case 0:
-            coord = coords0;
-            break;
-         case 1:
-            coord = coords1;
-            break;
-         case 2:
-            coord = coords2;
-            break;
-         case 3:
-            coord = coords3;
-            break;
-         default:
-            assert(0);
-         }
-
-         switch (faceTarget) {
-         case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
-            coord[0] = 1.0f;
-            coord[1] = -tc;
-            coord[2] = -sc;
-            break;
-         case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
-            coord[0] = -1.0f;
-            coord[1] = -tc;
-            coord[2] = sc;
-            break;
-         case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
-            coord[0] = sc;
-            coord[1] = 1.0f;
-            coord[2] = tc;
-            break;
-         case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
-            coord[0] = sc;
-            coord[1] = -1.0f;
-            coord[2] = -tc;
-            break;
-         case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
-            coord[0] = sc;
-            coord[1] = -tc;
-            coord[2] = 1.0f;
-            break;
-         case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
-            coord[0] = -sc;
-            coord[1] = -tc;
-            coord[2] = -1.0f;
-            break;
-         default:
-            assert(0);
-         }
-      }
-      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);
-   }
-
-   /* 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)
-{
-   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;
-   case GL_TEXTURE_2D:
-      mipmap->sampler_2d.type = "sampler2D";
-      mipmap->sampler_2d.func = "texture2D";
-      mipmap->sampler_2d.texcoords = "texCoords.xy";
-      return &mipmap->sampler_2d;
-   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;
-   case GL_TEXTURE_CUBE_MAP:
-      mipmap->sampler_cubemap.type = "samplerCube";
-      mipmap->sampler_cubemap.func = "textureCube";
-      mipmap->sampler_cubemap.texcoords = "texCoords";
-      return &mipmap->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;
-   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;
-   default:
-      _mesa_problem(NULL, "Unexpected texture target 0x%x in"
-                    " setup_texture_sampler()\n", target);
-      return NULL;
-   }
-}
-
-
-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"
-                                  "#ifdef GL_ES\n"
-                                  "precision highp float;\n"
-                                  "#endif\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"
-                                  "#ifdef GL_ES\n"
-                                  "precision highp float;\n"
-                                  "#endif\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)
-{
-   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;
-      }
+          * Not +/-1 to avoid cube face selection ambiguity near the edges,
+          * though that can still sometimes happen with this scale factor...
+          */
+         const GLfloat scale = 0.9999f;
+         const GLfloat sc = (2.0f * st[i][0] - 1.0f) * scale;
+         const GLfloat tc = (2.0f * st[i][1] - 1.0f) * scale;
+         GLfloat *coord;
 
-      assert(dstWidth == ctx->DrawBuffer->Width);
-      assert(dstHeight == ctx->DrawBuffer->Height);
+         switch (i) {
+         case 0:
+            coord = coords0;
+            break;
+         case 1:
+            coord = coords1;
+            break;
+         case 2:
+            coord = coords2;
+            break;
+         case 3:
+            coord = coords3;
+            break;
+         default:
+            unreachable("not reached");
+         }
 
-      /* setup viewport */
-      _mesa_set_viewport(ctx, 0, 0, 0, dstWidth, dstHeight);
+         coord[3] = (float) (slice / 6);
 
-      _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4);
+         switch (faceTarget) {
+         case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
+            coord[0] = 1.0f;
+            coord[1] = -tc;
+            coord[2] = -sc;
+            break;
+         case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
+            coord[0] = -1.0f;
+            coord[1] = -tc;
+            coord[2] = sc;
+            break;
+         case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
+            coord[0] = sc;
+            coord[1] = 1.0f;
+            coord[2] = tc;
+            break;
+         case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
+            coord[0] = sc;
+            coord[1] = -1.0f;
+            coord[2] = -tc;
+            break;
+         case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
+            coord[0] = sc;
+            coord[1] = -tc;
+            coord[2] = 1.0f;
+            break;
+         case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
+            coord[0] = -sc;
+            coord[1] = -tc;
+            coord[2] = -1.0f;
+            break;
+         default:
+            assert(0);
+         }
+      }
+      break;
+   default:
+      assert(!"unexpected target in _mesa_meta_setup_texture_coords()");
    }
+}
 
-   _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);
+static struct blit_shader *
+choose_blit_shader(GLenum target, struct blit_shader_table *table)
+{
+   switch(target) {
+   case GL_TEXTURE_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:
+      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.
+       */
+      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:
+      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:
+      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:
+      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);
+      return NULL;
+   }
 }
 
+void
+_mesa_meta_blit_shader_table_cleanup(struct blit_shader_table *table)
+{
+   _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;
-
-   baseFormat = _mesa_get_format_base_format(format);
+   const GLenum baseFormat = _mesa_get_format_base_format(format);
+   const GLenum datatype = _mesa_get_format_datatype(format);
+   const GLint format_red_bits = _mesa_get_format_bits(format, GL_RED_BITS);
 
    switch (baseFormat) {
    case GL_RGBA:
@@ -3827,30 +2734,24 @@ get_temp_image_type(struct gl_context *ctx, gl_format format)
    case GL_LUMINANCE:
    case GL_LUMINANCE_ALPHA:
    case GL_INTENSITY:
-      if (ctx->DrawBuffer->Visual.redBits <= 8) {
+      if (datatype == GL_INT || datatype == GL_UNSIGNED_INT) {
+         return datatype;
+      } else if (format_red_bits <= 8) {
          return GL_UNSIGNED_BYTE;
-      } else if (ctx->DrawBuffer->Visual.redBits <= 16) {
+      } else if (format_red_bits <= 16) {
          return GL_UNSIGNED_SHORT;
-      } else {
-         GLenum datatype = _mesa_get_format_datatype(format);
-         if (datatype == GL_INT || datatype == GL_UNSIGNED_INT)
-            return datatype;
-         return GL_FLOAT;
       }
-   case GL_DEPTH_COMPONENT: {
-      GLenum datatype = _mesa_get_format_datatype(format);
+      return GL_FLOAT;
+   case GL_DEPTH_COMPONENT:
       if (datatype == GL_FLOAT)
          return GL_FLOAT;
       else
          return GL_UNSIGNED_INT;
-   }
-   case GL_DEPTH_STENCIL: {
-      GLenum datatype = _mesa_get_format_datatype(format);
+   case GL_DEPTH_STENCIL:
       if (datatype == GL_FLOAT)
          return GL_FLOAT_32_UNSIGNED_INT_24_8_REV;
       else
          return GL_UNSIGNED_INT_24_8;
-   }
    default:
       _mesa_problem(ctx, "Unexpected format %d in get_temp_image_type()",
                    baseFormat);
@@ -3858,6 +2759,86 @@ get_temp_image_type(struct gl_context *ctx, gl_format format)
    }
 }
 
+/**
+ * Attempts to wrap the destination texture in an FBO and use
+ * glBlitFramebuffer() to implement glCopyTexSubImage().
+ */
+static bool
+copytexsubimage_using_blit_framebuffer(struct gl_context *ctx, GLuint dims,
+                                       struct gl_texture_image *texImage,
+                                       GLint xoffset,
+                                       GLint yoffset,
+                                       GLint zoffset,
+                                       struct gl_renderbuffer *rb,
+                                       GLint x, GLint y,
+                                       GLsizei width, GLsizei height)
+{
+   struct gl_texture_object *texObj = texImage->TexObject;
+   GLuint fbo;
+   bool success = false;
+   GLbitfield mask;
+   GLenum status;
+
+   if (!ctx->Extensions.ARB_framebuffer_object)
+      return false;
+
+   _mesa_unlock_texture(ctx, texObj);
+
+   _mesa_meta_begin(ctx, MESA_META_ALL & ~MESA_META_DRAW_BUFFERS);
+
+   _mesa_GenFramebuffers(1, &fbo);
+   _mesa_BindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
+
+   if (rb->_BaseFormat == GL_DEPTH_STENCIL ||
+       rb->_BaseFormat == GL_DEPTH_COMPONENT) {
+      _mesa_meta_bind_fbo_image(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
+                                texImage, zoffset);
+      mask = GL_DEPTH_BUFFER_BIT;
+
+      if (rb->_BaseFormat == GL_DEPTH_STENCIL &&
+          texImage->_BaseFormat == GL_DEPTH_STENCIL) {
+         _mesa_meta_bind_fbo_image(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
+                                   texImage, zoffset);
+         mask |= GL_STENCIL_BUFFER_BIT;
+      }
+      _mesa_DrawBuffer(GL_NONE);
+   } else {
+      _mesa_meta_bind_fbo_image(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+                                texImage, zoffset);
+      mask = GL_COLOR_BUFFER_BIT;
+      _mesa_DrawBuffer(GL_COLOR_ATTACHMENT0);
+   }
+
+   status = _mesa_CheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
+   if (status != GL_FRAMEBUFFER_COMPLETE)
+      goto out;
+
+   ctx->Meta->Blit.no_ctsi_fallback = true;
+
+   /* Since we've bound a new draw framebuffer, we need to update
+    * its derived state -- _Xmin, etc -- for BlitFramebuffer's clipping to
+    * be correct.
+    */
+   _mesa_update_state(ctx);
+
+   /* We skip the core BlitFramebuffer checks for format consistency, which
+    * are too strict for CopyTexImage.  We know meta will be fine with format
+    * changes.
+    */
+   mask = _mesa_meta_BlitFramebuffer(ctx, x, y,
+                                     x + width, y + height,
+                                     xoffset, yoffset,
+                                     xoffset + width, yoffset + height,
+                                     mask, GL_NEAREST);
+   ctx->Meta->Blit.no_ctsi_fallback = false;
+   success = mask == 0x0;
+
+ out:
+   _mesa_lock_texture(ctx, texObj);
+   _mesa_DeleteFramebuffers(1, &fbo);
+   _mesa_meta_end(ctx);
+   return success;
+}
 
 /**
  * Helper for _mesa_meta_CopyTexSubImage1/2/3D() functions.
@@ -3876,6 +2857,15 @@ _mesa_meta_CopyTexSubImage(struct gl_context *ctx, GLuint dims,
    GLint bpp;
    void *buf;
 
+   if (copytexsubimage_using_blit_framebuffer(ctx, dims,
+                                              texImage,
+                                              xoffset, yoffset, zoffset,
+                                              rb,
+                                              x, y,
+                                              width, height)) {
+      return;
+   }
+
    /* Choose format/type for temporary image buffer */
    format = _mesa_get_format_base_format(texImage->TexFormat);
    if (format == GL_LUMINANCE ||
@@ -3942,6 +2932,33 @@ _mesa_meta_CopyTexSubImage(struct gl_context *ctx, GLuint dims,
    free(buf);
 }
 
+static void
+meta_decompress_fbo_cleanup(struct decompress_fbo_state *decompress_fbo)
+{
+   if (decompress_fbo->FBO != 0) {
+      _mesa_DeleteFramebuffers(1, &decompress_fbo->FBO);
+      _mesa_DeleteRenderbuffers(1, &decompress_fbo->RBO);
+   }
+
+   memset(decompress_fbo, 0, sizeof(*decompress_fbo));
+}
+
+static void
+meta_decompress_cleanup(struct decompress_state *decompress)
+{
+   meta_decompress_fbo_cleanup(&decompress->byteFBO);
+   meta_decompress_fbo_cleanup(&decompress->floatFBO);
+
+   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
@@ -3952,7 +2969,7 @@ _mesa_meta_CopyTexSubImage(struct gl_context *ctx, GLuint dims,
  * \param dest  destination buffer
  * \param destRowLength  dest image rowLength (ala GL_PACK_ROW_LENGTH)
  */
-static void
+static bool
 decompress_texture_image(struct gl_context *ctx,
                          struct gl_texture_image *texImage,
                          GLuint slice,
@@ -3960,87 +2977,107 @@ decompress_texture_image(struct gl_context *ctx,
                          GLvoid *dest)
 {
    struct decompress_state *decompress = &ctx->Meta->Decompress;
+   struct decompress_fbo_state *decompress_fbo;
    struct gl_texture_object *texObj = texImage->TexObject;
    const GLint width = texImage->Width;
    const GLint height = texImage->Height;
    const GLint depth = texImage->Height;
    const GLenum target = texObj->Target;
+   GLenum rbFormat;
    GLenum faceTarget;
-   struct vertex {
-      GLfloat x, y, tex[3];
-   };
    struct vertex verts[4];
-   GLuint fboDrawSave, fboReadSave;
-   GLuint rbSave;
    GLuint samplerSave;
+   GLenum status;
+   const bool use_glsl_version = ctx->Extensions.ARB_vertex_shader &&
+                                      ctx->Extensions.ARB_fragment_shader;
+
+   switch (_mesa_get_format_datatype(texImage->TexFormat)) {
+   case GL_FLOAT:
+      decompress_fbo = &decompress->floatFBO;
+      rbFormat = GL_RGBA32F;
+      break;
+   case GL_UNSIGNED_NORMALIZED:
+      decompress_fbo = &decompress->byteFBO;
+      rbFormat = GL_RGBA;
+      break;
+   default:
+      return false;
+   }
 
    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 false;
+
+   case GL_TEXTURE_3D:
+      assert(!"No compressed 3D textures.");
+      return false;
+
+   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()) */
-   fboDrawSave = ctx->DrawBuffer->Name;
-   fboReadSave = ctx->ReadBuffer->Name;
-   rbSave = ctx->CurrentRenderbuffer ? ctx->CurrentRenderbuffer->Name : 0;
-
-   _mesa_meta_begin(ctx, MESA_META_ALL & ~MESA_META_PIXEL_STORE);
+   _mesa_meta_begin(ctx, MESA_META_ALL & ~(MESA_META_PIXEL_STORE |
+                                           MESA_META_DRAW_BUFFERS));
 
    samplerSave = ctx->Texture.Unit[ctx->Texture.CurrentUnit].Sampler ?
          ctx->Texture.Unit[ctx->Texture.CurrentUnit].Sampler->Name : 0;
 
    /* Create/bind FBO/renderbuffer */
-   if (decompress->FBO == 0) {
-      _mesa_GenFramebuffers(1, &decompress->FBO);
-      _mesa_GenRenderbuffers(1, &decompress->RBO);
-      _mesa_BindFramebuffer(GL_FRAMEBUFFER_EXT, decompress->FBO);
-      _mesa_BindRenderbuffer(GL_RENDERBUFFER_EXT, decompress->RBO);
+   if (decompress_fbo->FBO == 0) {
+      _mesa_GenFramebuffers(1, &decompress_fbo->FBO);
+      _mesa_GenRenderbuffers(1, &decompress_fbo->RBO);
+      _mesa_BindFramebuffer(GL_FRAMEBUFFER_EXT, decompress_fbo->FBO);
+      _mesa_BindRenderbuffer(GL_RENDERBUFFER_EXT, decompress_fbo->RBO);
       _mesa_FramebufferRenderbuffer(GL_FRAMEBUFFER_EXT,
                                        GL_COLOR_ATTACHMENT0_EXT,
                                        GL_RENDERBUFFER_EXT,
-                                       decompress->RBO);
+                                       decompress_fbo->RBO);
    }
    else {
-      _mesa_BindFramebuffer(GL_FRAMEBUFFER_EXT, decompress->FBO);
+      _mesa_BindFramebuffer(GL_FRAMEBUFFER_EXT, decompress_fbo->FBO);
    }
 
    /* alloc dest surface */
-   if (width > decompress->Width || height > decompress->Height) {
-      _mesa_BindRenderbuffer(GL_RENDERBUFFER_EXT, decompress->RBO);
-      _mesa_RenderbufferStorage(GL_RENDERBUFFER_EXT, GL_RGBA,
-                                   width, height);
-      decompress->Width = width;
-      decompress->Height = height;
+   if (width > decompress_fbo->Width || height > decompress_fbo->Height) {
+      _mesa_BindRenderbuffer(GL_RENDERBUFFER_EXT, decompress_fbo->RBO);
+      _mesa_RenderbufferStorage(GL_RENDERBUFFER_EXT, rbFormat,
+                                width, height);
+      status = _mesa_CheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
+      if (status != GL_FRAMEBUFFER_COMPLETE) {
+         /* If the framebuffer isn't complete then we'll leave
+          * decompress_fbo->Width as zero so that it will fail again next time
+          * too */
+         _mesa_meta_end(ctx);
+         return false;
+      }
+      decompress_fbo->Width = width;
+      decompress_fbo->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) {
@@ -4059,25 +3096,25 @@ 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_MatrixMode(GL_PROJECTION);
-   _mesa_LoadIdentity();
-   _mesa_Ortho(0.0, width, 0.0, height, -1.0, 1.0);
    _mesa_set_viewport(ctx, 0, 0, 0, width, height);
 
    /* upload new vertex data */
@@ -4085,7 +3122,9 @@ decompress_texture_image(struct gl_context *ctx,
 
    /* 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 */
@@ -4145,21 +3184,14 @@ 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);
 
    _mesa_meta_end(ctx);
 
-   /* restore fbo bindings */
-   if (fboDrawSave == fboReadSave) {
-      _mesa_BindFramebuffer(GL_FRAMEBUFFER_EXT, fboDrawSave);
-   }
-   else {
-      _mesa_BindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, fboDrawSave);
-      _mesa_BindFramebuffer(GL_READ_FRAMEBUFFER_EXT, fboReadSave);
-   }
-   _mesa_BindRenderbuffer(GL_RENDERBUFFER_EXT, rbSave);
+   return true;
 }
 
 
@@ -4173,20 +3205,17 @@ _mesa_meta_GetTexImage(struct gl_context *ctx,
                        GLenum format, GLenum type, GLvoid *pixels,
                        struct gl_texture_image *texImage)
 {
-   /* We can only use the decompress-with-blit method here if the texels are
-    * unsigned, normalized values.  We could handle signed and unnormalized 
-    * with floating point renderbuffers...
-    */
-   if (_mesa_is_format_compressed(texImage->TexFormat) &&
-       _mesa_get_format_datatype(texImage->TexFormat)
-       == GL_UNSIGNED_NORMALIZED) {
+   if (_mesa_is_format_compressed(texImage->TexFormat)) {
       struct gl_texture_object *texObj = texImage->TexObject;
       GLuint slice;
+      bool result;
+
       /* Need to unlock the texture here to prevent deadlock... */
       _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
@@ -4202,14 +3231,19 @@ _mesa_meta_GetTexImage(struct gl_context *ctx,
          else {
             dst = pixels;
          }
-         decompress_texture_image(ctx, texImage, slice, format, type, dst);
+         result = decompress_texture_image(ctx, texImage, slice,
+                                           format, type, dst);
+         if (!result)
+            break;
       }
       /* ... and relock it */
       _mesa_lock_texture(ctx, texObj);
+
+      if (result)
+         return;
    }
-   else {
-      _mesa_get_teximage(ctx, format, type, pixels, texImage);
-   }
+
+   _mesa_get_teximage(ctx, format, type, pixels, texImage);
 }
 
 
@@ -4234,13 +3268,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);
@@ -4264,7 +3298,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);
    }
 
@@ -4298,7 +3332,7 @@ _mesa_meta_DrawTex(struct gl_context *ctx, GLfloat x, GLfloat y, GLfloat z,
          GLfloat s, t, s1, t1;
          GLuint tw, th;
 
-         if (!ctx->Texture.Unit[i]._ReallyEnabled) {
+         if (!ctx->Texture.Unit[i]._Current) {
             GLuint j;
             for (j = 0; j < 4; j++) {
                verts[j].st[i][0] = 0.0f;
@@ -4337,3 +3371,192 @@ _mesa_meta_DrawTex(struct gl_context *ctx, GLfloat x, GLfloat y, GLfloat z,
 
    _mesa_meta_end(ctx);
 }
+
+static bool
+cleartexsubimage_color(struct gl_context *ctx,
+                       struct gl_texture_image *texImage,
+                       const GLvoid *clearValue,
+                       GLint zoffset)
+{
+   mesa_format format;
+   union gl_color_union colorValue;
+   GLenum datatype;
+   GLenum status;
+
+   _mesa_meta_bind_fbo_image(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+                             texImage, zoffset);
+
+   status = _mesa_CheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
+   if (status != GL_FRAMEBUFFER_COMPLETE)
+      return false;
+
+   /* We don't want to apply an sRGB conversion so override the format */
+   format = _mesa_get_srgb_format_linear(texImage->TexFormat);
+   datatype = _mesa_get_format_datatype(format);
+
+   switch (datatype) {
+   case GL_UNSIGNED_INT:
+   case GL_INT:
+      if (clearValue)
+         _mesa_unpack_uint_rgba_row(format, 1, clearValue,
+                                    (GLuint (*)[4]) colorValue.ui);
+      else
+         memset(&colorValue, 0, sizeof colorValue);
+      if (datatype == GL_INT)
+         _mesa_ClearBufferiv(GL_COLOR, 0, colorValue.i);
+      else
+         _mesa_ClearBufferuiv(GL_COLOR, 0, colorValue.ui);
+      break;
+   default:
+      if (clearValue)
+         _mesa_unpack_rgba_row(format, 1, clearValue,
+                               (GLfloat (*)[4]) colorValue.f);
+      else
+         memset(&colorValue, 0, sizeof colorValue);
+      _mesa_ClearBufferfv(GL_COLOR, 0, colorValue.f);
+      break;
+   }
+
+   return true;
+}
+
+static bool
+cleartexsubimage_depth_stencil(struct gl_context *ctx,
+                               struct gl_texture_image *texImage,
+                               const GLvoid *clearValue,
+                               GLint zoffset)
+{
+   GLint stencilValue;
+   GLfloat depthValue;
+   GLenum status;
+
+   _mesa_meta_bind_fbo_image(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
+                             texImage, zoffset);
+
+   if (texImage->_BaseFormat == GL_DEPTH_STENCIL)
+      _mesa_meta_bind_fbo_image(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
+                                texImage, zoffset);
+
+   status = _mesa_CheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
+   if (status != GL_FRAMEBUFFER_COMPLETE)
+      return false;
+
+   if (clearValue) {
+      GLuint depthStencilValue[2];
+
+      /* Convert the clearValue from whatever format it's in to a floating
+       * point value for the depth and an integer value for the stencil index
+       */
+      _mesa_unpack_float_32_uint_24_8_depth_stencil_row(texImage->TexFormat,
+                                                        1, /* n */
+                                                        clearValue,
+                                                        depthStencilValue);
+      /* We need a memcpy here instead of a cast because we need to
+       * reinterpret the bytes as a float rather than converting it
+       */
+      memcpy(&depthValue, depthStencilValue, sizeof depthValue);
+      stencilValue = depthStencilValue[1] & 0xff;
+   } else {
+      depthValue = 0.0f;
+      stencilValue = 0;
+   }
+
+   if (texImage->_BaseFormat == GL_DEPTH_STENCIL)
+      _mesa_ClearBufferfi(GL_DEPTH_STENCIL, 0, depthValue, stencilValue);
+   else
+      _mesa_ClearBufferfv(GL_DEPTH, 0, &depthValue);
+
+   return true;
+}
+
+static bool
+cleartexsubimage_for_zoffset(struct gl_context *ctx,
+                             struct gl_texture_image *texImage,
+                             GLint zoffset,
+                             const GLvoid *clearValue)
+{
+   GLuint fbo;
+   bool success;
+
+   _mesa_GenFramebuffers(1, &fbo);
+   _mesa_BindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
+
+   switch(texImage->_BaseFormat) {
+   case GL_DEPTH_STENCIL:
+   case GL_DEPTH_COMPONENT:
+      success = cleartexsubimage_depth_stencil(ctx, texImage,
+                                               clearValue, zoffset);
+      break;
+   default:
+      success = cleartexsubimage_color(ctx, texImage, clearValue, zoffset);
+      break;
+   }
+
+   _mesa_DeleteFramebuffers(1, &fbo);
+
+   return success;
+}
+
+static bool
+cleartexsubimage_using_fbo(struct gl_context *ctx,
+                           struct gl_texture_image *texImage,
+                           GLint xoffset, GLint yoffset, GLint zoffset,
+                           GLsizei width, GLsizei height, GLsizei depth,
+                           const GLvoid *clearValue)
+{
+   bool success = true;
+   GLint z;
+
+   _mesa_meta_begin(ctx,
+                    MESA_META_SCISSOR |
+                    MESA_META_COLOR_MASK |
+                    MESA_META_DITHER |
+                    MESA_META_FRAMEBUFFER_SRGB);
+
+   _mesa_set_enable(ctx, GL_DITHER, GL_FALSE);
+
+   _mesa_set_enable(ctx, GL_SCISSOR_TEST, GL_TRUE);
+   _mesa_Scissor(xoffset, yoffset, width, height);
+
+   for (z = zoffset; z < zoffset + depth; z++) {
+      if (!cleartexsubimage_for_zoffset(ctx, texImage, z, clearValue)) {
+         success = false;
+         break;
+      }
+   }
+
+   _mesa_meta_end(ctx);
+
+   return success;
+}
+
+extern void
+_mesa_meta_ClearTexSubImage(struct gl_context *ctx,
+                            struct gl_texture_image *texImage,
+                            GLint xoffset, GLint yoffset, GLint zoffset,
+                            GLsizei width, GLsizei height, GLsizei depth,
+                            const GLvoid *clearValue)
+{
+   bool res;
+
+   _mesa_unlock_texture(ctx, texImage->TexObject);
+
+   res = cleartexsubimage_using_fbo(ctx, texImage,
+                                    xoffset, yoffset, zoffset,
+                                    width, height, depth,
+                                    clearValue);
+
+   _mesa_lock_texture(ctx, texImage->TexObject);
+
+   if (res)
+      return;
+
+   _mesa_warning(ctx,
+                 "Falling back to mapping the texture in "
+                 "glClearTexSubImage\n");
+
+   _mesa_store_cleartexsubimage(ctx, texImage,
+                                xoffset, yoffset, zoffset,
+                                width, height, depth,
+                                clearValue);
+}