From 30af30b78075159fce477ae99cc72540133714d0 Mon Sep 17 00:00:00 2001
From: marha <marha@users.sourceforge.net>
Date: Sun, 26 Jan 2014 20:05:50 +0100
Subject: xserver randrproto libxtrans fontconfig libxcb xcb-proto mesa git
 update 26 Jan 2014

xserver          commit c1ce807d9f18f215332d7eeb844e8c640f71c53c
libxcb           commit e7263931aff3e3450dc938ad465a7577f943549f
libxcb/xcb-proto commit d898fd39ad6c82207eb78666b2daad982dd757b5
randrproto       commit a4a6694c059d74247c16527eef4a0ec9f56bbef6
libxtrans        commit e1e6121a1638d43d9929589b4723da2b38cb6b44
fontconfig       commit e2b406053c2937799da8636c56b72a77998bcab0
mesa             commit 07149f0252c52b4ac58b6df4e307fd786b49b490
---
 mesalib/src/mesa/main/api_validate.c         |  10 +-
 mesalib/src/mesa/main/attrib.c               |  40 ++-
 mesalib/src/mesa/main/config.h               |   5 +-
 mesalib/src/mesa/main/context.c              |  72 ++++--
 mesalib/src/mesa/main/dlist.c                |   1 +
 mesalib/src/mesa/main/enable.c               |  36 ++-
 mesalib/src/mesa/main/extensions.c           |   2 +
 mesalib/src/mesa/main/fbobject.c             |   2 +-
 mesalib/src/mesa/main/ff_fragment_shader.cpp |   8 +-
 mesalib/src/mesa/main/ffvertex_prog.c        |   2 +-
 mesalib/src/mesa/main/formats.c              |  12 +
 mesalib/src/mesa/main/framebuffer.c          |  86 ++++---
 mesalib/src/mesa/main/framebuffer.h          |   5 +
 mesalib/src/mesa/main/get.c                  | 229 +++++++++++++++++-
 mesalib/src/mesa/main/get.h                  |   6 +
 mesalib/src/mesa/main/get_hash_params.py     |  13 +-
 mesalib/src/mesa/main/glformats.c            | 130 +++++-----
 mesalib/src/mesa/main/macros.h               |   2 +
 mesalib/src/mesa/main/mtypes.h               |  46 +++-
 mesalib/src/mesa/main/rastpos.c              |   5 +-
 mesalib/src/mesa/main/scissor.c              | 161 +++++++++++--
 mesalib/src/mesa/main/scissor.h              |  10 +-
 mesalib/src/mesa/main/shaderapi.c            |  62 ++---
 mesalib/src/mesa/main/shaderapi.h            |   3 +
 mesalib/src/mesa/main/shaderobj.c            |   4 +-
 mesalib/src/mesa/main/shared.c               |   4 +-
 mesalib/src/mesa/main/state.c                |  24 +-
 mesalib/src/mesa/main/texobj.c               |   8 +-
 mesalib/src/mesa/main/texstate.c             |  75 +++---
 mesalib/src/mesa/main/texstorage.c           |  40 ++-
 mesalib/src/mesa/main/transformfeedback.c    |  51 +++-
 mesalib/src/mesa/main/viewport.c             | 347 ++++++++++++++++++++++-----
 mesalib/src/mesa/main/viewport.h             |  21 +-
 33 files changed, 1150 insertions(+), 372 deletions(-)

(limited to 'mesalib/src/mesa/main')

diff --git a/mesalib/src/mesa/main/api_validate.c b/mesalib/src/mesa/main/api_validate.c
index 96b178905..694558443 100644
--- a/mesalib/src/mesa/main/api_validate.c
+++ b/mesalib/src/mesa/main/api_validate.c
@@ -128,7 +128,7 @@ check_valid_to_render(struct gl_context *ctx, const char *function)
    case API_OPENGL_CORE:
       {
          const struct gl_shader_program *vsProg =
-            ctx->Shader.CurrentVertexProgram;
+            ctx->Shader.CurrentProgram[MESA_SHADER_VERTEX];
          GLboolean haveVertexShader = (vsProg && vsProg->LinkStatus);
          GLboolean haveVertexProgram = ctx->VertexProgram._Enabled;
          if (haveVertexShader || haveVertexProgram) {
@@ -269,9 +269,9 @@ _mesa_valid_prim_mode(struct gl_context *ctx, GLenum mode, const char *name)
     *   TRIANGLES_ADJACENCY_ARB or TRIANGLE_STRIP_ADJACENCY_ARB.
     *
    */
-   if (ctx->Shader.CurrentGeometryProgram) {
+   if (ctx->Shader.CurrentProgram[MESA_SHADER_GEOMETRY]) {
       const GLenum geom_mode =
-         ctx->Shader.CurrentGeometryProgram->Geom.InputType;
+         ctx->Shader.CurrentProgram[MESA_SHADER_GEOMETRY]->Geom.InputType;
       switch (mode) {
       case GL_POINTS:
          valid_enum = (geom_mode == GL_POINTS);
@@ -330,8 +330,8 @@ _mesa_valid_prim_mode(struct gl_context *ctx, GLenum mode, const char *name)
    if (_mesa_is_xfb_active_and_unpaused(ctx)) {
       GLboolean pass = GL_TRUE;
 
-      if(ctx->Shader.CurrentGeometryProgram) {
-         switch (ctx->Shader.CurrentGeometryProgram->Geom.OutputType) {
+      if(ctx->Shader.CurrentProgram[MESA_SHADER_GEOMETRY]) {
+         switch (ctx->Shader.CurrentProgram[MESA_SHADER_GEOMETRY]->Geom.OutputType) {
          case GL_POINTS:
             pass = ctx->TransformFeedback.Mode == GL_POINTS;
             break;
diff --git a/mesalib/src/mesa/main/attrib.c b/mesalib/src/mesa/main/attrib.c
index 30c815d67..7b7cf0ef3 100644
--- a/mesalib/src/mesa/main/attrib.c
+++ b/mesalib/src/mesa/main/attrib.c
@@ -112,7 +112,7 @@ struct gl_enable_attrib
    GLboolean PolygonSmooth;
    GLboolean PolygonStipple;
    GLboolean RescaleNormals;
-   GLboolean Scissor;
+   GLbitfield Scissor;
    GLboolean Stencil;
    GLboolean StencilTwoSide;          /* GL_EXT_stencil_two_side */
    GLboolean MultisampleEnabled;      /* GL_ARB_multisample */
@@ -354,7 +354,7 @@ _mesa_PushAttrib(GLbitfield mask)
       attr->PolygonSmooth = ctx->Polygon.SmoothFlag;
       attr->PolygonStipple = ctx->Polygon.StippleFlag;
       attr->RescaleNormals = ctx->Transform.RescaleNormals;
-      attr->Scissor = ctx->Scissor.Enabled;
+      attr->Scissor = ctx->Scissor.EnableFlags;
       attr->Stencil = ctx->Stencil.Enabled;
       attr->StencilTwoSide = ctx->Stencil.TestTwoSide;
       attr->MultisampleEnabled = ctx->Multisample.Enabled;
@@ -533,8 +533,9 @@ _mesa_PushAttrib(GLbitfield mask)
 
    if (mask & GL_VIEWPORT_BIT) {
       if (!push_attrib(ctx, &head, GL_VIEWPORT_BIT,
-                       sizeof(struct gl_viewport_attrib),
-                       (void*)&ctx->Viewport))
+                       sizeof(struct gl_viewport_attrib)
+                       * ctx->Const.MaxViewports,
+                       (void*)&ctx->ViewportArray))
          goto end;
    }
 
@@ -658,7 +659,13 @@ pop_enable_group(struct gl_context *ctx, const struct gl_enable_attrib *enable)
                    GL_POLYGON_SMOOTH);
    TEST_AND_UPDATE(ctx->Polygon.StippleFlag, enable->PolygonStipple,
                    GL_POLYGON_STIPPLE);
-   TEST_AND_UPDATE(ctx->Scissor.Enabled, enable->Scissor, GL_SCISSOR_TEST);
+   if (ctx->Scissor.EnableFlags != enable->Scissor) {
+      unsigned i;
+
+      for (i = 0; i < ctx->Const.MaxViewports; i++) {
+         _mesa_set_enablei(ctx, GL_SCISSOR_TEST, i, (enable->Scissor >> i) & 1);
+      }
+   }
    TEST_AND_UPDATE(ctx->Stencil.Enabled, enable->Stencil, GL_STENCIL_TEST);
    if (ctx->Extensions.EXT_stencil_two_side) {
       TEST_AND_UPDATE(ctx->Stencil.TestTwoSide, enable->StencilTwoSide, GL_STENCIL_TEST_TWO_SIDE_EXT);
@@ -1262,11 +1269,19 @@ _mesa_PopAttrib(void)
 	    break;
          case GL_SCISSOR_BIT:
             {
+               unsigned i;
                const struct gl_scissor_attrib *scissor;
                scissor = (const struct gl_scissor_attrib *) attr->data;
-               _mesa_Scissor(scissor->X, scissor->Y,
-                             scissor->Width, scissor->Height);
-               _mesa_set_enable(ctx, GL_SCISSOR_TEST, scissor->Enabled);
+
+               for (i = 0; i < ctx->Const.MaxViewports; i++) {
+                  _mesa_set_scissor(ctx, i,
+                                    scissor->ScissorArray[i].X,
+                                    scissor->ScissorArray[i].Y,
+                                    scissor->ScissorArray[i].Width,
+                                    scissor->ScissorArray[i].Height);
+                  _mesa_set_enablei(ctx, GL_SCISSOR_TEST, i,
+                                    (scissor->EnableFlags >> i) & 1);
+               }
             }
             break;
          case GL_STENCIL_BUFFER_BIT:
@@ -1342,10 +1357,15 @@ _mesa_PopAttrib(void)
             break;
          case GL_VIEWPORT_BIT:
             {
+               unsigned i;
                const struct gl_viewport_attrib *vp;
                vp = (const struct gl_viewport_attrib *) attr->data;
-               _mesa_Viewport(vp->X, vp->Y, vp->Width, vp->Height);
-               _mesa_DepthRange(vp->Near, vp->Far);
+
+               for (i = 0; i < ctx->Const.MaxViewports; i++) {
+                  _mesa_set_viewport(ctx, i, vp[i].X, vp[i].Y, vp[i].Width,
+                                     vp[i].Height);
+                  _mesa_set_depth_range(ctx, i, vp[i].Near, vp[i].Far);
+               }
             }
             break;
          case GL_MULTISAMPLE_BIT_ARB:
diff --git a/mesalib/src/mesa/main/config.h b/mesalib/src/mesa/main/config.h
index ff9da779b..0c1782ad7 100644
--- a/mesalib/src/mesa/main/config.h
+++ b/mesalib/src/mesa/main/config.h
@@ -121,7 +121,7 @@
  * Max number of texture image units.  Also determines number of texture
  * samplers in shaders.
  */
-#define MAX_TEXTURE_IMAGE_UNITS 16
+#define MAX_TEXTURE_IMAGE_UNITS 32
 
 /**
  * Larger of MAX_TEXTURE_COORD_UNITS and MAX_TEXTURE_IMAGE_UNITS.
@@ -137,6 +137,9 @@
 #define MAX_VIEWPORT_WIDTH 16384
 #define MAX_VIEWPORT_HEIGHT 16384
 
+/** Maximun number of viewports supported with ARB_viewport_array */
+#define MAX_VIEWPORTS 16
+
 /** Maxmimum size for CVA.  May be overridden by the drivers.  */
 #define MAX_ARRAY_LOCK_SIZE 3000
 
diff --git a/mesalib/src/mesa/main/context.c b/mesalib/src/mesa/main/context.c
index 0b8fb94e8..b7cd56866 100644
--- a/mesalib/src/mesa/main/context.c
+++ b/mesalib/src/mesa/main/context.c
@@ -587,6 +587,16 @@ _mesa_init_constants(struct gl_context *ctx)
    ctx->Const.MaxSpotExponent = 128.0;
    ctx->Const.MaxViewportWidth = MAX_VIEWPORT_WIDTH;
    ctx->Const.MaxViewportHeight = MAX_VIEWPORT_HEIGHT;
+   ctx->Const.MinMapBufferAlignment = 1;
+
+   /* Driver must override these values if ARB_viewport_array is supported. */
+   ctx->Const.MaxViewports = 1;
+   ctx->Const.ViewportSubpixelBits = 0;
+   ctx->Const.ViewportBounds.Min = 0;
+   ctx->Const.ViewportBounds.Max = 0;
+
+   /* Driver must override if it supports ARB_viewport_array */
+   ctx->Const.MaxViewports = 1;
 
    /** GL_ARB_uniform_buffer_object */
    ctx->Const.MaxCombinedUniformBlocks = 36;
@@ -1348,13 +1358,17 @@ _mesa_copy_context( const struct gl_context *src, struct gl_context *dst,
    }
    if (mask & GL_VIEWPORT_BIT) {
       /* Cannot use memcpy, because of pointers in GLmatrix _WindowMap */
-      dst->Viewport.X = src->Viewport.X;
-      dst->Viewport.Y = src->Viewport.Y;
-      dst->Viewport.Width = src->Viewport.Width;
-      dst->Viewport.Height = src->Viewport.Height;
-      dst->Viewport.Near = src->Viewport.Near;
-      dst->Viewport.Far = src->Viewport.Far;
-      _math_matrix_copy(&dst->Viewport._WindowMap, &src->Viewport._WindowMap);
+      unsigned i;
+      for (i = 0; i < src->Const.MaxViewports; i++) {
+         dst->ViewportArray[i].X = src->ViewportArray[i].X;
+         dst->ViewportArray[i].Y = src->ViewportArray[i].Y;
+         dst->ViewportArray[i].Width = src->ViewportArray[i].Width;
+         dst->ViewportArray[i].Height = src->ViewportArray[i].Height;
+         dst->ViewportArray[i].Near = src->ViewportArray[i].Near;
+         dst->ViewportArray[i].Far = src->ViewportArray[i].Far;
+         _math_matrix_copy(&dst->ViewportArray[i]._WindowMap,
+                           &src->ViewportArray[i]._WindowMap);
+      }
    }
 
    /* XXX FIXME:  Call callbacks?
@@ -1423,12 +1437,20 @@ void
 _mesa_check_init_viewport(struct gl_context *ctx, GLuint width, GLuint height)
 {
    if (!ctx->ViewportInitialized && width > 0 && height > 0) {
+      unsigned i;
+
       /* Note: set flag here, before calling _mesa_set_viewport(), to prevent
        * potential infinite recursion.
        */
       ctx->ViewportInitialized = GL_TRUE;
-      _mesa_set_viewport(ctx, 0, 0, width, height);
-      _mesa_set_scissor(ctx, 0, 0, width, height);
+
+      /* Note: ctx->Const.MaxViewports may not have been set by the driver
+       * yet, so just initialize all of them.
+       */
+      for (i = 0; i < MAX_VIEWPORTS; i++) {
+         _mesa_set_viewport(ctx, i, 0, 0, width, height);
+         _mesa_set_scissor(ctx, i, 0, 0, width, height);
+      }
    }
 }
 
@@ -1744,10 +1766,10 @@ _mesa_valid_to_render(struct gl_context *ctx, const char *where)
    if (ctx->NewState)
       _mesa_update_state(ctx);
 
-   if (ctx->Shader.CurrentVertexProgram) {
+   if (ctx->Shader.CurrentProgram[MESA_SHADER_VERTEX]) {
       vert_from_glsl_shader = true;
 
-      if (!ctx->Shader.CurrentVertexProgram->LinkStatus) {
+      if (!ctx->Shader.CurrentProgram[MESA_SHADER_VERTEX]->LinkStatus) {
          _mesa_error(ctx, GL_INVALID_OPERATION,
                      "%s(shader not linked)", where);
          return GL_FALSE;
@@ -1756,19 +1778,19 @@ _mesa_valid_to_render(struct gl_context *ctx, const char *where)
       {
          char errMsg[100];
          if (!_mesa_validate_shader_program(ctx,
-					    ctx->Shader.CurrentVertexProgram,
+					    ctx->Shader.CurrentProgram[MESA_SHADER_VERTEX],
                                             errMsg)) {
             _mesa_warning(ctx, "Shader program %u is invalid: %s",
-                          ctx->Shader.CurrentVertexProgram->Name, errMsg);
+                          ctx->Shader.CurrentProgram[MESA_SHADER_VERTEX]->Name, errMsg);
          }
       }
 #endif
    }
 
-   if (ctx->Shader.CurrentGeometryProgram) {
+   if (ctx->Shader.CurrentProgram[MESA_SHADER_GEOMETRY]) {
       geom_from_glsl_shader = true;
 
-      if (!ctx->Shader.CurrentGeometryProgram->LinkStatus) {
+      if (!ctx->Shader.CurrentProgram[MESA_SHADER_GEOMETRY]->LinkStatus) {
          _mesa_error(ctx, GL_INVALID_OPERATION,
                      "%s(shader not linked)", where);
          return GL_FALSE;
@@ -1777,19 +1799,20 @@ _mesa_valid_to_render(struct gl_context *ctx, const char *where)
       {
          char errMsg[100];
          if (!_mesa_validate_shader_program(ctx,
-					    ctx->Shader.CurrentGeometryProgram,
+					    ctx->Shader.CurrentProgram[MESA_SHADER_GEOMETRY],
                                             errMsg)) {
             _mesa_warning(ctx, "Shader program %u is invalid: %s",
-                          ctx->Shader.CurrentGeometryProgram->Name, errMsg);
+                          ctx->Shader.CurrentProgram[MESA_SHADER_GEOMETRY]->Name,
+                          errMsg);
          }
       }
 #endif
    }
 
-   if (ctx->Shader.CurrentFragmentProgram) {
+   if (ctx->Shader.CurrentProgram[MESA_SHADER_FRAGMENT]) {
       frag_from_glsl_shader = true;
 
-      if (!ctx->Shader.CurrentFragmentProgram->LinkStatus) {
+      if (!ctx->Shader.CurrentProgram[MESA_SHADER_FRAGMENT]->LinkStatus) {
          _mesa_error(ctx, GL_INVALID_OPERATION,
                      "%s(shader not linked)", where);
          return GL_FALSE;
@@ -1798,10 +1821,11 @@ _mesa_valid_to_render(struct gl_context *ctx, const char *where)
       {
          char errMsg[100];
          if (!_mesa_validate_shader_program(ctx,
-					    ctx->Shader.CurrentFragmentProgram,
+					    ctx->Shader.CurrentProgram[MESA_SHADER_FRAGMENT],
                                             errMsg)) {
             _mesa_warning(ctx, "Shader program %u is invalid: %s",
-                          ctx->Shader.CurrentFragmentProgram->Name, errMsg);
+                          ctx->Shader.CurrentProgram[MESA_SHADER_FRAGMENT]->Name,
+                          errMsg);
          }
       }
 #endif
@@ -1851,13 +1875,9 @@ _mesa_valid_to_render(struct gl_context *ctx, const char *where)
 
 #ifdef DEBUG
    if (ctx->Shader.Flags & GLSL_LOG) {
-      struct gl_shader_program *shProg[MESA_SHADER_STAGES];
+      struct gl_shader_program **shProg = ctx->Shader.CurrentProgram;
       gl_shader_stage i;
 
-      shProg[MESA_SHADER_VERTEX] = ctx->Shader.CurrentVertexProgram;
-      shProg[MESA_SHADER_GEOMETRY] = ctx->Shader.CurrentGeometryProgram;
-      shProg[MESA_SHADER_FRAGMENT] = ctx->Shader.CurrentFragmentProgram;
-
       for (i = 0; i < MESA_SHADER_STAGES; i++) {
 	 if (shProg[i] == NULL || shProg[i]->_Used
 	     || shProg[i]->_LinkedShaders[i] == NULL)
diff --git a/mesalib/src/mesa/main/dlist.c b/mesalib/src/mesa/main/dlist.c
index cb40ff4db..08943c9f9 100644
--- a/mesalib/src/mesa/main/dlist.c
+++ b/mesalib/src/mesa/main/dlist.c
@@ -767,6 +767,7 @@ _mesa_delete_list(struct gl_context *ctx, struct gl_display_list *dlist)
             break;
          case OPCODE_PIXEL_MAP:
             free(get_pointer(&n[3]));
+            n += InstSize[n[0].opcode];
             break;
 
          case OPCODE_CONTINUE:
diff --git a/mesalib/src/mesa/main/enable.c b/mesalib/src/mesa/main/enable.c
index fca306890..640db8490 100644
--- a/mesalib/src/mesa/main/enable.c
+++ b/mesalib/src/mesa/main/enable.c
@@ -659,10 +659,15 @@ _mesa_set_enable(struct gl_context *ctx, GLenum cap, GLboolean state)
          ctx->Transform.RescaleNormals = state;
          break;
       case GL_SCISSOR_TEST:
-         if (ctx->Scissor.Enabled == state)
-            return;
-         FLUSH_VERTICES(ctx, _NEW_SCISSOR);
-         ctx->Scissor.Enabled = state;
+         {
+            /* Must expand glEnable to all scissors */
+            GLbitfield newEnabled =
+               state * ((1 << ctx->Const.MaxViewports) - 1);
+            if (newEnabled != ctx->Scissor.EnableFlags) {
+               FLUSH_VERTICES(ctx, _NEW_SCISSOR);
+               ctx->Scissor.EnableFlags = newEnabled;
+            }
+         }
          break;
       case GL_STENCIL_TEST:
          if (ctx->Stencil.Enabled == state)
@@ -1076,6 +1081,20 @@ _mesa_set_enablei(struct gl_context *ctx, GLenum cap,
             ctx->Color.BlendEnabled &= ~(1 << index);
       }
       break;
+   case GL_SCISSOR_TEST:
+      if (index >= ctx->Const.MaxViewports) {
+         _mesa_error(ctx, GL_INVALID_VALUE, "%s(index=%u)",
+                     state ? "glEnablei" : "glDisablei", index);
+         return;
+      }
+      if (((ctx->Scissor.EnableFlags >> index) & 1) != state) {
+         FLUSH_VERTICES(ctx, _NEW_SCISSOR);
+         if (state)
+            ctx->Scissor.EnableFlags |= (1 << index);
+         else
+            ctx->Scissor.EnableFlags &= ~(1 << index);
+      }
+      break;
    default:
       goto invalid_enum_error;
    }
@@ -1117,6 +1136,13 @@ _mesa_IsEnabledi( GLenum cap, GLuint index )
          return GL_FALSE;
       }
       return (ctx->Color.BlendEnabled >> index) & 1;
+   case GL_SCISSOR_TEST:
+      if (index >= ctx->Const.MaxViewports) {
+         _mesa_error(ctx, GL_INVALID_VALUE, "glIsEnabledIndexed(index=%u)",
+                     index);
+         return GL_FALSE;
+      }
+      return (ctx->Scissor.EnableFlags >> index) & 1;
    default:
       _mesa_error(ctx, GL_INVALID_ENUM, "glIsEnabledIndexed(cap=%s)",
                   _mesa_lookup_enum_by_nr(cap));
@@ -1349,7 +1375,7 @@ _mesa_IsEnabled( GLenum cap )
             goto invalid_enum_error;
          return ctx->Transform.RescaleNormals;
       case GL_SCISSOR_TEST:
-	 return ctx->Scissor.Enabled;
+	 return ctx->Scissor.EnableFlags & 1;  /* return state for index 0 */
       case GL_STENCIL_TEST:
 	 return ctx->Stencil.Enabled;
       case GL_TEXTURE_1D:
diff --git a/mesalib/src/mesa/main/extensions.c b/mesalib/src/mesa/main/extensions.c
index 2e0ccc3b6..0676f1e3d 100644
--- a/mesalib/src/mesa/main/extensions.c
+++ b/mesalib/src/mesa/main/extensions.c
@@ -80,6 +80,7 @@ static const struct extension extension_table[] = {
    /* ARB Extensions */
    { "GL_ARB_ES2_compatibility",                   o(ARB_ES2_compatibility),                   GL,             2009 },
    { "GL_ARB_ES3_compatibility",                   o(ARB_ES3_compatibility),                   GL,             2012 },
+   { "GL_ARB_arrays_of_arrays",                    o(ARB_arrays_of_arrays),                    GL,             2012 },
    { "GL_ARB_base_instance",                       o(ARB_base_instance),                       GL,             2011 },
    { "GL_ARB_blend_func_extended",                 o(ARB_blend_func_extended),                 GL,             2009 },
    { "GL_ARB_clear_buffer_object",                 o(dummy_true),                              GL,             2012 },
@@ -176,6 +177,7 @@ static const struct extension extension_table[] = {
    { "GL_ARB_vertex_shader",                       o(ARB_vertex_shader),                       GL,             2002 },
    { "GL_ARB_vertex_type_10f_11f_11f_rev",         o(ARB_vertex_type_10f_11f_11f_rev),         GL,             2013 },
    { "GL_ARB_vertex_type_2_10_10_10_rev",          o(ARB_vertex_type_2_10_10_10_rev),          GL,             2009 },
+   { "GL_ARB_viewport_array",                      o(ARB_viewport_array),                      GLC,            2010 },
    { "GL_ARB_window_pos",                          o(dummy_true),                              GLL,            2001 },
    /* EXT extensions */
    { "GL_EXT_abgr",                                o(dummy_true),                              GL,             1995 },
diff --git a/mesalib/src/mesa/main/fbobject.c b/mesalib/src/mesa/main/fbobject.c
index dc7184ad4..943f40bd9 100644
--- a/mesalib/src/mesa/main/fbobject.c
+++ b/mesalib/src/mesa/main/fbobject.c
@@ -880,7 +880,7 @@ _mesa_test_framebuffer_completeness(struct gl_context *ctx,
    /* Covers max_layer_count, is_layered, and layer_tex_target */
    bool layer_info_valid = false;
    GLuint max_layer_count = 0, att_layer_count;
-   bool is_layered;
+   bool is_layered = false;
    GLenum layer_tex_target = 0;
 
    assert(_mesa_is_user_fbo(fb));
diff --git a/mesalib/src/mesa/main/ff_fragment_shader.cpp b/mesalib/src/mesa/main/ff_fragment_shader.cpp
index 8523edf41..cad67aa85 100644
--- a/mesalib/src/mesa/main/ff_fragment_shader.cpp
+++ b/mesalib/src/mesa/main/ff_fragment_shader.cpp
@@ -317,9 +317,9 @@ static GLbitfield get_fp_input_mask( struct gl_context *ctx )
 {
    /* _NEW_PROGRAM */
    const GLboolean vertexShader =
-      (ctx->Shader.CurrentVertexProgram &&
-       ctx->Shader.CurrentVertexProgram->LinkStatus &&
-       ctx->Shader.CurrentVertexProgram->_LinkedShaders[MESA_SHADER_VERTEX]);
+      (ctx->Shader.CurrentProgram[MESA_SHADER_VERTEX] &&
+       ctx->Shader.CurrentProgram[MESA_SHADER_VERTEX]->LinkStatus &&
+       ctx->Shader.CurrentProgram[MESA_SHADER_VERTEX]->_LinkedShaders[MESA_SHADER_VERTEX]);
    const GLboolean vertexProgram = ctx->VertexProgram._Enabled;
    GLbitfield fp_inputs = 0x0;
 
@@ -383,7 +383,7 @@ static GLbitfield get_fp_input_mask( struct gl_context *ctx )
        * validation (see additional comments in state.c).
        */
       if (vertexShader)
-         vprog = ctx->Shader.CurrentVertexProgram->_LinkedShaders[MESA_SHADER_VERTEX]->Program;
+         vprog = ctx->Shader.CurrentProgram[MESA_SHADER_VERTEX]->_LinkedShaders[MESA_SHADER_VERTEX]->Program;
       else
          vprog = &ctx->VertexProgram.Current->Base;
 
diff --git a/mesalib/src/mesa/main/ffvertex_prog.c b/mesalib/src/mesa/main/ffvertex_prog.c
index aec2b2dbc..4d71c55ee 100644
--- a/mesalib/src/mesa/main/ffvertex_prog.c
+++ b/mesalib/src/mesa/main/ffvertex_prog.c
@@ -1676,7 +1676,7 @@ _mesa_get_fixed_func_vertex_program(struct gl_context *ctx)
          return NULL;
 
       create_new_program( &key, prog,
-                          ctx->ShaderCompilerOptions[MESA_SHADER_VERTEX].PreferDP4,
+                          ctx->ShaderCompilerOptions[MESA_SHADER_VERTEX].OptimizeForAOS,
                           ctx->Const.Program[MESA_SHADER_VERTEX].MaxTemps );
 
 #if 0
diff --git a/mesalib/src/mesa/main/formats.c b/mesalib/src/mesa/main/formats.c
index 1246c4d92..7bde1f1a8 100644
--- a/mesalib/src/mesa/main/formats.c
+++ b/mesalib/src/mesa/main/formats.c
@@ -2032,6 +2032,9 @@ _mesa_get_format_color_encoding(gl_format format)
    case MESA_FORMAT_SRGBA_DXT3:
    case MESA_FORMAT_SRGBA_DXT5:
    case MESA_FORMAT_XBGR8888_SRGB:
+   case MESA_FORMAT_ETC2_SRGB8:
+   case MESA_FORMAT_ETC2_SRGB8_ALPHA8_EAC:
+   case MESA_FORMAT_ETC2_SRGB8_PUNCHTHROUGH_ALPHA1:
       return GL_SRGB;
    default:
       return GL_LINEAR;
@@ -2077,6 +2080,15 @@ _mesa_get_srgb_format_linear(gl_format format)
    case MESA_FORMAT_XBGR8888_SRGB:
       format = MESA_FORMAT_RGBX8888_REV;
       break;
+   case MESA_FORMAT_ETC2_SRGB8:
+      format = MESA_FORMAT_ETC2_RGB8;
+      break;
+   case MESA_FORMAT_ETC2_SRGB8_ALPHA8_EAC:
+      format = MESA_FORMAT_ETC2_RGBA8_EAC;
+      break;
+   case MESA_FORMAT_ETC2_SRGB8_PUNCHTHROUGH_ALPHA1:
+      format = MESA_FORMAT_ETC2_RGB8_PUNCHTHROUGH_ALPHA1;
+      break;
    default:
       break;
    }
diff --git a/mesalib/src/mesa/main/framebuffer.c b/mesalib/src/mesa/main/framebuffer.c
index 2fad45880..bd8f4933f 100644
--- a/mesalib/src/mesa/main/framebuffer.c
+++ b/mesalib/src/mesa/main/framebuffer.c
@@ -356,6 +356,56 @@ update_framebuffer_size(struct gl_context *ctx, struct gl_framebuffer *fb)
 }
 
 
+/**
+ * Calculate the inclusive bounding box for the scissor of a specific viewport
+ *
+ * \param ctx     GL context.
+ * \param buffer  Framebuffer to be checked against
+ * \param idx     Index of the desired viewport
+ * \param bbox    Bounding box for the scissored viewport.  Stored as xmin,
+ *                xmax, ymin, ymax.
+ *
+ * \warning This function assumes that the framebuffer dimensions are up to
+ * date (e.g., update_framebuffer_size has been recently called on \c buffer).
+ *
+ * \sa _mesa_clip_to_region
+ */
+void
+_mesa_scissor_bounding_box(const struct gl_context *ctx,
+                           const struct gl_framebuffer *buffer,
+                           unsigned idx, int *bbox)
+{
+   bbox[0] = 0;
+   bbox[2] = 0;
+   bbox[1] = buffer->Width;
+   bbox[3] = buffer->Height;
+
+   if (ctx->Scissor.EnableFlags & (1u << idx)) {
+      if (ctx->Scissor.ScissorArray[idx].X > bbox[0]) {
+         bbox[0] = ctx->Scissor.ScissorArray[idx].X;
+      }
+      if (ctx->Scissor.ScissorArray[idx].Y > bbox[2]) {
+         bbox[2] = ctx->Scissor.ScissorArray[idx].Y;
+      }
+      if (ctx->Scissor.ScissorArray[idx].X + ctx->Scissor.ScissorArray[idx].Width < bbox[1]) {
+         bbox[1] = ctx->Scissor.ScissorArray[idx].X + ctx->Scissor.ScissorArray[idx].Width;
+      }
+      if (ctx->Scissor.ScissorArray[idx].Y + ctx->Scissor.ScissorArray[idx].Height < bbox[3]) {
+         bbox[3] = ctx->Scissor.ScissorArray[idx].Y + ctx->Scissor.ScissorArray[idx].Height;
+      }
+      /* finally, check for empty region */
+      if (bbox[0] > bbox[1]) {
+         bbox[0] = bbox[1];
+      }
+      if (bbox[2] > bbox[3]) {
+         bbox[2] = bbox[3];
+      }
+   }
+
+   ASSERT(bbox[0] <= bbox[1]);
+   ASSERT(bbox[2] <= bbox[3]);
+}
+
 /**
  * Update the context's current drawing buffer's Xmin, Xmax, Ymin, Ymax fields.
  * These values are computed from the buffer's width and height and
@@ -366,6 +416,7 @@ void
 _mesa_update_draw_buffer_bounds(struct gl_context *ctx)
 {
    struct gl_framebuffer *buffer = ctx->DrawBuffer;
+   int bbox[4];
 
    if (!buffer)
       return;
@@ -375,35 +426,12 @@ _mesa_update_draw_buffer_bounds(struct gl_context *ctx)
       update_framebuffer_size(ctx, buffer);
    }
 
-   buffer->_Xmin = 0;
-   buffer->_Ymin = 0;
-   buffer->_Xmax = buffer->Width;
-   buffer->_Ymax = buffer->Height;
-
-   if (ctx->Scissor.Enabled) {
-      if (ctx->Scissor.X > buffer->_Xmin) {
-	 buffer->_Xmin = ctx->Scissor.X;
-      }
-      if (ctx->Scissor.Y > buffer->_Ymin) {
-	 buffer->_Ymin = ctx->Scissor.Y;
-      }
-      if (ctx->Scissor.X + ctx->Scissor.Width < buffer->_Xmax) {
-	 buffer->_Xmax = ctx->Scissor.X + ctx->Scissor.Width;
-      }
-      if (ctx->Scissor.Y + ctx->Scissor.Height < buffer->_Ymax) {
-	 buffer->_Ymax = ctx->Scissor.Y + ctx->Scissor.Height;
-      }
-      /* finally, check for empty region */
-      if (buffer->_Xmin > buffer->_Xmax) {
-         buffer->_Xmin = buffer->_Xmax;
-      }
-      if (buffer->_Ymin > buffer->_Ymax) {
-         buffer->_Ymin = buffer->_Ymax;
-      }
-   }
-
-   ASSERT(buffer->_Xmin <= buffer->_Xmax);
-   ASSERT(buffer->_Ymin <= buffer->_Ymax);
+   /* Default to the first scissor as that's always valid */
+   _mesa_scissor_bounding_box(ctx, buffer, 0, bbox);
+   buffer->_Xmin = bbox[0];
+   buffer->_Ymin = bbox[2];
+   buffer->_Xmax = bbox[1];
+   buffer->_Ymax = bbox[3];
 }
 
 
diff --git a/mesalib/src/mesa/main/framebuffer.h b/mesalib/src/mesa/main/framebuffer.h
index 264566477..a4274216e 100644
--- a/mesalib/src/mesa/main/framebuffer.h
+++ b/mesalib/src/mesa/main/framebuffer.h
@@ -71,6 +71,11 @@ _mesa_resize_framebuffer(struct gl_context *ctx, struct gl_framebuffer *fb,
 extern void
 _mesa_resizebuffers( struct gl_context *ctx );
 
+extern void
+_mesa_scissor_bounding_box(const struct gl_context *ctx,
+                           const struct gl_framebuffer *buffer,
+                           unsigned idx, int *bbox);
+
 extern void 
 _mesa_update_draw_buffer_bounds(struct gl_context *ctx);
 
diff --git a/mesalib/src/mesa/main/get.c b/mesalib/src/mesa/main/get.c
index b13f9a3db..16dce5b65 100644
--- a/mesalib/src/mesa/main/get.c
+++ b/mesalib/src/mesa/main/get.c
@@ -113,6 +113,7 @@ enum value_type {
    TYPE_FLOATN_3,
    TYPE_FLOATN_4,
    TYPE_DOUBLEN,
+   TYPE_DOUBLEN_2,
    TYPE_MATRIX,
    TYPE_MATRIX_T,
    TYPE_CONST
@@ -162,6 +163,7 @@ struct value_desc {
 union value {
    GLfloat value_float;
    GLfloat value_float_4[4];
+   GLdouble value_double_2[2];
    GLmatrix *value_matrix;
    GLint value_int;
    GLint value_int_4[4];
@@ -389,6 +391,7 @@ EXTRA_EXT(ARB_texture_gather);
 EXTRA_EXT(ARB_shader_atomic_counters);
 EXTRA_EXT(ARB_draw_indirect);
 EXTRA_EXT(ARB_shader_image_load_store);
+EXTRA_EXT(ARB_viewport_array);
 
 static const int
 extra_ARB_color_buffer_float_or_glcore[] = {
@@ -665,10 +668,14 @@ find_custom_value(struct gl_context *ctx, const struct value_desc *d, union valu
       break;
 
    case GL_SCISSOR_BOX:
-      v->value_int_4[0] = ctx->Scissor.X;
-      v->value_int_4[1] = ctx->Scissor.Y;
-      v->value_int_4[2] = ctx->Scissor.Width;
-      v->value_int_4[3] = ctx->Scissor.Height;
+      v->value_int_4[0] = ctx->Scissor.ScissorArray[0].X;
+      v->value_int_4[1] = ctx->Scissor.ScissorArray[0].Y;
+      v->value_int_4[2] = ctx->Scissor.ScissorArray[0].Width;
+      v->value_int_4[3] = ctx->Scissor.ScissorArray[0].Height;
+      break;
+
+   case GL_SCISSOR_TEST:
+      v->value_bool = ctx->Scissor.EnableFlags & 1;
       break;
 
    case GL_LIST_INDEX:
@@ -685,10 +692,15 @@ find_custom_value(struct gl_context *ctx, const struct value_desc *d, union valu
       break;
 
    case GL_VIEWPORT:
-      v->value_int_4[0] = ctx->Viewport.X;
-      v->value_int_4[1] = ctx->Viewport.Y;
-      v->value_int_4[2] = ctx->Viewport.Width;
-      v->value_int_4[3] = ctx->Viewport.Height;
+      v->value_float_4[0] = ctx->ViewportArray[0].X;
+      v->value_float_4[1] = ctx->ViewportArray[0].Y;
+      v->value_float_4[2] = ctx->ViewportArray[0].Width;
+      v->value_float_4[3] = ctx->ViewportArray[0].Height;
+      break;
+
+   case GL_DEPTH_RANGE:
+      v->value_double_2[0] = ctx->ViewportArray[0].Near;
+      v->value_double_2[1] = ctx->ViewportArray[0].Far;
       break;
 
    case GL_ACTIVE_STENCIL_FACE_EXT:
@@ -1235,6 +1247,8 @@ _mesa_GetBooleanv(GLenum pname, GLboolean *params)
       params[0] = FLOAT_TO_BOOLEAN(((GLfloat *) p)[0]);
       break;
 
+   case TYPE_DOUBLEN_2:
+      params[1] = FLOAT_TO_BOOLEAN(((GLdouble *) p)[1]);
    case TYPE_DOUBLEN:
       params[0] = FLOAT_TO_BOOLEAN(((GLdouble *) p)[0]);
       break;
@@ -1321,6 +1335,8 @@ _mesa_GetFloatv(GLenum pname, GLfloat *params)
       params[0] = ((GLfloat *) p)[0];
       break;
 
+   case TYPE_DOUBLEN_2:
+      params[1] = (GLfloat) (((GLdouble *) p)[1]);
    case TYPE_DOUBLEN:
       params[0] = (GLfloat) (((GLdouble *) p)[0]);
       break;
@@ -1413,6 +1429,8 @@ _mesa_GetIntegerv(GLenum pname, GLint *params)
       params[0] = FLOAT_TO_INT(((GLfloat *) p)[0]);
       break;
 
+   case TYPE_DOUBLEN_2:
+      params[1] = FLOAT_TO_INT(((GLdouble *) p)[1]);
    case TYPE_DOUBLEN:
       params[0] = FLOAT_TO_INT(((GLdouble *) p)[0]);
       break;
@@ -1505,6 +1523,8 @@ _mesa_GetInteger64v(GLenum pname, GLint64 *params)
       params[0] = FLOAT_TO_INT64(((GLfloat *) p)[0]);
       break;
 
+   case TYPE_DOUBLEN_2:
+      params[1] = FLOAT_TO_INT64(((GLdouble *) p)[1]);
    case TYPE_DOUBLEN:
       params[0] = FLOAT_TO_INT64(((GLdouble *) p)[0]);
       break;
@@ -1591,6 +1611,8 @@ _mesa_GetDoublev(GLenum pname, GLdouble *params)
       params[0] = ((GLfloat *) p)[0];
       break;
 
+   case TYPE_DOUBLEN_2:
+      params[1] = ((GLdouble *) p)[1];
    case TYPE_DOUBLEN:
       params[0] = ((GLdouble *) p)[0];
       break;
@@ -1719,6 +1741,31 @@ find_value_indexed(const char *func, GLenum pname, GLuint index, union value *v)
       v->value_int_4[3] = ctx->Color.ColorMask[index][ACOMP] ? 1 : 0;
       return TYPE_INT_4;
 
+   case GL_SCISSOR_BOX:
+      if (index >= ctx->Const.MaxViewports)
+         goto invalid_value;
+      v->value_int_4[0] = ctx->Scissor.ScissorArray[index].X;
+      v->value_int_4[1] = ctx->Scissor.ScissorArray[index].Y;
+      v->value_int_4[2] = ctx->Scissor.ScissorArray[index].Width;
+      v->value_int_4[3] = ctx->Scissor.ScissorArray[index].Height;
+      return TYPE_INT_4;
+
+   case GL_VIEWPORT:
+      if (index >= ctx->Const.MaxViewports)
+         goto invalid_value;
+      v->value_float_4[0] = ctx->ViewportArray[index].X;
+      v->value_float_4[1] = ctx->ViewportArray[index].Y;
+      v->value_float_4[2] = ctx->ViewportArray[index].Width;
+      v->value_float_4[3] = ctx->ViewportArray[index].Height;
+      return TYPE_FLOAT_4;
+
+   case GL_DEPTH_RANGE:
+      if (index >= ctx->Const.MaxViewports)
+         goto invalid_value;
+      v->value_double_2[0] = ctx->ViewportArray[index].Near;
+      v->value_double_2[1] = ctx->ViewportArray[index].Far;
+      return TYPE_DOUBLEN_2;
+
    case GL_TRANSFORM_FEEDBACK_BUFFER_START:
       if (index >= ctx->Const.MaxTransformFeedbackBuffers)
 	 goto invalid_value;
@@ -1927,6 +1974,26 @@ _mesa_GetIntegeri_v( GLenum pname, GLuint index, GLint *params )
       find_value_indexed("glGetIntegeri_v", pname, index, &v);
 
    switch (type) {
+   case TYPE_FLOAT_4:
+   case TYPE_FLOATN_4:
+      params[3] = IROUND(v.value_float_4[3]);
+   case TYPE_FLOAT_3:
+   case TYPE_FLOATN_3:
+      params[2] = IROUND(v.value_float_4[2]);
+   case TYPE_FLOAT_2:
+   case TYPE_FLOATN_2:
+      params[1] = IROUND(v.value_float_4[1]);
+   case TYPE_FLOAT:
+   case TYPE_FLOATN:
+      params[0] = IROUND(v.value_float_4[0]);
+      break;
+
+   case TYPE_DOUBLEN_2:
+      params[1] = IROUND(v.value_double_2[1]);
+   case TYPE_DOUBLEN:
+      params[0] = IROUND(v.value_double_2[0]);
+      break;
+
    case TYPE_INT:
       params[0] = v.value_int;
       break;
@@ -1969,6 +2036,150 @@ _mesa_GetInteger64i_v( GLenum pname, GLuint index, GLint64 *params )
    }
 }
 
+void GLAPIENTRY
+_mesa_GetFloati_v(GLenum pname, GLuint index, GLfloat *params)
+{
+   int i;
+   GLmatrix *m;
+   union value v;
+   enum value_type type =
+      find_value_indexed("glGetFloati_v", pname, index, &v);
+
+   switch (type) {
+   case TYPE_FLOAT_4:
+   case TYPE_FLOATN_4:
+      params[3] = v.value_float_4[3];
+   case TYPE_FLOAT_3:
+   case TYPE_FLOATN_3:
+      params[2] = v.value_float_4[2];
+   case TYPE_FLOAT_2:
+   case TYPE_FLOATN_2:
+      params[1] = v.value_float_4[1];
+   case TYPE_FLOAT:
+   case TYPE_FLOATN:
+      params[0] = v.value_float_4[0];
+      break;
+
+   case TYPE_DOUBLEN_2:
+      params[1] = (GLfloat) v.value_double_2[1];
+   case TYPE_DOUBLEN:
+      params[0] = (GLfloat) v.value_double_2[0];
+      break;
+
+   case TYPE_INT_4:
+      params[3] = (GLfloat) v.value_int_4[3];
+   case TYPE_INT_3:
+      params[2] = (GLfloat) v.value_int_4[2];
+   case TYPE_INT_2:
+   case TYPE_ENUM_2:
+      params[1] = (GLfloat) v.value_int_4[1];
+   case TYPE_INT:
+   case TYPE_ENUM:
+      params[0] = (GLfloat) v.value_int_4[0];
+      break;
+
+   case TYPE_INT_N:
+      for (i = 0; i < v.value_int_n.n; i++)
+	 params[i] = INT_TO_FLOAT(v.value_int_n.ints[i]);
+      break;
+
+   case TYPE_INT64:
+      params[0] = (GLfloat) v.value_int64;
+      break;
+
+   case TYPE_BOOLEAN:
+      params[0] = BOOLEAN_TO_FLOAT(v.value_bool);
+      break;
+
+   case TYPE_MATRIX:
+      m = *(GLmatrix **) &v;
+      for (i = 0; i < 16; i++)
+	 params[i] = m->m[i];
+      break;
+
+   case TYPE_MATRIX_T:
+      m = *(GLmatrix **) &v;
+      for (i = 0; i < 16; i++)
+	 params[i] = m->m[transpose[i]];
+      break;
+
+   default:
+      ;
+   }
+}
+
+void GLAPIENTRY
+_mesa_GetDoublei_v(GLenum pname, GLuint index, GLdouble *params)
+{
+   int i;
+   GLmatrix *m;
+   union value v;
+   enum value_type type =
+      find_value_indexed("glGetDoublei_v", pname, index, &v);
+
+   switch (type) {
+   case TYPE_FLOAT_4:
+   case TYPE_FLOATN_4:
+      params[3] = (GLdouble) v.value_float_4[3];
+   case TYPE_FLOAT_3:
+   case TYPE_FLOATN_3:
+      params[2] = (GLdouble) v.value_float_4[2];
+   case TYPE_FLOAT_2:
+   case TYPE_FLOATN_2:
+      params[1] = (GLdouble) v.value_float_4[1];
+   case TYPE_FLOAT:
+   case TYPE_FLOATN:
+      params[0] = (GLdouble) v.value_float_4[0];
+      break;
+
+   case TYPE_DOUBLEN_2:
+      params[1] = v.value_double_2[1];
+   case TYPE_DOUBLEN:
+      params[0] = v.value_double_2[0];
+      break;
+
+   case TYPE_INT_4:
+      params[3] = (GLdouble) v.value_int_4[3];
+   case TYPE_INT_3:
+      params[2] = (GLdouble) v.value_int_4[2];
+   case TYPE_INT_2:
+   case TYPE_ENUM_2:
+      params[1] = (GLdouble) v.value_int_4[1];
+   case TYPE_INT:
+   case TYPE_ENUM:
+      params[0] = (GLdouble) v.value_int_4[0];
+      break;
+
+   case TYPE_INT_N:
+      for (i = 0; i < v.value_int_n.n; i++)
+	 params[i] = (GLdouble) INT_TO_FLOAT(v.value_int_n.ints[i]);
+      break;
+
+   case TYPE_INT64:
+      params[0] = (GLdouble) v.value_int64;
+      break;
+
+   case TYPE_BOOLEAN:
+      params[0] = (GLdouble) BOOLEAN_TO_FLOAT(v.value_bool);
+      break;
+
+   case TYPE_MATRIX:
+      m = *(GLmatrix **) &v;
+      for (i = 0; i < 16; i++)
+	 params[i] = (GLdouble) m->m[i];
+      break;
+
+   case TYPE_MATRIX_T:
+      m = *(GLmatrix **) &v;
+      for (i = 0; i < 16; i++)
+	 params[i] = (GLdouble) m->m[transpose[i]];
+      break;
+
+   default:
+      ;
+   }
+}
+
 void GLAPIENTRY
 _mesa_GetFixedv(GLenum pname, GLfixed *params)
 {
@@ -2000,6 +2211,8 @@ _mesa_GetFixedv(GLenum pname, GLfixed *params)
       params[0] = FLOAT_TO_FIXED(((GLfloat *) p)[0]);
       break;
 
+   case TYPE_DOUBLEN_2:
+      params[1] = FLOAT_TO_FIXED(((GLdouble *) p)[1]);
    case TYPE_DOUBLEN:
       params[0] = FLOAT_TO_FIXED(((GLdouble *) p)[0]);
       break;
diff --git a/mesalib/src/mesa/main/get.h b/mesalib/src/mesa/main/get.h
index 0f72508a7..ce97cc586 100644
--- a/mesalib/src/mesa/main/get.h
+++ b/mesalib/src/mesa/main/get.h
@@ -65,6 +65,12 @@ _mesa_GetInteger64i_v( GLenum pname, GLuint index, GLint64 *params );
 extern void GLAPIENTRY
 _mesa_GetPointerv( GLenum pname, GLvoid **params );
 
+extern void GLAPIENTRY
+_mesa_GetFloati_v(GLenum target, GLuint index, GLfloat *data);
+
+extern void GLAPIENTRY
+_mesa_GetDoublei_v(GLenum target, GLuint index, GLdouble *data);
+
 extern const GLubyte * GLAPIENTRY
 _mesa_GetString( GLenum name );
 
diff --git a/mesalib/src/mesa/main/get_hash_params.py b/mesalib/src/mesa/main/get_hash_params.py
index bc2bbafa8..b45e1430b 100644
--- a/mesalib/src/mesa/main/get_hash_params.py
+++ b/mesalib/src/mesa/main/get_hash_params.py
@@ -11,7 +11,7 @@ descriptor=[
   [ "DEPTH_BITS", "BUFFER_INT(Visual.depthBits), extra_new_buffers" ],
   [ "DEPTH_CLEAR_VALUE", "CONTEXT_FIELD(Depth.Clear, TYPE_DOUBLEN), NO_EXTRA" ],
   [ "DEPTH_FUNC", "CONTEXT_ENUM(Depth.Func), NO_EXTRA" ],
-  [ "DEPTH_RANGE", "CONTEXT_FIELD(Viewport.Near, TYPE_FLOATN_2), NO_EXTRA" ],
+  [ "DEPTH_RANGE", "LOC_CUSTOM, TYPE_DOUBLEN_2, 0, NO_EXTRA" ],
   [ "DEPTH_TEST", "CONTEXT_BOOL(Depth.Test), NO_EXTRA" ],
   [ "DEPTH_WRITEMASK", "CONTEXT_BOOL(Depth.Mask), NO_EXTRA" ],
   [ "DITHER", "CONTEXT_BOOL(Color.DitherFlag), NO_EXTRA" ],
@@ -30,7 +30,7 @@ descriptor=[
   [ "POLYGON_OFFSET_FILL", "CONTEXT_BOOL(Polygon.OffsetFill), NO_EXTRA" ],
   [ "RED_BITS", "BUFFER_INT(Visual.redBits), extra_new_buffers" ],
   [ "SCISSOR_BOX", "LOC_CUSTOM, TYPE_INT_4, 0, NO_EXTRA" ],
-  [ "SCISSOR_TEST", "CONTEXT_BOOL(Scissor.Enabled), NO_EXTRA" ],
+  [ "SCISSOR_TEST", "LOC_CUSTOM, TYPE_BOOLEAN, NO_OFFSET, NO_EXTRA" ],
   [ "STENCIL_BITS", "BUFFER_INT(Visual.stencilBits), extra_new_buffers" ],
   [ "STENCIL_CLEAR_VALUE", "CONTEXT_INT(Stencil.Clear), NO_EXTRA" ],
   [ "STENCIL_FAIL", "LOC_CUSTOM, TYPE_ENUM, NO_OFFSET, NO_EXTRA" ],
@@ -44,7 +44,7 @@ descriptor=[
   [ "SUBPIXEL_BITS", "CONTEXT_INT(Const.SubPixelBits), NO_EXTRA" ],
   [ "TEXTURE_BINDING_2D", "LOC_CUSTOM, TYPE_INT, TEXTURE_2D_INDEX, NO_EXTRA" ],
   [ "UNPACK_ALIGNMENT", "CONTEXT_INT(Unpack.Alignment), NO_EXTRA" ],
-  [ "VIEWPORT", "LOC_CUSTOM, TYPE_INT_4, 0, NO_EXTRA" ],
+  [ "VIEWPORT", "LOC_CUSTOM, TYPE_FLOAT_4, 0, NO_EXTRA" ],
 
 # GL_ARB_multitexture
   [ "ACTIVE_TEXTURE", "LOC_CUSTOM, TYPE_INT, 0, NO_EXTRA" ],
@@ -759,6 +759,13 @@ descriptor=[
   [ "TEXTURE_BUFFER_OFFSET_ALIGNMENT", "CONTEXT_INT(Const.TextureBufferOffsetAlignment), extra_ARB_texture_buffer_range" ],
 # GL_ARB_draw_indirect
   [ "DRAW_INDIRECT_BUFFER_BINDING", "LOC_CUSTOM, TYPE_INT, 0, extra_ARB_draw_indirect" ],
+
+# GL_ARB_viewport_array
+  [ "MAX_VIEWPORTS", "CONTEXT_INT(Const.MaxViewports), extra_ARB_viewport_array" ],
+  [ "VIEWPORT_SUBPIXEL_BITS", "CONTEXT_INT(Const.ViewportSubpixelBits), extra_ARB_viewport_array" ],
+  [ "VIEWPORT_BOUNDS_RANGE", "CONTEXT_FLOAT2(Const.ViewportBounds), extra_ARB_viewport_array" ],
+  [ "LAYER_PROVOKING_VERTEX", "CONTEXT_ENUM(Light.ProvokingVertex), extra_ARB_viewport_array" ],
+  [ "VIEWPORT_INDEX_PROVOKING_VERTEX", "CONTEXT_ENUM(Light.ProvokingVertex), extra_ARB_viewport_array" ],
 ]}
 
 ]
diff --git a/mesalib/src/mesa/main/glformats.c b/mesalib/src/mesa/main/glformats.c
index bec7a9bbb..7d4a31057 100644
--- a/mesalib/src/mesa/main/glformats.c
+++ b/mesalib/src/mesa/main/glformats.c
@@ -1136,76 +1136,60 @@ GLenum
 _mesa_get_nongeneric_internalformat(GLenum format)
 {
    switch (format) {
-      /* GL 1.1 formats. */
-      case 4:
-      case GL_RGBA:
-         return GL_RGBA8;
-
-      case 3:
-      case GL_RGB:
-         return GL_RGB8;
-
-      case 2:
-      case GL_LUMINANCE_ALPHA:
-         return GL_LUMINANCE8_ALPHA8;
-
-      case 1:
-      case GL_LUMINANCE:
-         return GL_LUMINANCE8;
-
-      case GL_ALPHA:
-         return GL_ALPHA8;
-
-      case GL_INTENSITY:
-         return GL_INTENSITY8;
-
-      /* GL_ARB_texture_rg */
-      case GL_RED:
-         return GL_R8;
-
-      case GL_RG:
-         return GL_RG8;
-
-      /* GL_EXT_texture_sRGB */
-      case GL_SRGB:
-         return GL_SRGB8;
-
-      case GL_SRGB_ALPHA:
-         return GL_SRGB8_ALPHA8;
-
-      case GL_SLUMINANCE:
-         return GL_SLUMINANCE8;
-
-      case GL_SLUMINANCE_ALPHA:
-         return GL_SLUMINANCE8_ALPHA8;
-
-      /* GL_EXT_texture_snorm */
-      case GL_RGBA_SNORM:
-         return GL_RGBA8_SNORM;
-
-      case GL_RGB_SNORM:
-         return GL_RGB8_SNORM;
-
-      case GL_RG_SNORM:
-         return GL_RG8_SNORM;
-
-      case GL_RED_SNORM:
-         return GL_R8_SNORM;
-
-      case GL_LUMINANCE_ALPHA_SNORM:
-         return GL_LUMINANCE8_ALPHA8_SNORM;
-
-      case GL_LUMINANCE_SNORM:
-         return GL_LUMINANCE8_SNORM;
+   /* GL 1.1 formats. */
+   case 4:
+   case GL_RGBA:
+      return GL_RGBA8;
+   case 3:
+   case GL_RGB:
+      return GL_RGB8;
+   case 2:
+   case GL_LUMINANCE_ALPHA:
+      return GL_LUMINANCE8_ALPHA8;
+   case 1:
+   case GL_LUMINANCE:
+      return GL_LUMINANCE8;
+   case GL_ALPHA:
+      return GL_ALPHA8;
+   case GL_INTENSITY:
+      return GL_INTENSITY8;
 
-      case GL_ALPHA_SNORM:
-         return GL_ALPHA8_SNORM;
+   /* GL_ARB_texture_rg */
+   case GL_RED:
+      return GL_R8;
+   case GL_RG:
+      return GL_RG8;
 
-      case GL_INTENSITY_SNORM:
-         return GL_INTENSITY8_SNORM;
+   /* GL_EXT_texture_sRGB */
+   case GL_SRGB:
+      return GL_SRGB8;
+   case GL_SRGB_ALPHA:
+      return GL_SRGB8_ALPHA8;
+   case GL_SLUMINANCE:
+      return GL_SLUMINANCE8;
+   case GL_SLUMINANCE_ALPHA:
+      return GL_SLUMINANCE8_ALPHA8;
+
+   /* GL_EXT_texture_snorm */
+   case GL_RGBA_SNORM:
+      return GL_RGBA8_SNORM;
+   case GL_RGB_SNORM:
+      return GL_RGB8_SNORM;
+   case GL_RG_SNORM:
+      return GL_RG8_SNORM;
+   case GL_RED_SNORM:
+      return GL_R8_SNORM;
+   case GL_LUMINANCE_ALPHA_SNORM:
+      return GL_LUMINANCE8_ALPHA8_SNORM;
+   case GL_LUMINANCE_SNORM:
+      return GL_LUMINANCE8_SNORM;
+   case GL_ALPHA_SNORM:
+      return GL_ALPHA8_SNORM;
+   case GL_INTENSITY_SNORM:
+      return GL_INTENSITY8_SNORM;
 
-      default:
-         return format;
+   default:
+      return format;
    }
 }
 
@@ -1219,22 +1203,20 @@ _mesa_get_linear_internalformat(GLenum format)
    switch (format) {
    case GL_SRGB:
       return GL_RGB;
-
    case GL_SRGB_ALPHA:
       return GL_RGBA;
-
    case GL_SRGB8:
       return GL_RGB8;
-
    case GL_SRGB8_ALPHA8:
       return GL_RGBA8;
-
-   case GL_SLUMINANCE:
+   case GL_SLUMINANCE8:
       return GL_LUMINANCE8;
-
+   case GL_SLUMINANCE:
+      return GL_LUMINANCE;
    case GL_SLUMINANCE_ALPHA:
+      return GL_LUMINANCE_ALPHA;
+   case GL_SLUMINANCE8_ALPHA8:
       return GL_LUMINANCE8_ALPHA8;
-
    default:
       return format;
    }
diff --git a/mesalib/src/mesa/main/macros.h b/mesalib/src/mesa/main/macros.h
index 379f75663..dafeaa372 100644
--- a/mesalib/src/mesa/main/macros.h
+++ b/mesalib/src/mesa/main/macros.h
@@ -809,5 +809,7 @@ DIFFERENT_SIGNS(GLfloat x, GLfloat y)
 /* Compute the size of an array */
 #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
 
+/* Stringify */
+#define STRINGIFY(x) #x
 
 #endif
diff --git a/mesalib/src/mesa/main/mtypes.h b/mesalib/src/mesa/main/mtypes.h
index 33df682cf..9ab2de026 100644
--- a/mesalib/src/mesa/main/mtypes.h
+++ b/mesalib/src/mesa/main/mtypes.h
@@ -235,6 +235,7 @@ typedef enum
    VARYING_SLOT_CLIP_DIST1,
    VARYING_SLOT_PRIMITIVE_ID, /* Does not appear in VS */
    VARYING_SLOT_LAYER, /* Appears as VS or GS output */
+   VARYING_SLOT_VIEWPORT, /* Appears as VS or GS output */
    VARYING_SLOT_FACE, /* FS only */
    VARYING_SLOT_PNTC, /* FS only */
    VARYING_SLOT_VAR0, /* First generic varying slot */
@@ -270,6 +271,7 @@ typedef enum
 #define VARYING_BIT_CLIP_DIST1 BITFIELD64_BIT(VARYING_SLOT_CLIP_DIST1)
 #define VARYING_BIT_PRIMITIVE_ID BITFIELD64_BIT(VARYING_SLOT_PRIMITIVE_ID)
 #define VARYING_BIT_LAYER BITFIELD64_BIT(VARYING_SLOT_LAYER)
+#define VARYING_BIT_VIEWPORT BITFIELD64_BIT(VARYING_SLOT_VIEWPORT)
 #define VARYING_BIT_FACE BITFIELD64_BIT(VARYING_SLOT_FACE)
 #define VARYING_BIT_PNTC BITFIELD64_BIT(VARYING_SLOT_PNTC)
 #define VARYING_BIT_VAR(V) BITFIELD64_BIT(VARYING_SLOT_VAR0 + (V))
@@ -1009,12 +1011,16 @@ struct gl_polygon_attrib
 /**
  * Scissor attributes (GL_SCISSOR_BIT).
  */
-struct gl_scissor_attrib
+struct gl_scissor_rect
 {
-   GLboolean Enabled;		/**< Scissor test enabled? */
    GLint X, Y;			/**< Lower left corner of box */
    GLsizei Width, Height;	/**< Size of box */
 };
+struct gl_scissor_attrib
+{
+   GLbitfield EnableFlags;	/**< Scissor test enabled? */
+   struct gl_scissor_rect ScissorArray[MAX_VIEWPORTS];
+};
 
 
 /**
@@ -1428,9 +1434,9 @@ struct gl_transform_attrib
  */
 struct gl_viewport_attrib
 {
-   GLint X, Y;			/**< position */
-   GLsizei Width, Height;	/**< size */
-   GLfloat Near, Far;		/**< Depth buffer range */
+   GLfloat X, Y;		/**< position */
+   GLfloat Width, Height;	/**< size */
+   GLdouble Near, Far;		/**< Depth buffer range */
    GLmatrix _WindowMap;		/**< Mapping transformation as a matrix. */
 };
 
@@ -1809,7 +1815,9 @@ struct gl_transform_feedback_object
 
    /**
     * The shader program active when BeginTransformFeedback() was called.
-    * When active and unpaused, this equals ctx->Shader.CurrentVertexProgram.
+    * When active and unpaused, this equals ctx->Shader.CurrentProgram[stage],
+    * where stage is the pipeline stage that is the source of data for
+    * transform feedback.
     */
    struct gl_shader_program *shader_program;
 
@@ -2708,9 +2716,7 @@ struct gl_shader_state
     * GL_EXT_separate_shader_objects is not supported, each of these must point
     * to \c NULL or to the same program.
     */
-   struct gl_shader_program *CurrentVertexProgram;
-   struct gl_shader_program *CurrentGeometryProgram;
-   struct gl_shader_program *CurrentFragmentProgram;
+   struct gl_shader_program *CurrentProgram[MESA_SHADER_STAGES];
 
    struct gl_shader_program *_CurrentFragmentProgram;
 
@@ -2754,10 +2760,13 @@ struct gl_shader_compiler_options
    GLuint MaxUnrollIterations;
 
    /**
-    * Prefer DP4 instructions (rather than MUL/MAD) for matrix * vector
-    * operations, such as position transformation.
+    * Optimize code for array of structures backends.
+    *
+    * This is a proxy for:
+    *   - preferring DP4 instructions (rather than MUL/MAD) for
+    *     matrix * vector operations, such as position transformation.
     */
-   GLboolean PreferDP4;
+   GLboolean OptimizeForAOS;
 
    struct gl_sl_pragmas DefaultPragmas; /**< Default #pragma settings */
 };
@@ -3166,6 +3175,12 @@ struct gl_constants
    GLfloat MaxSpotExponent;                  /**< GL_NV_light_max_exponent */
 
    GLuint MaxViewportWidth, MaxViewportHeight;
+   GLuint MaxViewports;                      /**< GL_ARB_viewport_array */
+   GLuint ViewportSubpixelBits;              /**< GL_ARB_viewport_array */
+   struct {
+      GLfloat Min;
+      GLfloat Max;
+   } ViewportBounds;                         /**< GL_ARB_viewport_array */
 
    struct gl_program_constants Program[MESA_SHADER_STAGES];
    GLuint MaxProgramMatrices;
@@ -3366,6 +3381,7 @@ struct gl_extensions
    GLboolean ANGLE_texture_compression_dxt;
    GLboolean ARB_ES2_compatibility;
    GLboolean ARB_ES3_compatibility;
+   GLboolean ARB_arrays_of_arrays;
    GLboolean ARB_base_instance;
    GLboolean ARB_blend_func_extended;
    GLboolean ARB_color_buffer_float;
@@ -3434,6 +3450,7 @@ struct gl_extensions
    GLboolean ARB_vertex_shader;
    GLboolean ARB_vertex_type_10f_11f_11f_rev;
    GLboolean ARB_vertex_type_2_10_10_10_rev;
+   GLboolean ARB_viewport_array;
    GLboolean EXT_blend_color;
    GLboolean EXT_blend_equation_separate;
    GLboolean EXT_blend_func_separate;
@@ -3764,6 +3781,9 @@ struct gl_driver_flags
    /** gl_context::TransformFeedback::CurrentObject */
    GLbitfield NewTransformFeedback;
 
+   /** gl_context::TransformFeedback::CurrentObject::shader_program */
+   GLbitfield NewTransformFeedbackProg;
+
    /** gl_context::RasterDiscard */
    GLbitfield NewRasterizerDiscard;
 
@@ -3972,7 +3992,7 @@ struct gl_context
    struct gl_stencil_attrib	Stencil;	/**< Stencil buffer attributes */
    struct gl_texture_attrib	Texture;	/**< Texture attributes */
    struct gl_transform_attrib	Transform;	/**< Transformation attributes */
-   struct gl_viewport_attrib	Viewport;	/**< Viewport attributes */
+   struct gl_viewport_attrib	ViewportArray[MAX_VIEWPORTS];	/**< Viewport attributes */
    /*@}*/
 
    /** \name Client attribute stack */
diff --git a/mesalib/src/mesa/main/rastpos.c b/mesalib/src/mesa/main/rastpos.c
index 1acdb8b53..a9a6ceec0 100644
--- a/mesalib/src/mesa/main/rastpos.c
+++ b/mesalib/src/mesa/main/rastpos.c
@@ -227,8 +227,9 @@ window_pos3f(GLfloat x, GLfloat y, GLfloat z)
    FLUSH_VERTICES(ctx, 0);
    FLUSH_CURRENT(ctx, 0);
 
-   z2 = CLAMP(z, 0.0F, 1.0F) * (ctx->Viewport.Far - ctx->Viewport.Near)
-      + ctx->Viewport.Near;
+   z2 = CLAMP(z, 0.0F, 1.0F)
+      * (ctx->ViewportArray[0].Far - ctx->ViewportArray[0].Near)
+      + ctx->ViewportArray[0].Near;
 
    /* set raster position */
    ctx->Current.RasterPos[0] = x;
diff --git a/mesalib/src/mesa/main/scissor.c b/mesalib/src/mesa/main/scissor.c
index ac86bd591..14c8e8a6c 100644
--- a/mesalib/src/mesa/main/scissor.c
+++ b/mesalib/src/mesa/main/scissor.c
@@ -29,12 +29,38 @@
 #include "main/scissor.h"
 
 
+/**
+ * Set scissor rectangle data directly in ScissorArray
+ *
+ * This is an internal function that performs no error checking on the
+ * supplied data.  It also does \b not call \c dd_function_table::Scissor.
+ *
+ * \sa _mesa_set_scissor
+ */
+static void
+set_scissor_no_notify(struct gl_context *ctx, unsigned idx,
+                      GLint x, GLint y, GLsizei width, GLsizei height)
+{
+   if (x == ctx->Scissor.ScissorArray[idx].X &&
+       y == ctx->Scissor.ScissorArray[idx].Y &&
+       width == ctx->Scissor.ScissorArray[idx].Width &&
+       height == ctx->Scissor.ScissorArray[idx].Height)
+      return;
+
+   FLUSH_VERTICES(ctx, _NEW_SCISSOR);
+   ctx->Scissor.ScissorArray[idx].X = x;
+   ctx->Scissor.ScissorArray[idx].Y = y;
+   ctx->Scissor.ScissorArray[idx].Width = width;
+   ctx->Scissor.ScissorArray[idx].Height = height;
+}
+
 /**
  * Called via glScissor
  */
 void GLAPIENTRY
 _mesa_Scissor( GLint x, GLint y, GLsizei width, GLsizei height )
 {
+   unsigned i;
    GET_CURRENT_CONTEXT(ctx);
 
    if (MESA_VERBOSE & VERBOSE_API)
@@ -45,7 +71,23 @@ _mesa_Scissor( GLint x, GLint y, GLsizei width, GLsizei height )
       return;
    }
 
-   _mesa_set_scissor(ctx, x, y, width, height);
+   /* The GL_ARB_viewport_array spec says:
+    *
+    *     "Scissor sets the scissor rectangle for all viewports to the same
+    *     values and is equivalent (assuming no errors are generated) to:
+    *
+    *     for (uint i = 0; i < MAX_VIEWPORTS; i++) {
+    *         ScissorIndexed(i, left, bottom, width, height);
+    *     }"
+    *
+    * Set the scissor rectangle for all of the viewports supported by the
+    * implementation, but only signal the driver once at the end.
+    */
+   for (i = 0; i < ctx->Const.MaxViewports; i++)
+      set_scissor_no_notify(ctx, i, x, y, width, height);
+
+   if (ctx->Driver.Scissor)
+      ctx->Driver.Scissor(ctx);
 }
 
 
@@ -63,25 +105,108 @@ _mesa_Scissor( GLint x, GLint y, GLsizei width, GLsizei height )
  * the dd_function_table::Scissor callback.
  */
 void
-_mesa_set_scissor(struct gl_context *ctx, 
+_mesa_set_scissor(struct gl_context *ctx, unsigned idx,
                   GLint x, GLint y, GLsizei width, GLsizei height)
 {
-   if (x == ctx->Scissor.X &&
-       y == ctx->Scissor.Y &&
-       width == ctx->Scissor.Width &&
-       height == ctx->Scissor.Height)
+   set_scissor_no_notify(ctx, idx, x, y, width, height);
+
+   if (ctx->Driver.Scissor)
+      ctx->Driver.Scissor(ctx);
+}
+
+/**
+ * Define count scissor boxes starting at index.
+ *
+ * \param index  index of first scissor records to set
+ * \param count  number of scissor records to set
+ * \param x, y   pointer to array of struct gl_scissor_rects
+ *
+ * \sa glScissorArrayv().
+ *
+ * Verifies the parameters and call set_scissor_no_notify to do the work.
+ */
+void GLAPIENTRY
+_mesa_ScissorArrayv(GLuint first, GLsizei count, const GLint *v)
+{
+   int i;
+   struct gl_scissor_rect *p = (struct gl_scissor_rect *) v;
+   GET_CURRENT_CONTEXT(ctx);
+
+   if ((first + count) > ctx->Const.MaxViewports) {
+      _mesa_error(ctx, GL_INVALID_VALUE,
+                  "glScissorArrayv: first (%d) + count (%d) >= MaxViewports (%d)",
+                  first, count, ctx->Const.MaxViewports);
       return;
+   }
 
-   FLUSH_VERTICES(ctx, _NEW_SCISSOR);
-   ctx->Scissor.X = x;
-   ctx->Scissor.Y = y;
-   ctx->Scissor.Width = width;
-   ctx->Scissor.Height = height;
+   /* Verify width & height */
+   for (i = 0; i < count; i++) {
+      if (p[i].Width < 0 || p[i].Height < 0) {
+         _mesa_error(ctx, GL_INVALID_VALUE,
+                     "glScissorArrayv: index (%d) width or height < 0 (%d, %d)",
+                     i, p[i].Width, p[i].Height);
+      }
+   }
+
+   for (i = 0; i < count; i++)
+      set_scissor_no_notify(ctx, i + first,
+                            p[i].X, p[i].Y, p[i].Width, p[i].Height);
 
    if (ctx->Driver.Scissor)
       ctx->Driver.Scissor(ctx);
 }
 
+/**
+ * Define the scissor box.
+ *
+ * \param index  index of scissor records to set
+ * \param x, y   coordinates of the scissor box lower-left corner.
+ * \param width  width of the scissor box.
+ * \param height height of the scissor box.
+ *
+ * Verifies the parameters call set_scissor_no_notify to do the work.
+ */
+static void
+ScissorIndexed(GLuint index, GLint left, GLint bottom,
+               GLsizei width, GLsizei height, const char *function)
+{
+   GET_CURRENT_CONTEXT(ctx);
+
+   if (MESA_VERBOSE & VERBOSE_API)
+      _mesa_debug(ctx, "%s(%d, %d, %d, %d, %d)\n",
+                  function, index, left, bottom, width, height);
+
+   if (index >= ctx->Const.MaxViewports) {
+      _mesa_error(ctx, GL_INVALID_VALUE,
+                  "%s: index (%d) >= MaxViewports (%d)",
+                  function, index, ctx->Const.MaxViewports);
+      return;
+   }
+
+   if (width < 0 || height < 0) {
+      _mesa_error(ctx, GL_INVALID_VALUE,
+                  "%s: index (%d) width or height < 0 (%d, %d)",
+                  function, index, width, height);
+   }
+
+   set_scissor_no_notify(ctx, index, left, bottom, width, height);
+
+   if (ctx->Driver.Scissor)
+      ctx->Driver.Scissor(ctx);
+}
+
+void GLAPIENTRY
+_mesa_ScissorIndexed(GLuint index, GLint left, GLint bottom,
+                     GLsizei width, GLsizei height)
+{
+   ScissorIndexed(index, left, bottom, width, height, "glScissorIndexd");
+}
+
+void GLAPIENTRY
+_mesa_ScissorIndexedv(GLuint index, const GLint *v)
+{
+   ScissorIndexed(index, v[0], v[1], v[2], v[3], "glScissorIndexdv");
+}
 
 /**
  * Initialize the context's scissor state.
@@ -90,10 +215,14 @@ _mesa_set_scissor(struct gl_context *ctx,
 void
 _mesa_init_scissor(struct gl_context *ctx)
 {
+   unsigned i;
+
    /* Scissor group */
-   ctx->Scissor.Enabled = GL_FALSE;
-   ctx->Scissor.X = 0;
-   ctx->Scissor.Y = 0;
-   ctx->Scissor.Width = 0;
-   ctx->Scissor.Height = 0;
+   ctx->Scissor.EnableFlags = 0;
+
+   /* Note: ctx->Const.MaxViewports may not have been set by the driver yet,
+    * so just initialize all of them.
+    */
+   for (i = 0; i < MAX_VIEWPORTS; i++)
+      set_scissor_no_notify(ctx, i, 0, 0, 0, 0);
 }
diff --git a/mesalib/src/mesa/main/scissor.h b/mesalib/src/mesa/main/scissor.h
index 0d7e2010a..5f9a9945a 100644
--- a/mesalib/src/mesa/main/scissor.h
+++ b/mesalib/src/mesa/main/scissor.h
@@ -34,9 +34,17 @@ struct gl_context;
 extern void GLAPIENTRY
 _mesa_Scissor( GLint x, GLint y, GLsizei width, GLsizei height );
 
+extern void GLAPIENTRY
+_mesa_ScissorArrayv(GLuint first, GLsizei count, const GLint * v);
+
+extern void GLAPIENTRY
+_mesa_ScissorIndexed(GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height);
+
+extern void GLAPIENTRY
+_mesa_ScissorIndexedv(GLuint index, const GLint * v);
 
 extern void
-_mesa_set_scissor(struct gl_context *ctx, 
+_mesa_set_scissor(struct gl_context *ctx, unsigned idx,
                   GLint x, GLint y, GLsizei width, GLsizei height);
 
 
diff --git a/mesalib/src/mesa/main/shaderapi.c b/mesalib/src/mesa/main/shaderapi.c
index 6042fa896..61ac0e35a 100644
--- a/mesalib/src/mesa/main/shaderapi.c
+++ b/mesalib/src/mesa/main/shaderapi.c
@@ -130,11 +130,11 @@ _mesa_init_shader_state(struct gl_context *ctx)
 void
 _mesa_free_shader_state(struct gl_context *ctx)
 {
-   _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentVertexProgram, NULL);
-   _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentGeometryProgram,
-				  NULL);
-   _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentFragmentProgram,
-				  NULL);
+   int i;
+   for (i = 0; i < MESA_SHADER_STAGES; i++) {
+      _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentProgram[i],
+                                     NULL);
+   }
    _mesa_reference_shader_program(ctx, &ctx->Shader._CurrentFragmentProgram,
 				  NULL);
    _mesa_reference_shader_program(ctx, &ctx->Shader.ActiveProgram, NULL);
@@ -171,16 +171,23 @@ _mesa_copy_string(GLchar *dst, GLsizei maxLength,
  * \param type  Shader target
  *
  */
-static bool
-validate_shader_target(const struct gl_context *ctx, GLenum type)
-{
+bool
+_mesa_validate_shader_target(const struct gl_context *ctx, GLenum type)
+{
+   /* Note: when building built-in GLSL functions, this function may be
+    * invoked with ctx == NULL.  In that case, we can only validate that it's
+    * a shader target we recognize, not that it's supported in the current
+    * context.  But that's fine--we don't need any further validation than
+    * that when building built-in GLSL functions.
+    */
+
    switch (type) {
    case GL_FRAGMENT_SHADER:
-      return ctx->Extensions.ARB_fragment_shader;
+      return ctx == NULL || ctx->Extensions.ARB_fragment_shader;
    case GL_VERTEX_SHADER:
-      return ctx->Extensions.ARB_vertex_shader;
+      return ctx == NULL || ctx->Extensions.ARB_vertex_shader;
    case GL_GEOMETRY_SHADER_ARB:
-      return _mesa_has_geometry_shaders(ctx);
+      return ctx == NULL || _mesa_has_geometry_shaders(ctx);
    default:
       return false;
    }
@@ -273,7 +280,7 @@ create_shader(struct gl_context *ctx, GLenum type)
    struct gl_shader *sh;
    GLuint name;
 
-   if (!validate_shader_target(ctx, type)) {
+   if (!_mesa_validate_shader_target(ctx, type)) {
       _mesa_error(ctx, GL_INVALID_ENUM, "CreateShader(type)");
       return 0;
    }
@@ -939,32 +946,11 @@ use_shader_program(struct gl_context *ctx, GLenum type,
 		   struct gl_shader_program *shProg)
 {
    struct gl_shader_program **target;
+   gl_shader_stage stage = _mesa_shader_enum_to_shader_stage(type);
 
-   switch (type) {
-   case GL_VERTEX_SHADER:
-      target = &ctx->Shader.CurrentVertexProgram;
-      if ((shProg == NULL)
-	  || (shProg->_LinkedShaders[MESA_SHADER_VERTEX] == NULL)) {
-	 shProg = NULL;
-      }
-      break;
-   case GL_GEOMETRY_SHADER_ARB:
-      target = &ctx->Shader.CurrentGeometryProgram;
-      if ((shProg == NULL)
-	  || (shProg->_LinkedShaders[MESA_SHADER_GEOMETRY] == NULL)) {
-	 shProg = NULL;
-      }
-      break;
-   case GL_FRAGMENT_SHADER:
-      target = &ctx->Shader.CurrentFragmentProgram;
-      if ((shProg == NULL)
-	  || (shProg->_LinkedShaders[MESA_SHADER_FRAGMENT] == NULL)) {
-	 shProg = NULL;
-      }
-      break;
-   default:
-      return;
-   }
+   target = &ctx->Shader.CurrentProgram[stage];
+   if ((shProg == NULL) || (shProg->_LinkedShaders[stage] == NULL))
+      shProg = NULL;
 
    if (*target != shProg) {
       FLUSH_VERTICES(ctx, _NEW_PROGRAM | _NEW_PROGRAM_CONSTANTS);
@@ -1739,7 +1725,7 @@ _mesa_UseShaderProgramEXT(GLenum type, GLuint program)
    GET_CURRENT_CONTEXT(ctx);
    struct gl_shader_program *shProg = NULL;
 
-   if (!validate_shader_target(ctx, type)) {
+   if (!_mesa_validate_shader_target(ctx, type)) {
       _mesa_error(ctx, GL_INVALID_ENUM, "glUseShaderProgramEXT(type)");
       return;
    }
diff --git a/mesalib/src/mesa/main/shaderapi.h b/mesalib/src/mesa/main/shaderapi.h
index 4822e32c2..10f810caf 100644
--- a/mesalib/src/mesa/main/shaderapi.h
+++ b/mesalib/src/mesa/main/shaderapi.h
@@ -215,6 +215,9 @@ _mesa_copy_linked_program_data(gl_shader_stage type,
                                const struct gl_shader_program *src,
                                struct gl_program *dst);
 
+extern bool
+_mesa_validate_shader_target(const struct gl_context *ctx, GLenum type);
+
 
 #ifdef __cplusplus
 }
diff --git a/mesalib/src/mesa/main/shaderobj.c b/mesalib/src/mesa/main/shaderobj.c
index dc81bbc77..4f4bb69a8 100644
--- a/mesalib/src/mesa/main/shaderobj.c
+++ b/mesalib/src/mesa/main/shaderobj.c
@@ -34,6 +34,7 @@
 #include "main/context.h"
 #include "main/hash.h"
 #include "main/mtypes.h"
+#include "main/shaderapi.h"
 #include "main/shaderobj.h"
 #include "main/uniforms.h"
 #include "program/program.h"
@@ -105,8 +106,7 @@ struct gl_shader *
 _mesa_new_shader(struct gl_context *ctx, GLuint name, GLenum type)
 {
    struct gl_shader *shader;
-   assert(type == GL_FRAGMENT_SHADER || type == GL_VERTEX_SHADER ||
-          type == GL_GEOMETRY_SHADER_ARB);
+   assert(_mesa_validate_shader_target(ctx, type));
    shader = rzalloc(NULL, struct gl_shader);
    if (shader) {
       shader->Type = type;
diff --git a/mesalib/src/mesa/main/shared.c b/mesalib/src/mesa/main/shared.c
index 2f73cf3ca..c11c7f9e9 100644
--- a/mesalib/src/mesa/main/shared.c
+++ b/mesalib/src/mesa/main/shared.c
@@ -38,6 +38,7 @@
 #include "dlist.h"
 #include "samplerobj.h"
 #include "set.h"
+#include "shaderapi.h"
 #include "shaderobj.h"
 #include "syncobj.h"
 
@@ -218,8 +219,7 @@ delete_shader_cb(GLuint id, void *data, void *userData)
 {
    struct gl_context *ctx = (struct gl_context *) userData;
    struct gl_shader *sh = (struct gl_shader *) data;
-   if (sh->Type == GL_FRAGMENT_SHADER || sh->Type == GL_VERTEX_SHADER ||
-       sh->Type == GL_GEOMETRY_SHADER) {
+   if (_mesa_validate_shader_target(ctx, sh->Type)) {
       ctx->Driver.DeleteShader(ctx, sh);
    }
    else {
diff --git a/mesalib/src/mesa/main/state.c b/mesalib/src/mesa/main/state.c
index 33070b7e0..bdebbc141 100644
--- a/mesalib/src/mesa/main/state.c
+++ b/mesalib/src/mesa/main/state.c
@@ -94,9 +94,12 @@ update_program_enables(struct gl_context *ctx)
 static GLbitfield
 update_program(struct gl_context *ctx)
 {
-   const struct gl_shader_program *vsProg = ctx->Shader.CurrentVertexProgram;
-   const struct gl_shader_program *gsProg = ctx->Shader.CurrentGeometryProgram;
-   struct gl_shader_program *fsProg = ctx->Shader.CurrentFragmentProgram;
+   const struct gl_shader_program *vsProg =
+      ctx->Shader.CurrentProgram[MESA_SHADER_VERTEX];
+   const struct gl_shader_program *gsProg =
+      ctx->Shader.CurrentProgram[MESA_SHADER_GEOMETRY];
+   struct gl_shader_program *fsProg =
+      ctx->Shader.CurrentProgram[MESA_SHADER_FRAGMENT];
    const struct gl_vertex_program *prevVP = ctx->VertexProgram._Current;
    const struct gl_fragment_program *prevFP = ctx->FragmentProgram._Current;
    const struct gl_geometry_program *prevGP = ctx->GeometryProgram._Current;
@@ -269,6 +272,7 @@ static void
 update_viewport_matrix(struct gl_context *ctx)
 {
    const GLfloat depthMax = ctx->DrawBuffer->_DepthMaxF;
+   unsigned i;
 
    ASSERT(depthMax > 0);
 
@@ -276,11 +280,13 @@ update_viewport_matrix(struct gl_context *ctx)
     * and should be maintained elsewhere if at all.
     * NOTE: RasterPos uses this.
     */
-   _math_matrix_viewport(&ctx->Viewport._WindowMap,
-                         ctx->Viewport.X, ctx->Viewport.Y,
-                         ctx->Viewport.Width, ctx->Viewport.Height,
-                         ctx->Viewport.Near, ctx->Viewport.Far,
-                         depthMax);
+   for (i = 0; i < ctx->Const.MaxViewports; i++) {
+      _math_matrix_viewport(&ctx->ViewportArray[i]._WindowMap,
+                            ctx->ViewportArray[i].X, ctx->ViewportArray[i].Y,
+                            ctx->ViewportArray[i].Width, ctx->ViewportArray[i].Height,
+                            ctx->ViewportArray[i].Near, ctx->ViewportArray[i].Far,
+                            depthMax);
+   }
 }
 
 
@@ -304,7 +310,7 @@ update_multisample(struct gl_context *ctx)
 static void
 update_twoside(struct gl_context *ctx)
 {
-   if (ctx->Shader.CurrentVertexProgram ||
+   if (ctx->Shader.CurrentProgram[MESA_SHADER_VERTEX] ||
        ctx->VertexProgram._Enabled) {
       ctx->VertexProgram._TwoSideEnabled = ctx->VertexProgram.TwoSideEnabled;
    } else {
diff --git a/mesalib/src/mesa/main/texobj.c b/mesalib/src/mesa/main/texobj.c
index 3c64c4376..5d516c55f 100644
--- a/mesalib/src/mesa/main/texobj.c
+++ b/mesalib/src/mesa/main/texobj.c
@@ -1104,10 +1104,10 @@ unbind_texobj_from_texunits(struct gl_context *ctx,
  * and unbind it if that's the case.
  */
 static void
-unbind_texobj_from_imgunits(struct gl_context *ctx,
-                            struct gl_texture_object *texObj)
+unbind_texobj_from_image_units(struct gl_context *ctx,
+                               struct gl_texture_object *texObj)
 {
-   int i;
+   GLuint i;
 
    for (i = 0; i < ctx->Const.MaxImageUnits; i++) {
       struct gl_image_unit *unit = &ctx->ImageUnits[i];
@@ -1169,7 +1169,7 @@ _mesa_DeleteTextures( GLsizei n, const GLuint *textures)
              * image unit.  If so, unbind it.
              * See section 3.9.X of GL_ARB_shader_image_load_store.
              */
-            unbind_texobj_from_imgunits(ctx, delObj);
+            unbind_texobj_from_image_units(ctx, delObj);
 
             _mesa_unlock_texture(ctx, delObj);
 
diff --git a/mesalib/src/mesa/main/texstate.c b/mesalib/src/mesa/main/texstate.c
index 7720965a8..08725f601 100644
--- a/mesalib/src/mesa/main/texstate.c
+++ b/mesalib/src/mesa/main/texstate.c
@@ -527,27 +527,20 @@ static void
 update_texture_state( struct gl_context *ctx )
 {
    GLuint unit;
-   struct gl_program *fprog = NULL;
-   struct gl_program *vprog = NULL;
-   struct gl_program *gprog = NULL;
+   struct gl_program *prog[MESA_SHADER_STAGES];
    GLbitfield enabledFragUnits = 0x0;
-
-   if (ctx->Shader.CurrentVertexProgram &&
-       ctx->Shader.CurrentVertexProgram->LinkStatus) {
-      vprog = ctx->Shader.CurrentVertexProgram->_LinkedShaders[MESA_SHADER_VERTEX]->Program;
-   }
-
-   if (ctx->Shader.CurrentGeometryProgram &&
-       ctx->Shader.CurrentGeometryProgram->LinkStatus) {
-      gprog = ctx->Shader.CurrentGeometryProgram->_LinkedShaders[MESA_SHADER_GEOMETRY]->Program;
-   }
-
-   if (ctx->Shader.CurrentFragmentProgram &&
-       ctx->Shader.CurrentFragmentProgram->LinkStatus) {
-      fprog = ctx->Shader.CurrentFragmentProgram->_LinkedShaders[MESA_SHADER_FRAGMENT]->Program;
-   }
-   else if (ctx->FragmentProgram._Enabled) {
-      fprog = &ctx->FragmentProgram.Current->Base;
+   int i;
+
+   for (i = 0; i < MESA_SHADER_STAGES; i++) {
+      if (ctx->Shader.CurrentProgram[i] &&
+          ctx->Shader.CurrentProgram[i]->LinkStatus) {
+         prog[i] = ctx->Shader.CurrentProgram[i]->_LinkedShaders[i]->Program;
+      } else {
+         if (i == MESA_SHADER_FRAGMENT && ctx->FragmentProgram._Enabled)
+            prog[i] = &ctx->FragmentProgram.Current->Base;
+         else
+            prog[i] = NULL;
+      }
    }
 
    /* TODO: only set this if there are actual changes */
@@ -563,9 +556,7 @@ update_texture_state( struct gl_context *ctx )
     */
    for (unit = 0; unit < ctx->Const.MaxCombinedTextureImageUnits; unit++) {
       struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
-      GLbitfield enabledVertTargets = 0x0;
-      GLbitfield enabledFragTargets = 0x0;
-      GLbitfield enabledGeomTargets = 0x0;
+      GLbitfield enabledTargetsByStage[MESA_SHADER_STAGES];
       GLbitfield enabledTargets = 0x0;
       GLuint texIndex;
 
@@ -575,25 +566,16 @@ update_texture_state( struct gl_context *ctx )
        * by a fragment program/program.  When multiple flags are set, we'll
        * settle on the one with highest priority (see below).
        */
-      if (vprog) {
-         enabledVertTargets |= vprog->TexturesUsed[unit];
+      for (i = 0; i < MESA_SHADER_STAGES; i++) {
+         if (prog[i])
+            enabledTargetsByStage[i] = prog[i]->TexturesUsed[unit];
+         else if (i == MESA_SHADER_FRAGMENT)
+            enabledTargetsByStage[i] = texUnit->Enabled;
+         else
+            enabledTargetsByStage[i] = 0;
+         enabledTargets |= enabledTargetsByStage[i];
       }
 
-      if (gprog) {
-         enabledGeomTargets |= gprog->TexturesUsed[unit];
-      }
-
-      if (fprog) {
-         enabledFragTargets |= fprog->TexturesUsed[unit];
-      }
-      else {
-         /* fixed-function fragment program */
-         enabledFragTargets |= texUnit->Enabled;
-      }
-
-      enabledTargets = enabledVertTargets | enabledFragTargets |
-                       enabledGeomTargets;
-
       texUnit->_ReallyEnabled = 0x0;
 
       if (enabledTargets == 0x0) {
@@ -625,7 +607,7 @@ update_texture_state( struct gl_context *ctx )
       }
 
       if (!texUnit->_ReallyEnabled) {
-         if (fprog) {
+         if (prog[MESA_SHADER_FRAGMENT]) {
             /* If we get here it means the shader is expecting a texture
              * object, but there isn't one (or it's incomplete).  Use the
              * fallback texture.
@@ -655,25 +637,26 @@ update_texture_state( struct gl_context *ctx )
 
       ctx->Texture._EnabledUnits |= (1 << unit);
 
-      if (enabledFragTargets)
+      if (enabledTargetsByStage[MESA_SHADER_FRAGMENT])
          enabledFragUnits |= (1 << unit);
 
-      if (!fprog)
+      if (!prog[MESA_SHADER_FRAGMENT])
          update_tex_combine(ctx, texUnit);
    }
 
 
    /* Determine which texture coordinate sets are actually needed */
-   if (fprog) {
+   if (prog[MESA_SHADER_FRAGMENT]) {
       const GLuint coordMask = (1 << MAX_TEXTURE_COORD_UNITS) - 1;
       ctx->Texture._EnabledCoordUnits
-         = (fprog->InputsRead >> VARYING_SLOT_TEX0) & coordMask;
+         = (prog[MESA_SHADER_FRAGMENT]->InputsRead >> VARYING_SLOT_TEX0) &
+         coordMask;
    }
    else {
       ctx->Texture._EnabledCoordUnits = enabledFragUnits;
    }
 
-   if (!fprog || !vprog)
+   if (!prog[MESA_SHADER_FRAGMENT] || !prog[MESA_SHADER_VERTEX])
       update_texgen(ctx);
 
    _mesa_validate_image_units(ctx);
diff --git a/mesalib/src/mesa/main/texstorage.c b/mesalib/src/mesa/main/texstorage.c
index 5062fdb4f..22208572f 100644
--- a/mesalib/src/mesa/main/texstorage.c
+++ b/mesalib/src/mesa/main/texstorage.c
@@ -244,6 +244,10 @@ _mesa_alloc_texture_storage(struct gl_context *ctx,
    int face;
    int level;
 
+   (void) width;
+   (void) height;
+   (void) depth;
+
    for (face = 0; face < numFaces; face++) {
       for (level = 0; level < levels; level++) {
          struct gl_texture_image *const texImage = texObj->Image[face][level];
@@ -460,7 +464,16 @@ _mesa_TextureStorage1DEXT(GLuint texture, GLenum target, GLsizei levels,
                           GLenum internalformat,
                           GLsizei width)
 {
-   /* no-op */
+   GET_CURRENT_CONTEXT(ctx);
+
+   (void) texture;
+   (void) target;
+   (void) levels;
+   (void) internalformat;
+   (void) width;
+
+   _mesa_error(ctx, GL_INVALID_OPERATION,
+               "glTextureStorage1DEXT not supported");
 }
 
 
@@ -469,7 +482,17 @@ _mesa_TextureStorage2DEXT(GLuint texture, GLenum target, GLsizei levels,
                           GLenum internalformat,
                           GLsizei width, GLsizei height)
 {
-   /* no-op */
+   GET_CURRENT_CONTEXT(ctx);
+
+   (void) texture;
+   (void) target;
+   (void) levels;
+   (void) internalformat;
+   (void) width;
+   (void) height;
+
+   _mesa_error(ctx, GL_INVALID_OPERATION,
+               "glTextureStorage2DEXT not supported");
 }
 
 
@@ -479,5 +502,16 @@ _mesa_TextureStorage3DEXT(GLuint texture, GLenum target, GLsizei levels,
                           GLenum internalformat,
                           GLsizei width, GLsizei height, GLsizei depth)
 {
-   /* no-op */
+   GET_CURRENT_CONTEXT(ctx);
+
+   (void) texture;
+   (void) target;
+   (void) levels;
+   (void) internalformat;
+   (void) width;
+   (void) height;
+   (void) depth;
+
+   _mesa_error(ctx, GL_INVALID_OPERATION,
+               "glTextureStorage3DEXT not supported");
 }
diff --git a/mesalib/src/mesa/main/transformfeedback.c b/mesalib/src/mesa/main/transformfeedback.c
index 76d213b16..6b9565ca3 100644
--- a/mesalib/src/mesa/main/transformfeedback.c
+++ b/mesalib/src/mesa/main/transformfeedback.c
@@ -24,7 +24,7 @@
 
 
 /*
- * Vertex transform feedback support.
+ * Transform feedback support.
  *
  * Authors:
  *   Brian Paul
@@ -376,24 +376,48 @@ _mesa_compute_max_transform_feedback_vertices(
  **/
 
 
+/**
+ * Figure out which stage of the pipeline is the source of transform feedback
+ * data given the current context state, and return its gl_shader_program.
+ *
+ * If no active program can generate transform feedback data (i.e. no vertex
+ * shader is active), returns NULL.
+ */
+static struct gl_shader_program *
+get_xfb_source(struct gl_context *ctx)
+{
+   int i;
+   for (i = MESA_SHADER_GEOMETRY; i >= MESA_SHADER_VERTEX; i--) {
+      if (ctx->Shader.CurrentProgram[i] != NULL)
+         return ctx->Shader.CurrentProgram[i];
+   }
+   return NULL;
+}
+
+
 void GLAPIENTRY
 _mesa_BeginTransformFeedback(GLenum mode)
 {
    struct gl_transform_feedback_object *obj;
-   struct gl_transform_feedback_info *info;
+   struct gl_transform_feedback_info *info = NULL;
+   struct gl_shader_program *source;
    GLuint i;
    unsigned vertices_per_prim;
    GET_CURRENT_CONTEXT(ctx);
 
    obj = ctx->TransformFeedback.CurrentObject;
 
-   if (ctx->Shader.CurrentVertexProgram == NULL) {
+   /* Figure out what pipeline stage is the source of data for transform
+    * feedback.
+    */
+   source = get_xfb_source(ctx);
+   if (source == NULL) {
       _mesa_error(ctx, GL_INVALID_OPERATION,
                   "glBeginTransformFeedback(no program active)");
       return;
    }
 
-   info = &ctx->Shader.CurrentVertexProgram->LinkedTransformFeedback;
+   info = &source->LinkedTransformFeedback;
 
    if (info->NumOutputs == 0) {
       _mesa_error(ctx, GL_INVALID_OPERATION,
@@ -451,7 +475,10 @@ _mesa_BeginTransformFeedback(GLenum mode)
       obj->GlesRemainingPrims = max_vertices / vertices_per_prim;
    }
 
-   obj->shader_program = ctx->Shader.CurrentVertexProgram;
+   if (obj->shader_program != source) {
+      ctx->NewDriverState |= ctx->DriverFlags.NewTransformFeedbackProg;
+      obj->shader_program = source;
+   }
 
    assert(ctx->Driver.BeginTransformFeedback);
    ctx->Driver.BeginTransformFeedback(ctx, mode, obj);
@@ -518,7 +545,7 @@ bind_buffer_range(struct gl_context *ctx, GLuint index,
 
 
 /**
- * Specify a buffer object to receive vertex shader results.  Plus,
+ * Specify a buffer object to receive transform feedback results.  Plus,
  * specify the starting offset to place the results, and max size.
  * Called from the glBindBufferRange() function.
  */
@@ -562,7 +589,7 @@ _mesa_bind_buffer_range_transform_feedback(struct gl_context *ctx,
 
 
 /**
- * Specify a buffer object to receive vertex shader results.
+ * Specify a buffer object to receive transform feedback results.
  * As above, but start at offset = 0.
  * Called from the glBindBufferBase() function.
  */
@@ -591,7 +618,7 @@ _mesa_bind_buffer_base_transform_feedback(struct gl_context *ctx,
 
 
 /**
- * Specify a buffer object to receive vertex shader results, plus the
+ * Specify a buffer object to receive transform feedback results, plus the
  * offset in the buffer to start placing results.
  * This function is part of GL_EXT_transform_feedback, but not GL3.
  */
@@ -646,7 +673,7 @@ _mesa_BindBufferOffsetEXT(GLenum target, GLuint index, GLuint buffer,
 
 
 /**
- * This function specifies the vertex shader outputs to be written
+ * This function specifies the transform feedback outputs to be written
  * to the feedback buffer(s), and in what order.
  */
 void GLAPIENTRY
@@ -756,7 +783,7 @@ _mesa_TransformFeedbackVaryings(GLuint program, GLsizei count,
 
 
 /**
- * Get info about the vertex shader's outputs which are to be written
+ * Get info about the transform feedback outputs which are to be written
  * to the feedback buffer(s).
  */
 void GLAPIENTRY
@@ -993,9 +1020,9 @@ _mesa_ResumeTransformFeedback(void)
     *  the program object being used by the current transform feedback object
     *  is not active."
     */
-   if (obj->shader_program != ctx->Shader.CurrentVertexProgram) {
+   if (obj->shader_program != get_xfb_source(ctx)) {
       _mesa_error(ctx, GL_INVALID_OPERATION,
-                  "glResumeTransformFeedback(wrong vertex program bound)");
+                  "glResumeTransformFeedback(wrong program bound)");
       return;
    }
 
diff --git a/mesalib/src/mesa/main/viewport.c b/mesalib/src/mesa/main/viewport.c
index 3aaab2d46..6545bf68a 100644
--- a/mesalib/src/mesa/main/viewport.c
+++ b/mesalib/src/mesa/main/viewport.c
@@ -34,6 +34,60 @@
 #include "mtypes.h"
 #include "viewport.h"
 
+static void
+set_viewport_no_notify(struct gl_context *ctx, unsigned idx,
+                       GLfloat x, GLfloat y,
+                       GLfloat width, GLfloat height)
+{
+   /* clamp width and height to the implementation dependent range */
+   width  = MIN2(width, (GLfloat) ctx->Const.MaxViewportWidth);
+   height = MIN2(height, (GLfloat) ctx->Const.MaxViewportHeight);
+
+   /* The GL_ARB_viewport_array spec says:
+    *
+    *     "The location of the viewport's bottom-left corner, given by (x,y),
+    *     are clamped to be within the implementation-dependent viewport
+    *     bounds range.  The viewport bounds range [min, max] tuple may be
+    *     determined by calling GetFloatv with the symbolic constant
+    *     VIEWPORT_BOUNDS_RANGE (see section 6.1)."
+    */
+   if (ctx->Extensions.ARB_viewport_array) {
+      x = CLAMP(x,
+                ctx->Const.ViewportBounds.Min, ctx->Const.ViewportBounds.Max);
+      y = CLAMP(y,
+                ctx->Const.ViewportBounds.Min, ctx->Const.ViewportBounds.Max);
+   }
+
+   ctx->ViewportArray[idx].X = x;
+   ctx->ViewportArray[idx].Width = width;
+   ctx->ViewportArray[idx].Y = y;
+   ctx->ViewportArray[idx].Height = height;
+   ctx->NewState |= _NEW_VIEWPORT;
+
+#if 1
+   /* XXX remove this someday.  Currently the DRI drivers rely on
+    * the WindowMap matrix being up to date in the driver's Viewport
+    * and DepthRange functions.
+    */
+   _math_matrix_viewport(&ctx->ViewportArray[idx]._WindowMap,
+                         ctx->ViewportArray[idx].X,
+                         ctx->ViewportArray[idx].Y,
+                         ctx->ViewportArray[idx].Width,
+                         ctx->ViewportArray[idx].Height,
+                         ctx->ViewportArray[idx].Near,
+                         ctx->ViewportArray[idx].Far,
+                         ctx->DrawBuffer->_DepthMaxF);
+#endif
+}
+
+struct gl_viewport_inputs {
+   GLfloat X, Y;                /**< position */
+   GLfloat Width, Height;       /**< size */
+};
+
+struct gl_depthrange_inputs {
+   GLdouble Near, Far;          /**< Depth buffer range */
+};
 
 /**
  * Set the viewport.
@@ -45,9 +99,39 @@
 void GLAPIENTRY
 _mesa_Viewport(GLint x, GLint y, GLsizei width, GLsizei height)
 {
+   unsigned i;
    GET_CURRENT_CONTEXT(ctx);
    FLUSH_VERTICES(ctx, 0);
-   _mesa_set_viewport(ctx, x, y, width, height);
+
+   if (MESA_VERBOSE & VERBOSE_API)
+      _mesa_debug(ctx, "glViewport %d %d %d %d\n", x, y, width, height);
+
+   if (width < 0 || height < 0) {
+      _mesa_error(ctx,  GL_INVALID_VALUE,
+                   "glViewport(%d, %d, %d, %d)", x, y, width, height);
+      return;
+   }
+
+   /* The GL_ARB_viewport_array spec says:
+    *
+    *     "Viewport sets the parameters for all viewports to the same values
+    *     and is equivalent (assuming no errors are generated) to:
+    *
+    *     for (uint i = 0; i < MAX_VIEWPORTS; i++)
+    *         ViewportIndexedf(i, 1, (float)x, (float)y, (float)w, (float)h);"
+    *
+    * Set all of the viewports supported by the implementation, but only
+    * signal the driver once at the end.
+    */
+   for (i = 0; i < ctx->Const.MaxViewports; i++)
+      set_viewport_no_notify(ctx, i, x, y, width, height);
+
+   if (ctx->Driver.Viewport) {
+      /* Many drivers will use this call to check for window size changes
+       * and reallocate the z/stencil/accum/etc buffers if needed.
+       */
+      ctx->Driver.Viewport(ctx);
+   }
 }
 
 
@@ -56,31 +140,114 @@ _mesa_Viewport(GLint x, GLint y, GLsizei width, GLsizei height)
  * matrix).  Usually called from _mesa_Viewport().
  * 
  * \param ctx GL context.
+ * \param idx    Index of the viewport to be updated.
  * \param x, y coordinates of the lower left corner of the viewport rectangle.
  * \param width width of the viewport rectangle.
  * \param height height of the viewport rectangle.
  */
 void
-_mesa_set_viewport(struct gl_context *ctx, GLint x, GLint y,
-                    GLsizei width, GLsizei height)
+_mesa_set_viewport(struct gl_context *ctx, unsigned idx, GLfloat x, GLfloat y,
+                    GLfloat width, GLfloat height)
 {
+   set_viewport_no_notify(ctx, idx, x, y, width, height);
+
+   if (ctx->Driver.Viewport) {
+      /* Many drivers will use this call to check for window size changes
+       * and reallocate the z/stencil/accum/etc buffers if needed.
+       */
+      ctx->Driver.Viewport(ctx);
+   }
+}
+
+void GLAPIENTRY
+_mesa_ViewportArrayv(GLuint first, GLsizei count, const GLfloat *v)
+{
+   int i;
+   const struct gl_viewport_inputs *const p = (struct gl_viewport_inputs *) v;
+   GET_CURRENT_CONTEXT(ctx);
+
    if (MESA_VERBOSE & VERBOSE_API)
-      _mesa_debug(ctx, "glViewport %d %d %d %d\n", x, y, width, height);
+      _mesa_debug(ctx, "glViewportArrayv %d %d\n", first, count);
 
-   if (width < 0 || height < 0) {
-      _mesa_error(ctx,  GL_INVALID_VALUE,
-                   "glViewport(%d, %d, %d, %d)", x, y, width, height);
+   if ((first + count) > ctx->Const.MaxViewports) {
+      _mesa_error(ctx, GL_INVALID_VALUE,
+                  "glViewportArrayv: first (%d) + count (%d) > MaxViewports "
+                  "(%d)",
+                  first, count, ctx->Const.MaxViewports);
       return;
    }
 
-   /* clamp width and height to the implementation dependent range */
-   width  = MIN2(width, (GLsizei) ctx->Const.MaxViewportWidth);
-   height = MIN2(height, (GLsizei) ctx->Const.MaxViewportHeight);
+   /* Verify width & height */
+   for (i = 0; i < count; i++) {
+      if (p[i].Width < 0 || p[i].Height < 0) {
+         _mesa_error(ctx, GL_INVALID_VALUE,
+                     "glViewportArrayv: index (%d) width or height < 0 "
+                     "(%f, %f)",
+                     i + first, p[i].Width, p[i].Height);
+         return;
+      }
+   }
+
+   for (i = 0; i < count; i++)
+      set_viewport_no_notify(ctx, i + first,
+                             p[i].X, p[i].Y,
+                             p[i].Width, p[i].Height);
+
+   if (ctx->Driver.Viewport)
+      ctx->Driver.Viewport(ctx);
+}
 
-   ctx->Viewport.X = x;
-   ctx->Viewport.Width = width;
-   ctx->Viewport.Y = y;
-   ctx->Viewport.Height = height;
+static void
+ViewportIndexedf(GLuint index, GLfloat x, GLfloat y,
+                 GLfloat w, GLfloat h, const char *function)
+{
+   GET_CURRENT_CONTEXT(ctx);
+
+   if (MESA_VERBOSE & VERBOSE_API)
+      _mesa_debug(ctx, "%s(%d, %f, %f, %f, %f)\n",
+                  function, index, x, y, w, h);
+
+   if (index >= ctx->Const.MaxViewports) {
+      _mesa_error(ctx, GL_INVALID_VALUE,
+                  "%s: index (%d) >= MaxViewports (%d)",
+                  function, index, ctx->Const.MaxViewports);
+      return;
+   }
+
+   /* Verify width & height */
+   if (w < 0 || h < 0) {
+      _mesa_error(ctx, GL_INVALID_VALUE,
+                  "%s: index (%d) width or height < 0 (%f, %f)",
+                  function, index, w, h);
+      return;
+   }
+
+   _mesa_set_viewport(ctx, index, x, y, w, h);
+}
+
+void GLAPIENTRY
+_mesa_ViewportIndexedf(GLuint index, GLfloat x, GLfloat y,
+                       GLfloat w, GLfloat h)
+{
+   ViewportIndexedf(index, x, y, w, h, "glViewportIndexedf");
+}
+
+void GLAPIENTRY
+_mesa_ViewportIndexedfv(GLuint index, const GLfloat *v)
+{
+   ViewportIndexedf(index, v[0], v[1], v[2], v[3], "glViewportIndexedfv");
+}
+
+static void
+set_depth_range_no_notify(struct gl_context *ctx, unsigned idx,
+                          GLclampd nearval, GLclampd farval)
+{
+   if (ctx->ViewportArray[idx].Near == nearval &&
+       ctx->ViewportArray[idx].Far == farval)
+      return;
+
+   ctx->ViewportArray[idx].Near = CLAMP(nearval, 0.0, 1.0);
+   ctx->ViewportArray[idx].Far = CLAMP(farval, 0.0, 1.0);
    ctx->NewState |= _NEW_VIEWPORT;
 
 #if 1
@@ -88,21 +255,26 @@ _mesa_set_viewport(struct gl_context *ctx, GLint x, GLint y,
     * the WindowMap matrix being up to date in the driver's Viewport
     * and DepthRange functions.
     */
-   _math_matrix_viewport(&ctx->Viewport._WindowMap,
-                         ctx->Viewport.X, ctx->Viewport.Y,
-                         ctx->Viewport.Width, ctx->Viewport.Height,
-                         ctx->Viewport.Near, ctx->Viewport.Far,
+   _math_matrix_viewport(&ctx->ViewportArray[idx]._WindowMap,
+                         ctx->ViewportArray[idx].X,
+                         ctx->ViewportArray[idx].Y,
+                         ctx->ViewportArray[idx].Width,
+                         ctx->ViewportArray[idx].Height,
+                         ctx->ViewportArray[idx].Near,
+                         ctx->ViewportArray[idx].Far,
                          ctx->DrawBuffer->_DepthMaxF);
 #endif
-
-   if (ctx->Driver.Viewport) {
-      /* Many drivers will use this call to check for window size changes
-       * and reallocate the z/stencil/accum/etc buffers if needed.
-       */
-      ctx->Driver.Viewport(ctx);
-   }
 }
 
+void
+_mesa_set_depth_range(struct gl_context *ctx, unsigned idx,
+                      GLclampd nearval, GLclampd farval)
+{
+   set_depth_range_no_notify(ctx, idx, nearval, farval);
+
+   if (ctx->Driver.DepthRange)
+      ctx->Driver.DepthRange(ctx);
+}
 
 /**
  * Called by glDepthRange
@@ -115,6 +287,7 @@ _mesa_set_viewport(struct gl_context *ctx, GLint x, GLint y,
 void GLAPIENTRY
 _mesa_DepthRange(GLclampd nearval, GLclampd farval)
 {
+   unsigned i;
    GET_CURRENT_CONTEXT(ctx);
 
    FLUSH_VERTICES(ctx, 0);
@@ -122,25 +295,19 @@ _mesa_DepthRange(GLclampd nearval, GLclampd farval)
    if (MESA_VERBOSE&VERBOSE_API)
       _mesa_debug(ctx, "glDepthRange %f %f\n", nearval, farval);
 
-   if (ctx->Viewport.Near == nearval &&
-       ctx->Viewport.Far == farval)
-      return;
-
-   ctx->Viewport.Near = (GLfloat) CLAMP(nearval, 0.0, 1.0);
-   ctx->Viewport.Far = (GLfloat) CLAMP(farval, 0.0, 1.0);
-   ctx->NewState |= _NEW_VIEWPORT;
-
-#if 1
-   /* XXX remove this someday.  Currently the DRI drivers rely on
-    * the WindowMap matrix being up to date in the driver's Viewport
-    * and DepthRange functions.
+   /* The GL_ARB_viewport_array spec says:
+    *
+    *     "DepthRange sets the depth range for all viewports to the same
+    *     values and is equivalent (assuming no errors are generated) to:
+    *
+    *     for (uint i = 0; i < MAX_VIEWPORTS; i++)
+    *         DepthRangeIndexed(i, n, f);"
+    *
+    * Set the depth range for all of the viewports supported by the
+    * implementation, but only signal the driver once at the end.
     */
-   _math_matrix_viewport(&ctx->Viewport._WindowMap,
-                         ctx->Viewport.X, ctx->Viewport.Y,
-                         ctx->Viewport.Width, ctx->Viewport.Height,
-                         ctx->Viewport.Near, ctx->Viewport.Far,
-                         ctx->DrawBuffer->_DepthMaxF);
-#endif
+   for (i = 0; i < ctx->Const.MaxViewports; i++)
+      set_depth_range_no_notify(ctx, i, nearval, farval);
 
    if (ctx->Driver.DepthRange) {
       ctx->Driver.DepthRange(ctx);
@@ -153,6 +320,67 @@ _mesa_DepthRangef(GLclampf nearval, GLclampf farval)
    _mesa_DepthRange(nearval, farval);
 }
 
+/**
+ * Update a range DepthRange values
+ *
+ * \param first   starting array index
+ * \param count   count of DepthRange items to update
+ * \param v       pointer to memory containing
+ *                GLclampd near and far clip-plane values
+ */
+void GLAPIENTRY
+_mesa_DepthRangeArrayv(GLuint first, GLsizei count, const GLclampd *v)
+{
+   int i;
+   const struct gl_depthrange_inputs *const p =
+      (struct gl_depthrange_inputs *) v;
+   GET_CURRENT_CONTEXT(ctx);
+
+   if (MESA_VERBOSE & VERBOSE_API)
+      _mesa_debug(ctx, "glDepthRangeArrayv %d %d\n", first, count);
+
+   if ((first + count) > ctx->Const.MaxViewports) {
+      _mesa_error(ctx, GL_INVALID_VALUE,
+                  "glDepthRangev: first (%d) + count (%d) >= MaxViewports (%d)",
+                  first, count, ctx->Const.MaxViewports);
+      return;
+   }
+
+   for (i = 0; i < count; i++)
+      set_depth_range_no_notify(ctx, i + first, p[i].Near, p[i].Far);
+
+   if (ctx->Driver.DepthRange)
+      ctx->Driver.DepthRange(ctx);
+}
+
+/**
+ * Update a single DepthRange
+ *
+ * \param index    array index to update
+ * \param nearval  specifies the Z buffer value which should correspond to
+ *                 the near clip plane
+ * \param farval   specifies the Z buffer value which should correspond to
+ *                 the far clip plane
+ */
+void GLAPIENTRY
+_mesa_DepthRangeIndexed(GLuint index, GLclampd nearval, GLclampd farval)
+{
+   GET_CURRENT_CONTEXT(ctx);
+
+   if (MESA_VERBOSE & VERBOSE_API)
+      _mesa_debug(ctx, "glDepthRangeIndexed(%d, %f, %f)\n",
+                  index, nearval, farval);
+
+   if (index >= ctx->Const.MaxViewports) {
+      _mesa_error(ctx, GL_INVALID_VALUE,
+                  "glDepthRangeIndexed: index (%d) >= MaxViewports (%d)",
+                  index, ctx->Const.MaxViewports);
+      return;
+   }
+
+   _mesa_set_depth_range(ctx, index, nearval, farval);
+}
+
 /** 
  * Initialize the context viewport attribute group.
  * \param ctx  the GL context.
@@ -160,18 +388,24 @@ _mesa_DepthRangef(GLclampf nearval, GLclampf farval)
 void _mesa_init_viewport(struct gl_context *ctx)
 {
    GLfloat depthMax = 65535.0F; /* sorf of arbitrary */
+   unsigned i;
 
-   /* Viewport group */
-   ctx->Viewport.X = 0;
-   ctx->Viewport.Y = 0;
-   ctx->Viewport.Width = 0;
-   ctx->Viewport.Height = 0;
-   ctx->Viewport.Near = 0.0;
-   ctx->Viewport.Far = 1.0;
-   _math_matrix_ctr(&ctx->Viewport._WindowMap);
-
-   _math_matrix_viewport(&ctx->Viewport._WindowMap, 0, 0, 0, 0,
-                         0.0F, 1.0F, depthMax);
+   /* Note: ctx->Const.MaxViewports may not have been set by the driver yet,
+    * so just initialize all of them.
+    */
+   for (i = 0; i < MAX_VIEWPORTS; i++) {
+      /* Viewport group */
+      ctx->ViewportArray[i].X = 0;
+      ctx->ViewportArray[i].Y = 0;
+      ctx->ViewportArray[i].Width = 0;
+      ctx->ViewportArray[i].Height = 0;
+      ctx->ViewportArray[i].Near = 0.0;
+      ctx->ViewportArray[i].Far = 1.0;
+      _math_matrix_ctr(&ctx->ViewportArray[i]._WindowMap);
+
+      _math_matrix_viewport(&ctx->ViewportArray[i]._WindowMap, 0, 0, 0, 0,
+                            0.0F, 1.0F, depthMax);
+   }
 }
 
 
@@ -181,6 +415,9 @@ void _mesa_init_viewport(struct gl_context *ctx)
  */
 void _mesa_free_viewport_data(struct gl_context *ctx)
 {
-   _math_matrix_dtr(&ctx->Viewport._WindowMap);
+   unsigned i;
+
+   for (i = 0; i < MAX_VIEWPORTS; i++)
+      _math_matrix_dtr(&ctx->ViewportArray[i]._WindowMap);
 }
 
diff --git a/mesalib/src/mesa/main/viewport.h b/mesalib/src/mesa/main/viewport.h
index ffa3a729c..f2311c02b 100644
--- a/mesalib/src/mesa/main/viewport.h
+++ b/mesalib/src/mesa/main/viewport.h
@@ -34,10 +34,18 @@ struct gl_context;
 extern void GLAPIENTRY
 _mesa_Viewport(GLint x, GLint y, GLsizei width, GLsizei height);
 
+extern void GLAPIENTRY
+_mesa_ViewportArrayv(GLuint first, GLsizei count, const GLfloat * v);
+
+extern void GLAPIENTRY
+_mesa_ViewportIndexedf(GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h);
+
+extern void GLAPIENTRY
+_mesa_ViewportIndexedfv(GLuint index, const GLfloat * v);
 
 extern void 
-_mesa_set_viewport(struct gl_context *ctx, GLint x, GLint y,
-                   GLsizei width, GLsizei height);
+_mesa_set_viewport(struct gl_context *ctx, unsigned idx, GLfloat x, GLfloat y,
+                   GLfloat width, GLfloat height);
 
 
 extern void GLAPIENTRY
@@ -46,6 +54,15 @@ _mesa_DepthRange(GLclampd nearval, GLclampd farval);
 extern void GLAPIENTRY
 _mesa_DepthRangef(GLclampf nearval, GLclampf farval);
 
+extern void GLAPIENTRY
+_mesa_DepthRangeArrayv(GLuint first, GLsizei count, const GLclampd * v);
+
+extern void GLAPIENTRY
+_mesa_DepthRangeIndexed(GLuint index, GLclampd n, GLclampd f);
+
+extern void
+_mesa_set_depth_range(struct gl_context *ctx, unsigned idx,
+                      GLclampd nearval, GLclampd farval);
 
 extern void 
 _mesa_init_viewport(struct gl_context *ctx);
-- 
cgit v1.2.3