meta: Use the _mesa_meta_compile_and_link_program helper more places.
[mesa.git] / src / mesa / drivers / common / meta.c
index 439c7e2f6858449e3b33f9f56f79854f539b6480..bdcf316e455b81f3a13e4bd4a755dbed461c707a 100644 (file)
@@ -41,7 +41,6 @@
 #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/enable.h"
@@ -49,6 +48,7 @@
 #include "main/feedback.h"
 #include "main/formats.h"
 #include "main/format_unpack.h"
+#include "main/framebuffer.h"
 #include "main/glformats.h"
 #include "main/image.h"
 #include "main/macros.h"
@@ -62,6 +62,7 @@
 #include "main/polygon.h"
 #include "main/queryobj.h"
 #include "main/readpix.h"
+#include "main/renderbuffer.h"
 #include "main/scissor.h"
 #include "main/shaderapi.h"
 #include "main/shaderobj.h"
@@ -96,47 +97,28 @@ static struct blit_shader *
 choose_blit_shader(GLenum target, struct blit_shader_table *table);
 
 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);
+static void meta_glsl_clear_cleanup(struct gl_context *ctx,
+                                    struct clear_state *clear);
+static void meta_decompress_cleanup(struct gl_context *ctx,
+                                    struct decompress_state *decompress);
+static void meta_drawpix_cleanup(struct gl_context *ctx,
+                                 struct drawpix_state *drawpix);
 
 void
-_mesa_meta_bind_fbo_image(GLenum fboTarget, GLenum attachment,
-                          struct gl_texture_image *texImage, GLuint layer)
+_mesa_meta_framebuffer_texture_image(struct gl_context *ctx,
+                                     struct gl_framebuffer *fb,
+                                     GLenum attachment,
+                                     struct gl_texture_image *texImage,
+                                     GLuint layer)
 {
    struct gl_texture_object *texObj = texImage->TexObject;
    int level = texImage->Level;
-   GLenum texTarget = texObj->Target;
+   const GLenum texTarget = texObj->Target == GL_TEXTURE_CUBE_MAP
+      ? GL_TEXTURE_CUBE_MAP_POSITIVE_X + texImage->Face
+      : texObj->Target;
 
-   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;
-
-      _mesa_FramebufferTexture2D(fboTarget,
-                                 attachment,
-                                 texTarget,
-                                 texObj->Name,
-                                 level);
-   }
+   _mesa_framebuffer_texture(ctx, fb, attachment, texObj, texTarget,
+                             level, layer, false, __func__);
 }
 
 GLuint
@@ -225,8 +207,6 @@ _mesa_meta_compile_and_link_program(struct gl_context *ctx,
    _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);
@@ -243,23 +223,20 @@ _mesa_meta_compile_and_link_program(struct gl_context *ctx,
 void
 _mesa_meta_setup_blit_shader(struct gl_context *ctx,
                              GLenum target,
+                             bool do_depth,
                              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;
+   const char *fs_input, *vs_preprocess, *fs_preprocess;
+   void *mem_ctx;
 
    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";
@@ -272,17 +249,20 @@ _mesa_meta_setup_blit_shader(struct gl_context *ctx,
       return;
    }
 
+   mem_ctx = ralloc_context(NULL);
+
    vs_source = ralloc_asprintf(mem_ctx,
                 "%s\n"
-                "%s vec2 position;\n"
-                "%s vec4 textureCoords;\n"
-                "%s vec4 texCoords;\n"
+                "#extension GL_ARB_explicit_attrib_location: enable\n"
+                "layout(location = 0) in vec2 position;\n"
+                "layout(location = 1) in vec4 textureCoords;\n"
+                "out vec4 texCoords;\n"
                 "void main()\n"
                 "{\n"
                 "   texCoords = textureCoords;\n"
                 "   gl_Position = vec4(position, 0.0, 1.0);\n"
                 "}\n",
-                vs_preprocess, vs_input, vs_input, vs_output);
+                vs_preprocess);
 
    fs_source = ralloc_asprintf(mem_ctx,
                 "%s\n"
@@ -292,10 +272,11 @@ _mesa_meta_setup_blit_shader(struct gl_context *ctx,
                 "void main()\n"
                 "{\n"
                 "   gl_FragColor = %s(texSampler, %s);\n"
-                "   gl_FragDepth = gl_FragColor.x;\n"
+                "%s"
                 "}\n",
                 fs_preprocess, shader->type, fs_input,
-                shader->func, shader->texcoords);
+                shader->func, shader->texcoords,
+                do_depth ?  "   gl_FragDepth = gl_FragColor.x;\n" : "");
 
    _mesa_meta_compile_and_link_program(ctx, vs_source, fs_source,
                                        ralloc_asprintf(mem_ctx, "%s blit",
@@ -307,13 +288,13 @@ _mesa_meta_setup_blit_shader(struct gl_context *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.
+ * Regardless of whether a new VAO is created, the object referenced by \c VAO
+ * will be bound into the GL state vector when this function terminates.  The
+ * object referenced by \c VBO will \b not be bound.
  *
  * \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
+ * \param buf_obj   Storage for vertex buffer object pointer.  If \c NULL, 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,
@@ -330,57 +311,84 @@ _mesa_meta_setup_blit_shader(struct gl_context *ctx,
  * Use \c texcoord_size instead.
  */
 void
-_mesa_meta_setup_vertex_objects(GLuint *VAO, GLuint *VBO,
+_mesa_meta_setup_vertex_objects(struct gl_context *ctx,
+                                GLuint *VAO, struct gl_buffer_object **buf_obj,
                                 bool use_generic_attributes,
                                 unsigned vertex_size, unsigned texcoord_size,
                                 unsigned color_size)
 {
    if (*VAO == 0) {
-      assert(*VBO == 0);
+      struct gl_vertex_array_object *array_obj;
+      assert(*buf_obj == NULL);
 
       /* create vertex array object */
       _mesa_GenVertexArrays(1, VAO);
       _mesa_BindVertexArray(*VAO);
 
+      array_obj = _mesa_lookup_vao(ctx, *VAO);
+      assert(array_obj != NULL);
+
       /* 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);
+      *buf_obj = ctx->Driver.NewBufferObject(ctx, 0xDEADBEEF);
+      if (*buf_obj == NULL)
+         return;
+
+      _mesa_buffer_data(ctx, *buf_obj, GL_NONE, 4 * sizeof(struct vertex), NULL,
+                        GL_DYNAMIC_DRAW, __func__);
 
       /* 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);
-
+         _mesa_update_array_format(ctx, array_obj, VERT_ATTRIB_GENERIC(0),
+                                   vertex_size, GL_FLOAT, GL_RGBA, GL_FALSE,
+                                   GL_FALSE, GL_FALSE,
+                                   offsetof(struct vertex, x), true);
+         _mesa_bind_vertex_buffer(ctx, array_obj, VERT_ATTRIB_GENERIC(0),
+                                  *buf_obj, 0, sizeof(struct vertex));
+         _mesa_enable_vertex_array_attrib(ctx, array_obj,
+                                          VERT_ATTRIB_GENERIC(0));
          if (texcoord_size > 0) {
-            _mesa_VertexAttribPointer(1, texcoord_size, GL_FLOAT, GL_FALSE,
-                                      sizeof(struct vertex), OFFSET(tex));
-            _mesa_EnableVertexAttribArray(1);
+            _mesa_update_array_format(ctx, array_obj, VERT_ATTRIB_GENERIC(1),
+                                      texcoord_size, GL_FLOAT, GL_RGBA,
+                                      GL_FALSE, GL_FALSE, GL_FALSE,
+                                      offsetof(struct vertex, tex), false);
+            _mesa_bind_vertex_buffer(ctx, array_obj, VERT_ATTRIB_GENERIC(1),
+                                     *buf_obj, 0, sizeof(struct vertex));
+            _mesa_enable_vertex_array_attrib(ctx, array_obj,
+                                             VERT_ATTRIB_GENERIC(1));
          }
       } else {
-         _mesa_VertexPointer(vertex_size, GL_FLOAT, sizeof(struct vertex),
-                             OFFSET(x));
-         _mesa_EnableClientState(GL_VERTEX_ARRAY);
+         _mesa_update_array_format(ctx, array_obj, VERT_ATTRIB_POS,
+                                   vertex_size, GL_FLOAT, GL_RGBA, GL_FALSE,
+                                   GL_FALSE, GL_FALSE,
+                                   offsetof(struct vertex, x), true);
+         _mesa_bind_vertex_buffer(ctx, array_obj, VERT_ATTRIB_POS,
+                                  *buf_obj, 0, sizeof(struct vertex));
+         _mesa_enable_vertex_array_attrib(ctx, array_obj, VERT_ATTRIB_POS);
 
          if (texcoord_size > 0) {
-            _mesa_TexCoordPointer(texcoord_size, GL_FLOAT,
-                                  sizeof(struct vertex), OFFSET(tex));
-            _mesa_EnableClientState(GL_TEXTURE_COORD_ARRAY);
+            _mesa_update_array_format(ctx, array_obj, VERT_ATTRIB_TEX(0),
+                                      vertex_size, GL_FLOAT, GL_RGBA, GL_FALSE,
+                                      GL_FALSE, GL_FALSE,
+                                      offsetof(struct vertex, tex), false);
+            _mesa_bind_vertex_buffer(ctx, array_obj, VERT_ATTRIB_TEX(0),
+                                     *buf_obj, 0, sizeof(struct vertex));
+            _mesa_enable_vertex_array_attrib(ctx, array_obj, VERT_ATTRIB_TEX(0));
          }
 
          if (color_size > 0) {
-            _mesa_ColorPointer(color_size, GL_FLOAT,
-                               sizeof(struct vertex), OFFSET(r));
-            _mesa_EnableClientState(GL_COLOR_ARRAY);
+            _mesa_update_array_format(ctx, array_obj, VERT_ATTRIB_COLOR0,
+                                      vertex_size, GL_FLOAT, GL_RGBA, GL_FALSE,
+                                      GL_FALSE, GL_FALSE,
+                                      offsetof(struct vertex, r), false);
+            _mesa_bind_vertex_buffer(ctx, array_obj, VERT_ATTRIB_COLOR0,
+                                     *buf_obj, 0, sizeof(struct vertex));
+            _mesa_enable_vertex_array_attrib(ctx, array_obj, VERT_ATTRIB_COLOR0);
          }
       }
    } else {
       _mesa_BindVertexArray(*VAO);
-      _mesa_BindBuffer(GL_ARRAY_BUFFER, *VBO);
    }
 }
 
@@ -391,30 +399,11 @@ _mesa_meta_setup_vertex_objects(GLuint *VAO, GLuint *VBO,
 void
 _mesa_meta_init(struct gl_context *ctx)
 {
-   ASSERT(!ctx->Meta);
+   assert(!ctx->Meta);
 
    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.
  * To be called once during context destruction.
@@ -424,12 +413,12 @@ _mesa_meta_free(struct gl_context *ctx)
 {
    GET_CURRENT_CONTEXT(old_context);
    _mesa_make_current(ctx, NULL, NULL);
-   _mesa_meta_glsl_blit_cleanup(&ctx->Meta->Blit);
-   meta_glsl_clear_cleanup(&ctx->Meta->Clear);
-   _mesa_meta_glsl_generate_mipmap_cleanup(&ctx->Meta->Mipmap);
+   _mesa_meta_glsl_blit_cleanup(ctx, &ctx->Meta->Blit);
+   meta_glsl_clear_cleanup(ctx, &ctx->Meta->Clear);
+   _mesa_meta_glsl_generate_mipmap_cleanup(ctx, &ctx->Meta->Mipmap);
    cleanup_temp_texture(&ctx->Meta->TempTex);
-   meta_decompress_cleanup(&ctx->Meta->Decompress);
-   meta_drawpix_cleanup(&ctx->Meta->DrawPix);
+   meta_decompress_cleanup(ctx, &ctx->Meta->Decompress);
+   meta_drawpix_cleanup(ctx, &ctx->Meta->DrawPix);
    if (old_context)
       _mesa_make_current(old_context, old_context->WinSysDrawBuffer, old_context->WinSysReadBuffer);
    else
@@ -465,6 +454,16 @@ _mesa_meta_begin(struct gl_context *ctx, GLbitfield state)
    save->API = ctx->API;
    ctx->API = API_OPENGL_COMPAT;
 
+   /* Mesa's extension helper functions use the current context's API to look up
+    * the version required by an extension as a step in determining whether or
+    * not it has been advertised. Since meta aims to only be restricted by the
+    * driver capability (and not by whether or not an extension has been
+    * advertised), set the helper functions' Version variable to a value that
+    * will make the checks on the context API and version unconditionally pass.
+    */
+   save->ExtensionsVersion = ctx->Extensions.Version;
+   ctx->Extensions.Version = ~0;
+
    /* Pausing transform feedback needs to be done early, or else we won't be
     * able to change other state.
     */
@@ -615,7 +614,7 @@ _mesa_meta_begin(struct gl_context *ctx, GLbitfield state)
       /* 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++) {
+      for (i = 0; i < MESA_SHADER_STAGES; i++) {
          _mesa_reference_shader_program(ctx, &save->Shader[i],
                                         ctx->Shader.CurrentProgram[i]);
       }
@@ -636,7 +635,6 @@ _mesa_meta_begin(struct gl_context *ctx, GLbitfield state)
       GLuint u, tgt;
 
       save->ActiveUnit = ctx->Texture.CurrentUnit;
-      save->ClientActiveUnit = ctx->Array.ActiveTexture;
       save->EnvMode = ctx->Texture.Unit[0].EnvMode;
 
       /* Disable all texture units */
@@ -669,7 +667,6 @@ _mesa_meta_begin(struct gl_context *ctx, GLbitfield state)
 
       /* set defaults for unit[0] */
       _mesa_ActiveTexture(GL_TEXTURE0);
-      _mesa_ClientActiveTexture(GL_TEXTURE0);
       _mesa_TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
    }
 
@@ -699,6 +696,12 @@ _mesa_meta_begin(struct gl_context *ctx, GLbitfield state)
          _mesa_Ortho(0.0, ctx->DrawBuffer->Width,
                      0.0, ctx->DrawBuffer->Height,
                      -1.0, 1.0);
+
+      if (ctx->Extensions.ARB_clip_control) {
+         save->ClipOrigin = ctx->Transform.ClipOrigin;
+         save->ClipDepthMode = ctx->Transform.ClipDepthMode;
+         _mesa_ClipControl(GL_LOWER_LEFT, GL_NEGATIVE_ONE_TO_ONE);
+      }
    }
 
    if (state & MESA_META_CLIP) {
@@ -715,8 +718,6 @@ _mesa_meta_begin(struct gl_context *ctx, GLbitfield state)
       /* save vertex array object state */
       _mesa_reference_vao(ctx, &save->VAO,
                                    ctx->Array.VAO);
-      _mesa_reference_buffer_object(ctx, &save->ArrayBufferObj,
-                                    ctx->Array.ArrayBufferObj);
       /* set some default state? */
    }
 
@@ -738,7 +739,7 @@ _mesa_meta_begin(struct gl_context *ctx, GLbitfield state)
       save->DepthNear = ctx->ViewportArray[0].Near;
       save->DepthFar = ctx->ViewportArray[0].Far;
       /* set depth range to default */
-      _mesa_DepthRange(0.0, 1.0);
+      _mesa_set_depth_range(ctx, 0, 0.0, 1.0);
    }
 
    if (state & MESA_META_CLAMP_FRAGMENT_COLOR) {
@@ -806,20 +807,9 @@ _mesa_meta_begin(struct gl_context *ctx, GLbitfield state)
    }
 
    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;
-      }
+      struct gl_framebuffer *fb = ctx->DrawBuffer;
+      memcpy(save->ColorDrawBuffers, fb->ColorDrawBuffer,
+             sizeof(save->ColorDrawBuffers));
    }
 
    /* misc */
@@ -831,10 +821,8 @@ _mesa_meta_begin(struct gl_context *ctx, GLbitfield state)
       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);
+      _mesa_reference_framebuffer(&save->DrawBuffer, ctx->DrawBuffer);
+      _mesa_reference_framebuffer(&save->ReadBuffer, ctx->ReadBuffer);
    }
 }
 
@@ -845,19 +833,24 @@ _mesa_meta_begin(struct gl_context *ctx, GLbitfield state)
 void
 _mesa_meta_end(struct gl_context *ctx)
 {
+   assert(ctx->Meta->SaveStackDepth > 0);
+
    struct save_state *save = &ctx->Meta->Save[ctx->Meta->SaveStackDepth - 1];
    const GLbitfield state = save->SavedState;
    int i;
 
-   /* After starting a new occlusion query, initialize the results to the
-    * values saved previously. The driver will then continue to increment
-    * these values.
-    */
+   /* Grab the result of the old occlusion query before starting it again. The
+    * old result is added to the result of the new query so the driver will
+    * continue adding where it left off. */
    if (state & MESA_META_OCCLUSION_QUERY) {
       if (save->CurrentOcclusionObject) {
-         _mesa_BeginQuery(save->CurrentOcclusionObject->Target,
-                          save->CurrentOcclusionObject->Id);
-         ctx->Query.CurrentOcclusionObject->Result = save->CurrentOcclusionObject->Result;
+         struct gl_query_object *q = save->CurrentOcclusionObject;
+         GLuint64EXT result;
+         if (!q->Ready)
+            ctx->Driver.WaitQuery(ctx, q);
+         result = q->Result;
+         _mesa_BeginQuery(q->Target, q->Id);
+         ctx->Query.CurrentOcclusionObject->Result += result;
       }
    }
 
@@ -961,9 +954,13 @@ _mesa_meta_end(struct gl_context *ctx)
    if (state & MESA_META_SHADER) {
       static const GLenum targets[] = {
          GL_VERTEX_SHADER,
+         GL_TESS_CONTROL_SHADER,
+         GL_TESS_EVALUATION_SHADER,
          GL_GEOMETRY_SHADER,
          GL_FRAGMENT_SHADER,
+         GL_COMPUTE_SHADER,
       };
+      STATIC_ASSERT(MESA_SHADER_STAGES == ARRAY_SIZE(targets));
 
       bool any_shader;
 
@@ -989,7 +986,7 @@ _mesa_meta_end(struct gl_context *ctx)
       }
 
       any_shader = false;
-      for (i = 0; i <= MESA_SHADER_FRAGMENT; i++) {
+      for (i = 0; i < MESA_SHADER_STAGES; 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
@@ -1064,7 +1061,7 @@ _mesa_meta_end(struct gl_context *ctx)
    if (state & MESA_META_TEXTURE) {
       GLuint u, tgt;
 
-      ASSERT(ctx->Texture.CurrentUnit == 0);
+      assert(ctx->Texture.CurrentUnit == 0);
 
       /* restore texenv for unit[0] */
       _mesa_TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, save->EnvMode);
@@ -1094,7 +1091,6 @@ _mesa_meta_end(struct gl_context *ctx)
 
       /* restore current unit state */
       _mesa_ActiveTexture(GL_TEXTURE0 + save->ActiveUnit);
-      _mesa_ClientActiveTexture(GL_TEXTURE0 + save->ClientActiveUnit);
    }
 
    if (state & MESA_META_TRANSFORM) {
@@ -1111,6 +1107,9 @@ _mesa_meta_end(struct gl_context *ctx)
       _mesa_LoadMatrixf(save->ProjectionMatrix);
 
       _mesa_MatrixMode(save->MatrixMode);
+
+      if (ctx->Extensions.ARB_clip_control)
+         _mesa_ClipControl(save->ClipOrigin, save->ClipDepthMode);
    }
 
    if (state & MESA_META_CLIP) {
@@ -1125,10 +1124,6 @@ _mesa_meta_end(struct gl_context *ctx)
    }
 
    if (state & MESA_META_VERTEX) {
-      /* restore vertex buffer object */
-      _mesa_BindBuffer(GL_ARRAY_BUFFER_ARB, save->ArrayBufferObj->Name);
-      _mesa_reference_buffer_object(ctx, &save->ArrayBufferObj, NULL);
-
       /* restore vertex array object */
       _mesa_BindVertexArray(save->VAO->Name);
       _mesa_reference_vao(ctx, &save->VAO, NULL);
@@ -1142,7 +1137,7 @@ _mesa_meta_end(struct gl_context *ctx)
          _mesa_set_viewport(ctx, 0, save->ViewportX, save->ViewportY,
                             save->ViewportW, save->ViewportH);
       }
-      _mesa_DepthRange(save->DepthNear, save->DepthFar);
+      _mesa_set_depth_range(ctx, 0, save->DepthNear, save->DepthFar);
    }
 
    if (state & MESA_META_CLAMP_FRAGMENT_COLOR &&
@@ -1213,33 +1208,19 @@ _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);
+   _mesa_bind_framebuffers(ctx, save->DrawBuffer, save->ReadBuffer);
+   _mesa_reference_framebuffer(&save->DrawBuffer, NULL);
+   _mesa_reference_framebuffer(&save->ReadBuffer, NULL);
 
    if (state & MESA_META_DRAW_BUFFERS) {
-      _mesa_DrawBuffers(ctx->Const.MaxDrawBuffers, save->ColorDrawBuffers);
+      _mesa_drawbuffers(ctx, ctx->DrawBuffer, ctx->Const.MaxDrawBuffers,
+                        save->ColorDrawBuffers, NULL);
    }
 
    ctx->Meta->SaveStackDepth--;
 
    ctx->API = save->API;
-}
-
-
-/**
- * Determine whether Mesa is currently in a meta state.
- */
-GLboolean
-_mesa_meta_in_progress(struct gl_context *ctx)
-{
-   return ctx->Meta->SaveStackDepth != 0;
+   ctx->Extensions.Version = save->ExtensionsVersion;
 }
 
 
@@ -1250,7 +1231,7 @@ _mesa_meta_in_progress(struct gl_context *ctx)
  * Used by the meta-Clear, Draw/CopyPixels and Bitmap functions where the Z
  * value comes from the clear value or raster position.
  */
-static INLINE GLfloat
+static inline GLfloat
 invert_z(GLfloat normZ)
 {
    GLfloat objZ = 1.0f - 2.0f * normZ;
@@ -1358,8 +1339,8 @@ _mesa_meta_alloc_texture(struct temp_texture *tex,
 {
    GLboolean newTex = GL_FALSE;
 
-   ASSERT(width <= tex->MaxSize);
-   ASSERT(height <= tex->MaxSize);
+   assert(width <= tex->MaxSize);
+   assert(height <= tex->MaxSize);
 
    if (width > tex->Width ||
        height > tex->Height ||
@@ -1497,10 +1478,12 @@ _mesa_meta_setup_drawpix_texture(struct gl_context *ctx,
 }
 
 void
-_mesa_meta_setup_ff_tnl_for_blit(GLuint *VAO, GLuint *VBO,
+_mesa_meta_setup_ff_tnl_for_blit(struct gl_context *ctx,
+                                 GLuint *VAO, struct gl_buffer_object **buf_obj,
                                  unsigned texcoord_size)
 {
-   _mesa_meta_setup_vertex_objects(VAO, VBO, false, 2, texcoord_size, 0);
+   _mesa_meta_setup_vertex_objects(ctx, VAO, buf_obj, false, 2, texcoord_size,
+                                   0);
 
    /* setup projection matrix */
    _mesa_MatrixMode(GL_PROJECTION);
@@ -1527,17 +1510,20 @@ meta_glsl_clear_init(struct gl_context *ctx, struct clear_state *clear)
 {
    const char *vs_source =
       "#extension GL_AMD_vertex_shader_layer : enable\n"
-      "attribute vec4 position;\n"
-      "uniform int layer;\n"
+      "#extension GL_ARB_draw_instanced : enable\n"
+      "#extension GL_ARB_explicit_attrib_location :enable\n"
+      "layout(location = 0) in vec4 position;\n"
       "void main()\n"
       "{\n"
       "#ifdef GL_AMD_vertex_shader_layer\n"
-      "   gl_Layer = layer;\n"
+      "   gl_Layer = gl_InstanceID;\n"
       "#endif\n"
       "   gl_Position = position;\n"
       "}\n";
    const char *fs_source =
-      "uniform vec4 color;\n"
+      "#extension GL_ARB_explicit_attrib_location :enable\n"
+      "#extension GL_ARB_explicit_uniform_location :enable\n"
+      "layout(location = 0) uniform vec4 color;\n"
       "void main()\n"
       "{\n"
       "   gl_FragColor = color;\n"
@@ -1545,30 +1531,14 @@ meta_glsl_clear_init(struct gl_context *ctx, struct clear_state *clear)
    GLuint vs, fs;
    bool has_integer_textures;
 
-   _mesa_meta_setup_vertex_objects(&clear->VAO, &clear->VBO, true, 3, 0, 0);
+   _mesa_meta_setup_vertex_objects(ctx, &clear->VAO, &clear->buf_obj, true,
+                                   3, 0, 0);
 
    if (clear->ShaderProg != 0)
       return;
 
-   vs = _mesa_CreateShader(GL_VERTEX_SHADER);
-   _mesa_ShaderSource(vs, 1, &vs_source, NULL);
-   _mesa_CompileShader(vs);
-
-   fs = _mesa_CreateShader(GL_FRAGMENT_SHADER);
-   _mesa_ShaderSource(fs, 1, &fs_source, NULL);
-   _mesa_CompileShader(fs);
-
-   clear->ShaderProg = _mesa_CreateProgram();
-   _mesa_AttachShader(clear->ShaderProg, fs);
-   _mesa_DeleteShader(fs);
-   _mesa_AttachShader(clear->ShaderProg, 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");
-   clear->LayerLocation = _mesa_GetUniformLocation(clear->ShaderProg, "layer");
+   _mesa_meta_compile_and_link_program(ctx, vs_source, fs_source, "meta clear",
+                                       &clear->ShaderProg);
 
    has_integer_textures = _mesa_is_gles3(ctx) ||
       (_mesa_is_desktop_gl(ctx) && ctx->Const.GLSLVersion >= 130);
@@ -1579,19 +1549,22 @@ meta_glsl_clear_init(struct gl_context *ctx, struct clear_state *clear)
          ralloc_asprintf(shader_source_mem_ctx,
                          "#version 130\n"
                          "#extension GL_AMD_vertex_shader_layer : enable\n"
-                         "in vec4 position;\n"
-                         "uniform int layer;\n"
+                         "#extension GL_ARB_draw_instanced : enable\n"
+                         "#extension GL_ARB_explicit_attrib_location :enable\n"
+                         "layout(location = 0) in vec4 position;\n"
                          "void main()\n"
                          "{\n"
                          "#ifdef GL_AMD_vertex_shader_layer\n"
-                         "   gl_Layer = layer;\n"
+                         "   gl_Layer = gl_InstanceID;\n"
                          "#endif\n"
                          "   gl_Position = position;\n"
                          "}\n");
       const char *fs_int_source =
          ralloc_asprintf(shader_source_mem_ctx,
                          "#version 130\n"
-                         "uniform ivec4 color;\n"
+                         "#extension GL_ARB_explicit_attrib_location :enable\n"
+                         "#extension GL_ARB_explicit_uniform_location :enable\n"
+                         "layout(location = 0) uniform ivec4 color;\n"
                          "out ivec4 out_color;\n"
                          "\n"
                          "void main()\n"
@@ -1599,44 +1572,26 @@ meta_glsl_clear_init(struct gl_context *ctx, struct clear_state *clear)
                          "   out_color = color;\n"
                          "}\n");
 
-      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);
+      _mesa_meta_compile_and_link_program(ctx, vs_int_source, fs_int_source,
+                                          "integer clear",
+                                          &clear->IntegerShaderProg);
       ralloc_free(shader_source_mem_ctx);
 
-      clear->IntegerShaderProg = _mesa_CreateProgram();
-      _mesa_AttachShader(clear->IntegerShaderProg, fs);
-      _mesa_DeleteShader(fs);
-      _mesa_AttachShader(clear->IntegerShaderProg, vs);
-      _mesa_DeleteShader(vs);
-      _mesa_BindAttribLocation(clear->IntegerShaderProg, 0, "position");
-
       /* Note that user-defined out attributes get automatically assigned
        * locations starting from 0, so we don't need to explicitly
        * BindFragDataLocation to 0.
        */
-
-      _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");
-      clear->IntegerLayerLocation =
-         _mesa_GetUniformLocation(clear->IntegerShaderProg, "layer");
    }
 }
 
 static void
-meta_glsl_clear_cleanup(struct clear_state *clear)
+meta_glsl_clear_cleanup(struct gl_context *ctx, struct clear_state *clear)
 {
    if (clear->VAO == 0)
       return;
    _mesa_DeleteVertexArrays(1, &clear->VAO);
    clear->VAO = 0;
-   _mesa_DeleteBuffers(1, &clear->VBO);
-   clear->VBO = 0;
+   _mesa_reference_buffer_object(ctx, &clear->buf_obj, NULL);
    _mesa_DeleteProgram(clear->ShaderProg);
    clear->ShaderProg = 0;
 
@@ -1653,8 +1608,8 @@ meta_glsl_clear_cleanup(struct clear_state *clear)
  * Since the bitfield has no associated order, the assignment of draw buffer
  * indices to color attachment indices is rather arbitrary.
  */
-static void
-drawbuffers_from_bitfield(GLbitfield bits)
+void
+_mesa_meta_drawbuffers_from_bitfield(GLbitfield bits)
 {
    GLenum enums[MAX_DRAW_BUFFERS];
    int i = 0;
@@ -1744,7 +1699,8 @@ meta_clear(struct gl_context *ctx, GLbitfield buffers, bool glsl)
       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);
+      _mesa_meta_setup_vertex_objects(ctx, &clear->VAO, &clear->buf_obj, false,
+                                      3, 0, 4);
 
       x0 = (float) fb->_Xmin;
       y0 = (float) fb->_Ymin;
@@ -1756,18 +1712,16 @@ meta_clear(struct gl_context *ctx, GLbitfield buffers, bool glsl)
    if (fb->_IntegerColor) {
       assert(glsl);
       _mesa_UseProgram(clear->IntegerShaderProg);
-      _mesa_Uniform4iv(clear->IntegerColorLocation, 1,
-                         ctx->Color.ClearColor.i);
+      _mesa_Uniform4iv(0, 1, ctx->Color.ClearColor.i);
    } else if (glsl) {
       _mesa_UseProgram(clear->ShaderProg);
-      _mesa_Uniform4fv(clear->ColorLocation, 1,
-                         ctx->Color.ClearColor.f);
+      _mesa_Uniform4fv(0, 1, ctx->Color.ClearColor.f);
    }
 
    /* GL_COLOR_BUFFER_BIT */
    if (buffers & BUFFER_BITS_COLOR) {
       /* Only draw to the buffers we were asked to clear. */
-      drawbuffers_from_bitfield(buffers & BUFFER_BITS_COLOR);
+      _mesa_meta_drawbuffers_from_bitfield(buffers & BUFFER_BITS_COLOR);
 
       /* leave colormask state as-is */
 
@@ -1776,7 +1730,7 @@ meta_clear(struct gl_context *ctx, GLbitfield buffers, bool glsl)
          _mesa_ClampColor(GL_CLAMP_FRAGMENT_COLOR, GL_FALSE);
    }
    else {
-      ASSERT(metaSave & MESA_META_COLOR_MASK);
+      assert(metaSave & MESA_META_COLOR_MASK);
       _mesa_ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
    }
 
@@ -1827,20 +1781,12 @@ meta_clear(struct gl_context *ctx, GLbitfield buffers, bool glsl)
    }
 
    /* upload new vertex data */
-   _mesa_BufferData(GL_ARRAY_BUFFER_ARB, sizeof(verts), verts,
-                      GL_DYNAMIC_DRAW_ARB);
+   _mesa_buffer_data(ctx, clear->buf_obj, GL_NONE, sizeof(verts), verts,
+                     GL_DYNAMIC_DRAW, __func__);
 
    /* draw quad(s) */
    if (fb->MaxNumLayers > 0) {
-      unsigned layer;
-      assert(glsl && clear->LayerLocation != -1);
-      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);
    }
@@ -1882,7 +1828,7 @@ _mesa_meta_CopyPixels(struct gl_context *ctx, GLint srcX, GLint srcY,
                           MESA_META_VERTEX |
                           MESA_META_VIEWPORT));
 
-   _mesa_meta_setup_vertex_objects(&copypix->VAO, &copypix->VBO, false,
+   _mesa_meta_setup_vertex_objects(ctx, &copypix->VAO, &copypix->buf_obj, false,
                                    3, 2, 0);
 
    /* Silence valgrind warnings about reading uninitialized stack. */
@@ -1922,7 +1868,8 @@ _mesa_meta_CopyPixels(struct gl_context *ctx, GLint srcX, GLint srcY,
       verts[3].tex[1] = tex->Ttop;
 
       /* upload new vertex data */
-      _mesa_BufferSubData(GL_ARRAY_BUFFER_ARB, 0, sizeof(verts), verts);
+      _mesa_buffer_sub_data(ctx, copypix->buf_obj, 0, sizeof(verts), verts,
+                            __func__);
    }
 
    _mesa_set_enable(ctx, tex->Target, GL_TRUE);
@@ -1936,14 +1883,13 @@ _mesa_meta_CopyPixels(struct gl_context *ctx, GLint srcX, GLint srcY,
 }
 
 static void
-meta_drawpix_cleanup(struct drawpix_state *drawpix)
+meta_drawpix_cleanup(struct gl_context *ctx, struct drawpix_state *drawpix)
 {
    if (drawpix->VAO != 0) {
       _mesa_DeleteVertexArrays(1, &drawpix->VAO);
       drawpix->VAO = 0;
 
-      _mesa_DeleteBuffers(1, &drawpix->VBO);
-      drawpix->VBO = 0;
+      _mesa_reference_buffer_object(ctx, &drawpix->buf_obj, NULL);
    }
 
    if (drawpix->StencilFP != 0) {
@@ -2203,7 +2149,7 @@ _mesa_meta_DrawPixels(struct gl_context *ctx,
 
    newTex = _mesa_meta_alloc_texture(tex, width, height, texIntFormat);
 
-   _mesa_meta_setup_vertex_objects(&drawpix->VAO, &drawpix->VBO, false,
+   _mesa_meta_setup_vertex_objects(ctx, &drawpix->VAO, &drawpix->buf_obj, false,
                                    3, 2, 0);
 
    /* Silence valgrind warnings about reading uninitialized stack. */
@@ -2240,8 +2186,8 @@ _mesa_meta_DrawPixels(struct gl_context *ctx,
    }
 
    /* upload new vertex data */
-   _mesa_BufferData(GL_ARRAY_BUFFER_ARB, sizeof(verts),
-                       verts, GL_DYNAMIC_DRAW_ARB);
+   _mesa_buffer_data(ctx, drawpix->buf_obj, GL_NONE, sizeof(verts), verts,
+                     GL_DYNAMIC_DRAW, __func__);
 
    /* set given unpack params */
    ctx->Unpack = *unpack;
@@ -2396,7 +2342,8 @@ _mesa_meta_Bitmap(struct gl_context *ctx,
                           MESA_META_VERTEX |
                           MESA_META_VIEWPORT));
 
-   _mesa_meta_setup_vertex_objects(&bitmap->VAO, &bitmap->VBO, false, 3, 2, 4);
+   _mesa_meta_setup_vertex_objects(ctx, &bitmap->VAO, &bitmap->buf_obj, false,
+                                   3, 2, 4);
 
    newTex = _mesa_meta_alloc_texture(tex, width, height, texIntFormat);
 
@@ -2441,7 +2388,8 @@ _mesa_meta_Bitmap(struct gl_context *ctx,
       }
 
       /* upload new vertex data */
-      _mesa_BufferSubData(GL_ARRAY_BUFFER_ARB, 0, sizeof(verts), verts);
+      _mesa_buffer_sub_data(ctx, bitmap->buf_obj, 0, sizeof(verts), verts,
+                            __func__);
    }
 
    /* choose different foreground/background alpha values */
@@ -2482,30 +2430,53 @@ _mesa_meta_Bitmap(struct gl_context *ctx,
 
 /**
  * Compute the texture coordinates for the four vertices of a quad for
- * drawing a 2D texture image or slice of a cube/3D texture.
+ * drawing a 2D texture image or slice of a cube/3D texture.  The offset
+ * and width, height specify a sub-region of the 2D image.
+ *
  * \param faceTarget  GL_TEXTURE_1D/2D/3D or cube face name
  * \param slice  slice of a 1D/2D array texture or 3D texture
- * \param width  width of the texture image
- * \param height  height of the texture image
+ * \param xoffset  X position of sub texture
+ * \param yoffset  Y position of sub texture
+ * \param width  width of the sub texture image
+ * \param height  height of the sub texture image
+ * \param total_width  total width of the texture image
+ * \param total_height  total height of the texture image
+ * \param total_depth  total depth of the texture image
  * \param coords0/1/2/3  returns the computed texcoords
  */
 void
 _mesa_meta_setup_texture_coords(GLenum faceTarget,
                                 GLint slice,
+                                GLint xoffset,
+                                GLint yoffset,
                                 GLint width,
                                 GLint height,
-                                GLint depth,
+                                GLint total_width,
+                                GLint total_height,
+                                GLint total_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}
-   };
+   float st[4][2];
    GLuint i;
+   const float s0 = (float) xoffset / (float) total_width;
+   const float s1 = (float) (xoffset + width) / (float) total_width;
+   const float t0 = (float) yoffset / (float) total_height;
+   const float t1 = (float) (yoffset + height) / (float) total_height;
    GLfloat r;
 
+   /* setup the reference texcoords */
+   st[0][0] = s0;
+   st[0][1] = t0;
+   st[1][0] = s1;
+   st[1][1] = t0;
+   st[2][0] = s1;
+   st[2][1] = t1;
+   st[3][0] = s0;
+   st[3][1] = t1;
+
    if (faceTarget == GL_TEXTURE_CUBE_MAP_ARRAY)
       faceTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + slice % 6;
 
@@ -2522,52 +2493,52 @@ _mesa_meta_setup_texture_coords(GLenum faceTarget,
    case GL_TEXTURE_3D:
    case GL_TEXTURE_2D_ARRAY:
       if (faceTarget == GL_TEXTURE_3D) {
-         assert(slice < depth);
-         assert(depth >= 1);
-         r = (slice + 0.5f) / depth;
+         assert(slice < total_depth);
+         assert(total_depth >= 1);
+         r = (slice + 0.5f) / total_depth;
       }
       else if (faceTarget == GL_TEXTURE_2D_ARRAY)
          r = (float) slice;
       else
          r = 0.0F;
-      coords0[0] = 0.0F; /* s */
-      coords0[1] = 0.0F; /* t */
+      coords0[0] = st[0][0]; /* s */
+      coords0[1] = st[0][1]; /* t */
       coords0[2] = r; /* r */
-      coords1[0] = 1.0F;
-      coords1[1] = 0.0F;
+      coords1[0] = st[1][0];
+      coords1[1] = st[1][1];
       coords1[2] = r;
-      coords2[0] = 1.0F;
-      coords2[1] = 1.0F;
+      coords2[0] = st[2][0];
+      coords2[1] = st[2][1];
       coords2[2] = r;
-      coords3[0] = 0.0F;
-      coords3[1] = 1.0F;
+      coords3[0] = st[3][0];
+      coords3[1] = st[3][1];
       coords3[2] = r;
       break;
    case GL_TEXTURE_RECTANGLE_ARB:
-      coords0[0] = 0.0F; /* s */
-      coords0[1] = 0.0F; /* t */
+      coords0[0] = (float) xoffset; /* s */
+      coords0[1] = (float) yoffset; /* t */
       coords0[2] = 0.0F; /* r */
-      coords1[0] = (float) width;
-      coords1[1] = 0.0F;
+      coords1[0] = (float) (xoffset + width);
+      coords1[1] = (float) yoffset;
       coords1[2] = 0.0F;
-      coords2[0] = (float) width;
-      coords2[1] = (float) height;
+      coords2[0] = (float) (xoffset + width);
+      coords2[1] = (float) (yoffset + height);
       coords2[2] = 0.0F;
-      coords3[0] = 0.0F;
-      coords3[1] = (float) height;
+      coords3[0] = (float) xoffset;
+      coords3[1] = (float) (yoffset + height);
       coords3[2] = 0.0F;
       break;
    case GL_TEXTURE_1D_ARRAY:
-      coords0[0] = 0.0F; /* s */
+      coords0[0] = st[0][0]; /* s */
       coords0[1] = (float) slice; /* t */
       coords0[2] = 0.0F; /* r */
-      coords1[0] = 1.0f;
+      coords1[0] = st[1][0];
       coords1[1] = (float) slice;
       coords1[2] = 0.0F;
-      coords2[0] = 1.0F;
+      coords2[0] = st[2][0];
       coords2[1] = (float) slice;
       coords2[2] = 0.0F;
-      coords3[0] = 0.0F;
+      coords3[0] = st[3][0];
       coords3[1] = (float) slice;
       coords3[2] = 0.0F;
       break;
@@ -2784,8 +2755,7 @@ copytexsubimage_using_blit_framebuffer(struct gl_context *ctx, GLuint dims,
                                        GLint x, GLint y,
                                        GLsizei width, GLsizei height)
 {
-   struct gl_texture_object *texObj = texImage->TexObject;
-   GLuint fbo;
+   struct gl_framebuffer *drawFb;
    bool success = false;
    GLbitfield mask;
    GLenum status;
@@ -2793,34 +2763,37 @@ copytexsubimage_using_blit_framebuffer(struct gl_context *ctx, GLuint dims,
    if (!ctx->Extensions.ARB_framebuffer_object)
       return false;
 
-   _mesa_unlock_texture(ctx, texObj);
+   drawFb = ctx->Driver.NewFramebuffer(ctx, 0xDEADBEEF);
+   if (drawFb == NULL)
+      return false;
 
    _mesa_meta_begin(ctx, MESA_META_ALL & ~MESA_META_DRAW_BUFFERS);
-
-   _mesa_GenFramebuffers(1, &fbo);
-   _mesa_BindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
+   _mesa_bind_framebuffers(ctx, drawFb, ctx->ReadBuffer);
 
    if (rb->_BaseFormat == GL_DEPTH_STENCIL ||
        rb->_BaseFormat == GL_DEPTH_COMPONENT) {
-      _mesa_meta_bind_fbo_image(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
-                                texImage, zoffset);
+      _mesa_meta_framebuffer_texture_image(ctx, ctx->DrawBuffer,
+                                           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);
+         _mesa_meta_framebuffer_texture_image(ctx, ctx->DrawBuffer,
+                                              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);
+      _mesa_meta_framebuffer_texture_image(ctx, ctx->DrawBuffer,
+                                           GL_COLOR_ATTACHMENT0,
+                                           texImage, zoffset);
       mask = GL_COLOR_BUFFER_BIT;
       _mesa_DrawBuffer(GL_COLOR_ATTACHMENT0);
    }
 
-   status = _mesa_CheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
+   status = _mesa_check_framebuffer_status(ctx, ctx->DrawBuffer);
    if (status != GL_FRAMEBUFFER_COMPLETE)
       goto out;
 
@@ -2836,7 +2809,8 @@ copytexsubimage_using_blit_framebuffer(struct gl_context *ctx, GLuint dims,
     * are too strict for CopyTexImage.  We know meta will be fine with format
     * changes.
     */
-   mask = _mesa_meta_BlitFramebuffer(ctx, x, y,
+   mask = _mesa_meta_BlitFramebuffer(ctx, ctx->ReadBuffer, ctx->DrawBuffer,
+                                     x, y,
                                      x + width, y + height,
                                      xoffset, yoffset,
                                      xoffset + width, yoffset + height,
@@ -2845,8 +2819,7 @@ copytexsubimage_using_blit_framebuffer(struct gl_context *ctx, GLuint dims,
    success = mask == 0x0;
 
  out:
-   _mesa_lock_texture(ctx, texObj);
-   _mesa_DeleteFramebuffers(1, &fbo);
+   _mesa_reference_framebuffer(&drawFb, NULL);
    _mesa_meta_end(ctx);
    return success;
 }
@@ -2863,7 +2836,6 @@ _mesa_meta_CopyTexSubImage(struct gl_context *ctx, GLuint dims,
                            GLint x, GLint y,
                            GLsizei width, GLsizei height)
 {
-   struct gl_texture_object *texObj = texImage->TexObject;
    GLenum format, type;
    GLint bpp;
    void *buf;
@@ -2908,8 +2880,6 @@ _mesa_meta_CopyTexSubImage(struct gl_context *ctx, GLuint dims,
       return;
    }
 
-   _mesa_unlock_texture(ctx, texObj); /* need to unlock first */
-
    /*
     * Read image from framebuffer (disable pixel transfer ops)
     */
@@ -2938,35 +2908,33 @@ _mesa_meta_CopyTexSubImage(struct gl_context *ctx, GLuint dims,
 
    _mesa_meta_end(ctx);
 
-   _mesa_lock_texture(ctx, texObj); /* re-lock */
-
    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);
+   if (decompress_fbo->fb != NULL) {
+      _mesa_reference_framebuffer(&decompress_fbo->fb, NULL);
+      _mesa_reference_renderbuffer(&decompress_fbo->rb, NULL);
    }
 
    memset(decompress_fbo, 0, sizeof(*decompress_fbo));
 }
 
 static void
-meta_decompress_cleanup(struct decompress_state *decompress)
+meta_decompress_cleanup(struct gl_context *ctx,
+                        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);
+      _mesa_reference_buffer_object(ctx, &decompress->buf_obj, NULL);
    }
 
-   if (decompress->Sampler != 0)
-      _mesa_DeleteSamplers(1, &decompress->Sampler);
+   _mesa_reference_sampler_object(ctx, &decompress->samp_obj, NULL);
 
    memset(decompress, 0, sizeof(*decompress));
 }
@@ -2984,20 +2952,19 @@ static bool
 decompress_texture_image(struct gl_context *ctx,
                          struct gl_texture_image *texImage,
                          GLuint slice,
+                         GLint xoffset, GLint yoffset,
+                         GLsizei width, GLsizei height,
                          GLenum destFormat, GLenum destType,
                          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 verts[4];
-   GLuint samplerSave;
+   struct gl_sampler_object *samp_obj_save = NULL;
    GLenum status;
    const bool use_glsl_version = ctx->Extensions.ARB_vertex_shader &&
                                       ctx->Extensions.ARB_fragment_shader;
@@ -3047,30 +3014,38 @@ decompress_texture_image(struct gl_context *ctx,
    _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;
+   _mesa_reference_sampler_object(ctx, &samp_obj_save,
+                                  ctx->Texture.Unit[ctx->Texture.CurrentUnit].Sampler);
 
    /* Create/bind FBO/renderbuffer */
-   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_fbo->RBO);
+   if (decompress_fbo->fb == NULL) {
+      decompress_fbo->rb = ctx->Driver.NewRenderbuffer(ctx, 0xDEADBEEF);
+      if (decompress_fbo->rb == NULL) {
+         _mesa_meta_end(ctx);
+         return false;
+      }
+
+      decompress_fbo->rb->RefCount = 1;
+
+      decompress_fbo->fb = ctx->Driver.NewFramebuffer(ctx, 0xDEADBEEF);
+      if (decompress_fbo->fb == NULL) {
+         _mesa_meta_end(ctx);
+         return false;
+      }
+
+      _mesa_bind_framebuffers(ctx, decompress_fbo->fb, decompress_fbo->fb);
+      _mesa_framebuffer_renderbuffer(ctx, ctx->DrawBuffer, GL_COLOR_ATTACHMENT0,
+                                     decompress_fbo->rb);
    }
    else {
-      _mesa_BindFramebuffer(GL_FRAMEBUFFER_EXT, decompress_fbo->FBO);
+      _mesa_bind_framebuffers(ctx, decompress_fbo->fb, decompress_fbo->fb);
    }
 
    /* alloc dest surface */
    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);
+      _mesa_renderbuffer_storage(ctx, decompress_fbo->rb, rbFormat,
+                                 width, height, 0);
+      status = _mesa_check_framebuffer_status(ctx, ctx->DrawBuffer);
       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
@@ -3083,34 +3058,49 @@ decompress_texture_image(struct gl_context *ctx,
    }
 
    if (use_glsl_version) {
-      _mesa_meta_setup_vertex_objects(&decompress->VAO, &decompress->VBO, true,
+      _mesa_meta_setup_vertex_objects(ctx, &decompress->VAO,
+                                      &decompress->buf_obj, true,
                                       2, 4, 0);
 
-      _mesa_meta_setup_blit_shader(ctx, target, &decompress->shaders);
+      _mesa_meta_setup_blit_shader(ctx, target, false, &decompress->shaders);
    } else {
-      _mesa_meta_setup_ff_tnl_for_blit(&decompress->VAO, &decompress->VBO, 3);
+      _mesa_meta_setup_ff_tnl_for_blit(ctx, &decompress->VAO,
+                                       &decompress->buf_obj, 3);
    }
 
-   if (!decompress->Sampler) {
-      _mesa_GenSamplers(1, &decompress->Sampler);
-      _mesa_BindSampler(ctx->Texture.CurrentUnit, decompress->Sampler);
-      /* nearest filtering */
-      _mesa_SamplerParameteri(decompress->Sampler, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-      _mesa_SamplerParameteri(decompress->Sampler, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-      /* No sRGB decode or encode.*/
-      if (ctx->Extensions.EXT_texture_sRGB_decode) {
-         _mesa_SamplerParameteri(decompress->Sampler, GL_TEXTURE_SRGB_DECODE_EXT,
-                             GL_SKIP_DECODE_EXT);
+   if (decompress->samp_obj == NULL) {
+      decompress->samp_obj =  ctx->Driver.NewSamplerObject(ctx, 0xDEADBEEF);
+      if (decompress->samp_obj == NULL) {
+         _mesa_meta_end(ctx);
+
+         /* This is a bit lazy.  Flag out of memory, and then don't bother to
+          * clean up.  Once out of memory is flagged, the only realistic next
+          * move is to destroy the context.  That will trigger all the right
+          * clean up.
+          *
+          * Returning true prevents other GetTexImage methods from attempting
+          * anything since they will likely fail too.
+          */
+         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage");
+         return true;
       }
 
-   } else {
-      _mesa_BindSampler(ctx->Texture.CurrentUnit, decompress->Sampler);
+      /* nearest filtering */
+      _mesa_set_sampler_filters(ctx, decompress->samp_obj, GL_NEAREST, GL_NEAREST);
+
+      /* We don't want to encode or decode sRGB values; treat them as linear. */
+      _mesa_set_sampler_srgb_decode(ctx, decompress->samp_obj, GL_SKIP_DECODE_EXT);
    }
 
+   _mesa_bind_sampler(ctx, ctx->Texture.CurrentUnit, decompress->samp_obj);
+
    /* Silence valgrind warnings about reading uninitialized stack. */
    memset(verts, 0, sizeof(verts));
 
-   _mesa_meta_setup_texture_coords(faceTarget, slice, width, height, depth,
+   _mesa_meta_setup_texture_coords(faceTarget, slice,
+                                   xoffset, yoffset, width, height,
+                                   texImage->Width, texImage->Height,
+                                   texImage->Depth,
                                    verts[0].tex,
                                    verts[1].tex,
                                    verts[2].tex,
@@ -3129,7 +3119,8 @@ decompress_texture_image(struct gl_context *ctx,
    _mesa_set_viewport(ctx, 0, 0, 0, width, height);
 
    /* upload new vertex data */
-   _mesa_BufferSubData(GL_ARRAY_BUFFER_ARB, 0, sizeof(verts), verts);
+   _mesa_buffer_sub_data(ctx, decompress->buf_obj, 0, sizeof(verts), verts,
+                         __func__);
 
    /* setup texture state */
    _mesa_BindTexture(target, texObj->Name);
@@ -3144,8 +3135,10 @@ decompress_texture_image(struct gl_context *ctx,
 
       /* restrict sampling to the texture level of interest */
       if (target != GL_TEXTURE_RECTANGLE_ARB) {
-         _mesa_TexParameteri(target, GL_TEXTURE_BASE_LEVEL, texImage->Level);
-         _mesa_TexParameteri(target, GL_TEXTURE_MAX_LEVEL, texImage->Level);
+         _mesa_texture_parameteriv(ctx, texObj, GL_TEXTURE_BASE_LEVEL,
+                                   (GLint *) &texImage->Level, false);
+         _mesa_texture_parameteriv(ctx, texObj, GL_TEXTURE_MAX_LEVEL,
+                                   (GLint *) &texImage->Level, false);
       }
 
       /* render quad w/ texture into renderbuffer */
@@ -3155,8 +3148,10 @@ decompress_texture_image(struct gl_context *ctx,
        * 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_texture_parameteriv(ctx, texObj, GL_TEXTURE_BASE_LEVEL,
+                                   &baseLevelSave, false);
+         _mesa_texture_parameteriv(ctx, texObj, GL_TEXTURE_MAX_LEVEL,
+                                   &maxLevelSave, false);
       }
 
    }
@@ -3164,7 +3159,7 @@ decompress_texture_image(struct gl_context *ctx,
    /* read pixels from renderbuffer */
    {
       GLenum baseTexFormat = texImage->_BaseFormat;
-      GLenum destBaseFormat = _mesa_base_tex_format(ctx, destFormat);
+      GLenum destBaseFormat = _mesa_unpack_format_to_base_format(destFormat);
 
       /* The pixel transfer state will be set to default values at this point
        * (see MESA_META_PIXEL_TRANSFER) so pixel transfer ops are effectively
@@ -3173,19 +3168,13 @@ decompress_texture_image(struct gl_context *ctx,
        * returned as red and two-channel texture values are returned as
        * red/alpha.
        */
-      if ((baseTexFormat == GL_LUMINANCE ||
-           baseTexFormat == GL_LUMINANCE_ALPHA ||
-           baseTexFormat == GL_INTENSITY) ||
+      if (_mesa_need_luminance_to_rgb_conversion(baseTexFormat,
+                                                 destBaseFormat) ||
           /* If we're reading back an RGB(A) texture (using glGetTexImage) as
           * luminance then we need to return L=tex(R).
           */
-          ((baseTexFormat == GL_RGBA ||
-            baseTexFormat == GL_RGB  ||
-            baseTexFormat == GL_RG) &&
-          (destBaseFormat == GL_LUMINANCE ||
-           destBaseFormat == GL_LUMINANCE_ALPHA ||
-           destBaseFormat == GL_LUMINANCE_INTEGER_EXT ||
-           destBaseFormat == GL_LUMINANCE_ALPHA_INTEGER_EXT))) {
+          _mesa_need_rgb_to_luminance_conversion(baseTexFormat,
+                                                 destBaseFormat)) {
          /* Green and blue must be zero */
          _mesa_PixelTransferf(GL_GREEN_SCALE, 0.0f);
          _mesa_PixelTransferf(GL_BLUE_SCALE, 0.0f);
@@ -3198,7 +3187,8 @@ decompress_texture_image(struct gl_context *ctx,
    if (!use_glsl_version)
       _mesa_set_enable(ctx, target, GL_FALSE);
 
-   _mesa_BindSampler(ctx->Texture.CurrentUnit, samplerSave);
+   _mesa_bind_sampler(ctx, ctx->Texture.CurrentUnit, samp_obj_save);
+   _mesa_reference_sampler_object(ctx, &samp_obj_save, NULL);
 
    _mesa_meta_end(ctx);
 
@@ -3212,18 +3202,17 @@ decompress_texture_image(struct gl_context *ctx,
  * from core Mesa.
  */
 void
-_mesa_meta_GetTexImage(struct gl_context *ctx,
-                       GLenum format, GLenum type, GLvoid *pixels,
-                       struct gl_texture_image *texImage)
+_mesa_meta_GetTexSubImage(struct gl_context *ctx,
+                          GLint xoffset, GLint yoffset, GLint zoffset,
+                          GLsizei width, GLsizei height, GLsizei depth,
+                          GLenum format, GLenum type, GLvoid *pixels,
+                          struct gl_texture_image *texImage)
 {
    if (_mesa_is_format_compressed(texImage->TexFormat)) {
-      struct gl_texture_object *texObj = texImage->TexObject;
       GLuint slice;
-      bool result;
+      bool result = true;
 
-      /* Need to unlock the texture here to prevent deadlock... */
-      _mesa_unlock_texture(ctx, texObj);
-      for (slice = 0; slice < texImage->Depth; slice++) {
+      for (slice = 0; slice < depth; slice++) {
          void *dst;
          if (texImage->TexObject->Target == GL_TEXTURE_2D_ARRAY
              || texImage->TexObject->Target == GL_TEXTURE_CUBE_MAP_ARRAY) {
@@ -3235,26 +3224,25 @@ _mesa_meta_GetTexImage(struct gl_context *ctx,
             struct gl_pixelstore_attrib packing = ctx->Pack;
             packing.SkipPixels = 0;
             packing.SkipRows = 0;
-            dst = _mesa_image_address3d(&packing, pixels, texImage->Width,
-                                        texImage->Height, format, type,
-                                        slice, 0, 0);
+            dst = _mesa_image_address3d(&packing, pixels, width, height,
+                                        format, type, slice, 0, 0);
          }
          else {
             dst = pixels;
          }
          result = decompress_texture_image(ctx, texImage, slice,
+                                           xoffset, yoffset, width, height,
                                            format, type, dst);
          if (!result)
             break;
       }
-      /* ... and relock it */
-      _mesa_lock_texture(ctx, texObj);
 
       if (result)
          return;
    }
 
-   _mesa_get_teximage(ctx, format, type, pixels, texImage);
+   _mesa_GetTexSubImage_sw(ctx, xoffset, yoffset, zoffset,
+                           width, height, depth, format, type, pixels, texImage);
 }
 
 
@@ -3281,36 +3269,45 @@ _mesa_meta_DrawTex(struct gl_context *ctx, GLfloat x, GLfloat y, GLfloat z,
 
    if (drawtex->VAO == 0) {
       /* one-time setup */
-      GLint active_texture;
+      struct gl_vertex_array_object *array_obj;
 
       /* create vertex array object */
       _mesa_GenVertexArrays(1, &drawtex->VAO);
       _mesa_BindVertexArray(drawtex->VAO);
 
+      array_obj = _mesa_lookup_vao(ctx, drawtex->VAO);
+      assert(array_obj != NULL);
+
       /* create vertex array buffer */
-      _mesa_GenBuffers(1, &drawtex->VBO);
-      _mesa_BindBuffer(GL_ARRAY_BUFFER_ARB, drawtex->VBO);
-      _mesa_BufferData(GL_ARRAY_BUFFER_ARB, sizeof(verts),
-                          NULL, GL_DYNAMIC_DRAW_ARB);
+      drawtex->buf_obj = ctx->Driver.NewBufferObject(ctx, 0xDEADBEEF);
+      if (drawtex->buf_obj == NULL)
+         return;
 
-      /* client active texture is not part of the array object */
-      active_texture = ctx->Array.ActiveTexture;
+      _mesa_buffer_data(ctx, drawtex->buf_obj, GL_NONE, sizeof(verts), verts,
+                        GL_DYNAMIC_DRAW, __func__);
 
       /* setup vertex arrays */
-      _mesa_VertexPointer(3, GL_FLOAT, sizeof(struct vertex), OFFSET(x));
-      _mesa_EnableClientState(GL_VERTEX_ARRAY);
+      _mesa_update_array_format(ctx, array_obj, VERT_ATTRIB_POS,
+                                3, GL_FLOAT, GL_RGBA, GL_FALSE,
+                                GL_FALSE, GL_FALSE,
+                                offsetof(struct vertex, x), true);
+      _mesa_bind_vertex_buffer(ctx, array_obj, VERT_ATTRIB_POS,
+                               drawtex->buf_obj, 0, sizeof(struct vertex));
+      _mesa_enable_vertex_array_attrib(ctx, array_obj, VERT_ATTRIB_POS);
+
+
       for (i = 0; i < ctx->Const.MaxTextureUnits; i++) {
-         _mesa_ClientActiveTexture(GL_TEXTURE0 + i);
-         _mesa_TexCoordPointer(2, GL_FLOAT, sizeof(struct vertex), OFFSET(st[i]));
-         _mesa_EnableClientState(GL_TEXTURE_COORD_ARRAY);
+         _mesa_update_array_format(ctx, array_obj, VERT_ATTRIB_TEX(i),
+                                   2, GL_FLOAT, GL_RGBA, GL_FALSE,
+                                   GL_FALSE, GL_FALSE,
+                                   offsetof(struct vertex, st[i]), true);
+         _mesa_bind_vertex_buffer(ctx, array_obj, VERT_ATTRIB_TEX(i),
+                                  drawtex->buf_obj, 0, sizeof(struct vertex));
+         _mesa_enable_vertex_array_attrib(ctx, array_obj, VERT_ATTRIB_TEX(i));
       }
-
-      /* restore client active texture */
-      _mesa_ClientActiveTexture(GL_TEXTURE0 + active_texture);
    }
    else {
       _mesa_BindVertexArray(drawtex->VAO);
-      _mesa_BindBuffer(GL_ARRAY_BUFFER_ARB, drawtex->VBO);
    }
 
    /* vertex positions, texcoords */
@@ -3375,7 +3372,8 @@ _mesa_meta_DrawTex(struct gl_context *ctx, GLfloat x, GLfloat y, GLfloat z,
          verts[3].st[i][1] = t1;
       }
 
-      _mesa_BufferSubData(GL_ARRAY_BUFFER_ARB, 0, sizeof(verts), verts);
+      _mesa_buffer_sub_data(ctx, drawtex->buf_obj, 0, sizeof(verts), verts,
+                            __func__);
    }
 
    _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4);
@@ -3394,10 +3392,11 @@ cleartexsubimage_color(struct gl_context *ctx,
    GLenum datatype;
    GLenum status;
 
-   _mesa_meta_bind_fbo_image(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
-                             texImage, zoffset);
+   _mesa_meta_framebuffer_texture_image(ctx, ctx->DrawBuffer,
+                                        GL_COLOR_ATTACHMENT0,
+                                        texImage, zoffset);
 
-   status = _mesa_CheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
+   status = _mesa_check_framebuffer_status(ctx, ctx->DrawBuffer);
    if (status != GL_FRAMEBUFFER_COMPLETE)
       return false;
 
@@ -3441,14 +3440,16 @@ cleartexsubimage_depth_stencil(struct gl_context *ctx,
    GLfloat depthValue;
    GLenum status;
 
-   _mesa_meta_bind_fbo_image(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
-                             texImage, zoffset);
+   _mesa_meta_framebuffer_texture_image(ctx, ctx->DrawBuffer,
+                                        GL_DEPTH_ATTACHMENT,
+                                        texImage, zoffset);
 
    if (texImage->_BaseFormat == GL_DEPTH_STENCIL)
-      _mesa_meta_bind_fbo_image(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
-                                texImage, zoffset);
+      _mesa_meta_framebuffer_texture_image(ctx, ctx->DrawBuffer,
+                                           GL_STENCIL_ATTACHMENT,
+                                           texImage, zoffset);
 
-   status = _mesa_CheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
+   status = _mesa_check_framebuffer_status(ctx, ctx->DrawBuffer);
    if (status != GL_FRAMEBUFFER_COMPLETE)
       return false;
 
@@ -3486,11 +3487,14 @@ cleartexsubimage_for_zoffset(struct gl_context *ctx,
                              GLint zoffset,
                              const GLvoid *clearValue)
 {
-   GLuint fbo;
+   struct gl_framebuffer *drawFb;
    bool success;
 
-   _mesa_GenFramebuffers(1, &fbo);
-   _mesa_BindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
+   drawFb = ctx->Driver.NewFramebuffer(ctx, 0xDEADBEEF);
+   if (drawFb == NULL)
+      return false;
+
+   _mesa_bind_framebuffers(ctx, drawFb, ctx->ReadBuffer);
 
    switch(texImage->_BaseFormat) {
    case GL_DEPTH_STENCIL:
@@ -3503,7 +3507,7 @@ cleartexsubimage_for_zoffset(struct gl_context *ctx,
       break;
    }
 
-   _mesa_DeleteFramebuffers(1, &fbo);
+   _mesa_reference_framebuffer(&drawFb, NULL);
 
    return success;
 }
@@ -3550,15 +3554,11 @@ _mesa_meta_ClearTexSubImage(struct gl_context *ctx,
 {
    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;