Merge snations branch
diff --git a/build/regal.inc b/build/regal.inc
index ea3b679..f388151 100644
--- a/build/regal.inc
+++ b/build/regal.inc
@@ -47,7 +47,6 @@
 REGAL.CXX += src/regal/RegalFavicon.cpp
 REGAL.CXX += src/regal/RegalMac.cpp
 REGAL.CXX += src/regal/RegalSo.cpp
-REGAL.CXX += src/regal/RegalPpca.cpp
 REGAL.CXX += src/regal/RegalFilt.cpp
 REGAL.CXX += src/regal/RegalXfer.cpp
 REGAL.CXX += src/regal/RegalDllMain.cpp
@@ -90,7 +89,6 @@
 REGAL.H += src/regal/RegalMac.h
 REGAL.H += src/regal/RegalObj.h
 REGAL.H += src/regal/RegalPpa.h
-REGAL.H += src/regal/RegalPpc.h
 REGAL.H += src/regal/RegalPpca.h
 REGAL.H += src/regal/RegalPrecompile.h
 REGAL.H += src/regal/RegalPrivate.h
diff --git a/scripts/EmuEnable.py b/scripts/EmuEnable.py
old mode 100755
new mode 100644
diff --git a/scripts/EmuErrorString.py b/scripts/EmuErrorString.py
old mode 100755
new mode 100644
diff --git a/scripts/EmuExtensionQuery.py b/scripts/EmuExtensionQuery.py
old mode 100755
new mode 100644
diff --git a/scripts/EmuFilter.py b/scripts/EmuFilter.py
old mode 100755
new mode 100644
diff --git a/scripts/EmuForceCore.py b/scripts/EmuForceCore.py
old mode 100755
new mode 100644
diff --git a/scripts/EmuGetString.py b/scripts/EmuGetString.py
old mode 100755
new mode 100644
diff --git a/scripts/EmuLog.py b/scripts/EmuLog.py
old mode 100755
new mode 100644
diff --git a/scripts/EmuLookup.py b/scripts/EmuLookup.py
old mode 100755
new mode 100644
diff --git a/scripts/EmuMarker.py b/scripts/EmuMarker.py
old mode 100755
new mode 100644
diff --git a/scripts/EmuPpa.py b/scripts/EmuPpa.py
old mode 100755
new mode 100644
diff --git a/scripts/EmuPpca.py b/scripts/EmuPpca.py
index 9ba92ce..2b8e5db 100644
--- a/scripts/EmuPpca.py
+++ b/scripts/EmuPpca.py
@@ -1,171 +1,94 @@
 #!/usr/bin/python -B
 
-# Section numbers below are based on this version of the specficiation
-# http://www.opengl.org/registry/doc/glspec43.compatibility.20120806.pdf
-
 ppcaFormulae = {
-  # Client Pixel state
-  'ShadowPixelStore' : {
-    'entries'  : [ 'glPixelStore(i|f)' ],
-    'prefix'   : [ '_context->ppca->ShadowPixelStore( ${arg0plus} );', ],
-  },
 
-  # Client Vertex Array state
+  # Push/Pop ClientAttrib & Get
 
-  # 10.3.1 - Arrays for Generic Vertex Attributes
-
-  'ShadowVertexAttribFormat' : {
-    'entries'  : [ 'glVertexAttrib(|I|L)Format' ],
-    'prefix'   : [ '_context->ppca->ShadowVertexAttrib${m1}Format( ${arg0plus} );', ],
-  },
-
-  'ShadowBindVertexBuffer' : {
-    'entries'  : [ 'glBindVertexBuffer' ],
-    'prefix'   : [ '_context->ppca->ShadowBindVertexBuffer( ${arg0plus} );', ],
-  },
-
-  'ShadowVertexAttribBinding' : {
-    'entries'  : [ 'glVertexAttribBinding' ],
-    'prefix'   : [ '_context->ppca->ShadowVertexAttribBinding( ${arg0plus} );', ],
-  },
-
-  'ShadowVertexAttribPointer' : {
-    'entries'  : [ 'glVertex(I|L)Pointer' ],
-    'prefix'   : [ '_context->ppca->ShadowVertexAttrib${m1}Pointer( ${arg0plus} );', ],
-  },
-
-  'ShadowEnableDisableVertexAttribAttribArray' : {
-    'entries'  : [ 'gl(Enable|Disable)VertexAttribArray' ],
-    'prefix'   : [ '_context->ppca->Shadow${m1}VertexAttribArray( ${arg0plus} );', ],
-  },
-
-  # 10.3.2 - Arrays for Fixed-Function Attributes
-
-  'ShadowVertexDataPointer' : {
-    'entries'  : [ 'gl(Color|EdgeFlag|FogCoord|Index|Normal|SecondaryColor|TexCoord|Vertex)Pointer' ],
-    'prefix'   : [ '_context->ppca->Shadow${m1}Pointer( ${arg0plus} );', ],
-  },
-
-  'ShadowEnableDisableClientState' : {
-    'entries'  : [ 'gl(Enable|Disable)ClientState' ],
-    'prefix'   : [ '_context->ppca->Shadow${m1}ClientState( ${arg0plus} );', ],
-  },
-
-  'ShadowClientActiveTexture' : {
-    'entries'  : [ 'glClientActiveTexture' ],
-    'prefix'   : [ '_context->ppca->ShadowClientActiveTexture( ${arg0plus} );', ],
-  },
-
-  # 10.3.3 - Vertex Attribute Divisors
-
-  'ShadowVertexBindingDivisor' : {
-    'entries'  : [ 'glVertexBindingDivisor' ],
-    'prefix'   : [ '_context->ppca->ShadowVertexBindingDivisor( ${arg0plus} );', ],
-  },
-
-  'ShadowVertexAttribDivisor' : {
-    'entries'  : [ 'glVertexAttribDivisor' ],
-    'prefix'   : [ '_context->ppca->ShadowVertexAttribDivisor( ${arg0plus} );', ],
-  },
-
-  # 10.3.5 - Primitive Restart
-
-  'ShadowEnableDisable' : {
-    'entries'  : [ 'gl(Enable|Disable)' ],
-    'prefix'   : [ '_context->ppca->Shadow${m1}( ${arg0plus} );', ],
-  },
-
-  'ShadowPrimitiveRestartIndex' : {
-    'entries'  : [ 'glPrimitiveRestartIndex' ],
-    'prefix'   : [ '_context->ppca->ShadowPrimitiveRestartIndex( ${arg0plus} );', ],
-  },
-
-  # 10.3.8 - Vertex Arrays in Buffer Objects
-
-  'ShadowBindBuffer' : {
-    'entries'  : [ 'glBindBuffer' ],
-    'prefix'   : [ '_context->ppca->ShadowBindBuffer( ${arg0plus} );', ],
-  },
-
-  # 10.4 - Vertex Array Objects
-
-  'ShadowBindVertexArray' : {
-    'entries'  : [ 'glBindVertexArray' ],
-    'prefix'   : [ '_context->ppca->ShadowBindVertexArray( ${arg0plus} );', ],
-  },
-
-  # 10.5.1 - Interleaved Arrays
-
-  'ShadowInterleavedArrays' : {
-    'entries'  : [ 'glInterleavedArrays' ],
-    'prefix'   : [ '_context->ppca->ShadowInterleavedArrays( ${arg0plus} );', ],
-  },
-
-  # Direct State Access Extension
-  # http://www.opengl.org/registry/specs/EXT/direct_state_access.txt
-
-  'ClientAttribDefaultDSA' : {
-    'entries'  : [ 'gl(|Push)ClientAttribDefaultEXT' ],
-    'impl'     : [ '_context->ppca->${m1}ClientAttribDefaultDSA( _context, ${arg0} );', ],
-  },
-
-  'ShadowMultiTexCoordPointerDSA' : {
-    'entries'  : [ 'glMultiTexCoordPointerEXT' ],
-    'prefix'   : [ '_context->ppca->ShadowMultiTexCoordPointerDSA( ${arg0plus} );', ],
-  },
-
-  'ShadowEnableDisableClientStateIndexedDSA' : {
-    'entries'  : [ 'gl(Enable|Disable)ClientState(i|Indexed)EXT', ],
-    'prefix'   : [ '_context->ppca->Shadow${m1}ClientStateIndexedDSA( ${arg0plus} );', ],
-  },
-
-  'ShadowVertexArrayOffsetDSA' : {
-    'entries'  : ['glVertexArray(Vertex|Color|EdgeFlag|Index|Normal|TexCoord|MultiTexCoord|FogCoord|SecondaryColor|VertexAttrib|VertexAttribI)OffsetEXT' ],
-    'prefix'   : [ '_context->ppca->ShadowVertexArray${m1}OffsetDSA( ${arg0plus} );', ],
-  },
-
-  'ShadowEnableDisableVertexArrayDSA' : {
-    'entries'  : [ 'gl(Enable|Disable)VertexArrayEXT'],
-    'prefix'   : [ '_context->ppca->Shadow${m1}VertexArrayDSA( ${arg0plus} );', ],
-  },
-
-  'ShadowEnableDisableVertexArrayAttribDSA' : {
-    'entries'  : [ 'gl(Enable|Disable)VertexArrayAttribEXT'],
-    'prefix'   : [ '_context->ppca->Shadow${m1}VertexArrayAttribDSA( ${arg0plus} );', ],
-  },
-
-  # Deleting buffers
-
-  'ShadowDeleteBuffers' : {
-    'entries'  : [ 'glDeleteBuffers' ],
-    'prefix'   : [ '_context->ppca->ShadowDeleteBuffers( ${arg0plus} );', ],
-  },
-
-  'ShadowDeleteVertexArrays' : {
-    'entries'  : [ 'glDeleteVertexArrays' ],
-    'prefix'   : [ '_context->ppca->ShadowDeleteVertexArrays( ${arg0plus} );', ],
-  },
-
-  # Push/PopClientAttrib
-
-  'PushClientAtrrib' : {
+  'PushClientAttrib' : {
     'entries'  : [ 'glPushClientAttrib' ],
-    'impl'     : [ '_context->ppca->PushClientAttrib( _context, ${arg0} );', ],
+    'impl'     : [ '_context->ppca->glPushClientAttrib( _context, ${arg0} );', ],
   },
 
   'PopClientAttrib' : {
     'entries' : [ 'glPopClientAttrib' ],
-    'impl'    : [ '_context->ppca->PopClientAttrib( _context );', ],
+    'impl'    : [ '_context->ppca->glPopClientAttrib( _context );', ],
   },
 
-  # Get
+  'PushClientAttribDefaultEXT' : {
+    'entries'  : [ 'gl(Push|)ClientAttribDefaultEXT' ],
+    'impl'     : [ '_context->ppca->gl${m1}ClientAttribDefaultEXT( _context, ${arg0} );', ],
+  },
 
   'Get'       : {
-    'entries' : [ 'glGet(Integer|Integer64|Float|Double|Boolean)v' ],
+    'entries' : [ 'glGet(Integer|Float|Double|Boolean)v(EXT|)' ],
     'impl'    : [
-      'if( ! _context->ppca->Get( _context, ${arg0plus} ) ) {',
-      '  _context->dispatcher.emulation.glGet${m1}v( ${arg0plus} );',
+      'if ( ! _context->ppca->glGetv( _context, ${arg0plus} ) ) {',
+      '  if (!_context->info->core && !_context->info->es1 && !_context->info->es2) {',
+      '    _context->dispatcher.emulation.glGet${m1}v${m2}( ${arg0plus} );',
+      '  }',
       '}',
     ],
   },
+  # shadow all the client state
+
+  'Bind'      : {
+    'entries' : [ 'glBind(Vertex|)(Buffer|Array)(s|)' ],
+    'prefix'  : [ '_context->ppca->glBind${m1}${m2}${m3}( ${arg0plus} );', ],
+  },
+  'Delete'    : {
+    'entries' : [ 'glDelete(VertexArrays|Buffers)' ],
+    'prefix'  : [ '_context->ppca->glDelete${m1}( ${arg0plus} );', ],
+  },
+  'EnableDisable' : {
+    'entries' : [ 'gl(Enable|Disable)(ClientState|VertexAttribArray|)(i|Indexed|)(EXT|)' ],
+    'prefix'  : [ '_context->ppca->gl${m1}${m2}${m3}${m4}( ${arg0plus} );', ],
+  },
+  'Pointer'   : {
+    'entries' : [ 'gl(Color|EdgeFlag|FogCoord|Index|Normal|SecondaryColor|TexCoord|Vertex)Pointer' ],
+    'prefix'  : [ '_context->ppca->gl${m1}Pointer( ${arg0plus} );', ],
+  },
+  'VertexAttrib' : {
+    'entries' : [ 'glVertexAttrib(I|L|)(Binding|Format)' ],
+    'prefix'  : [ '_context->ppca->glVertexAttrib${m1}${m2}( ${arg0plus} );', ],
+  },
+  'MultiTexCoordPointerEXT': {
+    'entries' : [ 'glMultiTexCoordPointerEXT' ],
+    'prefix'  : [ '_context->ppca->glMultiTexCoordPointerEXT( ${arg0plus} );', ],
+  },
+  'ClientActiveTexture' : {
+    'entries' : [ 'glClientActiveTexture' ],
+    'prefix'  : [ '_context->ppca->glClientActiveTexture( ${arg0plus} );', ],
+  },
+  'PrimitiveRestartIndex' : {
+    'entries' : [ 'glPrimitiveRestartIndex' ],
+    'prefix'  : [ '_context->ppca->glPrimitiveRestartIndex( ${arg0plus} );', ],
+  },
+  'VertexDivisor' : {
+    'entries' : [ 'glVertex(Attrib|Binding)Divisor' ],
+    'prefix'  : [ '_context->ppca->glVertex${m1}Divisor( ${arg0plus} );', ],
+  },
+  'VertexAttribPointer' : {
+    'entries' : [ 'glVertexAttrib(I|L|)Pointer' ],
+    'prefix'  : [ '_context->ppca->glVertexAttrib${m1}Pointer( ${arg0plus} );', ],
+  },
+  'VertexArrayEnable' : {
+      'entries' : [ 'gl(Enable|Disable)VertexArrayEXT' ],
+      'prefix'  : [ '_context->ppca->gl${m1}VertexArrayEXT( ${arg0plus} );', ],
+  },
+  'VertexArrayAttribEnable' : {
+      'entries' : [ 'gl(Enable|Disable)VertexArrayAttribEXT' ],
+      'prefix'  : [ '_context->ppca->gl${m1}VertexArrayAttribEXT( ${arg0plus} );', ],
+  },
+  'DsaVertexArrayOffsetCommands' : {
+      'entries' : [ 'glVertexArray(EdgeFlag|Index|Normal|FogCoord|Vertex|Color|TexCoord|SecondaryColor|VertexAttribI|MultiTexCoord|VertexAttrib)OffsetEXT' ],
+      'prefix'  : [ '_context->ppca->glVertexArray${m1}OffsetEXT( ${arg0plus} );', ],
+  },
+  'InterleavedArrays ' : {
+      'entries' : [ 'glInterleavedArrays' ],
+      'prefix'  : [ '_context->ppca->glInterleavedArrays( ${arg0plus} );', ],
+  },
+  'PixelStore' : {
+      'entries' : [ 'glPixelStore(i|f)' ],
+      'prefix'  : [ '_context->ppca->glPixelStore( ${arg0plus} );', ],
+  },
 }
diff --git a/src/regal/RegalBaseVertex.h b/src/regal/RegalBaseVertex.h
index 312c246..7562a83 100644
--- a/src/regal/RegalBaseVertex.h
+++ b/src/regal/RegalBaseVertex.h
@@ -63,7 +63,7 @@
 
 namespace Emu {
 
-struct BaseVertex : public Client::State::VertexArray
+struct BaseVertex : public ClientState::VertexArray
 {
   void Init(RegalContext &ctx)
   {
@@ -79,11 +79,11 @@
   {
     UNUSED_PARAMETER(ctx);
 
-    GLuint currentVBO = Client::State::VertexArray::arrayBufferBinding;
+    GLuint currentVBO = ClientState::VertexArray::arrayBufferBinding;
 
-    for (GLuint ii=0; ii<Client::State::nNamedArrays; ii++)
+    for (GLuint ii=0; ii<ClientState::nNamedArrays; ii++)
     {
-      Client::State::NamedVertexArray &n = Client::State::VertexArray::named[ii];
+      ClientState::NamedVertexArray &n = ClientState::VertexArray::named[ii];
       if (n.enabled)
       {
         if (currentVBO != n.buffer)
@@ -96,25 +96,25 @@
         {
           switch (ii)
           {
-            case Client::State::VERTEX:
+            case ClientState::VERTEX:
               dt.call(&dt.glVertexPointer)(n.size, n.type, n.stride, n.pointer);
               break;
-            case Client::State::NORMAL:
+            case ClientState::NORMAL:
               dt.call(&dt.glNormalPointer)(n.type, n.stride, n.pointer);
               break;
-            case Client::State::FOG_COORD:
+            case ClientState::FOG_COORD:
               dt.call(&dt.glFogCoordPointer)(n.type, n.stride, n.pointer);
               break;
-            case Client::State::COLOR:
+            case ClientState::COLOR:
               dt.call(&dt.glColorPointer)(n.size, n.type, n.stride, n.pointer);
               break;
-            case Client::State::SECONDARY_COLOR:
+            case ClientState::SECONDARY_COLOR:
               dt.call(&dt.glSecondaryColorPointer)(n.size, n.type, n.stride, n.pointer);
               break;
-            case Client::State::INDEX:
+            case ClientState::INDEX:
               dt.call(&dt.glIndexPointer)(n.type, n.stride, n.pointer);
               break;
-            case Client::State::EDGE_FLAG:
+            case ClientState::EDGE_FLAG:
               dt.call(&dt.glEdgeFlagPointer)(n.stride, n.pointer);
               break;
             default:
@@ -131,10 +131,10 @@
 
     for (GLuint ii=0; ii<REGAL_EMU_MAX_VERTEX_ATTRIBS; ii++)
     {
-      Client::State::GenericVertexArray &g = Client::State::VertexArray::generic[ii];
+      ClientState::GenericVertexArray &g = ClientState::VertexArray::generic[ii];
       if (g.enabled)
       {
-        Client::State::VertexBufferBindPoint &b = Client::State::VertexArray::bindings[g.bindingIndex];
+        ClientState::VertexBufferBindPoint &b = ClientState::VertexArray::bindings[g.bindingIndex];
         GLvoid *p = reinterpret_cast<GLvoid *>(b.offset + (b.stride*basevertex));
 
         if (currentVBO != b.buffer)
@@ -152,8 +152,8 @@
       }
     }
 
-    if (currentVBO != Client::State::VertexArray::arrayBufferBinding)
-      dt.call(&dt.glBindBuffer)(GL_ARRAY_BUFFER, Client::State::VertexArray::arrayBufferBinding);
+    if (currentVBO != ClientState::VertexArray::arrayBufferBinding)
+      dt.call(&dt.glBindBuffer)(GL_ARRAY_BUFFER, ClientState::VertexArray::arrayBufferBinding);
   }
 
   bool glDrawElementsBaseVertex(RegalContext &ctx, GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLint basevertex)
diff --git a/src/regal/RegalClientState.h b/src/regal/RegalClientState.h
index c8399df..dd1914d 100644
--- a/src/regal/RegalClientState.h
+++ b/src/regal/RegalClientState.h
@@ -84,10 +84,7 @@
 //    http://graphics.stanford.edu/papers/cr/
 //
 
-namespace Client
-{
-
-namespace State
+namespace ClientState
 {
 
   using   ::boost::print::hex;
@@ -160,13 +157,18 @@
     GLint      stride;   // GL_x_ARRAY_STRIDE
 
     inline NamedVertexArray()
-    : enabled(GL_FALSE)
-    , pointer(NULL)
-    , buffer(0)
-    , size(4)
-    , type(GL_FLOAT)
-    , stride(0)
     {
+      Reset();
+    }
+
+    inline void Reset()
+    {
+      enabled = GL_FALSE;
+      pointer = NULL;
+      buffer = 0;
+      size = 4;
+      type = GL_FLOAT;
+      stride = 0;
     }
 
     inline NamedVertexArray &swap(NamedVertexArray &other)
@@ -184,7 +186,7 @@
     {
       GLint vaInt = static_cast<GLint>(va);
       RegalAssert(vaInt >= 0 && vaInt < static_cast<GLint>(nNamedArrays));
-      if (vaInt >= 0)
+      if (vaInt >= 0 && vaInt < static_cast<GLint>(nNamedArrays))
       {
         if (vaInt < 7)
         {
@@ -211,61 +213,150 @@
       return *this;
     }
 
-    const NamedVertexArray &set(DispatchTableGL &dt, vaName va) const
+    const NamedVertexArray &set(DispatchTableGL &dt, vaName va, bool driverAllowsVertexAttributeArraysWithoutBoundBuffer) const
     {
       GLint vaInt = static_cast<GLint>(va);
       RegalAssert(vaInt >= 0 && vaInt < static_cast<GLint>(nNamedArrays));
-      if (vaInt >= 0)
+      if (buffer || driverAllowsVertexAttributeArraysWithoutBoundBuffer)
       {
-        if (vaInt < 7)
+        if (vaInt >= 0 && vaInt < static_cast<GLint>(nNamedArrays))
         {
-          enable(dt,vaEnum[vaInt][0],enabled);
-          dt.call(&dt.glBindBuffer)(GL_ARRAY_BUFFER,buffer);
-          switch (vaInt)
+          if (vaInt < 7)
           {
-            case VERTEX:
-              dt.call(&dt.glVertexPointer)(size,type,stride,pointer);
-              break;
-            case NORMAL:
-              dt.call(&dt.glNormalPointer)(type,stride,pointer);
-              break;
-            case FOG_COORD:
-              dt.call(&dt.glFogCoordPointer)(type,stride,pointer);
-              break;
-            case COLOR:
-              dt.call(&dt.glColorPointer)(size,type,stride,pointer);
-              break;
-            case SECONDARY_COLOR:
-              dt.call(&dt.glSecondaryColorPointer)(size,type,stride,pointer);
-              break;
-            case INDEX:
-              dt.call(&dt.glIndexPointer)(type,stride,pointer);
-              break;
-            case EDGE_FLAG:
-              dt.call(&dt.glEdgeFlagPointer)(stride,pointer);
-              break;
-            default:
-              break;
+            enable(dt,vaEnum[vaInt][0],enabled);
+            dt.call(&dt.glBindBuffer)(GL_ARRAY_BUFFER,buffer);
+            switch (vaInt)
+            {
+              case VERTEX:
+                dt.call(&dt.glVertexPointer)(size,type,stride,pointer);
+                break;
+              case NORMAL:
+                dt.call(&dt.glNormalPointer)(type,stride,pointer);
+                break;
+              case FOG_COORD:
+                dt.call(&dt.glFogCoordPointer)(type,stride,pointer);
+                break;
+              case COLOR:
+                dt.call(&dt.glColorPointer)(size,type,stride,pointer);
+                break;
+              case SECONDARY_COLOR:
+                dt.call(&dt.glSecondaryColorPointer)(size,type,stride,pointer);
+                break;
+              case INDEX:
+                dt.call(&dt.glIndexPointer)(type,stride,pointer);
+                break;
+              case EDGE_FLAG:
+                dt.call(&dt.glEdgeFlagPointer)(stride,pointer);
+                break;
+              default:
+                break;
+            }
           }
-        }
-        else
-        {
-          GLuint index = static_cast<GLuint>(vaInt - 7);
-          enablei(dt,vaEnum[7][0],index,enabled);
-          dt.call(&dt.glBindBuffer)(GL_ARRAY_BUFFER,buffer);
-          dt.call(&dt.glMultiTexCoordPointerEXT)(GL_TEXTURE0+index,size,type,stride,pointer);
+          else
+          {
+            GLuint index = static_cast<GLuint>(vaInt - 7);
+            enablei(dt,vaEnum[7][0],index,enabled);
+            dt.call(&dt.glBindBuffer)(GL_ARRAY_BUFFER,buffer);
+            dt.call(&dt.glMultiTexCoordPointerEXT)(GL_TEXTURE0+index,size,type,stride,pointer);
+          }
         }
       }
       return *this;
     }
 
+    void transition(DispatchTableGL &dt, NamedVertexArray &to, vaName va, bool driverAllowsVertexAttributeArraysWithoutBoundBuffer)
+    {
+      GLint vaInt = static_cast<GLint>(va);
+      RegalAssert(vaInt >= 0 && vaInt < static_cast<GLint>(nNamedArrays));
+      if (buffer || driverAllowsVertexAttributeArraysWithoutBoundBuffer)
+      {
+        if (vaInt >= 0 && vaInt < static_cast<GLint>(nNamedArrays))
+        {
+          if (vaInt < 7)
+          {
+            if (enabled != to.enabled)
+            {
+              enabled = to.enabled;
+              enable(dt,vaEnum[vaInt][0],enabled);
+            }
+            if (buffer != to.buffer)
+            {
+              buffer = to.buffer;
+              dt.call(&dt.glBindBuffer)(GL_ARRAY_BUFFER,buffer);
+            }
+            if (size != to.size ||
+                type != to.type ||
+                stride != to.stride ||
+                pointer != to.pointer)
+            {
+              size = to.size;
+              type = to.type;
+              stride = to.stride;
+              pointer = to.pointer;
+              switch (vaInt)
+              {
+                case VERTEX:
+                  dt.call(&dt.glVertexPointer)(size,type,stride,pointer);
+                  break;
+                case NORMAL:
+                  dt.call(&dt.glNormalPointer)(type,stride,pointer);
+                  break;
+                case FOG_COORD:
+                  dt.call(&dt.glFogCoordPointer)(type,stride,pointer);
+                  break;
+                case COLOR:
+                  dt.call(&dt.glColorPointer)(size,type,stride,pointer);
+                  break;
+                case SECONDARY_COLOR:
+                  dt.call(&dt.glSecondaryColorPointer)(size,type,stride,pointer);
+                  break;
+                case INDEX:
+                  dt.call(&dt.glIndexPointer)(type,stride,pointer);
+                  break;
+                case EDGE_FLAG:
+                  dt.call(&dt.glEdgeFlagPointer)(stride,pointer);
+                  break;
+                default:
+                  break;
+              }
+            }
+          }
+          else
+          {
+            GLuint index = static_cast<GLuint>(vaInt - 7);
+            if (enabled != to.enabled)
+            {
+              enabled = to.enabled;
+              enablei(dt,vaEnum[7][0], index, enabled);
+            }
+            if (buffer != to.buffer)
+            {
+              buffer = to.buffer;
+              dt.call(&dt.glBindBuffer)(GL_ARRAY_BUFFER,buffer);
+            }
+            if (size != to.size ||
+                type != to.type ||
+                stride != to.stride ||
+                pointer != to.pointer)
+            {
+              size = to.size;
+              type = to.type;
+              stride = to.stride;
+              pointer = to.pointer;
+              dt.call(&dt.glMultiTexCoordPointerEXT)(GL_TEXTURE0+index,size,type,stride,pointer);
+            }
+          }
+        }
+      }
+    }
+
     std::string toString(vaName va, const char *delim = "\n") const
     {
       string_list tmp;
 
       GLint vaInt = static_cast<GLint>(va);
       RegalAssert(vaInt >= 0 && vaInt < static_cast<GLint>(nNamedArrays));
-      if (vaInt >= 0)
+      if (vaInt >= 0 && vaInt < static_cast<GLint>(nNamedArrays))
       {
         if (vaInt < 7)
         {
@@ -318,11 +409,16 @@
     GLuint    divisor;  // GL_VERTEX_ATTRIB_ARRAY_DIVISOR
 
     inline VertexBufferBindPoint()
-    : buffer(0)
-    , offset(0)
-    , stride(0)
-    , divisor(0)
     {
+      Reset();
+    }
+
+    inline void Reset()
+    {
+      buffer = 0;
+      offset = 0;
+      stride = 16;
+      divisor = 0;
     }
 
     inline VertexBufferBindPoint &swap(VertexBufferBindPoint &other)
@@ -358,6 +454,28 @@
       return *this;
     }
 
+    void transition(DispatchTableGL &dt, VertexBufferBindPoint &to, GLuint index)
+    {
+      RegalAssert(index < REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS);
+      if (index < REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS)
+      {
+        if (buffer != to.buffer ||
+            offset != to.offset ||
+            stride != to.stride)
+        {
+          buffer = to.buffer;
+          offset = to.offset;
+          stride = to.stride;
+          dt.call(&dt.glBindVertexBuffer)(index,buffer,offset,stride);
+        }
+        if (divisor != to.divisor)
+        {
+          divisor = to.divisor;
+          dt.call(&dt.glVertexBindingDivisor)(index,divisor);
+        }
+      }
+    }
+
     std::string toString(GLuint index, const char *delim = "\n") const
     {
       string_list tmp;
@@ -374,7 +492,7 @@
   struct GenericVertexArray
   {
     GLboolean  enabled;         // GL_VERTEX_ATTRIB_ARRAY_ENABLED
-    GLint      size;            // GL_VERTEX_ATTRIB_ARRAY_SIZE
+    GLuint     size;            // GL_VERTEX_ATTRIB_ARRAY_SIZE
     GLenum     type;            // GL_VERTEX_ATTRIB_ARRAY_TYPE
     GLuint     relativeOffset;  // GL_VERTEX_ATTRIB_RELATIVE_OFFSET
     GLboolean  normalized;      // GL_VERTEX_ATTRIB_ARRAY_NORMALIZED
@@ -383,15 +501,20 @@
     GLuint     bindingIndex;    // GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING
 
     inline GenericVertexArray()
-    : enabled(GL_FALSE)
-    , size(4)
-    , type(GL_FLOAT)
-    , relativeOffset(0)
-    , normalized(GL_FALSE)
-    , isInteger(GL_FALSE)
-    , isLong(GL_FALSE)
-    , bindingIndex(0)
     {
+      Reset(0);
+    }
+
+    inline void Reset(GLuint index)
+    {
+      enabled = GL_FALSE;
+      size = 4;
+      type = GL_FLOAT;
+      relativeOffset = 0;
+      normalized = GL_FALSE;
+      isInteger = GL_FALSE;
+      isLong = GL_FALSE;
+      bindingIndex = index;
     }
 
     inline GenericVertexArray &swap(GenericVertexArray &other)
@@ -416,7 +539,7 @@
 
         dt.call(&dt.glGetVertexAttribiv)(index,GL_VERTEX_ATTRIB_ARRAY_ENABLED,&val);
         enabled = static_cast<GLboolean>(val);
-        dt.call(&dt.glGetVertexAttribiv)(index,GL_VERTEX_ATTRIB_ARRAY_SIZE,&size);
+        dt.call(&dt.glGetVertexAttribiv)(index,GL_VERTEX_ATTRIB_ARRAY_SIZE,reinterpret_cast<GLint*>(&size));
         dt.call(&dt.glGetVertexAttribiv)(index,GL_VERTEX_ATTRIB_ARRAY_TYPE,reinterpret_cast<GLint*>(&type));
         dt.call(&dt.glGetVertexAttribiv)(index,GL_VERTEX_ATTRIB_RELATIVE_OFFSET,reinterpret_cast<GLint*>(&relativeOffset));
         dt.call(&dt.glGetVertexAttribiv)(index,GL_VERTEX_ATTRIB_ARRAY_NORMALIZED,&val);
@@ -450,6 +573,48 @@
       return *this;
     }
 
+    void transition(DispatchTableGL &dt, GenericVertexArray &to, GLuint index)
+    {
+      RegalAssert(index < REGAL_EMU_MAX_VERTEX_ATTRIBS);
+      if (index < REGAL_EMU_MAX_VERTEX_ATTRIBS)
+      {
+        if (enabled != to.enabled)
+        {
+          enabled = to.enabled;
+          if (enabled)
+            dt.call(&dt.glEnableVertexAttribArray)(index);
+          else
+            dt.call(&dt.glDisableVertexAttribArray)(index);
+        }
+        if (isInteger != to.isInteger ||
+            isLong != to.isLong ||
+            normalized != to.normalized ||
+            size != to.size ||
+            type != to.type ||
+            relativeOffset != to.relativeOffset)
+        {
+          isInteger = to.isInteger;
+          isLong = to.isLong;
+          normalized = to.normalized;
+          size = to.size;
+          type = to.type;
+          relativeOffset = to.relativeOffset;
+
+          if (isInteger)
+            dt.call(&dt.glVertexAttribIFormat)(index,size,type,relativeOffset);
+          else if (isLong)
+            dt.call(&dt.glVertexAttribLFormat)(index,size,type,relativeOffset);
+          else
+            dt.call(&dt.glVertexAttribFormat)(index,size,type,normalized,relativeOffset);
+        }
+        if (bindingIndex != to.bindingIndex)
+        {
+          bindingIndex = to.bindingIndex;
+          dt.call(&dt.glVertexAttribBinding)(index,bindingIndex);
+        }
+      }
+    }
+
     std::string toString(GLuint index, const char *delim = "\n") const
     {
       string_list tmp;
@@ -493,16 +658,22 @@
     GLuint     vertexArrayBinding;               // GL_VERTEX_ARRAY_BINDING
 
     inline VertexArray()
-    : elementArrayBufferBinding(0)
-    , clientActiveTexture(GL_TEXTURE0)
-    , primitiveRestartFixedIndex(GL_FALSE)
-    , primitiveRestart(GL_FALSE)
-    , primitiveRestartIndex(0)
-    , arrayBufferBinding(0)
-    , vertexArrayBinding(0)
     {
+      Reset();
+    }
+
+    void Reset()
+    {
+      elementArrayBufferBinding = 0;
+      clientActiveTexture = GL_TEXTURE0;
+      primitiveRestartFixedIndex = GL_FALSE;
+      primitiveRestart = GL_FALSE;
+      primitiveRestartIndex = 0;
+      arrayBufferBinding = 0;
+      vertexArrayBinding = 0;
+
       for (GLuint ii=0; ii<nNamedArrays; ii++)
-        named[ii]= NamedVertexArray();
+        named[ii].Reset();
 
       named[NORMAL].size = 3;
       named[FOG_COORD].size = 1;
@@ -512,13 +683,13 @@
       named[EDGE_FLAG].type = GL_BOOL;
 
       for (GLuint ii=0; ii<REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS; ii++)
-        bindings[ii] = VertexBufferBindPoint();
+        bindings[ii].Reset();
 
       for (GLuint ii=0; ii<REGAL_EMU_MAX_VERTEX_ATTRIBS; ii++)
-        generic[ii] = GenericVertexArray();
+        generic[ii].Reset(ii);
     }
 
-    inline VertexArray &swap(VertexArray &other)
+    VertexArray &swap(VertexArray &other)
     {
       for (GLuint ii=0; ii<nNamedArrays; ii++)
         named[ii].swap(other.named[ii]);
@@ -536,7 +707,7 @@
       return *this;
     }
 
-    inline VertexArray &get(DispatchTableGL &dt)
+    VertexArray &get(DispatchTableGL &dt)
     {
       dt.call(&dt.glGetIntegerv)(GL_VERTEX_ARRAY_BINDING,reinterpret_cast<GLint*>(&vertexArrayBinding));
       if (vertexArrayBinding)
@@ -558,26 +729,81 @@
       return *this;
     }
 
-    inline const VertexArray &set(DispatchTableGL &dt) const
+    const VertexArray &set(DispatchTableGL &dt, bool driverAllowsVertexAttributeArraysWithoutBoundBuffer) const
     {
       dt.call(&dt.glBindVertexArray)(0);
-      for (GLuint ii=0; ii<nNamedArrays; ii++)
-        named[ii].set(dt,static_cast<vaName>(ii));
+      for (GLint ii=nNamedArrays-1; ii>=0; ii--)
+        named[ii].set(dt,static_cast<vaName>(ii),driverAllowsVertexAttributeArraysWithoutBoundBuffer);
       for (GLuint ii=0; ii<REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS; ii++)
         bindings[ii].set(dt,ii);
-      for (GLuint ii=0; ii<REGAL_EMU_MAX_VERTEX_ATTRIBS; ii++)
+      for (GLint ii=REGAL_EMU_MAX_VERTEX_ATTRIBS-1; ii>=0; ii--)
         generic[ii].set(dt,ii);
       dt.call(&dt.glBindBuffer)(GL_ELEMENT_ARRAY_BUFFER,elementArrayBufferBinding);
       dt.call(&dt.glClientActiveTexture)(clientActiveTexture);
-      enable(dt,GL_PRIMITIVE_RESTART_FIXED_INDEX,primitiveRestartFixedIndex);
-      enable(dt,GL_PRIMITIVE_RESTART,primitiveRestart);
+      if (primitiveRestartFixedIndex)
+        dt.call(&dt.glEnable)(GL_PRIMITIVE_RESTART_FIXED_INDEX);
+      else
+        dt.call(&dt.glDisable)(GL_PRIMITIVE_RESTART_FIXED_INDEX);
+      if (primitiveRestart)
+        dt.call(&dt.glEnable)(GL_PRIMITIVE_RESTART);
+      else
+        dt.call(&dt.glDisable)(GL_PRIMITIVE_RESTART);
       dt.call(&dt.glPrimitiveRestartIndex)(primitiveRestartIndex);
       dt.call(&dt.glBindBuffer)(GL_ARRAY_BUFFER,arrayBufferBinding);
       dt.call(&dt.glBindVertexArray)(vertexArrayBinding);
       return *this;
     }
 
-    inline std::string toString(const char *delim = "\n") const
+    void transition(DispatchTableGL &dt, VertexArray &to, bool driverAllowsVertexAttributeArraysWithoutBoundBuffer)
+    {
+      GLuint tmpVertexArrayBinding = to.vertexArrayBinding;
+      if (vertexArrayBinding) {
+        vertexArrayBinding = 0;
+        dt.call(&dt.glBindVertexArray)(vertexArrayBinding);
+      }
+      for (GLint ii=nNamedArrays-1; ii>=0; ii--)
+        named[ii].transition(dt,to.named[ii],static_cast<vaName>(ii),driverAllowsVertexAttributeArraysWithoutBoundBuffer);
+      for (GLuint ii=0; ii<REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS; ii++)
+        bindings[ii].transition(dt,to.bindings[ii],ii);
+      for (GLint ii=REGAL_EMU_MAX_VERTEX_ATTRIBS-1; ii>=0; ii--)
+        generic[ii].transition(dt,to.generic[ii],ii);
+      if (elementArrayBufferBinding != to.elementArrayBufferBinding) {
+        elementArrayBufferBinding = to.elementArrayBufferBinding;
+        dt.call(&dt.glBindBuffer)(GL_ELEMENT_ARRAY_BUFFER,elementArrayBufferBinding);
+      }
+      if (clientActiveTexture != to.clientActiveTexture) {
+        clientActiveTexture = to.clientActiveTexture;
+        dt.call(&dt.glClientActiveTexture)(clientActiveTexture);
+      }
+      if (primitiveRestartFixedIndex != to.primitiveRestartFixedIndex) {
+        primitiveRestartFixedIndex = to.primitiveRestartFixedIndex;
+        if (primitiveRestartFixedIndex)
+          dt.call(&dt.glEnable)(GL_PRIMITIVE_RESTART_FIXED_INDEX);
+        else
+          dt.call(&dt.glDisable)(GL_PRIMITIVE_RESTART_FIXED_INDEX);
+      }
+      if (primitiveRestart != to.primitiveRestart) {
+        primitiveRestart = to.primitiveRestart;
+        if (primitiveRestart)
+          dt.call(&dt.glEnable)(GL_PRIMITIVE_RESTART);
+        else
+          dt.call(&dt.glDisable)(GL_PRIMITIVE_RESTART);
+      }
+      if (primitiveRestartIndex != to.primitiveRestartIndex) {
+        primitiveRestartIndex = to.primitiveRestartIndex;
+        dt.call(&dt.glPrimitiveRestartIndex)(primitiveRestartIndex);
+      }
+      if (arrayBufferBinding != to.arrayBufferBinding) {
+        arrayBufferBinding = to.arrayBufferBinding;
+        dt.call(&dt.glBindBuffer)(GL_ARRAY_BUFFER,arrayBufferBinding);
+      }
+      if (vertexArrayBinding != tmpVertexArrayBinding) {
+        vertexArrayBinding = tmpVertexArrayBinding;
+        dt.call(&dt.glBindVertexArray)(vertexArrayBinding);
+      }
+    }
+
+    std::string toString(const char *delim = "\n") const
     {
       string_list tmp;
       for (GLuint ii=0; ii<nNamedArrays; ii++)
@@ -589,8 +815,15 @@
 
       tmp << print_string("glBindBuffer(GL_ELEMENT_ARRAY_BUFFER",elementArrayBufferBinding,");",delim);
       tmp << print_string("glClientActiveTexture(",clientActiveTexture,");",delim);
-      enableToString(tmp,primitiveRestartFixedIndex,"GL_PRIMITIVE_RESTART_FIXED_INDEX",delim);
-      enableToString(tmp,primitiveRestart,"GL_PRIMITIVE_RESTART",delim);
+
+      if (primitiveRestartFixedIndex)
+        tmp << print_string("glEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX);",delim);
+      else
+        tmp << print_string("glDisable(GL_PRIMITIVE_RESTART_FIXED_INDEX);",delim);
+      if (primitiveRestart)
+        tmp << print_string("glEnable(GL_PRIMITIVE_RESTART);",delim);
+      else
+        tmp << print_string("glDisable(GL_PRIMITIVE_RESTART);",delim);
       tmp << print_string("glPrimitiveRestartIndex(",primitiveRestartIndex,");",delim);
       tmp << print_string("glBindBuffer(GL_ARRAY_BUFFER,",arrayBufferBinding,");",delim);
       tmp << print_string("glBindVertexArray(",vertexArrayBinding,");",delim);
@@ -674,7 +907,8 @@
           named[EDGE_FLAG].enabled = enabled;
           break;
         case GL_TEXTURE_COORD_ARRAY:
-          named[index+7].enabled = enabled;
+          if (index < REGAL_EMU_MAX_TEXTURE_COORDS)
+            named[index+7].enabled = enabled;
           break;
         default:
           break;
@@ -683,12 +917,18 @@
 
     inline void glEnableClientState(GLenum cap)
     {
-      SetEnableClientStatei(vertexArrayBinding, cap, 0, GL_TRUE);
+      if (cap == GL_TEXTURE_COORD_ARRAY)
+        SetEnableClientStatei(vertexArrayBinding, cap, clientActiveTexture - GL_TEXTURE0, GL_TRUE);
+      else
+        SetEnableClientStatei(vertexArrayBinding, cap, 0, GL_TRUE);
     }
 
     inline void glDisableClientState(GLenum cap)
     {
-      SetEnableClientStatei(vertexArrayBinding, cap, 0, GL_FALSE);
+      if (cap == GL_TEXTURE_COORD_ARRAY)
+        SetEnableClientStatei(vertexArrayBinding, cap, clientActiveTexture - GL_TEXTURE0, GL_FALSE);
+      else
+        SetEnableClientStatei(vertexArrayBinding, cap, 0, GL_FALSE);
     }
 
     inline void glEnableClientStateiEXT(GLenum cap, GLuint index)
@@ -727,6 +967,20 @@
       }
     }
 
+    void glDeleteBuffers( GLsizei n, const GLuint *buffers )
+    {
+      for (GLsizei ii=0; ii<n; ii++)
+      {
+        if (buffers[ii] == arrayBufferBinding)
+          arrayBufferBinding = 0;
+        if (buffers[ii] == elementArrayBufferBinding)
+          elementArrayBufferBinding = 0;
+        for (GLsizei jj=0; jj<REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS; jj++)
+          if (buffers[ii] == bindings[jj].buffer)
+            bindings[jj].buffer = 0;
+      }
+    }
+
     inline void glVertexPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)
     {
       if (!vertexArrayBinding)
@@ -824,19 +1078,25 @@
 
     inline void glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid * pointer)
     {
-      if (!vertexArrayBinding)
+      if (!vertexArrayBinding &&
+          index < REGAL_EMU_MAX_VERTEX_ATTRIBS &&
+          index < REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS)
         glVertexArrayVertexAttribOffsetEXT(vertexArrayBinding, arrayBufferBinding, index, size, type, normalized, stride, ((char *)pointer - (char *)NULL));
     }
 
     inline void glVertexAttribIPointer(GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid * pointer)
     {
-      if (!vertexArrayBinding)
+      if (!vertexArrayBinding &&
+          index < REGAL_EMU_MAX_VERTEX_ATTRIBS &&
+          index < REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS)
         glVertexArrayVertexAttribIOffsetEXT(vertexArrayBinding, arrayBufferBinding, index, size, type, stride, ((char *)pointer - (char *)NULL));
     }
 
     void glVertexAttribLPointer(GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid * pointer)
     {
-      if (!vertexArrayBinding)
+      if (!vertexArrayBinding &&
+          index < REGAL_EMU_MAX_VERTEX_ATTRIBS &&
+          index < REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS)
       {
         glVertexAttribLFormat(index, size, type, 0);
         glVertexAttribBinding(index, index);
@@ -845,19 +1105,39 @@
       }
     }
 
+    void glBindVertexBuffers( GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizei *strides )
+    {
+      if (!vertexArrayBinding && ((first + count) >= first) && (first + count) <= REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS)
+      {
+        if (buffers)
+          for (GLsizei ii = 0; ii < count; ii++)
+          {
+            bindings[first].buffer = buffers[ii];
+            bindings[first].offset = offsets[ii];
+            bindings[first].stride = strides[ii];
+            first++;
+          }
+        else
+          for (GLsizei ii = 0; ii < count; ii++)
+          {
+            bindings[first].buffer = 0;
+            bindings[first].offset = 0;
+            bindings[first].stride = 16;
+            first++;
+          }
+      }
+    }
+
     void glBindVertexBuffer(GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride)
     {
-      if (!vertexArrayBinding)
-      {
-        bindings[bindingindex].buffer = buffer;
-        bindings[bindingindex].offset = offset;
-        bindings[bindingindex].stride = stride;
-      }
+      glBindVertexBuffers( bindingindex, 1, &buffer, &offset, &stride );
     }
 
     inline void glVertexAttribDivisor(GLuint index, GLuint divisor)
     {
-      if (!vertexArrayBinding)
+      if (!vertexArrayBinding &&
+          index < REGAL_EMU_MAX_VERTEX_ATTRIBS &&
+          index < REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS)
       {
         generic[index].bindingIndex = index;
         bindings[index].divisor = divisor;
@@ -866,31 +1146,31 @@
 
     inline void glVertexBindingDivisor(GLuint bindingindex, GLuint divisor)
     {
-      if (!vertexArrayBinding)
+      if (!vertexArrayBinding && bindingindex < REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS)
         bindings[bindingindex].divisor = divisor;
     }
 
     inline void glEnableVertexAttribArray(GLuint index)
     {
-      if (!vertexArrayBinding)
+      if (!vertexArrayBinding && index < REGAL_EMU_MAX_VERTEX_ATTRIBS)
         generic[index].enabled = GL_TRUE;
     }
 
     inline void glDisableVertexAttribArray(GLuint index)
     {
-      if (!vertexArrayBinding)
+      if (!vertexArrayBinding && index < REGAL_EMU_MAX_VERTEX_ATTRIBS)
         generic[index].enabled = GL_FALSE;
     }
 
     inline void glVertexAttribBinding(GLuint attribindex, GLuint bindingindex)
     {
-      if (!vertexArrayBinding)
+      if (!vertexArrayBinding && attribindex < REGAL_EMU_MAX_VERTEX_ATTRIBS)
         generic[attribindex].bindingIndex = bindingindex;
     }
 
     inline void glVertexAttribIFormat(GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset)
     {
-      if (!vertexArrayBinding)
+      if (!vertexArrayBinding && attribindex < REGAL_EMU_MAX_VERTEX_ATTRIBS)
       {
         generic[attribindex].size = size;
         generic[attribindex].type = type;
@@ -903,7 +1183,7 @@
 
     inline void glVertexAttribLFormat(GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset)
     {
-      if (!vertexArrayBinding)
+      if (!vertexArrayBinding && attribindex < REGAL_EMU_MAX_VERTEX_ATTRIBS)
       {
         generic[attribindex].size = size;
         generic[attribindex].type = type;
@@ -916,7 +1196,7 @@
 
     inline void glVertexAttribFormat(GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset)
     {
-      if (!vertexArrayBinding)
+      if (!vertexArrayBinding && attribindex < REGAL_EMU_MAX_VERTEX_ATTRIBS)
       {
         generic[attribindex].size = size;
         generic[attribindex].type = type;
@@ -929,7 +1209,8 @@
 
     inline void glClientActiveTexture(GLenum texture)
     {
-      clientActiveTexture = texture;
+      if ( (texture - GL_TEXTURE0) < REGAL_EMU_MAX_TEXTURE_COORDS)
+        clientActiveTexture = texture;
     }
 
     inline void glPrimitiveRestartIndex(GLuint index)
@@ -942,27 +1223,44 @@
       vertexArrayBinding = array;
     }
 
+    inline void glDeleteVertexArrays( GLsizei n, const GLuint *arrays )
+    {
+      for (GLsizei ii=0; ii<n; ii++)
+        if (arrays[ii] == vertexArrayBinding)
+          vertexArrayBinding = 0;
+    }
+
     inline void glEnableVertexArrayEXT(GLuint vaobj, GLenum array)
     {
       if (!vaobj)
-        SetEnableClientStatei(vaobj, array, 0, GL_TRUE);
+      {
+        if (array == GL_TEXTURE_COORD_ARRAY)
+          SetEnableClientStatei(vaobj, array, clientActiveTexture - GL_TEXTURE0, GL_TRUE);
+        else
+          SetEnableClientStatei(vaobj, array, 0, GL_TRUE);
+      }
     }
 
     inline void glDisableVertexArrayEXT(GLuint vaobj, GLenum array)
     {
       if (!vaobj)
-        SetEnableClientStatei(vaobj, array, 0, GL_FALSE);
+      {
+        if (array == GL_TEXTURE_COORD_ARRAY)
+          SetEnableClientStatei(vaobj, array, clientActiveTexture - GL_TEXTURE0, GL_FALSE);
+        else
+          SetEnableClientStatei(vaobj, array, 0, GL_FALSE);
+      }
     }
 
     inline void glEnableVertexArrayAttribEXT(GLuint vaobj, GLuint index)
     {
-      if (!vaobj)
+      if (!vaobj && index < REGAL_EMU_MAX_VERTEX_ATTRIBS)
         generic[index].enabled = GL_TRUE;
     }
 
     inline void glDisableVertexArrayAttribEXT(GLuint vaobj, GLuint index)
     {
-      if (!vaobj)
+      if (!vaobj && index < REGAL_EMU_MAX_VERTEX_ATTRIBS)
         generic[index].enabled = GL_FALSE;
     }
 
@@ -983,6 +1281,7 @@
       if (!vaobj)
       {
         named[NORMAL].buffer = buffer;
+        named[NORMAL].size = 3;
         named[NORMAL].type = type;
         named[NORMAL].stride = stride;
         named[NORMAL].pointer = reinterpret_cast<const GLvoid *>(offset);
@@ -1018,6 +1317,7 @@
       if (!vaobj)
       {
         named[INDEX].buffer = buffer;
+        named[INDEX].size = 1;
         named[INDEX].type = type;
         named[INDEX].stride = stride;
         named[INDEX].pointer = reinterpret_cast<const GLvoid *>(offset);
@@ -1029,6 +1329,8 @@
       if (!vaobj)
       {
         named[EDGE_FLAG].buffer = buffer;
+        named[EDGE_FLAG].size = 1;
+        named[EDGE_FLAG].type = GL_BOOL;
         named[EDGE_FLAG].stride = stride;
         named[EDGE_FLAG].pointer = reinterpret_cast<const GLvoid *>(offset);
       }
@@ -1039,22 +1341,27 @@
       if (!vaobj)
       {
         named[FOG_COORD].buffer = buffer;
+        named[FOG_COORD].size = 1;
         named[FOG_COORD].type = type;
         named[FOG_COORD].stride = stride;
         named[FOG_COORD].pointer = reinterpret_cast<const GLvoid *>(offset);
       }
     }
 
-    void glVertexArrayMultiTexCoordOffsetEXT(GLuint vaobj, GLuint buffer, GLenum index, GLint size, GLenum type, GLsizei stride, GLintptr offset)
+    void glVertexArrayMultiTexCoordOffsetEXT(GLuint vaobj, GLuint buffer, GLenum texture, GLint size, GLenum type, GLsizei stride, GLintptr offset)
     {
       if (!vaobj)
       {
-        GLuint ii = 7 + (index - GL_TEXTURE0);
-        named[ii].buffer = buffer;
-        named[ii].size = size;
-        named[ii].type = type;
-        named[ii].stride = stride;
-        named[ii].pointer = reinterpret_cast<const GLvoid *>(offset);
+        GLuint index = texture - GL_TEXTURE0;
+        if (index < REGAL_EMU_MAX_TEXTURE_COORDS && index <= texture)
+        {
+          GLuint ii = 7 + index;
+          named[ii].buffer = buffer;
+          named[ii].size = size;
+          named[ii].type = type;
+          named[ii].stride = stride;
+          named[ii].pointer = reinterpret_cast<const GLvoid *>(offset);
+        }
       }
     }
 
@@ -1067,10 +1374,13 @@
     {
       if (!vaobj)
       {
+        GLuint originalVABinding = vertexArrayBinding;
+        vertexArrayBinding = 0;
         glVertexAttribFormat(index, size, type, normalized, 0);
         glVertexAttribBinding(index, index);
         GLsizei effectiveStride = computeEffectiveStride(stride, size, type);
-        glBindVertexBuffer(index, buffer, offset, effectiveStride);
+        glBindVertexBuffers(index, 1, &buffer, &offset, &effectiveStride);
+        vertexArrayBinding = originalVABinding;
       }
     }
 
@@ -1078,10 +1388,13 @@
     {
       if (!vaobj)
       {
+        GLuint originalVABinding = vertexArrayBinding;
+        vertexArrayBinding = 0;
         glVertexAttribIFormat(index, size, type, 0);
         glVertexAttribBinding(index, index);
         GLsizei effectiveStride = computeEffectiveStride(stride, size, type);
-        glBindVertexBuffer(index, buffer, offset, effectiveStride);
+        glBindVertexBuffers(index, 1, &buffer, &offset, &effectiveStride);
+        vertexArrayBinding = originalVABinding;
       }
     }
 
@@ -1102,8 +1415,8 @@
       GLsizei   pc, pn, pv;
       GLsizei   s;
 
-      const int f = sizeof(GL_FLOAT);
-      const int c = 4 * sizeof(GL_UNSIGNED_BYTE);
+      const int f = sizeof(GLfloat);
+      const int c = int( float( 4 * sizeof(GLubyte) ) / float(f) + float(0.5) ) * f;
 
       switch(format)
       {
@@ -1352,29 +1665,34 @@
     GLint      packSkipRows;              // GL_PACK_SKIP_ROWS
     GLint      packSkipPixels;            // GL_PACK_SKIP_PIXELS
     GLint      packAlignment;             // GL_PACK_ALIGNMENT
-    GLint      pixelUnpackBufferBinding;  // GL_PIXEL_UNPACK_BUFFER_BINDING
-    GLint      pixelPackBufferBinding;    // GL_PIXEL_PACK_BUFFER_BINDING
+    GLuint     pixelUnpackBufferBinding;  // GL_PIXEL_UNPACK_BUFFER_BINDING
+    GLuint     pixelPackBufferBinding;    // GL_PIXEL_PACK_BUFFER_BINDING
 
     inline PixelStore()
-      : unpackSwapBytes(GL_FALSE)
-      , unpackLsbFirst(GL_FALSE)
-      , unpackImageHeight(0)
-      , unpackSkipImages(0)
-      , unpackRowLength(0)
-      , unpackSkipRows(0)
-      , unpackSkipPixels(0)
-      , unpackAlignment(4)
-      , packSwapBytes(GL_FALSE)
-      , packLsbFirst(GL_FALSE)
-      , packImageHeight(0)
-      , packSkipImages(0)
-      , packRowLength(0)
-      , packSkipRows(0)
-      , packSkipPixels(0)
-      , packAlignment(4)
-      , pixelUnpackBufferBinding(0)
-      , pixelPackBufferBinding(0)
     {
+      Reset();
+    }
+
+    inline void Reset()
+    {
+      unpackSwapBytes = GL_FALSE;
+      unpackLsbFirst = GL_FALSE;
+      unpackImageHeight = 0;
+      unpackSkipImages = 0;
+      unpackRowLength = 0;
+      unpackSkipRows = 0;
+      unpackSkipPixels = 0;
+      unpackAlignment = 4;
+      packSwapBytes = GL_FALSE;
+      packLsbFirst = GL_FALSE;
+      packImageHeight = 0;
+      packSkipImages = 0;
+      packRowLength = 0;
+      packSkipRows = 0;
+      packSkipPixels = 0;
+      packAlignment = 4;
+      pixelUnpackBufferBinding = 0;
+      pixelPackBufferBinding = 0;
     }
 
     inline PixelStore &swap(PixelStore &other)
@@ -1400,7 +1718,7 @@
       return *this;
     }
 
-    inline PixelStore &get(DispatchTableGL &dt)
+    PixelStore &get(DispatchTableGL &dt)
     {
       dt.call(&dt.glGetBooleanv)(GL_UNPACK_SWAP_BYTES,&unpackSwapBytes);
       dt.call(&dt.glGetBooleanv)(GL_UNPACK_LSB_FIRST,&unpackLsbFirst);
@@ -1418,12 +1736,12 @@
       dt.call(&dt.glGetIntegerv)(GL_PACK_SKIP_ROWS,&packSkipRows);
       dt.call(&dt.glGetIntegerv)(GL_PACK_SKIP_PIXELS,&packSkipPixels);
       dt.call(&dt.glGetIntegerv)(GL_PACK_ALIGNMENT,&packAlignment);
-      dt.call(&dt.glGetIntegerv)(GL_PIXEL_UNPACK_BUFFER_BINDING,&pixelUnpackBufferBinding);
-      dt.call(&dt.glGetIntegerv)(GL_PIXEL_PACK_BUFFER_BINDING,&pixelPackBufferBinding);
+      dt.call(&dt.glGetIntegerv)(GL_PIXEL_UNPACK_BUFFER_BINDING,reinterpret_cast<GLint*>(&pixelUnpackBufferBinding));
+      dt.call(&dt.glGetIntegerv)(GL_PIXEL_PACK_BUFFER_BINDING,reinterpret_cast<GLint*>(&pixelPackBufferBinding));
       return *this;
     }
 
-    inline const PixelStore &set(DispatchTableGL &dt) const
+    const PixelStore &set(DispatchTableGL &dt) const
     {
       dt.call(&dt.glPixelStorei)(GL_UNPACK_SWAP_BYTES,unpackSwapBytes);
       dt.call(&dt.glPixelStorei)(GL_UNPACK_LSB_FIRST,unpackLsbFirst);
@@ -1441,12 +1759,88 @@
       dt.call(&dt.glPixelStorei)(GL_PACK_SKIP_ROWS,packSkipRows);
       dt.call(&dt.glPixelStorei)(GL_PACK_SKIP_PIXELS,packSkipPixels);
       dt.call(&dt.glPixelStorei)(GL_PACK_ALIGNMENT,packAlignment);
-      dt.call(&dt.glBindBuffer)(GL_PIXEL_UNPACK_BUFFER_BINDING,pixelUnpackBufferBinding);
-      dt.call(&dt.glBindBuffer)(GL_PIXEL_PACK_BUFFER_BINDING,pixelPackBufferBinding);
+      dt.call(&dt.glBindBuffer)(GL_PIXEL_UNPACK_BUFFER,pixelUnpackBufferBinding);
+      dt.call(&dt.glBindBuffer)(GL_PIXEL_PACK_BUFFER,pixelPackBufferBinding);
       return *this;
     }
 
-    inline std::string toString(const char *delim = "\n") const
+    void transition(DispatchTableGL &dt, PixelStore &to)
+    {
+      if (unpackSwapBytes != to.unpackSwapBytes) {
+        unpackSwapBytes = to.unpackSwapBytes;
+        dt.call(&dt.glPixelStorei)(GL_UNPACK_SWAP_BYTES,unpackSwapBytes);
+      }
+      if (unpackLsbFirst != to.unpackLsbFirst) {
+        unpackLsbFirst = to.unpackLsbFirst;
+        dt.call(&dt.glPixelStorei)(GL_UNPACK_LSB_FIRST,unpackLsbFirst);
+      }
+      if (unpackImageHeight != to.unpackImageHeight) {
+        unpackImageHeight = to.unpackImageHeight;
+        dt.call(&dt.glPixelStorei)(GL_UNPACK_IMAGE_HEIGHT,unpackImageHeight);
+      }
+      if (unpackSkipImages != to.unpackSkipImages) {
+        unpackSkipImages = to.unpackSkipImages;
+        dt.call(&dt.glPixelStorei)(GL_UNPACK_SKIP_IMAGES,unpackSkipImages);
+      }
+      if (unpackRowLength != to.unpackRowLength) {
+        unpackRowLength = to.unpackRowLength;
+        dt.call(&dt.glPixelStorei)(GL_UNPACK_ROW_LENGTH,unpackRowLength);
+      }
+      if (unpackSkipRows != to.unpackSkipRows) {
+        unpackSkipRows = to.unpackSkipRows;
+        dt.call(&dt.glPixelStorei)(GL_UNPACK_SKIP_ROWS,unpackSkipRows);
+      }
+      if (unpackSkipPixels != to.unpackSkipPixels) {
+        unpackSkipPixels = to.unpackSkipPixels;
+        dt.call(&dt.glPixelStorei)(GL_UNPACK_SKIP_PIXELS,unpackSkipPixels);
+      }
+      if (unpackAlignment != to.unpackAlignment) {
+        unpackAlignment = to.unpackAlignment;
+        dt.call(&dt.glPixelStorei)(GL_UNPACK_ALIGNMENT,unpackAlignment);
+      }
+      if (packSwapBytes != to.packSwapBytes) {
+        packSwapBytes = to.packSwapBytes;
+        dt.call(&dt.glPixelStorei)(GL_PACK_SWAP_BYTES,packSwapBytes);
+      }
+      if (packLsbFirst != to.packLsbFirst) {
+        packLsbFirst = to.packLsbFirst;
+        dt.call(&dt.glPixelStorei)(GL_PACK_LSB_FIRST,packLsbFirst);
+      }
+      if (packImageHeight != to.packImageHeight) {
+        packImageHeight = to.packImageHeight;
+        dt.call(&dt.glPixelStorei)(GL_PACK_IMAGE_HEIGHT,packImageHeight);
+      }
+      if (packSkipImages != to.packSkipImages) {
+        packSkipImages = to.packSkipImages;
+        dt.call(&dt.glPixelStorei)(GL_PACK_SKIP_IMAGES,packSkipImages);
+      }
+      if (packRowLength != to.packRowLength) {
+        packRowLength = to.packRowLength;
+        dt.call(&dt.glPixelStorei)(GL_PACK_ROW_LENGTH,packRowLength);
+      }
+      if (packSkipRows != to.packSkipRows) {
+        packSkipRows = to.packSkipRows;
+        dt.call(&dt.glPixelStorei)(GL_PACK_SKIP_ROWS,packSkipRows);
+      }
+      if (packSkipPixels != to.packSkipPixels) {
+        packSkipPixels = to.packSkipPixels;
+        dt.call(&dt.glPixelStorei)(GL_PACK_SKIP_PIXELS,packSkipPixels);
+      }
+      if (packAlignment != to.packAlignment) {
+        packAlignment = to.packAlignment;
+        dt.call(&dt.glPixelStorei)(GL_PACK_ALIGNMENT,packAlignment);
+      }
+      if (pixelUnpackBufferBinding != to.pixelUnpackBufferBinding) {
+        pixelUnpackBufferBinding = to.pixelUnpackBufferBinding;
+        dt.call(&dt.glBindBuffer)(GL_PIXEL_UNPACK_BUFFER,pixelUnpackBufferBinding);
+      }
+      if (pixelPackBufferBinding != to.pixelPackBufferBinding) {
+        pixelPackBufferBinding = to.pixelPackBufferBinding;
+        dt.call(&dt.glBindBuffer)(GL_PIXEL_PACK_BUFFER,pixelPackBufferBinding);
+      }
+    }
+
+    std::string toString(const char *delim = "\n") const
     {
       string_list tmp;
       tmp << print_string("glPixelStorei(GL_UNPACK_SWAP_BYTES,",unpackSwapBytes,");",delim);
@@ -1465,8 +1859,8 @@
       tmp << print_string("glPixelStorei(GL_PACK_SKIP_ROWS,",packSkipRows,");",delim);
       tmp << print_string("glPixelStorei(GL_PACK_SKIP_PIXELS,",packSkipPixels,");",delim);
       tmp << print_string("glPixelStorei(GL_PACK_ALIGNMENT,",packAlignment,");",delim);
-      tmp << print_string("glBindBuffer(GL_PIXEL_UNPACK_BUFFER_BINDING,",pixelUnpackBufferBinding,");",delim);
-      tmp << print_string("glBindBuffer(GL_PIXEL_PACK_BUFFER_BINDING,",pixelPackBufferBinding,");",delim);
+      tmp << print_string("glBindBuffer(GL_PIXEL_UNPACK_BUFFER,",pixelUnpackBufferBinding,");",delim);
+      tmp << print_string("glBindBuffer(GL_PIXEL_PACK_BUFFER,",pixelPackBufferBinding,");",delim);
       return tmp;
     }
 
@@ -1474,22 +1868,22 @@
     {
       switch (pname)
       {
-        case GL_UNPACK_SWAP_BYTES:   unpackSwapBytes   = param; break;
-        case GL_UNPACK_LSB_FIRST:    unpackLsbFirst    = param; break;
-        case GL_UNPACK_IMAGE_HEIGHT: unpackImageHeight = param; break;
-        case GL_UNPACK_SKIP_IMAGES:  unpackSkipImages  = param; break;
-        case GL_UNPACK_ROW_LENGTH:   unpackRowLength   = param; break;
-        case GL_UNPACK_SKIP_ROWS:    unpackSkipRows    = param; break;
-        case GL_UNPACK_SKIP_PIXELS:  unpackSkipPixels  = param; break;
-        case GL_UNPACK_ALIGNMENT:    unpackAlignment   = param; break;
-        case GL_PACK_SWAP_BYTES:     packSwapBytes     = param; break;
-        case GL_PACK_LSB_FIRST:      packLsbFirst      = param; break;
-        case GL_PACK_IMAGE_HEIGHT:   packImageHeight   = param; break;
-        case GL_PACK_SKIP_IMAGES:    packSkipImages    = param; break;
-        case GL_PACK_ROW_LENGTH:     packRowLength     = param; break;
-        case GL_PACK_SKIP_ROWS:      packSkipRows      = param; break;
-        case GL_PACK_SKIP_PIXELS:    packSkipPixels    = param; break;
-        case GL_PACK_ALIGNMENT:      packAlignment     = param; break;
+        case GL_UNPACK_SWAP_BYTES:   unpackSwapBytes   = static_cast<GLboolean>(param != T(0)); break;
+        case GL_UNPACK_LSB_FIRST:    unpackLsbFirst    = static_cast<GLboolean>(param != T(0)); break;
+        case GL_UNPACK_IMAGE_HEIGHT: unpackImageHeight = static_cast<GLint>(param);             break;
+        case GL_UNPACK_SKIP_IMAGES:  unpackSkipImages  = static_cast<GLint>(param);             break;
+        case GL_UNPACK_ROW_LENGTH:   unpackRowLength   = static_cast<GLint>(param);             break;
+        case GL_UNPACK_SKIP_ROWS:    unpackSkipRows    = static_cast<GLint>(param);             break;
+        case GL_UNPACK_SKIP_PIXELS:  unpackSkipPixels  = static_cast<GLint>(param);             break;
+        case GL_UNPACK_ALIGNMENT:    unpackAlignment   = static_cast<GLint>(param);             break;
+        case GL_PACK_SWAP_BYTES:     packSwapBytes     = static_cast<GLboolean>(param != T(0)); break;
+        case GL_PACK_LSB_FIRST:      packLsbFirst      = static_cast<GLboolean>(param != T(0)); break;
+        case GL_PACK_IMAGE_HEIGHT:   packImageHeight   = static_cast<GLint>(param);             break;
+        case GL_PACK_SKIP_IMAGES:    packSkipImages    = static_cast<GLint>(param);             break;
+        case GL_PACK_ROW_LENGTH:     packRowLength     = static_cast<GLint>(param);             break;
+        case GL_PACK_SKIP_ROWS:      packSkipRows      = static_cast<GLint>(param);             break;
+        case GL_PACK_SKIP_PIXELS:    packSkipPixels    = static_cast<GLint>(param);             break;
+        case GL_PACK_ALIGNMENT:      packAlignment     = static_cast<GLint>(param);             break;
         default:
           break;
       }
@@ -1499,19 +1893,28 @@
     {
       switch (target)
       {
-        case GL_PIXEL_UNPACK_BUFFER_BINDING:
+        case GL_PIXEL_UNPACK_BUFFER:
           pixelUnpackBufferBinding = buffer;
           break;
-        case GL_PIXEL_PACK_BUFFER_BINDING:
+        case GL_PIXEL_PACK_BUFFER:
           pixelPackBufferBinding = buffer;
           break;
         default:
           break;
       }
     }
-  };
 
-}
+    void glDeleteBuffers( GLsizei n, const GLuint *buffers )
+    {
+      for (GLsizei ii=0; ii<n; ii++)
+      {
+        if (buffers[ii] == pixelUnpackBufferBinding)
+          pixelUnpackBufferBinding = 0;
+        if (buffers[ii] == pixelPackBufferBinding)
+          pixelPackBufferBinding = 0;
+      }
+    }
+  };
 
 }
 
diff --git a/src/regal/RegalDispatchEmu.cpp b/src/regal/RegalDispatchEmu.cpp
index 961e883..240f5ff 100644
--- a/src/regal/RegalDispatchEmu.cpp
+++ b/src/regal/RegalDispatchEmu.cpp
@@ -3157,7 +3157,7 @@
       {
         Push<int> pushLevel(_context->emuLevel);
         _context->emuLevel = 11;
-        _context->ppca->ShadowDisable( cap );
+        _context->ppca->glDisable( cap );
       }
       #endif
     case 11 :
@@ -3522,7 +3522,7 @@
       {
         Push<int> pushLevel(_context->emuLevel);
         _context->emuLevel = 11;
-        _context->ppca->ShadowEnable( cap );
+        _context->ppca->glEnable( cap );
       }
       #endif
     case 11 :
@@ -5174,8 +5174,10 @@
       {
         Push<int> pushLevel(_context->emuLevel);
         _context->emuLevel = 11;
-        if( ! _context->ppca->Get( _context, pname, params ) ) {
-          _context->dispatcher.emulation.glGetBooleanv( pname, params );
+        if ( ! _context->ppca->glGetv( _context, pname, params ) ) {
+          if (!_context->info->core && !_context->info->es1 && !_context->info->es2) {
+            _context->dispatcher.emulation.glGetBooleanv( pname, params );
+          }
         }
         return;
       }
@@ -5319,8 +5321,10 @@
       {
         Push<int> pushLevel(_context->emuLevel);
         _context->emuLevel = 11;
-        if( ! _context->ppca->Get( _context, pname, params ) ) {
-          _context->dispatcher.emulation.glGetDoublev( pname, params );
+        if ( ! _context->ppca->glGetv( _context, pname, params ) ) {
+          if (!_context->info->core && !_context->info->es1 && !_context->info->es2) {
+            _context->dispatcher.emulation.glGetDoublev( pname, params );
+          }
         }
         return;
       }
@@ -5487,8 +5491,10 @@
       {
         Push<int> pushLevel(_context->emuLevel);
         _context->emuLevel = 11;
-        if( ! _context->ppca->Get( _context, pname, params ) ) {
-          _context->dispatcher.emulation.glGetFloatv( pname, params );
+        if ( ! _context->ppca->glGetv( _context, pname, params ) ) {
+          if (!_context->info->core && !_context->info->es1 && !_context->info->es2) {
+            _context->dispatcher.emulation.glGetFloatv( pname, params );
+          }
         }
         return;
       }
@@ -5655,8 +5661,10 @@
       {
         Push<int> pushLevel(_context->emuLevel);
         _context->emuLevel = 11;
-        if( ! _context->ppca->Get( _context, pname, params ) ) {
-          _context->dispatcher.emulation.glGetIntegerv( pname, params );
+        if ( ! _context->ppca->glGetv( _context, pname, params ) ) {
+          if (!_context->info->core && !_context->info->es1 && !_context->info->es2) {
+            _context->dispatcher.emulation.glGetIntegerv( pname, params );
+          }
         }
         return;
       }
@@ -9984,7 +9992,7 @@
       {
         Push<int> pushLevel(_context->emuLevel);
         _context->emuLevel = 11;
-        _context->ppca->ShadowPixelStore( pname, param );
+        _context->ppca->glPixelStore( pname, param );
       }
       #endif
     case 11 :
@@ -10076,7 +10084,7 @@
       {
         Push<int> pushLevel(_context->emuLevel);
         _context->emuLevel = 11;
-        _context->ppca->ShadowPixelStore( pname, param );
+        _context->ppca->glPixelStore( pname, param );
       }
       #endif
     case 11 :
@@ -19136,7 +19144,7 @@
       {
         Push<int> pushLevel(_context->emuLevel);
         _context->emuLevel = 11;
-        _context->ppca->ShadowColorPointer( size, type, stride, pointer );
+        _context->ppca->glColorPointer( size, type, stride, pointer );
       }
       #endif
     case 11 :
@@ -19386,7 +19394,7 @@
       {
         Push<int> pushLevel(_context->emuLevel);
         _context->emuLevel = 11;
-        _context->ppca->ShadowDisableClientState( cap );
+        _context->ppca->glDisableClientState( cap );
       }
       #endif
     case 11 :
@@ -19621,7 +19629,7 @@
       {
         Push<int> pushLevel(_context->emuLevel);
         _context->emuLevel = 11;
-        _context->ppca->ShadowEdgeFlagPointer( stride, pointer );
+        _context->ppca->glEdgeFlagPointer( stride, pointer );
       }
       #endif
     case 11 :
@@ -19699,7 +19707,7 @@
       {
         Push<int> pushLevel(_context->emuLevel);
         _context->emuLevel = 11;
-        _context->ppca->ShadowEnableClientState( cap );
+        _context->ppca->glEnableClientState( cap );
       }
       #endif
     case 11 :
@@ -19900,7 +19908,7 @@
       {
         Push<int> pushLevel(_context->emuLevel);
         _context->emuLevel = 11;
-        _context->ppca->ShadowIndexPointer( type, stride, pointer );
+        _context->ppca->glIndexPointer( type, stride, pointer );
       }
       #endif
     case 11 :
@@ -19943,7 +19951,7 @@
       {
         Push<int> pushLevel(_context->emuLevel);
         _context->emuLevel = 11;
-        _context->ppca->ShadowInterleavedArrays( format, stride, pointer );
+        _context->ppca->glInterleavedArrays( format, stride, pointer );
       }
       #endif
     case 11 :
@@ -20069,7 +20077,7 @@
       {
         Push<int> pushLevel(_context->emuLevel);
         _context->emuLevel = 11;
-        _context->ppca->ShadowNormalPointer( type, stride, pointer );
+        _context->ppca->glNormalPointer( type, stride, pointer );
       }
       #endif
     case 11 :
@@ -20218,7 +20226,7 @@
       {
         Push<int> pushLevel(_context->emuLevel);
         _context->emuLevel = 11;
-        _context->ppca->PopClientAttrib( _context );
+        _context->ppca->glPopClientAttrib( _context );
         return;
       }
       #endif
@@ -20268,7 +20276,7 @@
       {
         Push<int> pushLevel(_context->emuLevel);
         _context->emuLevel = 11;
-        _context->ppca->PushClientAttrib( _context, mask );
+        _context->ppca->glPushClientAttrib( _context, mask );
         return;
       }
       #endif
@@ -20303,7 +20311,7 @@
       {
         Push<int> pushLevel(_context->emuLevel);
         _context->emuLevel = 11;
-        _context->ppca->ShadowTexCoordPointer( size, type, stride, pointer );
+        _context->ppca->glTexCoordPointer( size, type, stride, pointer );
       }
       #endif
     case 11 :
@@ -20523,7 +20531,7 @@
       {
         Push<int> pushLevel(_context->emuLevel);
         _context->emuLevel = 11;
-        _context->ppca->ShadowVertexPointer( size, type, stride, pointer );
+        _context->ppca->glVertexPointer( size, type, stride, pointer );
       }
       #endif
     case 11 :
@@ -20996,7 +21004,7 @@
       {
         Push<int> pushLevel(_context->emuLevel);
         _context->emuLevel = 11;
-        _context->ppca->ShadowClientActiveTexture( texture );
+        _context->ppca->glClientActiveTexture( texture );
       }
       #endif
     case 11 :
@@ -23560,7 +23568,7 @@
       {
         Push<int> pushLevel(_context->emuLevel);
         _context->emuLevel = 11;
-        _context->ppca->ShadowFogCoordPointer( type, stride, pointer );
+        _context->ppca->glFogCoordPointer( type, stride, pointer );
       }
       #endif
     case 11 :
@@ -24898,7 +24906,7 @@
       {
         Push<int> pushLevel(_context->emuLevel);
         _context->emuLevel = 11;
-        _context->ppca->ShadowSecondaryColorPointer( size, type, stride, pointer );
+        _context->ppca->glSecondaryColorPointer( size, type, stride, pointer );
       }
       #endif
     case 11 :
@@ -26319,7 +26327,7 @@
       {
         Push<int> pushLevel(_context->emuLevel);
         _context->emuLevel = 11;
-        _context->ppca->ShadowBindBuffer( target, buffer );
+        _context->ppca->glBindBuffer( target, buffer );
       }
       #endif
     case 11 :
@@ -26510,7 +26518,7 @@
       {
         Push<int> pushLevel(_context->emuLevel);
         _context->emuLevel = 11;
-        _context->ppca->ShadowDeleteBuffers( n, buffers );
+        _context->ppca->glDeleteBuffers( n, buffers );
       }
       #endif
     case 11 :
@@ -26990,7 +26998,7 @@
       {
         Push<int> pushLevel(_context->emuLevel);
         _context->emuLevel = 11;
-        _context->ppca->ShadowDisableVertexAttribArray( index );
+        _context->ppca->glDisableVertexAttribArray( index );
       }
       #endif
     case 11 :
@@ -27182,7 +27190,7 @@
       {
         Push<int> pushLevel(_context->emuLevel);
         _context->emuLevel = 11;
-        _context->ppca->ShadowEnableVertexAttribArray( index );
+        _context->ppca->glEnableVertexAttribArray( index );
       }
       #endif
     case 11 :
@@ -30718,6 +30726,14 @@
     case 14 :
     case 13 :
     case 12 :
+      #if REGAL_EMU_PPCA
+      if (_context->ppca)
+      {
+        Push<int> pushLevel(_context->emuLevel);
+        _context->emuLevel = 11;
+        _context->ppca->glVertexAttribPointer( index, size, type, normalized, stride, pointer );
+      }
+      #endif
     case 11 :
     case 10 :
     case 9 :
@@ -31102,6 +31118,14 @@
       if (_context->ppa) break;
       #endif
     case 12 :
+      #if REGAL_EMU_PPCA
+      if (_context->ppca)
+      {
+        Push<int> pushLevel(_context->emuLevel);
+        _context->emuLevel = 11;
+        _context->ppca->glDisablei( cap, index );
+      }
+      #endif
     case 11 :
     case 10 :
     case 9 :
@@ -31186,6 +31210,14 @@
       if (_context->ppa) break;
       #endif
     case 12 :
+      #if REGAL_EMU_PPCA
+      if (_context->ppca)
+      {
+        Push<int> pushLevel(_context->emuLevel);
+        _context->emuLevel = 11;
+        _context->ppca->glEnablei( cap, index );
+      }
+      #endif
     case 11 :
     case 10 :
     case 9 :
@@ -31978,6 +32010,14 @@
     case 14 :
     case 13 :
     case 12 :
+      #if REGAL_EMU_PPCA
+      if (_context->ppca)
+      {
+        Push<int> pushLevel(_context->emuLevel);
+        _context->emuLevel = 11;
+        _context->ppca->glVertexAttribIPointer( index, size, type, stride, pointer );
+      }
+      #endif
     case 11 :
     case 10 :
     case 9 :
@@ -32150,7 +32190,7 @@
       {
         Push<int> pushLevel(_context->emuLevel);
         _context->emuLevel = 11;
-        _context->ppca->ShadowPrimitiveRestartIndex( index );
+        _context->ppca->glPrimitiveRestartIndex( index );
       }
       #endif
     case 11 :
@@ -32315,7 +32355,7 @@
       {
         Push<int> pushLevel(_context->emuLevel);
         _context->emuLevel = 11;
-        _context->ppca->ShadowVertexAttribDivisor( index, divisor );
+        _context->ppca->glVertexAttribDivisor( index, divisor );
       }
       #endif
     case 11 :
@@ -36306,6 +36346,37 @@
 
 // GL_ARB_multi_bind
 
+static void REGAL_CALL emu_glBindVertexBuffers(GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizei *strides)
+{
+  RegalContext *_context = REGAL_GET_CONTEXT();
+  RegalAssert(_context);
+  DispatchTableGL &_dispatch = _context->dispatcher.emulation;
+
+  // prefix
+  switch( _context->emuLevel )
+  {
+    case 15 :
+    case 14 :
+    case 13 :
+    case 12 :
+      #if REGAL_EMU_PPCA
+      if (_context->ppca)
+      {
+        Push<int> pushLevel(_context->emuLevel);
+        _context->emuLevel = 11;
+        _context->ppca->glBindVertexBuffers( first, count, buffers, offsets, strides );
+      }
+      #endif
+    case 1 :
+    default:
+      break;
+  }
+
+  DispatchTableGL *_next = _dispatch.next();
+  RegalAssert(_next);
+  _next->call(& _next->glBindVertexBuffers)(first, count, buffers, offsets, strides);
+}
+
 // GL_ARB_multi_draw_indirect
 
 static void REGAL_CALL emu_glMultiDrawArraysIndirect(GLenum mode, const GLvoid *indirect, GLsizei primcount, GLsizei stride)
@@ -40447,9 +40518,6 @@
     case 14 :
     case 13 :
     case 12 :
-      #if REGAL_EMU_PPCA
-      if (_context->ppca) break;
-      #endif
     case 11 :
     case 10 :
     case 9 :
@@ -40481,17 +40549,6 @@
     case 14 :
     case 13 :
     case 12 :
-      #if REGAL_EMU_PPCA
-      if (_context->ppca)
-      {
-        Push<int> pushLevel(_context->emuLevel);
-        _context->emuLevel = 11;
-        if( ! _context->ppca->Get( _context, pname, params ) ) {
-          _context->dispatcher.emulation.glGetInteger64v( pname, params );
-        }
-        return;
-      }
-      #endif
     case 11 :
     case 10 :
     case 9 :
@@ -41451,7 +41508,7 @@
       {
         Push<int> pushLevel(_context->emuLevel);
         _context->emuLevel = 11;
-        _context->ppca->ShadowBindVertexArray( array );
+        _context->ppca->glBindVertexArray( array );
       }
       #endif
     case 11 :
@@ -41569,7 +41626,7 @@
       {
         Push<int> pushLevel(_context->emuLevel);
         _context->emuLevel = 11;
-        _context->ppca->ShadowDeleteVertexArrays( n, arrays );
+        _context->ppca->glDeleteVertexArrays( n, arrays );
       }
       #endif
     case 11 :
@@ -41839,6 +41896,14 @@
     case 14 :
     case 13 :
     case 12 :
+      #if REGAL_EMU_PPCA
+      if (_context->ppca)
+      {
+        Push<int> pushLevel(_context->emuLevel);
+        _context->emuLevel = 11;
+        _context->ppca->glVertexAttribLPointer( index, size, type, stride, pointer );
+      }
+      #endif
     case 11 :
     case 10 :
     case 9 :
@@ -41881,7 +41946,7 @@
       {
         Push<int> pushLevel(_context->emuLevel);
         _context->emuLevel = 11;
-        _context->ppca->ShadowBindVertexBuffer( bindingindex, buffer, offset, stride );
+        _context->ppca->glBindVertexBuffer( bindingindex, buffer, offset, stride );
       }
       #endif
     case 11 :
@@ -41924,7 +41989,7 @@
       {
         Push<int> pushLevel(_context->emuLevel);
         _context->emuLevel = 11;
-        _context->ppca->ShadowVertexAttribBinding( attribindex, bindingindex );
+        _context->ppca->glVertexAttribBinding( attribindex, bindingindex );
       }
       #endif
     case 11 :
@@ -41967,7 +42032,7 @@
       {
         Push<int> pushLevel(_context->emuLevel);
         _context->emuLevel = 11;
-        _context->ppca->ShadowVertexAttribFormat( attribindex, size, type, normalized, relativeoffset );
+        _context->ppca->glVertexAttribFormat( attribindex, size, type, normalized, relativeoffset );
       }
       #endif
     case 11 :
@@ -42010,7 +42075,7 @@
       {
         Push<int> pushLevel(_context->emuLevel);
         _context->emuLevel = 11;
-        _context->ppca->ShadowVertexAttribIFormat( attribindex, size, type, relativeoffset );
+        _context->ppca->glVertexAttribIFormat( attribindex, size, type, relativeoffset );
       }
       #endif
     case 11 :
@@ -42053,7 +42118,7 @@
       {
         Push<int> pushLevel(_context->emuLevel);
         _context->emuLevel = 11;
-        _context->ppca->ShadowVertexAttribLFormat( attribindex, size, type, relativeoffset );
+        _context->ppca->glVertexAttribLFormat( attribindex, size, type, relativeoffset );
       }
       #endif
     case 11 :
@@ -42096,7 +42161,7 @@
       {
         Push<int> pushLevel(_context->emuLevel);
         _context->emuLevel = 11;
-        _context->ppca->ShadowVertexBindingDivisor( bindingindex, divisor );
+        _context->ppca->glVertexBindingDivisor( bindingindex, divisor );
       }
       #endif
     case 11 :
@@ -47071,7 +47136,7 @@
       {
         Push<int> pushLevel(_context->emuLevel);
         _context->emuLevel = 11;
-        _context->ppca->ClientAttribDefaultDSA( _context, mask );
+        _context->ppca->glClientAttribDefaultEXT( _context, mask );
         return;
       }
       #endif
@@ -48597,7 +48662,7 @@
       {
         Push<int> pushLevel(_context->emuLevel);
         _context->emuLevel = 11;
-        _context->ppca->ShadowDisableClientStateIndexedDSA( array, index );
+        _context->ppca->glDisableClientStateIndexedEXT( array, index );
       }
       #endif
     case 11 :
@@ -48680,7 +48745,7 @@
       {
         Push<int> pushLevel(_context->emuLevel);
         _context->emuLevel = 11;
-        _context->ppca->ShadowDisableClientStateIndexedDSA( array, index );
+        _context->ppca->glDisableClientStateiEXT( array, index );
       }
       #endif
     case 11 :
@@ -48763,7 +48828,7 @@
       {
         Push<int> pushLevel(_context->emuLevel);
         _context->emuLevel = 11;
-        _context->ppca->ShadowDisableVertexArrayAttribDSA( vaobj, array );
+        _context->ppca->glDisableVertexArrayAttribEXT( vaobj, array );
       }
       #endif
     case 11 :
@@ -48846,7 +48911,7 @@
       {
         Push<int> pushLevel(_context->emuLevel);
         _context->emuLevel = 11;
-        _context->ppca->ShadowDisableVertexArrayDSA( vaobj, array );
+        _context->ppca->glDisableVertexArrayEXT( vaobj, array );
       }
       #endif
     case 11 :
@@ -48934,7 +48999,7 @@
       {
         Push<int> pushLevel(_context->emuLevel);
         _context->emuLevel = 11;
-        _context->ppca->ShadowEnableClientStateIndexedDSA( array, index );
+        _context->ppca->glEnableClientStateIndexedEXT( array, index );
       }
       #endif
     case 11 :
@@ -49017,7 +49082,7 @@
       {
         Push<int> pushLevel(_context->emuLevel);
         _context->emuLevel = 11;
-        _context->ppca->ShadowEnableClientStateIndexedDSA( array, index );
+        _context->ppca->glEnableClientStateiEXT( array, index );
       }
       #endif
     case 11 :
@@ -49100,7 +49165,7 @@
       {
         Push<int> pushLevel(_context->emuLevel);
         _context->emuLevel = 11;
-        _context->ppca->ShadowEnableVertexArrayAttribDSA( vaobj, array );
+        _context->ppca->glEnableVertexArrayAttribEXT( vaobj, array );
       }
       #endif
     case 11 :
@@ -49183,7 +49248,7 @@
       {
         Push<int> pushLevel(_context->emuLevel);
         _context->emuLevel = 11;
-        _context->ppca->ShadowEnableVertexArrayDSA( vaobj, array );
+        _context->ppca->glEnableVertexArrayEXT( vaobj, array );
       }
       #endif
     case 11 :
@@ -54023,7 +54088,7 @@
       {
         Push<int> pushLevel(_context->emuLevel);
         _context->emuLevel = 11;
-        _context->ppca->ShadowMultiTexCoordPointerDSA( texunit, size, type, stride, pointer );
+        _context->ppca->glMultiTexCoordPointerEXT( texunit, size, type, stride, pointer );
       }
       #endif
     case 11 :
@@ -60802,7 +60867,7 @@
       {
         Push<int> pushLevel(_context->emuLevel);
         _context->emuLevel = 11;
-        _context->ppca->PushClientAttribDefaultDSA( _context, mask );
+        _context->ppca->glPushClientAttribDefaultEXT( _context, mask );
         return;
       }
       #endif
@@ -61883,7 +61948,7 @@
       {
         Push<int> pushLevel(_context->emuLevel);
         _context->emuLevel = 11;
-        _context->ppca->ShadowVertexArrayColorOffsetDSA( vaobj, buffer, size, type, stride, offset );
+        _context->ppca->glVertexArrayColorOffsetEXT( vaobj, buffer, size, type, stride, offset );
       }
       #endif
     case 11 :
@@ -61966,7 +62031,7 @@
       {
         Push<int> pushLevel(_context->emuLevel);
         _context->emuLevel = 11;
-        _context->ppca->ShadowVertexArrayEdgeFlagOffsetDSA( vaobj, buffer, stride, offset );
+        _context->ppca->glVertexArrayEdgeFlagOffsetEXT( vaobj, buffer, stride, offset );
       }
       #endif
     case 11 :
@@ -62049,7 +62114,7 @@
       {
         Push<int> pushLevel(_context->emuLevel);
         _context->emuLevel = 11;
-        _context->ppca->ShadowVertexArrayFogCoordOffsetDSA( vaobj, buffer, type, stride, offset );
+        _context->ppca->glVertexArrayFogCoordOffsetEXT( vaobj, buffer, type, stride, offset );
       }
       #endif
     case 11 :
@@ -62132,7 +62197,7 @@
       {
         Push<int> pushLevel(_context->emuLevel);
         _context->emuLevel = 11;
-        _context->ppca->ShadowVertexArrayIndexOffsetDSA( vaobj, buffer, type, stride, offset );
+        _context->ppca->glVertexArrayIndexOffsetEXT( vaobj, buffer, type, stride, offset );
       }
       #endif
     case 11 :
@@ -62215,7 +62280,7 @@
       {
         Push<int> pushLevel(_context->emuLevel);
         _context->emuLevel = 11;
-        _context->ppca->ShadowVertexArrayMultiTexCoordOffsetDSA( vaobj, buffer, texunit, size, type, stride, offset );
+        _context->ppca->glVertexArrayMultiTexCoordOffsetEXT( vaobj, buffer, texunit, size, type, stride, offset );
       }
       #endif
     case 11 :
@@ -62298,7 +62363,7 @@
       {
         Push<int> pushLevel(_context->emuLevel);
         _context->emuLevel = 11;
-        _context->ppca->ShadowVertexArrayNormalOffsetDSA( vaobj, buffer, type, stride, offset );
+        _context->ppca->glVertexArrayNormalOffsetEXT( vaobj, buffer, type, stride, offset );
       }
       #endif
     case 11 :
@@ -62381,7 +62446,7 @@
       {
         Push<int> pushLevel(_context->emuLevel);
         _context->emuLevel = 11;
-        _context->ppca->ShadowVertexArraySecondaryColorOffsetDSA( vaobj, buffer, size, type, stride, offset );
+        _context->ppca->glVertexArraySecondaryColorOffsetEXT( vaobj, buffer, size, type, stride, offset );
       }
       #endif
     case 11 :
@@ -62464,7 +62529,7 @@
       {
         Push<int> pushLevel(_context->emuLevel);
         _context->emuLevel = 11;
-        _context->ppca->ShadowVertexArrayTexCoordOffsetDSA( vaobj, buffer, size, type, stride, offset );
+        _context->ppca->glVertexArrayTexCoordOffsetEXT( vaobj, buffer, size, type, stride, offset );
       }
       #endif
     case 11 :
@@ -62547,7 +62612,7 @@
       {
         Push<int> pushLevel(_context->emuLevel);
         _context->emuLevel = 11;
-        _context->ppca->ShadowVertexArrayVertexAttribIOffsetDSA( vaobj, buffer, index, size, type, stride, offset );
+        _context->ppca->glVertexArrayVertexAttribIOffsetEXT( vaobj, buffer, index, size, type, stride, offset );
       }
       #endif
     case 11 :
@@ -62630,7 +62695,7 @@
       {
         Push<int> pushLevel(_context->emuLevel);
         _context->emuLevel = 11;
-        _context->ppca->ShadowVertexArrayVertexAttribOffsetDSA( vaobj, buffer, index, size, type, normalized, stride, offset );
+        _context->ppca->glVertexArrayVertexAttribOffsetEXT( vaobj, buffer, index, size, type, normalized, stride, offset );
       }
       #endif
     case 11 :
@@ -62713,7 +62778,7 @@
       {
         Push<int> pushLevel(_context->emuLevel);
         _context->emuLevel = 11;
-        _context->ppca->ShadowVertexArrayVertexOffsetDSA( vaobj, buffer, size, type, stride, offset );
+        _context->ppca->glVertexArrayVertexOffsetEXT( vaobj, buffer, size, type, stride, offset );
       }
       #endif
     case 11 :
@@ -62874,6 +62939,14 @@
     case 14 :
     case 13 :
     case 12 :
+      #if REGAL_EMU_PPCA
+      if (_context->ppca)
+      {
+        Push<int> pushLevel(_context->emuLevel);
+        _context->emuLevel = 11;
+        _context->ppca->glDisableIndexedEXT( target, index );
+      }
+      #endif
     case 11 :
     case 10 :
     case 9 :
@@ -62984,6 +63057,14 @@
     case 14 :
     case 13 :
     case 12 :
+      #if REGAL_EMU_PPCA
+      if (_context->ppca)
+      {
+        Push<int> pushLevel(_context->emuLevel);
+        _context->emuLevel = 11;
+        _context->ppca->glEnableIndexedEXT( target, index );
+      }
+      #endif
     case 11 :
     case 10 :
     case 9 :
@@ -70175,6 +70256,10 @@
    tbl.glFlushMappedBufferRange = emu_glFlushMappedBufferRange;
    tbl.glMapBufferRange = emu_glMapBufferRange;
 
+// GL_ARB_multi_bind
+
+   tbl.glBindVertexBuffers = emu_glBindVertexBuffers;
+
 // GL_ARB_multi_draw_indirect
 
    tbl.glMultiDrawArraysIndirect = emu_glMultiDrawArraysIndirect;
diff --git a/src/regal/RegalEmu.h b/src/regal/RegalEmu.h
index 8152554..f179ce4 100644
--- a/src/regal/RegalEmu.h
+++ b/src/regal/RegalEmu.h
@@ -59,7 +59,7 @@
 #endif
 
 #ifndef REGAL_EMU_MAX_TEXTURE_COORDS
-#define REGAL_EMU_MAX_TEXTURE_COORDS 16
+#define REGAL_EMU_MAX_TEXTURE_COORDS 8
 #endif
 
 #ifndef REGAL_EMU_MAX_VERTEX_ATTRIBS
@@ -70,6 +70,13 @@
 #define REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS 32
 #endif
 
+// glspec43.compatibility.20130214.withchanges.pdf Table 23.65, p. 709
+// lists the minumum value for MAX_CLIENT_ATTRIB_STACK_DEPTH as 16
+
+#ifndef REGAL_EMU_MAX_CLIENT_ATTRIB_STACK_DEPTH
+#define REGAL_EMU_MAX_CLIENT_ATTRIB_STACK_DEPTH 16
+#endif
+
 REGAL_NAMESPACE_END
 
 #endif // REGAL_EMULATION
diff --git a/src/regal/RegalPpc.h b/src/regal/RegalPpc.h
deleted file mode 100644
index ae214ba..0000000
--- a/src/regal/RegalPpc.h
+++ /dev/null
@@ -1,1877 +0,0 @@
-/*
-  Copyright (c) 2011-2012 NVIDIA Corporation
-  Copyright (c) 2011-2012 Cass Everitt
-  Copyright (c) 2012 Scott Nations
-  Copyright (c) 2012 Mathias Schott
-  Copyright (c) 2012 Nigel Stewart
-  All rights reserved.
-
-  Redistribution and use in source and binary forms, with or without modification,
-  are permitted provided that the following conditions are met:
-
-    Redistributions of source code must retain the above copyright notice, this
-    list of conditions and the following disclaimer.
-
-    Redistributions in binary form must reproduce the above copyright notice,
-    this list of conditions and the following disclaimer in the documentation
-    and/or other materials provided with the distribution.
-
-  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
-  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
-  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
-  OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
-  OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
-
-/*
-
- Regal push / pop client attrib
- Scott Nations
-
- TODO:
-
-   check vertex-array state against spec
-   track dsa versions of routines
-   are we handling all ARB version of routines
-   what do do about deletebuffers
-   journal changes
-
-*/
-
-#ifndef __REGAL_PPC_H__
-#define __REGAL_PPC_H__
-
-#include "RegalUtil.h"
-
-REGAL_GLOBAL_BEGIN
-
-#include "RegalUtil.h"
-#include "RegalPrivate.h"
-#include "RegalEmu.h"
-
-REGAL_GLOBAL_END
-
-REGAL_NAMESPACE_BEGIN
-
-#define REGAL_PPC_MAX_CLIENT_ATTRIB_STACK_DEPTH 16
-#define REGAL_PPC_MAX_VERTEX_ATTRIBS 16
-#define REGAL_PPC_MAX_TEXTURE_COORDS 16
-
-
-struct RegalPpc {
-
-    struct ClientPixelStoreState {
-
-        ClientPixelStoreState()
-        : pixelPackBufferBinding( 0 )
-        , pixelUnpackBufferBinding( 0 )
-        , packSwapBytes( GL_FALSE )
-        , packLsbFirst( GL_FALSE )
-        , packRowLength( 0 )
-        , packImageHeight( 0 )
-        , packSkipRows( 0 )
-        , packSkipPixels( 0 )
-        , packSkipImages( 0 )
-        , packAlignment( 4 )
-        , unpackSwapBytes( GL_FALSE )
-        , unpackLsbFirst( GL_FALSE )
-        , unpackRowLength( 0 )
-        , unpackImageHeight( 0 )
-        , unpackSkipRows( 0 )
-        , unpackSkipPixels( 0 )
-        , unpackSkipImages( 0 )
-        , unpackAlignment( 4 )
-        {
-        }
-
-        void Restore(RegalContext * ctx)
-        {
-            RegalAssert( ctx );
-
-            DispatchTable &tbl = ctx->dsp.emuTbl;
-
-            tbl.glBindBuffer( GL_PIXEL_PACK_BUFFER, pixelPackBufferBinding );
-            tbl.glBindBuffer( GL_PIXEL_UNPACK_BUFFER, pixelUnpackBufferBinding );
-
-            tbl.glPixelStorei( GL_PACK_ALIGNMENT, packAlignment );
-            tbl.glPixelStorei( GL_PACK_IMAGE_HEIGHT, packImageHeight );
-            tbl.glPixelStorei( GL_PACK_LSB_FIRST, packLsbFirst );
-            tbl.glPixelStorei( GL_PACK_ROW_LENGTH, packRowLength );
-            tbl.glPixelStorei( GL_PACK_SKIP_IMAGES, packSkipImages );
-            tbl.glPixelStorei( GL_PACK_SKIP_PIXELS, packSkipPixels );
-            tbl.glPixelStorei( GL_PACK_SKIP_ROWS, packSkipRows );
-            tbl.glPixelStorei( GL_PACK_SWAP_BYTES, packSwapBytes );
-            tbl.glPixelStorei( GL_UNPACK_ALIGNMENT, unpackAlignment );
-            tbl.glPixelStorei( GL_UNPACK_IMAGE_HEIGHT, unpackImageHeight );
-            tbl.glPixelStorei( GL_UNPACK_LSB_FIRST, unpackLsbFirst );
-            tbl.glPixelStorei( GL_UNPACK_ROW_LENGTH, unpackRowLength );
-            tbl.glPixelStorei( GL_UNPACK_SKIP_IMAGES, unpackSkipImages );
-            tbl.glPixelStorei( GL_UNPACK_SKIP_PIXELS, unpackSkipPixels );
-            tbl.glPixelStorei( GL_UNPACK_SKIP_ROWS, unpackSkipRows );
-            tbl.glPixelStorei( GL_UNPACK_SWAP_BYTES, unpackSwapBytes );
-        }
-
-        GLuint pixelPackBufferBinding;
-        GLuint pixelUnpackBufferBinding;
-        GLboolean packSwapBytes;
-        GLboolean packLsbFirst;
-        GLint packRowLength;
-        GLint packImageHeight;
-        GLint packSkipRows;
-        GLint packSkipPixels;
-        GLint packSkipImages;
-        GLint packAlignment;
-        GLboolean unpackSwapBytes;
-        GLboolean unpackLsbFirst;
-        GLint unpackRowLength;
-        GLint unpackImageHeight;
-        GLint unpackSkipRows;
-        GLint unpackSkipPixels;
-        GLint unpackSkipImages;
-        GLint unpackAlignment;
-    };
-
-    struct VertexArrayState {
-
-        VertexArrayState()
-        {
-            Init( GL_NONE );
-        }
-
-        VertexArrayState(GLenum _cap)
-        {
-            Init( _cap );
-        }
-
-        void Init(GLenum _cap)
-        {
-            cap = _cap;
-            index = 0;
-            enabled = GL_FALSE;
-            buffer = 0;
-            size = 4;
-            type = GL_FLOAT;
-            normalized = GL_FALSE;
-            stride = 0;
-            pointer = NULL;
-            integer = GL_FALSE;
-            divisor = 0;
-        }
-
-        void SetPointer( GLuint _buffer,
-                         GLuint _index,
-                         GLint _size,
-                         GLenum _type,
-                         GLboolean _normalized,
-                         GLboolean _integer,
-                         GLsizei _stride,
-                         const GLvoid * _pointer )
-        {
-            buffer = _buffer;
-            index = _index;
-            size = _size;
-            type = _type;
-            normalized = _normalized;
-            integer = integer;
-            stride = _stride;
-            pointer = _pointer;
-        }
-
-        void Restore(RegalContext * ctx)
-        {
-            RegalAssert( ctx );
-
-            DispatchTable &tbl = ctx->dsp.emuTbl;
-
-            tbl.glBindBuffer(GL_ARRAY_BUFFER, buffer);
-
-            switch (cap)
-            {
-                case GL_NONE:
-                    tbl.glVertexAttribDivisor(index, divisor);
-                    tbl.glVertexAttribPointer(index, size, type, normalized,
-                                              stride, pointer);
-                    break;
-                case GL_COLOR_ARRAY:
-                    tbl.glColorPointer(size, type, stride, pointer);
-                    break;
-                case GL_EDGE_FLAG_ARRAY:
-                    tbl.glEdgeFlagPointer(stride, pointer);
-                    break;
-                case GL_FOG_COORD_ARRAY:
-                    tbl.glFogCoordPointer(type, stride, pointer);
-                    break;
-                case GL_INDEX_ARRAY:
-                    tbl.glIndexPointer(type, stride, pointer);
-                    break;
-                case GL_NORMAL_ARRAY:
-                    tbl.glNormalPointer(type, stride, pointer);
-                    break;
-                case GL_SECONDARY_COLOR_ARRAY:
-                    tbl.glSecondaryColorPointer(size, type, stride, pointer);
-                    break;
-                case GL_TEXTURE_COORD_ARRAY:
-                    tbl.glTexCoordPointer(size, type, stride, pointer);
-                    break;
-                case GL_VERTEX_ARRAY:
-                    tbl.glVertexPointer(size, type, stride, pointer);
-                    break;
-                default:
-                    RegalAssert( !"unhandled cap value" );
-                    break;
-            }
-
-            if ( enabled == GL_TRUE ) {
-                if ( cap == GL_NONE ) {
-                    tbl.glEnableVertexAttribArray( index );
-                } else {
-                    tbl.glEnableClientState( cap );
-                }
-            } else {
-                if ( cap == GL_NONE ) {
-                    tbl.glDisableVertexAttribArray( index );
-                } else {
-                    tbl.glDisableClientState( cap );
-                }
-            }
-        }
-
-        GLenum cap;
-        GLuint index;
-        GLboolean enabled;
-        GLint buffer;
-        GLint size;
-        GLenum type;
-        GLboolean normalized;
-        GLsizei stride;
-        const GLvoid * pointer;
-        GLboolean integer;
-        GLint divisor;
-    };
-
-    struct ClientVertexArrayState {
-
-        ClientVertexArrayState()
-        : vertexBuffer( 0 )
-        , indexBuffer( 0 )
-        , vertexArrayObject( 0 )
-        , clientActiveTexture( GL_TEXTURE0 )
-        , primitiveRestart( GL_FALSE )
-        , primitiveRestartIndex( 0 )
-        , edgeFlagArrayState( GL_EDGE_FLAG_ARRAY )
-        , indexArrayState( GL_INDEX_ARRAY )
-        {
-        }
-
-        ClientVertexArrayState(const ClientVertexArrayState &rhs)
-        : vertexBuffer( rhs.vertexBuffer )
-        , indexBuffer( rhs.indexBuffer )
-        , vertexArrayObject( rhs.vertexArrayObject )
-        , clientActiveTexture( rhs.clientActiveTexture )
-        , primitiveRestart( rhs.primitiveRestart )
-        , primitiveRestartIndex( rhs.primitiveRestartIndex )
-        , edgeFlagArrayState( rhs.edgeFlagArrayState )
-        , indexArrayState( rhs.indexArrayState )
-        {
-            for (int ii=0; ii<REGAL_PPC_MAX_VERTEX_ATTRIBS; ii++) {
-                genericArrayState[ii] = rhs.genericArrayState[ii];
-            }
-        }
-
-        ClientVertexArrayState&
-        operator= (const ClientVertexArrayState &rhs)
-        {
-            if (this == &rhs)
-                return *this;
-
-            vertexBuffer = rhs.vertexBuffer;
-            indexBuffer = rhs.indexBuffer;
-            vertexArrayObject = rhs.vertexArrayObject;
-            clientActiveTexture = rhs.clientActiveTexture;
-            primitiveRestart = rhs.primitiveRestart;
-            primitiveRestartIndex = rhs.primitiveRestartIndex;
-            edgeFlagArrayState = rhs.edgeFlagArrayState;
-            indexArrayState = rhs.indexArrayState;
-
-            for (int ii=0; ii<REGAL_PPC_MAX_VERTEX_ATTRIBS; ii++) {
-                genericArrayState[ii] = rhs.genericArrayState[ii];
-            }
-
-            return *this;
-        }
-
-        void Restore(RegalContext * ctx)
-        {
-            RegalAssert( ctx );
-
-            ctx->dsp.emuTbl.glClientActiveTexture( clientActiveTexture );
-
-            ctx->dsp.emuTbl.glBindBuffer( GL_ARRAY_BUFFER, vertexBuffer );
-
-            if ( primitiveRestart == GL_TRUE ) {
-                ctx->dsp.emuTbl.glEnable( GL_PRIMITIVE_RESTART );
-            } else {
-                ctx->dsp.emuTbl.glDisable( GL_PRIMITIVE_RESTART );
-            }
-            ctx->dsp.emuTbl.glPrimitiveRestartIndex( primitiveRestartIndex );
-
-            ctx->dsp.emuTbl.glBindVertexArray( vertexArrayObject );
-
-            if (vertexArrayObject != 0) {
-
-                LoadStateFromGL( ctx );
-
-            } else {
-
-                edgeFlagArrayState.Restore( ctx );
-                indexArrayState.Restore( ctx );
-
-                ctx->dsp.emuTbl.glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, indexBuffer );
-
-                for (int ii=0; ii<REGAL_PPC_MAX_VERTEX_ATTRIBS; ii++) {
-                    genericArrayState[ii].Restore( ctx );
-                }
-
-                ctx->dsp.emuTbl.glBindBuffer( GL_ARRAY_BUFFER, vertexBuffer );
-            }
-        }
-
-        void LoadStateFromGL( RegalContext * ctx )
-        {
-            GLint bah = 0;
-            GLvoid* bah2 = NULL;
-
-            DispatchTable &tbl = ctx->dsp.emuTbl;
-
-            for (int ii=0; ii<REGAL_PPC_MAX_VERTEX_ATTRIBS; ii++) {
-                VertexArrayState &gas = genericArrayState[ii];
-                tbl.glGetVertexAttribiv( ii, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &gas.buffer );
-                tbl.glGetVertexAttribiv( ii, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &bah );
-                gas.enabled = bah;
-                tbl.glGetVertexAttribiv( ii, GL_VERTEX_ATTRIB_ARRAY_SIZE, &gas.size );
-                tbl.glGetVertexAttribiv( ii, GL_VERTEX_ATTRIB_ARRAY_DIVISOR, &gas.divisor );
-                tbl.glGetVertexAttribiv( ii, GL_VERTEX_ATTRIB_ARRAY_STRIDE, &gas.stride );
-                tbl.glGetVertexAttribiv( ii, GL_VERTEX_ATTRIB_ARRAY_TYPE, &bah );
-                gas.type = bah;
-                tbl.glGetVertexAttribiv( ii, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, &bah );
-                gas.normalized = bah;
-                tbl.glGetVertexAttribiv( ii, GL_VERTEX_ATTRIB_ARRAY_INTEGER, &bah );
-                gas.integer = bah;
-                tbl.glGetVertexAttribPointerv( ii, GL_VERTEX_ATTRIB_ARRAY_POINTER, &bah2 );
-                gas.pointer = bah2;
-            }
-
-            VertexArrayState &gas = indexArrayState;
-            gas.enabled = tbl.glIsEnabled( GL_INDEX_ARRAY  );
-            tbl.glGetIntegerv( GL_INDEX_ARRAY_TYPE, &bah );
-            gas.type = bah;
-            tbl.glGetIntegerv( GL_INDEX_ARRAY_STRIDE, &gas.stride );
-            tbl.glGetPointerv( GL_INDEX_ARRAY_POINTER, &bah2 );
-            gas.pointer = bah2;
-            tbl.glGetIntegerv( GL_INDEX_ARRAY_BUFFER_BINDING, &gas.buffer );
-
-            gas = edgeFlagArrayState;
-            gas.enabled = tbl.glIsEnabled( GL_EDGE_FLAG_ARRAY );
-            tbl.glGetIntegerv( GL_EDGE_FLAG_ARRAY_STRIDE, &gas.stride );
-            tbl.glGetPointerv( GL_EDGE_FLAG_ARRAY_POINTER, &bah2 );
-            gas.pointer = bah2;
-            tbl.glGetIntegerv( GL_EDGE_FLAG_ARRAY_BUFFER_BINDING, &gas.buffer );
-
-            tbl.glGetIntegerv( GL_ELEMENT_ARRAY_BUFFER_BINDING, &bah );
-            indexBuffer = bah;
-        }
-
-        GLuint vertexBuffer;
-        GLuint indexBuffer;
-        GLuint vertexArrayObject;
-        GLenum clientActiveTexture;
-        GLboolean primitiveRestart;
-        GLint primitiveRestartIndex;
-        VertexArrayState edgeFlagArrayState;
-        VertexArrayState indexArrayState;
-        VertexArrayState genericArrayState[REGAL_PPC_MAX_VERTEX_ATTRIBS];
-    };
-
-    struct ClientState {
-
-        ClientState()
-        : pushPopMask( 0 )
-        {
-        }
-
-        void Restore( RegalContext * ctx )
-        {
-            RegalAssert( ctx );
-
-            switch ( pushPopMask )
-            {
-                case GL_CLIENT_ALL_ATTRIB_BITS:
-                case GL_CLIENT_PIXEL_STORE_BIT:
-                    pixelStoreState.Restore( ctx );
-                    if ( pushPopMask == GL_CLIENT_PIXEL_STORE_BIT )
-                        break;
-                case GL_CLIENT_VERTEX_ARRAY_BIT:
-                    vertexArrayState.Restore( ctx );
-                    break;
-                default:
-                    RegalAssert( !"unhandled pushPopMask value" );
-                    return;
-            }
-        }
-
-        GLbitfield pushPopMask;
-        ClientPixelStoreState  pixelStoreState;
-        ClientVertexArrayState vertexArrayState;
-    };
-
-    int topOfStack;
-    ClientState stack[REGAL_PPC_MAX_CLIENT_ATTRIB_STACK_DEPTH];
-    ClientState currentClientState;
-
-    // to alias vertex arrays to generic attribs
-    GLuint ffAttrMap[ REGAL_PPC_MAX_VERTEX_ATTRIBS ];
-    GLuint ffAttrInvMap[ REGAL_PPC_MAX_VERTEX_ATTRIBS ];
-    GLuint ffAttrTexBegin;
-    GLuint ffAttrTexEnd;
-    GLuint ffAttrNumTex;
-    GLuint maxVertexAttribs;
-
-    void Init( RegalContext * ctx )
-    {
-        topOfStack = -1;
-
-        maxVertexAttribs = ctx->ctxInf->maxVertexAttribs;
-
-        // we have RFF2A maps for sets of 8 and 16 attributes. if
-        // REGAL_PPC_MAX_VERTEX_ATTRIBS > 16 a new map needs to be added
-
-        RegalAssert( REGAL_PPC_MAX_VERTEX_ATTRIBS <= 16 );
-
-        if ( maxVertexAttribs >= 16 ) {
-            RegalAssert( REGAL_PPC_MAX_VERTEX_ATTRIBS == 16);
-            //RegalOutput( "Setting up for %d Vertex Attribs\n", maxVertexAttribs );
-            for( int i = 0; i < 16; i++ ) {
-                ffAttrMap[i] = RFF2AMap16[i];
-                ffAttrInvMap[i] = RFF2AInvMap16[i];
-            }
-            ffAttrTexBegin = RFF2ATexBegin16;
-            ffAttrTexEnd = RFF2ATexEnd16;
-        } else {
-            RegalAssert( maxVertexAttribs >= 8 );
-            //RegalOutput( "Setting up for 8 Vertex Attribs" );
-            for( int i = 0; i < 8; i++ ) {
-                ffAttrMap[i] = RFF2AMap8[i];
-                ffAttrInvMap[i] = RFF2AInvMap8[i];
-            }
-            for( int i = 8; i < REGAL_PPC_MAX_VERTEX_ATTRIBS; i++ ) {
-                ffAttrMap[i] = -1;
-                ffAttrInvMap[i] = -1;
-            }
-            ffAttrTexBegin = RFF2ATexBegin8;
-            ffAttrTexEnd = RFF2ATexEnd8;
-        }
-        ffAttrNumTex = ffAttrTexEnd - ffAttrTexBegin;
-    }
-
-    GLuint ClientStateToAttribIndex( GLenum array )
-    {
-        switch ( array )
-        {
-            case GL_VERTEX_ARRAY:
-                return ffAttrMap[ RFF2A_Vertex ];
-            case GL_NORMAL_ARRAY:
-                return ffAttrMap[ RFF2A_Normal ];
-            case GL_COLOR_ARRAY:
-                 return ffAttrMap[ RFF2A_Color ];
-            case GL_SECONDARY_COLOR_ARRAY:
-                return ffAttrMap[ RFF2A_SecondaryColor ];
-            case GL_FOG_COORD_ARRAY:
-                return ffAttrMap[ RFF2A_FogCoord ];
-            case GL_TEXTURE_COORD_ARRAY:
-                {
-                    GLuint index = currentClientState.vertexArrayState.clientActiveTexture - GL_TEXTURE0;
-                    RegalAssert(index >= 0);
-                    RegalAssert(index < REGAL_PPC_MAX_TEXTURE_COORDS);
-                    if ( index < ffAttrNumTex )
-                        return ffAttrTexBegin + index;
-                }
-                break;
-            default:
-                break;
-        }
-        return ~0;
-    }
-
-    VertexArrayState*
-    ClientStateToAttribState( GLenum array )
-    {
-        VertexArrayState* pAS = NULL;
-        switch ( array )
-        {
-            case GL_EDGE_FLAG_ARRAY:
-                pAS = &currentClientState.vertexArrayState.edgeFlagArrayState;
-                break;
-            case GL_INDEX_ARRAY:
-                pAS = &currentClientState.vertexArrayState.indexArrayState;
-                break;
-            case GL_NORMAL_ARRAY:
-            case GL_FOG_COORD_ARRAY:
-            case GL_COLOR_ARRAY:
-            case GL_SECONDARY_COLOR_ARRAY:
-            case GL_VERTEX_ARRAY:
-            case GL_TEXTURE_COORD_ARRAY:
-                {
-                    const GLuint index = ClientStateToAttribIndex( array );
-                    if ( index != GLuint(~0) )
-                        pAS = &currentClientState.vertexArrayState.genericArrayState[index];
-                }
-                break;
-            default:
-                RegalAssert( !"unhandled state value" );
-                break;
-        }
-        return pAS;
-    }
-
-    void BindBuffer( RegalContext * ctx, GLenum target, GLuint buffer)
-    {
-        switch (target)
-        {
-            case GL_ARRAY_BUFFER:
-                currentClientState.vertexArrayState.vertexBuffer = buffer;
-                break;
-            case GL_ELEMENT_ARRAY_BUFFER:
-                currentClientState.vertexArrayState.indexBuffer = buffer;
-                break;
-            case GL_PIXEL_PACK_BUFFER_BINDING:
-                currentClientState.pixelStoreState.pixelPackBufferBinding = buffer;
-                break;
-            case GL_PIXEL_UNPACK_BUFFER_BINDING:
-                currentClientState.pixelStoreState.pixelUnpackBufferBinding = buffer;
-                break;
-            default:
-                break;
-        }
-    }
-
-    void DeleteBuffers( RegalContext * ctx, GLsizei n, const GLuint *buffers )
-    {
-        //<> hmmm... what to do here?
-    }
-
-    void BindVertexArray( RegalContext * ctx, GLuint array)
-    {
-        currentClientState.vertexArrayState.vertexArrayObject = array;
-        ctx->dsp.emuTbl.glBindVertexArray( array );
-        if ( array != 0 )
-            currentClientState.vertexArrayState.LoadStateFromGL( ctx );
-    }
-
-    void DeleteVertexArrays( RegalContext * ctx, GLsizei n, const GLuint *arrays )
-    {
-        //<> hmmm... what to do here?
-    }
-
-    void ClientActiveTexture( RegalContext * ctx, GLenum _texture)
-    {
-        if ( ctx->depthBeginEnd )
-            return;
-
-        GLint index = _texture - GL_TEXTURE0;
-
-        if (index >= 0 && index < REGAL_PPC_MAX_TEXTURE_COORDS)
-            currentClientState.vertexArrayState.clientActiveTexture = _texture;
-    }
-
-    void InterleavedArrays( RegalContext * ctx, GLenum format,
-                            GLsizei stride, const GLvoid *pointer)
-    {
-        if ( ctx->depthBeginEnd )
-            return;
-
-        //<> how can stride be invalid?
-        //<> if ( stride is invalid )
-            //<> return;
-
-        switch ( format )
-        {
-            case GL_V2F:
-            case GL_V3F:
-            case GL_C4UB_V2F:
-            case GL_C4UB_V3F:
-            case GL_C3F_V3F:
-            case GL_N3F_V3F:
-            case GL_C4F_N3F_V3F:
-            case GL_T2F_V3F:
-            case GL_T4F_V4F:
-            case GL_T2F_C4UB_V3F:
-            case GL_T2F_C3F_V3F:
-            case GL_T2F_N3F_V3F:
-            case GL_T2F_C4F_N3F_V3F:
-            case GL_T4F_C4F_N3F_V4F:
-                break;
-            default:
-                RegalAssert( !"unhandled format value" );
-                return;
-        }
-
-        GLsizei f = sizeof(GL_FLOAT);
-        GLsizei c = 4 * sizeof(GL_UNSIGNED_BYTE);
-        //<> need to round up c to the nearest multiple of f
-
-        GLsizei pc = 0;
-        GLsizei pn = 0;
-        GLsizei pv = 0;
-        GLsizei s  = 0;
-
-        switch ( format )
-        {
-            case GL_V2F:
-                pc = 0;
-                pn = 0;
-                pv = 0;
-                s  = 2 * f;
-                break;
-            case GL_V3F:
-                pc = 0;
-                pn = 0;
-                pv = 0;
-                s  = 3 * f;
-                break;
-            case GL_C4UB_V2F:
-                pc = 0;
-                pn = 0;
-                pv = c + 0;
-                s  = c + 2 * f;
-                break;
-            case GL_C4UB_V3F:
-                pc = 0;
-                pn = 0;
-                pv = c + 0;
-                s  = c + 3 * f;
-                break;
-            case GL_C3F_V3F:
-                pc = 0;
-                pn = 0;
-                pv = 3 * f;
-                s  = 6 * f;
-                break;
-            case GL_N3F_V3F:
-                pc = 0;
-                pn = 0;
-                pv = 3 * f;
-                s  = 6 * f;
-                break;
-            case GL_C4F_N3F_V3F:
-                pc = 0;
-                pn = 4 * f;
-                pv = 7 * f;
-                s  = 10;
-                break;
-            case GL_T2F_V3F:
-                pc = 0;
-                pn = 0;
-                pv = 2 * f;
-                s  = 5 * f;
-                break;
-            case GL_T4F_V4F:
-                pc = 0;
-                pn = 0;
-                pv = 4 * f;
-                s  = 8 * f;
-                break;
-            case GL_T2F_C4UB_V3F:
-                pc = 2 * f;
-                pn = 0;
-                pv = c + 2 * f;
-                s  = c + 5 * f;
-                break;
-            case GL_T2F_C3F_V3F:
-                pc = 2 * f;
-                pn = 0;
-                pv = 5 * f;
-                s  = 8 * f;
-                break;
-            case GL_T2F_N3F_V3F:
-                pc = 0;
-                pn = 2 * f;
-                pv = 5 * f;
-                s  = 8 * f;
-                break;
-            case GL_T2F_C4F_N3F_V3F:
-                pc = 2 * f;
-                pn = 6 * f;
-                pv = 9 * f;
-                s  = 12 * f;
-                break;
-            case GL_T4F_C4F_N3F_V4F:
-                pc = 4 * f;
-                pn = 8 * f;
-                pv = 11 * f;
-                s  = 15 * f;
-                break;
-            default:
-                RegalAssert( !"unhandled format value" );
-                break;
-        }
-
-        GLubyte* pointerc = static_cast<GLubyte*>( const_cast<GLvoid *>(pointer) ) + pc;
-        GLubyte* pointern = static_cast<GLubyte*>( const_cast<GLvoid *>(pointer) ) + pn;
-        GLubyte* pointerv = static_cast<GLubyte*>( const_cast<GLvoid *>(pointer) ) + pv;
-
-        if ( stride == 0 ) {
-            stride = s;
-        }
-
-        ShadowEnableDisableClientState( ctx, GL_EDGE_FLAG_ARRAY, GL_FALSE );
-        ShadowEnableDisableClientState( ctx, GL_INDEX_ARRAY, GL_FALSE );
-        ShadowEnableDisableClientState( ctx, GL_SECONDARY_COLOR_ARRAY, GL_FALSE );
-        ShadowEnableDisableClientState( ctx, GL_FOG_COORD_ARRAY, GL_FALSE );
-
-        GLint size = 0;
-        GLenum type = GL_FLOAT;
-
-        switch ( format )
-        {
-            case GL_T2F_V3F:
-            case GL_T4F_V4F:
-            case GL_T2F_C4UB_V3F:
-            case GL_T2F_C3F_V3F:
-            case GL_T2F_N3F_V3F:
-            case GL_T2F_C4F_N3F_V3F:
-            case GL_T4F_C4F_N3F_V4F:
-                size = ((format == GL_T4F_V4F) || (format == GL_T4F_C4F_N3F_V4F)) ? 4 : 2;
-                ShadowEnableDisableClientState( ctx, GL_TEXTURE_COORD_ARRAY, GL_TRUE );
-                TexCoordPointer(ctx, size, GL_FLOAT, stride, pointer);
-                break;
-            default:
-                ShadowEnableDisableClientState( ctx, GL_TEXTURE_COORD_ARRAY, GL_FALSE );
-                break;
-        }
-
-        switch ( format )
-        {
-            case GL_C4UB_V2F:
-            case GL_C4UB_V3F:
-            case GL_C3F_V3F:
-            case GL_C4F_N3F_V3F:
-            case GL_T2F_C4UB_V3F:
-            case GL_T2F_C3F_V3F:
-            case GL_T2F_C4F_N3F_V3F:
-            case GL_T4F_C4F_N3F_V4F:
-                size = ((format == GL_C3F_V3F) || (format == GL_T2F_C3F_V3F)) ? 3 : 4;
-                ShadowEnableDisableClientState( ctx, GL_COLOR_ARRAY, GL_TRUE );
-                ColorPointer(ctx, size, type, stride, pointerc);
-                break;
-            default:
-                ShadowEnableDisableClientState( ctx, GL_COLOR_ARRAY, GL_FALSE );
-                break;
-        }
-
-        switch ( format )
-        {
-            case GL_N3F_V3F:
-            case GL_C4F_N3F_V3F:
-            case GL_T2F_N3F_V3F:
-            case GL_T2F_C4F_N3F_V3F:
-            case GL_T4F_C4F_N3F_V4F:
-                ShadowEnableDisableClientState( ctx, GL_NORMAL_ARRAY, GL_TRUE );
-                NormalPointer(ctx, GL_FLOAT, stride, pointern);
-                break;
-            default:
-                ShadowEnableDisableClientState( ctx, GL_NORMAL_ARRAY, GL_FALSE );
-                break;
-        }
-
-        switch ( format )
-        {
-            case GL_V2F:
-            case GL_C4UB_V2F:
-                size = 2;
-                break;
-            case GL_V3F:
-            case GL_C4UB_V3F:
-            case GL_C3F_V3F:
-            case GL_N3F_V3F:
-            case GL_C4F_N3F_V3F:
-            case GL_T2F_V3F:
-            case GL_T2F_C4UB_V3F:
-            case GL_T2F_C3F_V3F:
-            case GL_T2F_N3F_V3F:
-            case GL_T2F_C4F_N3F_V3F:
-                size = 3;
-                break;
-            case GL_T4F_V4F:
-            case GL_T4F_C4F_N3F_V4F:
-                size = 4;
-                break;
-            default:
-                RegalAssert( !"unhandled format value" );
-                break;
-        }
-
-        ShadowEnableDisableClientState( ctx, GL_VERTEX_ARRAY, GL_TRUE );
-        VertexPointer(ctx, size, GL_FLOAT, stride, pointerv);
-    }
-
-    template <typename T> void PixelStore( RegalContext * ctx, GLenum pname, T param )
-    {
-        if ( ctx->depthBeginEnd )
-            return;
-
-        switch (pname)
-        {
-            case GL_PACK_SWAP_BYTES:
-                currentClientState.pixelStoreState.packSwapBytes =
-                       (param ? GL_TRUE : GL_FALSE);
-                return;
-
-            case GL_PACK_LSB_FIRST:
-                currentClientState.pixelStoreState.packLsbFirst =
-                       (param ? GL_TRUE : GL_FALSE);
-                return;
-
-            case GL_PACK_ROW_LENGTH:
-                if ( param >= 0 ) {
-                    currentClientState.pixelStoreState.packRowLength =
-                       static_cast<GLint>(param);
-                }
-                return;
-
-            case GL_PACK_IMAGE_HEIGHT:
-                if ( param >= 0 ) {
-                   currentClientState.pixelStoreState.packImageHeight =
-                       static_cast<GLint>(param);
-                }
-                return;
-
-            case GL_PACK_SKIP_ROWS:
-                if ( param >= 0 ) {
-                   currentClientState.pixelStoreState.packSkipRows =
-                       static_cast<GLint>(param);
-                }
-                return;
-
-            case GL_PACK_SKIP_PIXELS:
-                if ( param >= 0 ) {
-                   currentClientState.pixelStoreState.packSkipPixels =
-                       static_cast<GLint>(param);
-                }
-                return;
-
-            case GL_PACK_SKIP_IMAGES:
-                if ( param >= 0 ) {
-                   currentClientState.pixelStoreState.packSkipImages =
-                       static_cast<GLint>(param);
-                }
-                return;
-
-            case GL_PACK_ALIGNMENT:
-                if ( param == 1 || param == 2 || param == 4 || param == 8 ) {
-                   currentClientState.pixelStoreState.packAlignment =
-                       static_cast<GLint>(param);
-                }
-                return;
-
-            case GL_UNPACK_SWAP_BYTES:
-                currentClientState.pixelStoreState.unpackSwapBytes =
-                       (param ? GL_TRUE : GL_FALSE);
-                return;
-
-            case GL_UNPACK_LSB_FIRST:
-                currentClientState.pixelStoreState.unpackLsbFirst =
-                       (param ? GL_TRUE : GL_FALSE);
-                return;
-
-            case GL_UNPACK_ROW_LENGTH:
-                if ( param >= 0 ) {
-                   currentClientState.pixelStoreState.unpackRowLength =
-                       static_cast<GLint>(param);
-                }
-                return;
-
-            case GL_UNPACK_IMAGE_HEIGHT:
-                if ( param >= 0 ) {
-                   currentClientState.pixelStoreState.unpackImageHeight =
-                       static_cast<GLint>(param);
-                }
-                return;
-
-            case GL_UNPACK_SKIP_ROWS:
-                if ( param >= 0 ) {
-                   currentClientState.pixelStoreState.unpackSkipRows =
-                       static_cast<GLint>(param);
-                }
-                return;
-
-            case GL_UNPACK_SKIP_PIXELS:
-                if ( param >= 0 ) {
-                   currentClientState.pixelStoreState.unpackSkipPixels =
-                       static_cast<GLint>(param);
-                }
-                return;
-
-            case GL_UNPACK_SKIP_IMAGES:
-                if ( param >= 0 ) {
-                   currentClientState.pixelStoreState.unpackSkipImages =
-                       static_cast<GLint>(param);
-                }
-                return;
-
-            case GL_UNPACK_ALIGNMENT:
-                if ( param == 1 || param == 2 || param == 4 || param == 8 ) {
-                   currentClientState.pixelStoreState.unpackAlignment =
-                       static_cast<GLint>(param);
-                }
-                return;
-
-            default:
-                RegalAssert( !"unhandled pname value" );
-                break;
-        }
-    }
-
-    void ShadowEnableDisable( RegalContext * ctx, GLenum target, GLboolean enabled )
-    {
-        switch (target)
-        {
-            case GL_PRIMITIVE_RESTART:
-                currentClientState.vertexArrayState.primitiveRestart = enabled;
-                break;
-            default:
-                break;
-        }
-    }
-
-    void Enable( RegalContext * ctx, GLenum target )
-    {
-        ShadowEnableDisable( ctx, target, GL_TRUE );
-    }
-
-    void Disable( RegalContext * ctx, GLenum target )
-    {
-        ShadowEnableDisable( ctx, target, GL_FALSE );
-    }
-
-    void ShadowEnableDisableClientState( RegalContext * ctx, GLenum array, GLboolean enabled )
-    {
-        VertexArrayState* pAS = ClientStateToAttribState( array );
-        if (pAS)
-            pAS->enabled = enabled;
-    }
-
-    void EnableClientState( RegalContext * ctx, GLenum array )
-    {
-        if ( ctx->depthBeginEnd )
-            return;
-
-        ShadowEnableDisableClientState( ctx, array, GL_TRUE );
-    }
-
-    void DisableClientState( RegalContext * ctx, GLenum array )
-    {
-        if ( ctx->depthBeginEnd )
-            return;
-
-        ShadowEnableDisableClientState( ctx, array, GL_FALSE );
-    }
-
-    void ShadowEnableDisableVertexAttribArray( RegalContext * ctx, GLuint index,
-                                               GLboolean enabled )
-    {
-        if (index < REGAL_PPC_MAX_VERTEX_ATTRIBS)
-            currentClientState.vertexArrayState.genericArrayState[index].enabled = enabled;
-    }
-
-    void EnableVertexAttribArray( RegalContext * ctx, GLenum cap )
-    {
-        ShadowEnableDisableVertexAttribArray( ctx, cap, GL_TRUE );
-    }
-
-    void DisableVertexAttribArray( RegalContext * ctx, GLenum cap )
-    {
-        ShadowEnableDisableVertexAttribArray( ctx, cap, GL_FALSE );
-    }
-
-    void ShadowVertexAttribPointer( RegalContext * ctx,
-                                    GLuint _index,
-                                    GLint _size,
-                                    GLenum _type,
-                                    GLboolean _normalized,
-                                    GLboolean _integer,
-                                    GLsizei _stride,
-                                    const GLvoid * _pointer)
-    {
-        // do nothing for these various error conditions
-
-        if ( ctx->depthBeginEnd )
-            return;
-
-        if (_index >= REGAL_PPC_MAX_VERTEX_ATTRIBS)
-            return;
-
-        switch (_size)
-        {
-            case 1:
-            case 2:
-            case 3:
-            case 4:
-                break;
-            case GL_BGRA:
-                switch (_type)
-                {
-                    case GL_UNSIGNED_BYTE:
-                    case GL_INT_2_10_10_10_REV:
-                    case GL_UNSIGNED_INT_2_10_10_10_REV:
-                        break;
-                    default:
-                        return;
-                }
-                break;
-            default:
-                return;
-        }
-
-        switch (_type)
-        {
-            case GL_BYTE:
-            case GL_UNSIGNED_BYTE:
-            case GL_SHORT:
-            case GL_UNSIGNED_SHORT:
-            case GL_INT:
-            case GL_UNSIGNED_INT:
-            case GL_FLOAT:
-            case GL_DOUBLE:
-                break;
-            case GL_INT_2_10_10_10_REV:
-            case GL_UNSIGNED_INT_2_10_10_10_REV:
-                if (_size != 4 && _size != GL_BGRA)
-                    return;
-                break;
-            default:
-                return;
-        }
-
-        if (_size == GL_BGRA && _normalized == GL_FALSE) {
-            return;
-        }
-
-        if (_stride < 0) {
-            return;
-        }
-
-        if ( ( currentClientState.vertexArrayState.vertexArrayObject != 0 ) &&
-             ( currentClientState.vertexArrayState.vertexBuffer == 0 ) &&
-             ( _pointer != NULL ) ) {
-            return;
-        }
-
-        // otherwise shadow the generic vertex array state
-
-        currentClientState.vertexArrayState.genericArrayState[_index].SetPointer(
-             currentClientState.vertexArrayState.vertexBuffer,
-             _index, _size, _type, _normalized, _integer, _stride, _pointer );
-    }
-
-    void VertexAttribPointer( RegalContext * ctx,
-                              GLuint _index,
-                              GLint _size,
-                              GLenum _type,
-                              GLboolean _normalized,
-                              GLsizei _stride,
-                              const GLvoid * _pointer)
-    {
-        ShadowVertexAttribPointer( ctx, _index, _size, _type, _normalized, GL_FALSE,
-                                   _stride, _pointer );
-    }
-
-    void VertexAttribIPointer( RegalContext * ctx,
-                               GLuint _index,
-                               GLint _size,
-                               GLenum _type,
-                               GLsizei _stride,
-                               const GLvoid * _pointer)
-    {
-        ShadowVertexAttribPointer( ctx, _index, _size, _type, GL_FALSE, GL_TRUE,
-                                   _stride, _pointer );
-    }
-
-
-    void VertexAttribDivisor( RegalContext * ctx, GLuint index, GLint divisor )
-    {
-        if (index < REGAL_PPC_MAX_VERTEX_ATTRIBS)
-            currentClientState.vertexArrayState.genericArrayState[index].divisor = divisor;
-    }
-
-    void PrimitiveRestartIndex( RegalContext * ctx, GLuint index )
-    {
-        if (index < REGAL_PPC_MAX_VERTEX_ATTRIBS)
-            currentClientState.vertexArrayState.primitiveRestartIndex = index;
-    }
-
-    void ShadowVertexArrayPointer( RegalContext * ctx, GLenum array, GLint size,
-                                 GLenum type, GLsizei stride, const GLvoid * pointer)
-    {
-        if ( ( currentClientState.vertexArrayState.vertexArrayObject != 0 ) &&
-             ( currentClientState.vertexArrayState.vertexBuffer == 0 ) &&
-             ( pointer != NULL ) ) {
-            return;
-        }
-
-        VertexArrayState* pAS = ClientStateToAttribState( array );
-        GLuint index = ClientStateToAttribIndex( array );
-
-        if (pAS)
-            pAS->SetPointer( currentClientState.vertexArrayState.vertexBuffer,
-                             index, size, type, GL_TRUE, GL_FALSE, stride, pointer );
-
-    }
-
-    void ColorPointer(RegalContext * ctx, GLint size, GLenum type, GLsizei stride, const GLvoid * pointer)
-    {
-        if ( ctx->depthBeginEnd )
-            return;
-
-        switch (size)
-        {
-            case 3:
-            case 4:
-                break;
-            default:
-                return;
-        }
-
-        switch (type)
-        {
-            case GL_BYTE:
-            case GL_UNSIGNED_BYTE:
-            case GL_SHORT:
-            case GL_UNSIGNED_SHORT:
-            case GL_INT:
-            case GL_UNSIGNED_INT:
-            case GL_FLOAT:
-            case GL_DOUBLE:
-                break;
-            default:
-                return;
-        }
-
-        if (stride < 0)
-            return;
-
-        ShadowVertexArrayPointer(ctx, GL_COLOR_ARRAY, size, type, stride, pointer);
-    }
-
-    void SecondaryColorPointer(RegalContext * ctx, GLint size, GLenum type, GLsizei stride, const GLvoid * pointer)
-    {
-        if ( ctx->depthBeginEnd )
-            return;
-
-        if (size != 3)
-            return;
-
-        switch (type)
-        {
-            case GL_BYTE:
-            case GL_UNSIGNED_BYTE:
-            case GL_SHORT:
-            case GL_UNSIGNED_SHORT:
-            case GL_INT:
-            case GL_UNSIGNED_INT:
-            case GL_FLOAT:
-            case GL_DOUBLE:
-                break;
-            default:
-                return;
-        }
-
-        if (stride < 0)
-            return;
-
-        ShadowVertexArrayPointer(ctx, GL_SECONDARY_COLOR_ARRAY, size, type, stride, pointer);
-    }
-
-    void TexCoordPointer(RegalContext * ctx, GLint size, GLenum type, GLsizei stride, const GLvoid * pointer)
-    {
-        if ( ctx->depthBeginEnd )
-            return;
-
-        switch (size)
-        {
-            case 1:
-            case 2:
-            case 3:
-            case 4:
-                break;
-            default:
-                return;
-        }
-
-        switch (type)
-        {
-            case GL_SHORT:
-            case GL_INT:
-            case GL_FLOAT:
-            case GL_DOUBLE:
-                break;
-            default:
-                return;
-        }
-
-        if (stride < 0)
-            return;
-
-        ShadowVertexArrayPointer(ctx, GL_TEXTURE_COORD_ARRAY, size, type, stride, pointer);
-    }
-
-    void VertexPointer(RegalContext * ctx, GLint size, GLenum type, GLsizei stride, const GLvoid * pointer)
-    {
-        if ( ctx->depthBeginEnd )
-            return;
-
-        switch (size)
-        {
-            case 2:
-            case 3:
-            case 4:
-                break;
-            default:
-                return;
-        }
-
-        switch (type)
-        {
-            case GL_SHORT:
-            case GL_INT:
-            case GL_FLOAT:
-            case GL_DOUBLE:
-                break;
-            default:
-                return;
-        }
-
-        if (stride < 0)
-            return;
-
-        ShadowVertexArrayPointer(ctx, GL_VERTEX_ARRAY, size, type, stride, pointer);
-    }
-
-    void IndexPointer(RegalContext * ctx, GLenum type, GLsizei stride, const GLvoid * pointer)
-    {
-        if ( ctx->depthBeginEnd )
-            return;
-
-        switch (type)
-        {
-            case GL_UNSIGNED_BYTE:
-            case GL_SHORT:
-            case GL_INT:
-            case GL_FLOAT:
-            case GL_DOUBLE:
-                break;
-            default:
-                return;
-        }
-
-        if (stride < 0)
-            return;
-
-        ShadowVertexArrayPointer(ctx, GL_INDEX_ARRAY, 0, type, stride, pointer);
-    }
-
-    void NormalPointer(RegalContext * ctx, GLenum type, GLsizei stride, const GLvoid * pointer)
-    {
-        if ( ctx->depthBeginEnd )
-            return;
-
-        switch (type)
-        {
-            case GL_BYTE:
-            case GL_SHORT:
-            case GL_INT:
-            case GL_FLOAT:
-            case GL_DOUBLE:
-                break;
-            default:
-                return;
-        }
-
-        if (stride < 0)
-            return;
-
-        ShadowVertexArrayPointer(ctx, GL_NORMAL_ARRAY, 0, type, stride, pointer);
-    }
-
-    void FogCoordPointer(RegalContext * ctx, GLenum type, GLsizei stride, const GLvoid * pointer)
-    {
-        if ( ctx->depthBeginEnd )
-            return;
-
-        switch (type)
-        {
-            case GL_FLOAT:
-            case GL_DOUBLE:
-                break;
-            default:
-                return;
-        }
-
-        if (stride < 0)
-            return;
-
-        ShadowVertexArrayPointer(ctx, GL_FOG_COORD_ARRAY, 0, type, stride, pointer);
-    }
-
-    void EdgeFlagPointer(RegalContext * ctx, GLsizei stride, const GLvoid * pointer)
-    {
-        if ( ctx->depthBeginEnd )
-            return;
-
-        if (stride < 0)
-            return;
-
-        ShadowVertexArrayPointer(ctx, GL_EDGE_FLAG_ARRAY, 0, GL_FLOAT, stride, pointer);
-    }
-
-    void PushClientAttrib( RegalContext * ctx, GLbitfield mask )
-    {
-        if ( ctx->depthBeginEnd )
-            return;
-
-        if (topOfStack >= REGAL_PPC_MAX_CLIENT_ATTRIB_STACK_DEPTH-1) {
-            // GL_STACK_OVERFLOW. Don't do anything
-            return;
-        }
-
-        switch (mask)
-        {
-            case GL_CLIENT_ALL_ATTRIB_BITS:
-            case GL_CLIENT_VERTEX_ARRAY_BIT:
-            case GL_CLIENT_PIXEL_STORE_BIT:
-                break;
-            default:
-                RegalAssert( !"unhandled mask value" );
-                return;
-        }
-
-        currentClientState.pushPopMask = mask;
-        topOfStack++;
-        RegalAssert( topOfStack < REGAL_PPC_MAX_CLIENT_ATTRIB_STACK_DEPTH );
-        stack[topOfStack] = currentClientState;
-    }
-
-    void PopClientAttrib( RegalContext * ctx )
-    {
-        if ( ctx->depthBeginEnd )
-            return;
-
-        if (topOfStack < 0) {
-            // GL_STACK_UNDERFLOW. Don't do anything
-            return;
-        }
-
-        GLbitfield mask = stack[topOfStack].pushPopMask;
-
-        switch ( mask )
-        {
-            case GL_CLIENT_PIXEL_STORE_BIT:
-            case GL_CLIENT_VERTEX_ARRAY_BIT:
-            case GL_CLIENT_ALL_ATTRIB_BITS:
-                break;
-            default:
-                RegalAssert( !"unhandled mask value" );
-                return;
-        }
-
-        RegalAssert( topOfStack >= -1);
-
-        currentClientState = stack[topOfStack];
-        topOfStack--;
-
-        currentClientState.Restore( ctx );
-    }
-
-    template <typename T> bool Get( GLenum pname, T * params )
-    {
-        VertexArrayState* pAS = NULL;
-
-        switch (pname)
-        {
-            case GL_PACK_SWAP_BYTES:
-                *params = static_cast<T>(currentClientState.pixelStoreState.packSwapBytes );
-                break;
-
-            case GL_PACK_LSB_FIRST:
-                *params = static_cast<T>(currentClientState.pixelStoreState.packLsbFirst );
-                break;
-
-            case GL_PACK_ROW_LENGTH:
-                *params = static_cast<T>(currentClientState.pixelStoreState.packRowLength );
-                break;
-
-            case GL_PACK_IMAGE_HEIGHT:
-                *params = static_cast<T>(currentClientState.pixelStoreState.packImageHeight );
-                break;
-
-            case GL_PACK_SKIP_ROWS:
-                *params = static_cast<T>(currentClientState.pixelStoreState.packSkipRows );
-                break;
-
-            case GL_PACK_SKIP_PIXELS:
-                *params = static_cast<T>(currentClientState.pixelStoreState.packSkipPixels );
-                break;
-
-            case GL_PACK_SKIP_IMAGES:
-                *params = static_cast<T>(currentClientState.pixelStoreState.packSkipImages );
-                break;
-
-            case GL_PACK_ALIGNMENT:
-                *params = static_cast<T>(currentClientState.pixelStoreState.packAlignment );
-                break;
-
-            case GL_UNPACK_SWAP_BYTES:
-                *params = static_cast<T>(currentClientState.pixelStoreState.unpackSwapBytes );
-                break;
-
-            case GL_UNPACK_LSB_FIRST:
-                *params = static_cast<T>(currentClientState.pixelStoreState.unpackLsbFirst );
-                break;
-
-            case GL_UNPACK_ROW_LENGTH:
-                *params = static_cast<T>(currentClientState.pixelStoreState.unpackRowLength );
-                break;
-
-            case GL_UNPACK_IMAGE_HEIGHT:
-                *params = static_cast<T>(currentClientState.pixelStoreState.unpackImageHeight );
-                break;
-
-            case GL_UNPACK_SKIP_ROWS:
-                *params = static_cast<T>(currentClientState.pixelStoreState.unpackSkipRows );
-                break;
-
-            case GL_UNPACK_SKIP_PIXELS:
-                *params = static_cast<T>(currentClientState.pixelStoreState.unpackSkipPixels );
-                break;
-
-            case GL_UNPACK_SKIP_IMAGES:
-                *params = static_cast<T>(currentClientState.pixelStoreState.unpackSkipImages );
-                break;
-
-            case GL_UNPACK_ALIGNMENT:
-                *params = static_cast<T>(currentClientState.pixelStoreState.unpackAlignment );
-                break;
-
-            case GL_ARRAY_BUFFER_BINDING:
-                *params = static_cast<T>(currentClientState.vertexArrayState.vertexBuffer);
-                break;
-
-            case GL_ELEMENT_ARRAY_BUFFER_BINDING:
-                *params = static_cast<T>(currentClientState.vertexArrayState.indexBuffer);
-                break;
-
-            case GL_PIXEL_PACK_BUFFER_BINDING:
-                *params = static_cast<T>(currentClientState.pixelStoreState.pixelPackBufferBinding);
-                break;
-
-            case GL_PIXEL_UNPACK_BUFFER_BINDING:
-                *params = static_cast<T>(currentClientState.pixelStoreState.pixelUnpackBufferBinding);
-                break;
-
-            case GL_ATTRIB_STACK_DEPTH:
-                *params = static_cast<T>(topOfStack+1);
-                break;
-
-            case GL_MAX_VERTEX_ATTRIBS:
-                *params = static_cast<T>(REGAL_PPC_MAX_VERTEX_ATTRIBS);
-                break;
-
-            case GL_MAX_CLIENT_ATTRIB_STACK_DEPTH:
-                *params = static_cast<T>(REGAL_PPC_MAX_CLIENT_ATTRIB_STACK_DEPTH);
-                break;
-
-            case GL_MAX_TEXTURE_COORDS:
-                *params = static_cast<T>(ffAttrNumTex);
-                break;
-
-            case GL_CLIENT_ACTIVE_TEXTURE:
-                *params = static_cast<T>(currentClientState.vertexArrayState.clientActiveTexture);
-                break;
-
-            case GL_VERTEX_ARRAY_BUFFER_BINDING:
-                pAS = ClientStateToAttribState( GL_VERTEX_ARRAY );
-                if (pAS)
-                    *params = static_cast<T>(pAS->buffer);
-                break;
-
-            case GL_COLOR_ARRAY_BUFFER_BINDING:
-                pAS = ClientStateToAttribState( GL_COLOR_ARRAY );
-                if (pAS)
-                    *params = static_cast<T>(pAS->buffer);
-                break;
-
-            case GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING:
-                pAS = ClientStateToAttribState( GL_SECONDARY_COLOR_ARRAY );
-                if (pAS)
-                    *params = static_cast<T>(pAS->buffer);
-                break;
-
-            case GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING:
-                pAS = ClientStateToAttribState( GL_TEXTURE_COORD_ARRAY );
-                if (pAS)
-                    *params = static_cast<T>(pAS->buffer);
-                break;
-
-            case GL_FOG_COORD_ARRAY_BUFFER_BINDING:
-                pAS = ClientStateToAttribState( GL_FOG_COORD_ARRAY );
-                if (pAS)
-                    *params = static_cast<T>(pAS->buffer);
-                break;
-
-            case GL_NORMAL_ARRAY_BUFFER_BINDING:
-                pAS = ClientStateToAttribState( GL_NORMAL_ARRAY );
-                if (pAS)
-                    *params = static_cast<T>(pAS->buffer);
-                break;
-
-            case GL_INDEX_ARRAY_BUFFER_BINDING:
-                pAS = ClientStateToAttribState( GL_INDEX_ARRAY );
-                if (pAS)
-                    *params = static_cast<T>(pAS->buffer);
-                break;
-
-            case GL_EDGE_FLAG_ARRAY_BUFFER_BINDING:
-                pAS = ClientStateToAttribState( GL_EDGE_FLAG_ARRAY );
-                if (pAS)
-                    *params = static_cast<T>(pAS->buffer);
-                break;
-
-            case GL_COLOR_ARRAY_SIZE:
-                pAS = ClientStateToAttribState( GL_COLOR_ARRAY );
-                if (pAS)
-                    *params = static_cast<T>(pAS->size);
-                break;
-
-            case GL_VERTEX_ARRAY_SIZE:
-                pAS = ClientStateToAttribState( GL_VERTEX_ARRAY );
-                if (pAS)
-                    *params = static_cast<T>(pAS->size);
-                break;
-
-            case GL_SECONDARY_COLOR_ARRAY_SIZE:
-                *params = static_cast<T>(3);
-                break;
-
-            case GL_TEXTURE_COORD_ARRAY_SIZE:
-                pAS = ClientStateToAttribState( GL_TEXTURE_COORD_ARRAY );
-                if (pAS)
-                    *params = static_cast<T>(pAS->size);
-                break;
-
-            case GL_SECONDARY_COLOR_ARRAY_TYPE:
-                pAS = ClientStateToAttribState( GL_SECONDARY_COLOR_ARRAY );
-                if (pAS)
-                    *params = static_cast<T>(pAS->type);
-                break;
-
-            case GL_COLOR_ARRAY_TYPE:
-                pAS = ClientStateToAttribState( GL_COLOR_ARRAY );
-                if (pAS)
-                    *params = static_cast<T>(pAS->type);
-                break;
-
-            case GL_VERTEX_ARRAY_TYPE:
-                pAS = ClientStateToAttribState( GL_VERTEX_ARRAY );
-                if (pAS)
-                    *params = static_cast<T>(pAS->type);
-                break;
-
-            case GL_TEXTURE_COORD_ARRAY_TYPE:
-                pAS = ClientStateToAttribState( GL_TEXTURE_COORD_ARRAY );
-                if (pAS)
-                    *params = static_cast<T>(pAS->type);
-                break;
-
-            case GL_FOG_COORD_ARRAY_TYPE:
-                pAS = ClientStateToAttribState( GL_FOG_COORD_ARRAY );
-                if (pAS)
-                    *params = static_cast<T>(pAS->type);
-                break;
-
-            case GL_NORMAL_ARRAY_TYPE:
-                pAS = ClientStateToAttribState( GL_NORMAL_ARRAY );
-                if (pAS)
-                    *params = static_cast<T>(pAS->type);
-                break;
-
-            case GL_SECONDARY_COLOR_ARRAY_STRIDE:
-                pAS = ClientStateToAttribState( GL_SECONDARY_COLOR_ARRAY );
-                if (pAS)
-                    *params = static_cast<T>(pAS->stride);
-                break;
-
-            case GL_COLOR_ARRAY_STRIDE:
-                pAS = ClientStateToAttribState( GL_COLOR_ARRAY );
-                if (pAS)
-                    *params = static_cast<T>(pAS->stride);
-                break;
-
-            case GL_VERTEX_ARRAY_STRIDE:
-                pAS = ClientStateToAttribState( GL_VERTEX_ARRAY );
-                if (pAS)
-                    *params = static_cast<T>(pAS->stride);
-                break;
-
-            case GL_FOG_COORD_ARRAY_STRIDE:
-                pAS = ClientStateToAttribState( GL_FOG_COORD_ARRAY );
-                if (pAS)
-                    *params = static_cast<T>(pAS->stride);
-                break;
-
-            case GL_TEXTURE_COORD_ARRAY_STRIDE:
-                pAS = ClientStateToAttribState( GL_TEXTURE_COORD_ARRAY );
-                if (pAS)
-                    *params = static_cast<T>(pAS->stride);
-                break;
-
-            case GL_NORMAL_ARRAY_STRIDE:
-                pAS = ClientStateToAttribState( GL_NORMAL_ARRAY );
-                if (pAS)
-                    *params = static_cast<T>(pAS->stride);
-                break;
-
-            case GL_INDEX_ARRAY_TYPE:
-                pAS = ClientStateToAttribState( GL_INDEX_ARRAY );
-                if (pAS)
-                    *params = static_cast<T>(pAS->type);
-                break;
-
-            case GL_INDEX_ARRAY_STRIDE:
-                pAS = ClientStateToAttribState( GL_INDEX_ARRAY );
-                if (pAS)
-                    *params = static_cast<T>(pAS->stride);
-                break;
-
-            case GL_EDGE_FLAG_ARRAY_STRIDE:
-                pAS = ClientStateToAttribState( GL_EDGE_FLAG_ARRAY );
-                if (pAS)
-                    *params = static_cast<T>(pAS->stride);
-                break;
-
-            case GL_PRIMITIVE_RESTART_INDEX:
-                *params = static_cast<T>(currentClientState.vertexArrayState.primitiveRestartIndex);
-                break;
-
-            case GL_VERTEX_ARRAY_BINDING:
-                *params = static_cast<T>(currentClientState.vertexArrayState.vertexArrayObject);
-                break;
-
-            default:
-                return false;
-        }
-        return true;
-    }
-
-    template <typename T> bool GetIndexed( GLenum pname, GLuint index, T * params )
-    {
-        RegalAssert(index >= 0);
-        RegalAssert(index < REGAL_PPC_MAX_TEXTURE_COORDS);
-
-        if ( index >= ffAttrNumTex )
-            return false;
-
-        index += ffAttrTexBegin;
-
-        VertexArrayState* pAS =
-             &currentClientState.vertexArrayState.genericArrayState[index];
-
-        switch (pname)
-        {
-            case GL_TEXTURE_COORD_ARRAY_SIZE:
-                *params = static_cast<T>(pAS->size);
-                break;
-
-            case GL_TEXTURE_COORD_ARRAY_TYPE:
-                *params = static_cast<T>(pAS->type);
-                break;
-
-            case GL_TEXTURE_COORD_ARRAY_STRIDE:
-                *params = static_cast<T>(pAS->stride);
-                break;
-
-            case GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING:
-                *params = static_cast<T>(pAS->buffer);
-                break;
-
-            default:
-                return false;
-        }
-        return true;
-    }
-
-    bool IsEnabled( GLenum cap, GLboolean &enabled )
-    {
-        VertexArrayState* pAS = NULL;
-
-        switch (cap)
-        {
-            case GL_PRIMITIVE_RESTART:
-                enabled = currentClientState.vertexArrayState.primitiveRestart;
-                break;
-
-            case GL_EDGE_FLAG_ARRAY:
-            case GL_NORMAL_ARRAY:
-            case GL_INDEX_ARRAY:
-            case GL_FOG_COORD_ARRAY:
-            case GL_VERTEX_ARRAY:
-            case GL_COLOR_ARRAY:
-            case GL_SECONDARY_COLOR_ARRAY:
-            case GL_TEXTURE_COORD_ARRAY:
-                pAS = ClientStateToAttribState( cap );
-                if ( pAS == NULL )
-                    return false;
-                enabled = pAS->enabled;
-                break;
-
-            default:
-                return false;
-        }
-        return true;
-    }
-
-    bool IsEnabledIndexed( GLenum array, GLuint index, GLboolean &enabled )
-    {
-        switch ( array )
-        {
-            case GL_TEXTURE_COORD_ARRAY:
-                RegalAssert(index >= 0);
-                RegalAssert(index < REGAL_PPC_MAX_TEXTURE_COORDS);
-                if ( index >= ffAttrNumTex )
-                    return false;
-                index += ffAttrTexBegin;
-                enabled = currentClientState.vertexArrayState.genericArrayState[index].enabled;
-                break;
-
-            default:
-                return false;
-        }
-        return true;
-    }
-
-    bool GetPointerv( GLenum pname, GLvoid ** params)
-    {
-        VertexArrayState* pAS = NULL;
-
-        switch (pname)
-        {
-            case GL_EDGE_FLAG_ARRAY_POINTER:
-                pAS = ClientStateToAttribState( GL_EDGE_FLAG_ARRAY );
-                break;
-
-            case GL_INDEX_ARRAY_POINTER:
-                pAS = ClientStateToAttribState( GL_INDEX_ARRAY );
-                break;
-
-            case GL_NORMAL_ARRAY_POINTER:
-                pAS = ClientStateToAttribState( GL_NORMAL_ARRAY );
-                break;
-
-            case GL_FOG_COORD_ARRAY_POINTER:
-                pAS = ClientStateToAttribState( GL_FOG_COORD_ARRAY );
-                break;
-
-            case GL_VERTEX_ARRAY_POINTER:
-                pAS = ClientStateToAttribState( GL_VERTEX_ARRAY );
-                break;
-
-            case GL_COLOR_ARRAY_POINTER:
-                pAS = ClientStateToAttribState( GL_COLOR_ARRAY );
-                break;
-
-            case GL_SECONDARY_COLOR_ARRAY_POINTER:
-                pAS = ClientStateToAttribState( GL_SECONDARY_COLOR_ARRAY );
-                break;
-
-            case GL_TEXTURE_COORD_ARRAY_POINTER:
-                pAS = ClientStateToAttribState( GL_TEXTURE_COORD_ARRAY );
-                break;
-
-            default:
-                return false;
-        }
-
-        if ( pAS == NULL )
-            return false;
-
-        *params = const_cast<GLvoid *>(pAS->pointer);
-        return true;
-    }
-
-    bool GetVertexAttribPointerv( GLuint index, GLenum pname, GLvoid ** pointer)
-    {
-        if ( ( pname == GL_VERTEX_ATTRIB_ARRAY_POINTER ) &&
-                 ( index < REGAL_PPC_MAX_VERTEX_ATTRIBS ) ) {
-            *pointer = const_cast<GLvoid *>(currentClientState.vertexArrayState.genericArrayState[index].pointer);
-            return true;
-        }
-        return false;
-    }
-
-    template <typename T> bool GetVertexAttribv( GLuint index, GLenum pname, T * params )
-    {
-        if ( index >= REGAL_PPC_MAX_VERTEX_ATTRIBS )
-            return false;
-
-        if ( index == 0 && pname == GL_CURRENT_VERTEX_ATTRIB)
-            return false;
-
-        VertexArrayState &gas = currentClientState.vertexArrayState.genericArrayState[index];
-
-        switch (pname)
-        {
-            case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
-                *params = static_cast<T>(gas.buffer);
-                break;
-
-            case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
-                *params = static_cast<T>(gas.enabled);
-                break;
-
-            case GL_VERTEX_ATTRIB_ARRAY_SIZE:
-                *params = static_cast<T>(gas.size);
-                break;
-
-            case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
-                *params = static_cast<T>(gas.divisor);
-                break;
-
-            case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
-                *params = static_cast<T>(gas.stride);
-                break;
-
-            case GL_VERTEX_ATTRIB_ARRAY_TYPE:
-                *params = static_cast<T>(gas.type);
-                break;
-
-            case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
-                *params = static_cast<T>(gas.normalized);
-                break;
-
-            case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
-                *params = static_cast<T>(gas.integer);
-                break;
-
-            default:
-                return false;
-        }
-        return true;
-    }
-};
-
-REGAL_NAMESPACE_END
-
-#endif // ! __REGAL_PPC_H__
diff --git a/src/regal/RegalPpca.cpp b/src/regal/RegalPpca.cpp
deleted file mode 100644
index 068abc5..0000000
--- a/src/regal/RegalPpca.cpp
+++ /dev/null
@@ -1,2419 +0,0 @@
-/*
-  Copyright (c) 2011-2012 NVIDIA Corporation
-  Copyright (c) 2011-2012 Cass Everitt
-  Copyright (c) 2012 Scott Nations
-  Copyright (c) 2012 Mathias Schott
-  Copyright (c) 2012 Nigel Stewart
-  Copyright (c) 2013 Google Inc.
-  All rights reserved.
-
-  Redistribution and use in source and binary forms, with or without modification,
-  are permitted provided that the following conditions are met:
-
-    Redistributions of source code must retain the above copyright notice, this
-    list of conditions and the following disclaimer.
-
-    Redistributions in binary form must reproduce the above copyright notice,
-    this list of conditions and the following disclaimer in the documentation
-    and/or other materials provided with the distribution.
-
-  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
-  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
-  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
-  OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
-  OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
-
-#include "pch.h" /* For MS precompiled header support */
-
-#include "RegalUtil.h"
-
-#if REGAL_EMULATION
-
-REGAL_GLOBAL_BEGIN
-
-#include <math.h>
-#include <algorithm>
-
-#include "RegalPpca.h"
-#include "RegalContext.h"
-#include "RegalContextInfo.h"
-
-REGAL_GLOBAL_END
-
-REGAL_NAMESPACE_BEGIN
-
-namespace {
-
-// Helper function for swapping fixed size arrays of some type.
-template <typename T, size_t N> void swap_array( T( &lhs )[ N ], T( &rhs )[ N ] ) {
-  using std::swap;
-  for ( size_t i = 0; i < N; ++i ) {
-    swap( lhs[ i ], rhs[ i ] );
-  }
-}
-
-} // namespace
-
-// ====================================
-// ClientState::PixelStore
-// ====================================
-
-namespace ClientState {
-namespace PixelStore {
-
-const GLenum State::indexToPName[ STATE_COUNT ] = {
-  GL_PACK_SWAP_BYTES,
-  GL_PACK_LSB_FIRST,
-  GL_PACK_ROW_LENGTH,
-  GL_PACK_IMAGE_HEIGHT,
-  GL_PACK_SKIP_ROWS,
-  GL_PACK_SKIP_PIXELS,
-  GL_PACK_SKIP_IMAGES,
-  GL_PACK_ALIGNMENT,
-
-  GL_UNPACK_SWAP_BYTES,
-  GL_UNPACK_LSB_FIRST,
-  GL_UNPACK_ROW_LENGTH,
-  GL_UNPACK_IMAGE_HEIGHT,
-  GL_UNPACK_SKIP_ROWS,
-  GL_UNPACK_SKIP_PIXELS,
-  GL_UNPACK_SKIP_IMAGES,
-  GL_UNPACK_ALIGNMENT,
-};
-
-void State::Reset() {
-  // Most state defaults to zero.
-  for ( size_t i = 0; i < STATE_COUNT; ++i ) {
-    data[ i ] = 0;
-  }
-  // The two alignments default to four.
-  data[ 7 ] = 4;
-  data[ 15 ] = 4;
-
-  pixelPackBufferBinding = 0;
-  pixelUnpackBufferBinding = 0;
-}
-
-void State::Set( GLenum pname, GLint pvalue ) {
-  size_t index = PNameToIndex( pname );
-  if ( index >= STATE_COUNT ) {
-    return;
-  }
-  data[ index ] = pvalue;
-}
-
-GLint State::Get( GLenum pname ) const {
-  size_t index = PNameToIndex( pname );
-  if ( index >= STATE_COUNT ) {
-    return 0;
-  }
-  return data[ index ];
-}
-
-void swap( State& lhs, State& rhs ) {
-  using std::swap;
-
-  swap_array( lhs.data, rhs.data );
-  swap( lhs.pixelPackBufferBinding, rhs.pixelPackBufferBinding );
-  swap( lhs.pixelUnpackBufferBinding, rhs.pixelUnpackBufferBinding );
-}
-
-size_t PNameToIndex( GLenum pname ) {
-  switch ( pname ) {
-    default:                     return INVALID_INDEX;
-
-    case GL_PACK_SWAP_BYTES:     return 0;
-    case GL_PACK_LSB_FIRST:      return 1;
-    case GL_PACK_ROW_LENGTH:     return 2;
-    case GL_PACK_IMAGE_HEIGHT:   return 3;
-    case GL_PACK_SKIP_ROWS:      return 4;
-    case GL_PACK_SKIP_PIXELS:    return 5;
-    case GL_PACK_SKIP_IMAGES:    return 6;
-    case GL_PACK_ALIGNMENT:      return 7;
-
-    case GL_UNPACK_SWAP_BYTES:   return 8;
-    case GL_UNPACK_LSB_FIRST:    return 9;
-    case GL_UNPACK_ROW_LENGTH:   return 10;
-    case GL_UNPACK_IMAGE_HEIGHT: return 11;
-    case GL_UNPACK_SKIP_ROWS:    return 12;
-    case GL_UNPACK_SKIP_PIXELS:  return 13;
-    case GL_UNPACK_SKIP_IMAGES:  return 14;
-    case GL_UNPACK_ALIGNMENT:    return 15;
-  }
-}
-
-void Transition( const Capabilities& cap, const DispatchTableGL& dt, const State& current, const State& target )
-{
-  UNUSED_PARAMETER(cap);
-  RegalAssert( dt.glPixelStorei );
-
-  for ( size_t i = 0; i < STATE_COUNT; ++i ) {
-    if ( current.data[ i ] != target.data[ i ] ) {
-      dt.glPixelStorei( State::indexToPName[ i ], target.data[ i ] );
-    }
-  }
-
-  if ( current.pixelPackBufferBinding != target.pixelPackBufferBinding ) {
-    dt.glBindBuffer( GL_PIXEL_PACK_BUFFER_BINDING, target.pixelPackBufferBinding );
-  }
-
-  if ( current.pixelUnpackBufferBinding != target.pixelUnpackBufferBinding ) {
-    dt.glBindBuffer( GL_PIXEL_UNPACK_BUFFER_BINDING, target.pixelUnpackBufferBinding );
-  }
-}
-
-} // namespace PixelStore
-} // namespace ClientState
-
-// ====================================
-// ClientState::VertexArray::Fixed
-// ====================================
-
-namespace ClientState {
-namespace VertexArray {
-namespace Fixed {
-namespace {
-
-bool operator != ( const State::Source& lhs, const State::Source& rhs ) {
-  return ( lhs.buffer != rhs.buffer ) || ( lhs.size != rhs.size ) || ( lhs.type != rhs.type ) || ( lhs.stride != rhs.stride ) || ( lhs.offset != rhs.offset );
-}
-
-void ApplyAttribPointer( const State::Source& target, void (REGAL_CALL *dispatchAttribPointer )( GLint, GLenum, GLsizei, const GLvoid* ) ) {
-  dispatchAttribPointer( target.size, target.type, target.stride, reinterpret_cast<const GLvoid*>( target.offset ) );
-}
-
-void ApplyAttribPointer( const State::Source& target, void (REGAL_CALL *dispatchAttribPointer )( GLenum, GLsizei, const GLvoid* ) ) {
-  dispatchAttribPointer( target.type, target.stride, reinterpret_cast<const GLvoid*>( target.offset ) );
-}
-
-void ApplyAttribPointer( const State::Source& target, void (REGAL_CALL *dispatchAttribPointer )( GLsizei, const GLvoid* ) ) {
-  dispatchAttribPointer( target.stride, reinterpret_cast<const GLvoid*>( target.offset ) );
-}
-
-void ApplyClientStateEnable( const DispatchTableGL& dt, GLenum array, bool enable ) {
-  ( enable ? dt.glEnableClientState : dt.glDisableClientState )( array );
-}
-
-template <typename T>
-void Transition( const Capabilities& cap, const DispatchTableGL& dt, const State::Attrib& current, const State::Attrib& target, GLenum array, T dispatchAttribPointer, GLuint& inoutArrayBufferBinding ) {
-  if ( target.enabled != current.enabled ) {
-    ApplyClientStateEnable( dt, array, target.enabled );
-  }
-
-  if ( target.source != current.source ) {
-    if ( ( target.source.buffer != 0 ) || cap.driverAllowsVertexAttributeArraysWithoutBoundBuffer ) {
-      if ( target.source.buffer != inoutArrayBufferBinding ) {
-        dt.glBindBuffer( GL_ARRAY_BUFFER, target.source.buffer );
-        inoutArrayBufferBinding = target.source.buffer;
-      }
-      ApplyAttribPointer( target.source, dispatchAttribPointer );
-    }
-  }
-}
-
-void TransitionTextureCoords( const Capabilities& cap, const DispatchTableGL& dt, const State::Attrib& current, const State::Attrib& target, GLenum texture, GLenum& inoutClientActiveTexture, GLuint& inoutArrayBufferBinding ) {
-  bool sourceDelta = target.source != current.source;
-
-  if ( ( current.enabled != target.enabled ) || sourceDelta ) {
-    if ( inoutClientActiveTexture != texture ) {
-      dt.glClientActiveTexture( texture );
-      inoutClientActiveTexture = texture;
-    }
-  }
-
-  if ( current.enabled != target.enabled ) {
-    ApplyClientStateEnable( dt, GL_TEXTURE_COORD_ARRAY, target.enabled );
-  }
-
-  if ( sourceDelta ) {
-    if ( ( target.source.buffer != 0 ) || cap.driverAllowsVertexAttributeArraysWithoutBoundBuffer ) {
-      if ( target.source.buffer != inoutArrayBufferBinding ) {
-        dt.glBindBuffer( GL_ARRAY_BUFFER, target.source.buffer );
-        inoutArrayBufferBinding = target.source.buffer;
-      }
-      ApplyAttribPointer( target.source, dt.glTexCoordPointer );
-    }
-  }
-}
-
-void swap( State::Source& lhs, State::Source& rhs ) {
-  using std::swap;
-  swap( lhs.buffer, rhs.buffer );
-  swap( lhs.size, rhs.size );
-  swap( lhs.type, rhs.type );
-  swap( lhs.stride, rhs.stride );
-  swap( lhs.offset, rhs.offset );
-}
-
-void swap( State::Attrib& lhs, State::Attrib& rhs ) {
-  using std::swap;
-  swap( lhs.enabled, rhs.enabled );
-  swap( lhs.source, rhs.source );
-}
-
-} // namespace
-
-void State::Reset() {
-  for ( size_t i = 0; i < COUNT_ATTRIBS; ++i ) {
-    attrib[ i ].enabled = false;
-
-    attrib[ i ].source.buffer = 0;
-    attrib[ i ].source.size   = 4;
-    attrib[ i ].source.type   = GL_FLOAT;
-    attrib[ i ].source.stride = 0;
-    attrib[ i ].source.offset = 0;
-  }
-
-  //  GL_NORMAL_ARRAY.size must be 3
-  attrib[ 1 ].source.size = 3;
-  //  GL_SECONDARY_COLOR_ARRAY.size must be 3
-  attrib[ 3 ].source.size = 3;
-  //  GL_INDEX_ARRAY.size must be 1
-  attrib[ 4 ].source.size = 1;
-  //  GL_EDGE_FLAG_ARRAY.size must be 1
-  //  GL_EDGE_FLAG_ARRAY.type must be boolean
-  attrib[ 5 ].source.size = 1;
-  attrib[ 5 ].source.type = GL_BOOL;
-  //  GL_FOG_COORD_ARRAY must be 1
-  attrib[ 6 ].source.size = 1;
-}
-
-void State::SetEnable( size_t attribIndex, bool enabled ) {
-  if ( attribIndex >= COUNT_ATTRIBS ) {
-    return;
-  }
-
-  attrib[ attribIndex ].enabled = enabled;
-}
-
-void State::SetData( size_t attribIndex, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset ) {
-  if ( attribIndex >= COUNT_ATTRIBS ) {
-    return;
-  }
-  State::Source& source = attrib[ attribIndex ].source;
-
-  source.buffer = buffer;
-  source.size = size;
-  source.type = type;
-  source.stride = stride;
-  source.offset = offset;
-}
-
-void swap( State& lhs, State& rhs ) {
-  swap_array( lhs.attrib, rhs.attrib );
-}
-
-size_t ArrayNameToAttribIndex( GLenum array, GLenum texunit ) {
-  switch ( array ) {
-    default:                        return INVALID_ATTRIB_INDEX;
-
-    case GL_VERTEX_ARRAY:           return BASE_NAMED_ATTRIBS + 0;
-    case GL_NORMAL_ARRAY:           return BASE_NAMED_ATTRIBS + 1;
-    case GL_COLOR_ARRAY:            return BASE_NAMED_ATTRIBS + 2;
-    case GL_SECONDARY_COLOR_ARRAY:  return BASE_NAMED_ATTRIBS + 3;
-    case GL_INDEX_ARRAY:            return BASE_NAMED_ATTRIBS + 4;
-    case GL_EDGE_FLAG_ARRAY:        return BASE_NAMED_ATTRIBS + 5;
-    case GL_FOG_COORD_ARRAY:        return BASE_NAMED_ATTRIBS + 6;
-
-    case GL_TEXTURE_COORD_ARRAY:
-      {
-        size_t index = texunit - GL_TEXTURE0;
-        if ( index < COUNT_TEXTURE_COORD_ATTRIBS ) {
-          return BASE_TEXTURE_COORD_ATTRIBS + index;
-        }
-        return INVALID_ATTRIB_INDEX;
-      }
-  }
-}
-
-size_t IndexedArrayNameToAttribIndex( GLenum array, GLuint index ) {
-  switch ( array ) {
-    default:
-      return INVALID_ATTRIB_INDEX;
-
-    case GL_TEXTURE_COORD_ARRAY:
-      {
-        if ( index < COUNT_TEXTURE_COORD_ATTRIBS ) {
-          return BASE_TEXTURE_COORD_ATTRIBS + index;
-        }
-        return INVALID_ATTRIB_INDEX;
-      }
-  }
-}
-
-void Transition( const Capabilities& cap, const DispatchTableGL& dt, const State& current, const State& target, GLenum& inoutClientActiveTexture, GLuint& inoutArrayBufferBinding ) {
-  RegalAssert( dt.glEnableClientState );
-  RegalAssert( dt.glDisableClientState );
-
-  RegalAssert( dt.glVertexPointer );
-  RegalAssert( dt.glNormalPointer );
-  RegalAssert( dt.glColorPointer );
-  RegalAssert( dt.glSecondaryColorPointer );
-  RegalAssert( dt.glIndexPointer );
-  RegalAssert( dt.glEdgeFlagPointer );
-  RegalAssert( dt.glFogCoordPointer );
-
-  RegalAssert( dt.glClientActiveTexture );
-  RegalAssert( dt.glTexCoordPointer );
-
-  Transition( cap, dt, current.attrib[ 0 ], target.attrib [ 0 ], GL_VERTEX_ARRAY,          dt.glVertexPointer,         inoutArrayBufferBinding );
-  Transition( cap, dt, current.attrib[ 1 ], target.attrib [ 1 ], GL_NORMAL_ARRAY,          dt.glNormalPointer,         inoutArrayBufferBinding );
-  Transition( cap, dt, current.attrib[ 2 ], target.attrib [ 2 ], GL_COLOR_ARRAY,           dt.glColorPointer,          inoutArrayBufferBinding );
-  Transition( cap, dt, current.attrib[ 3 ], target.attrib [ 3 ], GL_SECONDARY_COLOR_ARRAY, dt.glSecondaryColorPointer, inoutArrayBufferBinding );
-  Transition( cap, dt, current.attrib[ 4 ], target.attrib [ 4 ], GL_INDEX_ARRAY,           dt.glIndexPointer,          inoutArrayBufferBinding );
-  Transition( cap, dt, current.attrib[ 5 ], target.attrib [ 5 ], GL_EDGE_FLAG_ARRAY,       dt.glEdgeFlagPointer,       inoutArrayBufferBinding );
-  Transition( cap, dt, current.attrib[ 6 ], target.attrib [ 6 ], GL_FOG_COORD_ARRAY,       dt.glFogCoordPointer,       inoutArrayBufferBinding );
-
-  for ( size_t i = 0; i < COUNT_TEXTURE_COORD_ATTRIBS; ++i ) {
-    TransitionTextureCoords( cap, dt, current.attrib[ 7 + i ], target.attrib[ 7 + i ], static_cast<GLenum>(GL_TEXTURE0 + i), inoutClientActiveTexture, inoutArrayBufferBinding );
-  }
-}
-
-} // namespace Fixed
-} // namespace VertexArray
-} // namespace ClientState
-
-// ====================================
-// ClientState::VertexArray::Generic
-// ====================================
-
-namespace ClientState {
-namespace VertexArray {
-namespace Generic {
-namespace {
-
-bool operator != ( const State::Source lhs, const State::Source rhs ) {
-  return ( lhs.size != rhs.size ) || ( lhs.type != rhs.type ) || ( lhs.normalized != rhs.normalized ) || ( lhs.pureInteger != rhs.pureInteger ) || ( lhs.relativeOffset != rhs.relativeOffset );
-}
-
-void swap( State::Source& lhs, State::Source& rhs ) {
-  using std::swap;
-  swap( lhs.size, rhs.size );
-  swap( lhs.type, rhs.type );
-  swap( lhs.normalized, rhs.normalized );
-  swap( lhs.pureInteger, rhs.pureInteger );
-  swap( lhs.relativeOffset, rhs.relativeOffset );
-}
-
-void swap( State::Attrib& lhs, State::Attrib& rhs ) {
-  using std::swap;
-  swap( lhs.enabled, rhs.enabled );
-  swap( lhs.bindingIndex, rhs.bindingIndex );
-  swap( lhs.source, rhs.source );
-}
-
-void swap( State::Buffer& lhs, State::Buffer& rhs ) {
-  using std::swap;
-  swap( lhs.buffer, rhs.buffer );
-  swap( lhs.offset, rhs.offset );
-  swap( lhs.stride, rhs.stride );
-  swap( lhs.divisor, rhs.divisor );
-}
-
-void ApplyVertexAttribArrayEnable( const DispatchTableGL& dt, GLuint index, bool enable ) {
-  ( enable ? dt.glEnableVertexAttribArray : dt.glDisableVertexAttribArray )( index );
-}
-
-void Transition( const Capabilities& cap, const DispatchTableGL& dt, const State::Attrib& current, const State::Attrib& target, GLuint index )
-{
-  UNUSED_PARAMETER(cap);
-
-  if ( target.enabled != current.enabled ) {
-    ApplyVertexAttribArrayEnable( dt, index, target.enabled );
-  }
-
-  if ( target.source != current.source ) {
-    if ( target.source.pureInteger ) {
-      dt.glVertexAttribIFormat( index, target.source.size, target.source.type, target.source.relativeOffset );
-    } else {
-      dt.glVertexAttribFormat( index, target.source.size, target.source.type, target.source.normalized ? GL_TRUE : GL_FALSE, target.source.relativeOffset );
-    }
-  }
-
-  if ( target.bindingIndex != current.bindingIndex ) {
-    dt.glVertexAttribBinding( index, target.bindingIndex );
-  }
-}
-
-void Transition( const Capabilities& cap, const DispatchTableGL& dt, const State::Buffer& current, const State::Buffer& target, GLuint index )
-{
-  UNUSED_PARAMETER(cap);
-
-  if ( ( target.buffer != current.buffer ) || ( target.offset != current.offset ) || ( target.stride != current.stride ) ) {
-    dt.glBindVertexBuffer( index, target.buffer, target.offset, target.stride );
-  }
-  if ( target.divisor != current.divisor ) {
-    dt.glVertexBindingDivisor( index, target.divisor );
-  }
-}
-
-} // namespace
-
-void State::Reset() {
-  for ( size_t i = 0; i < COUNT_ATTRIBS; ++i ) {
-    State::Attrib& attrib = this->attrib[ i ];
-    attrib.enabled = false;
-    attrib.bindingIndex = static_cast<GLuint>(i);
-
-    State::Source& source = attrib.source;
-    source.size = 4;
-    source.type = GL_FLOAT;
-    source.normalized = false;
-    source.pureInteger = false;
-    source.relativeOffset = 0;
-  }
-
-  for ( size_t i = 0; i < COUNT_BUFFERS; ++i ) {
-    State::Buffer& buffer = this->buffer[ i ];
-    buffer.buffer = 0;
-    buffer.offset = 0;
-    buffer.stride = 16;
-    buffer.divisor = 0;
-  }
-}
-
-void State::SetAttribSource( GLuint attribIndex, GLint size, GLenum type, bool normalized, bool pureInteger, GLuint relativeOffset ) {
-  if ( attribIndex >= COUNT_ATTRIBS ) {
-    return;
-  }
-
-  attrib[ attribIndex ].source.size = size;
-  attrib[ attribIndex ].source.type = type;
-  attrib[ attribIndex ].source.normalized = normalized;
-  attrib[ attribIndex ].source.pureInteger = pureInteger;
-  attrib[ attribIndex ].source.relativeOffset = relativeOffset;
-}
-
-void State::SetBuffer( GLuint bindingIndex, GLuint buffer, GLintptr offset, GLsizei stride ) {
-  if ( bindingIndex >= COUNT_BUFFERS ) {
-    return;
-  }
-
-  this->buffer[ bindingIndex ].buffer = buffer;
-  this->buffer[ bindingIndex ].offset = offset;
-  this->buffer[ bindingIndex ].stride = stride;
-}
-
-void State::SetBufferDivisor( GLuint bindingIndex, GLuint divisor ) {
-  if ( bindingIndex >= COUNT_BUFFERS ) {
-    return;
-  }
-
-  this->buffer[ bindingIndex ].divisor = divisor;
-}
-
-void State::SetAttribBinding( GLuint attribIndex, GLuint bindingIndex ) {
-  if ( attribIndex >= COUNT_ATTRIBS ) {
-    return;
-  }
-  if ( bindingIndex >= COUNT_BUFFERS ) {
-    return;
-  }
-
-  attrib [ attribIndex ].bindingIndex = bindingIndex;
-}
-
-void State::SetEnable( GLuint attribIndex, bool enabled ) {
-  if ( attribIndex >= COUNT_ATTRIBS ) {
-    return;
-  }
-
-  attrib [ attribIndex ].enabled = enabled;
-}
-
-void swap( State& lhs, State& rhs ) {
-  swap_array( lhs.attrib, rhs.attrib );
-  swap_array( lhs.buffer, rhs.buffer );
-}
-
-void Transition( const Capabilities& cap, const DispatchTableGL& dt, const State& current, const State& target ) {
-  for ( GLuint i = 0; i < COUNT_ATTRIBS; ++i ) {
-    Transition( cap, dt, current.attrib[ i ], target.attrib[ i ], i );
-  }
-  for ( GLuint i = 0; i < COUNT_BUFFERS; ++i ) {
-    Transition( cap, dt, current.buffer[ i ], target.buffer[ i ], i );
-  }
-}
-
-} // namespace Generic
-} // namespace VertexArray
-} // namespace ClientState
-
-// ====================================
-// ClientState::VertexArray
-// ====================================
-
-namespace ClientState {
-namespace VertexArray {
-namespace {
-
-void swap( VertexArrayObjectState& lhs, VertexArrayObjectState& rhs ) {
-  using std::swap;
-
-  swap( lhs.fixed, rhs.fixed );
-  swap( lhs.generic, rhs.generic );
-
-  swap( lhs.elementArrayBufferBinding, rhs.elementArrayBufferBinding );
-}
-
-} // namespace
-
-void State::Reset() {
-  vertexArrayObjectZero.fixed.Reset();
-  vertexArrayObjectZero.generic.Reset();
-  vertexArrayObjectZero.elementArrayBufferBinding = 0;
-
-  clientActiveTexture = GL_TEXTURE0;
-  arrayBufferBinding = 0;
-  drawIndirectBufferBinding = 0;
-  vertexArrayBinding = 0;
-  primitiveRestartEnabled = false;
-  primitiveRestartFixedIndexEnabled = false;
-  primitiveRestartIndex = 0;
-}
-
-VertexArrayObjectState* State::GetVertexArrayObject( GLuint vao ) {
-  // TODO: Optionally support vertex array objects other than zero
-  // properly.
-  //
-  // Option 1: Track their allocation/deallocation alone so we know which
-  // integers are actually valid, so the code here can ignore the ones that are
-  // not. This would be some code added to the ShadowBindVertexArray call
-  //
-  // Option 2: Track their internal state as well, so that we can shadow
-  // everything about them as needed. This means returning a pointer to a valid
-  // VertexArrayObjectState object here, so that it is then set by the various
-  // places that call this function.
-
-  if ( vao != 0 ) {
-    return NULL;
-  }
-
-  return &vertexArrayObjectZero;
-}
-
-VertexArrayObjectState* State::GetVertexArrayObject() {
-  return GetVertexArrayObject( vertexArrayBinding );
-}
-
-void swap( State& lhs, State& rhs ) {
-  using std::swap;
-  swap( lhs.vertexArrayObjectZero, rhs.vertexArrayObjectZero );
-  swap( lhs.clientActiveTexture, rhs.clientActiveTexture );
-  swap( lhs.arrayBufferBinding, rhs.arrayBufferBinding );
-  swap( lhs.drawIndirectBufferBinding, rhs.drawIndirectBufferBinding );
-  swap( lhs.vertexArrayBinding, rhs.vertexArrayBinding );
-  swap( lhs.primitiveRestartEnabled, rhs.primitiveRestartEnabled );
-  swap( lhs.primitiveRestartFixedIndexEnabled, rhs.primitiveRestartFixedIndexEnabled );
-  swap( lhs.primitiveRestartIndex, rhs.primitiveRestartIndex );
-}
-
-void Transition( const Capabilities& cap, const DispatchTableGL& dt, const State& current, const State& target ) {
-  RegalAssert( dt.glBindVertexArray );
-  RegalAssert( dt.glClientActiveTexture );
-  RegalAssert( dt.glBindBuffer );
-  RegalAssert( dt.glEnable );
-  RegalAssert( dt.glDisable );
-  RegalAssert( dt.glPrimitiveRestartIndex );
-
-  // To properly restore client vertex array state for vertexArrayObjectZero,
-  // we need to bind vertex array zero!.
-  if ( current.vertexArrayBinding != 0 ) {
-    dt.glBindVertexArray( 0 );
-  }
-
-  GLenum clientActiveTexture = current.clientActiveTexture;
-  GLuint arrayBufferBinding = current.arrayBufferBinding;
-
-  Transition( cap, dt, current.vertexArrayObjectZero.fixed, target.vertexArrayObjectZero.fixed, clientActiveTexture, arrayBufferBinding );
-  Transition( cap, dt, current.vertexArrayObjectZero.generic, target.vertexArrayObjectZero.generic );
-
-  if ( target.vertexArrayObjectZero.elementArrayBufferBinding != current.vertexArrayObjectZero.elementArrayBufferBinding ) {
-    dt.glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, target.vertexArrayObjectZero.elementArrayBufferBinding );
-  }
-
-  // We are done with calls involving vertexArrayObjectZero state, so we can
-  // now restore the actual vertex array binding object.
-  if ( target.vertexArrayBinding != 0 ) {
-    dt.glBindVertexArray( target.vertexArrayBinding );
-  }
-
-  if ( target.clientActiveTexture != clientActiveTexture ) {
-    dt.glClientActiveTexture( target.clientActiveTexture );
-  }
-
-  if ( target.arrayBufferBinding != arrayBufferBinding ) {
-    dt.glBindBuffer( GL_ARRAY_BUFFER, target.arrayBufferBinding );
-  }
-
-  if ( target.drawIndirectBufferBinding != current.drawIndirectBufferBinding ) {
-    dt.glBindBuffer( GL_DRAW_INDIRECT_BUFFER, target.drawIndirectBufferBinding );
-  }
-
-  if ( target.primitiveRestartEnabled != current.primitiveRestartEnabled ) {
-    if ( target.primitiveRestartEnabled ) {
-      dt.glEnable( GL_PRIMITIVE_RESTART );
-    } else {
-      dt.glDisable( GL_PRIMITIVE_RESTART );
-    }
-  }
-
-  if ( target.primitiveRestartFixedIndexEnabled != current.primitiveRestartFixedIndexEnabled ) {
-    if ( target.primitiveRestartFixedIndexEnabled ) {
-      dt.glEnable( GL_PRIMITIVE_RESTART_FIXED_INDEX );
-    } else {
-      dt.glDisable( GL_PRIMITIVE_RESTART_FIXED_INDEX );
-    }
-  }
-
-  if ( target.primitiveRestartIndex != current.primitiveRestartIndex ) {
-    dt.glPrimitiveRestartIndex( target.primitiveRestartIndex );
-  }
-}
-
-} // namespace VertexArray
-} // namespace ClientState
-
-// ====================================
-// Ppca
-// ====================================
-
-namespace Emu {
-namespace {
-
-GLsizei EffectiveStride( GLsizei stride, GLint size, GLenum type ) {
-  if ( stride != 0 ) {
-    return stride;
-  }
-
-  if ( size == GL_BGRA ) {
-    size = 4;
-  }
-
-  switch ( type ) {
-    default:
-      // This should not happen, and is probably an error.
-      RegalAssert( false );
-      return 16;
-
-    case GL_BYTE:
-    case GL_UNSIGNED_BYTE:
-      return size;
-
-    case GL_SHORT:
-    case GL_UNSIGNED_SHORT:
-    case GL_HALF_FLOAT:
-      return size * 2;
-
-    case GL_INT:
-    case GL_UNSIGNED_INT:
-    case GL_FLOAT:
-    case GL_FIXED:
-    case GL_INT_2_10_10_10_REV:
-    case GL_UNSIGNED_INT_2_10_10_10_REV:
-      return size * 4;
-
-    case GL_DOUBLE:
-      return size * 8;
-  }
-}
-
-} // namespace
-
-using ClientState::PixelStore::PNameToIndex;
-using ClientState::VertexArray::VertexArrayObjectState;
-using ClientState::VertexArray::Fixed::ArrayNameToAttribIndex;
-using ClientState::VertexArray::Fixed::IndexedArrayNameToAttribIndex;
-
-
-Ppca::Ppca() {
-}
-
-void Ppca::Init( RegalContext& ctx )
-{
-  Reset();
-
-  PFNGLGETINTEGERVPROC getIntegerv = ctx.dispatcher.emulation.call(&ctx.dispatcher.emulation.glGetIntegerv);
-  RegalAssert(getIntegerv);
-
-  if ( ctx.info->gl_arb_vertex_attrib_binding && !ctx.info->es2)
-  {
-    getIntegerv( GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET, reinterpret_cast<GLint *>( &capabilities.maxVertexAttribRelativeOffset ) );
-    getIntegerv( GL_MAX_VERTEX_ATTRIB_BINDINGS, reinterpret_cast<GLint *>( &capabilities.maxVertexAttribBindings ) );
-  }
-
-  if ( !ctx.info->es2 && !ctx.info->core )
-    getIntegerv( GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, reinterpret_cast<GLint *>( &capabilities.maxVertexTextureImageUnits ) );
-
-  capabilities.maxVertexAttribs = 0;
-  getIntegerv( GL_MAX_VERTEX_ATTRIBS, reinterpret_cast<GLint *>( &capabilities.maxVertexAttribs ) );
-
-  if ( !ctx.info->es2 && !ctx.info->core )
-    getIntegerv( GL_MAX_CLIENT_ATTRIB_STACK_DEPTH, reinterpret_cast<GLint *>( &capabilities.maxClientAttribStackDepth ) );
-
-  capabilities.maxVertexTextureImageUnits = std::min ( capabilities.maxVertexTextureImageUnits, static_cast<GLuint>( ClientState::VertexArray::Fixed::COUNT_TEXTURE_COORD_ATTRIBS ) );
-  capabilities.maxVertexAttribs           = std::min ( capabilities.maxVertexAttribs,           static_cast<GLuint>( ClientState::VertexArray::Generic::COUNT_ATTRIBS ) );
-  capabilities.maxVertexAttribBindings    = std::min ( capabilities.maxVertexAttribBindings,    static_cast<GLuint>( ClientState::VertexArray::Generic::COUNT_BUFFERS ) );
-  capabilities.maxClientAttribStackDepth  = std::min ( capabilities.maxClientAttribStackDepth,  static_cast<GLuint>( REGAL_PPCA_MAX_CLIENT_ATTRIB_STACK_DEPTH ) );
-
-  capabilities.maxVertexAttribBindings    = std::min ( capabilities.maxVertexAttribBindings,    capabilities.maxVertexAttribs );
-
-  DetectVertexAttributeArrayWithoutBoundBufferSupport( ctx );
-}
-
-void Ppca::Reset() {
-  capabilities.maxVertexAttribRelativeOffset = ~0u;
-  capabilities.maxVertexTextureImageUnits    = ClientState::VertexArray::Fixed::COUNT_TEXTURE_COORD_ATTRIBS;
-  capabilities.maxVertexAttribs              = ClientState::VertexArray::Generic::COUNT_ATTRIBS;
-  capabilities.maxVertexAttribBindings       = ClientState::VertexArray::Generic::COUNT_BUFFERS;
-  capabilities.maxClientAttribStackDepth     = REGAL_PPCA_MAX_CLIENT_ATTRIB_STACK_DEPTH;
-  capabilities.driverAllowsVertexAttributeArraysWithoutBoundBuffer = true;
-
-  pss.Reset();
-  vas.Reset();
-
-  ClientAttribMaskStack tmp1;
-  clientAttribMaskStack_.swap( tmp1 );
-  PixelStoreStateStack tmp2;
-  pixelStoreStateStack_.swap( tmp2 );
-  VertexArrayStateStack tmp3;
-  vertexArrayStateStack_.swap( tmp3 );
-}
-
-void Ppca::DetectVertexAttributeArrayWithoutBoundBufferSupport( RegalContext& ctx ) {
-  if ( !ctx.info->es2 ) {
-    return;
-  }
-
-  // Chromium/PepperAPI/WebGL GLES generates an error (visible through glGetError) and
-  // logs a message if a call is made to glVertexAttribPointer and no
-  // GL_ARRAY_BUFFER is bound.
-  if ( ctx.info->vendor == "Chromium" || ctx.info->webgl ) {
-    capabilities.driverAllowsVertexAttributeArraysWithoutBoundBuffer = false;
-  }
-}
-
-void Ppca::ShadowPixelStore( GLenum pname, GLint pvalue ) {
-  pss.Set( pname, pvalue );
-}
-
-void Ppca::ShadowPixelStore( GLenum pname, GLfloat pvalue ) {
-  pss.Set( pname, static_cast<GLint>( floorf( pvalue + 0.5f ) ) );
-}
-
-// Generic Vertex Attributes
-void Ppca::ShadowVertexAttribFormat( GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset ) {
-  VertexArrayObjectState* vao = vas.GetVertexArrayObject();
-  if ( vao == NULL ) {
-    return;
-  }
-
-  // Validate the arguments. Return silently if invalid.
-
-  switch ( size ) {
-    default:
-      return;
-    case 1:
-    case 2:
-    case 3:
-    case 4:
-      break;
-    case GL_BGRA:
-      if ( ( type != GL_UNSIGNED_BYTE ) || ( type != GL_INT_2_10_10_10_REV ) || ( type != GL_UNSIGNED_INT_2_10_10_10_REV ) ) {
-        return;
-      }
-      if ( normalized == GL_FALSE ) {
-        return;
-      }
-      break;
-  }
-
-  switch ( type ) {
-    default:
-      return;
-    case GL_BYTE:
-    case GL_UNSIGNED_BYTE:
-    case GL_SHORT:
-    case GL_UNSIGNED_SHORT:
-    case GL_INT:
-    case GL_UNSIGNED_INT:
-    case GL_FIXED:
-    case GL_HALF_FLOAT:
-    case GL_FLOAT:
-    case GL_DOUBLE:
-      break;
-    case GL_INT_2_10_10_10_REV:
-    case GL_UNSIGNED_INT_2_10_10_10_REV:
-      if ( ( size != 4 ) || ( size != GL_BGRA ) ) {
-        return;
-      }
-      break;
-  }
-
-  if ( attribindex >= capabilities.maxVertexAttribs ) {
-    return;
-  }
-  if ( relativeoffset > capabilities.maxVertexAttribRelativeOffset ) {
-    return;
-  }
-
-  vao->generic.SetAttribSource( attribindex, size, type, normalized == GL_TRUE, false, relativeoffset );
-}
-
-void Ppca::ShadowVertexAttribIFormat( GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset ) {
-  VertexArrayObjectState* vao = vas.GetVertexArrayObject();
-  if ( vao == NULL ) {
-    return;
-  }
-
-  // Validate the arguments. Return silently if invalid.
-
-  switch ( size ) {
-    default:
-      return;
-    case 1:
-    case 2:
-    case 3:
-    case 4:
-      break;
-  }
-
-  switch ( type ) {
-    default:
-      return;
-    case GL_BYTE:
-    case GL_UNSIGNED_BYTE:
-    case GL_SHORT:
-    case GL_UNSIGNED_SHORT:
-    case GL_INT:
-    case GL_UNSIGNED_INT:
-      break;
-  }
-
-  if ( attribindex >= capabilities.maxVertexAttribs ) {
-    return;
-  }
-  if ( relativeoffset > capabilities.maxVertexAttribRelativeOffset ) {
-    return;
-  }
-
-  vao->generic.SetAttribSource ( attribindex, size, type, false, true, relativeoffset );
-}
-
-void Ppca::ShadowVertexAttribLFormat( GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset ) {
-  VertexArrayObjectState* vao = vas.GetVertexArrayObject();
-  if ( vao == NULL ) {
-    return;
-  }
-
-  // Validate the arguments. Return silently if invalid.
-
-  switch ( size ) {
-    default:
-      return;
-    case 1:
-    case 2:
-    case 3:
-    case 4:
-      break;
-  }
-
-  switch ( type ) {
-    default:
-      return;
-    case GL_DOUBLE:
-      break;
-  }
-
-  if ( attribindex >= capabilities.maxVertexAttribs ) {
-    return;
-  }
-  if ( relativeoffset > capabilities.maxVertexAttribRelativeOffset ) {
-    return;
-  }
-
-  vao->generic.SetAttribSource ( attribindex, size, type, false, false, relativeoffset );
-}
-
-void Ppca::ShadowBindVertexBuffer( GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride ) {
-  VertexArrayObjectState* vao = vas.GetVertexArrayObject();
-  if ( vao == NULL ) {
-    return;
-  }
-
-  // Validate the arguments. Return silently if invalid.
-
-  if ( ( offset < 0 ) || ( stride < 0 ) ) {
-    return;
-  }
-  if ( bindingindex >= capabilities.maxVertexAttribBindings ) {
-    return;
-  }
-
-  vao->generic.SetBuffer( bindingindex, buffer, offset, stride );
-}
-
-void Ppca::ShadowVertexAttribBinding( GLuint attribindex, GLuint bindingindex ) {
-  VertexArrayObjectState* vao = vas.GetVertexArrayObject();
-  if ( vao == NULL ) {
-    return;
-  }
-
-  // Validate the arguments. Return silently if invalid.
-
-  if ( attribindex >= capabilities.maxVertexAttribs ) {
-    return;
-  }
-  if ( bindingindex >= capabilities.maxVertexAttribBindings ) {
-    return;
-  }
-
-  vao->generic.SetAttribBinding( attribindex, bindingindex );
-}
-
-void Ppca::ShadowVertexAttribPointer( GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* pointer ) {
-  VertexArrayObjectState* vao = vas.GetVertexArrayObject();
-  if ( vao == NULL ) {
-    return;
-  }
-
-  // Validate the arguments. Return silently if invalid.
-
-  switch ( size ) {
-    default:
-      return;
-    case 1:
-    case 2:
-    case 3:
-    case 4:
-      break;
-    case GL_BGRA:
-      if ( ( type != GL_UNSIGNED_BYTE ) || ( type != GL_INT_2_10_10_10_REV ) || ( type != GL_UNSIGNED_INT_2_10_10_10_REV ) ) {
-        return;
-      }
-      if ( normalized == GL_FALSE ) {
-        return;
-      }
-      break;
-  }
-
-  switch ( type ) {
-    default:
-      return;
-    case GL_BYTE:
-    case GL_UNSIGNED_BYTE:
-    case GL_SHORT:
-    case GL_UNSIGNED_SHORT:
-    case GL_INT:
-    case GL_UNSIGNED_INT:
-    case GL_FIXED:
-    case GL_HALF_FLOAT:
-    case GL_FLOAT:
-    case GL_DOUBLE:
-      break;
-    case GL_INT_2_10_10_10_REV:
-    case GL_UNSIGNED_INT_2_10_10_10_REV:
-      if ( ( size != 4 ) || ( size != GL_BGRA ) ) {
-        return;
-      }
-      break;
-  }
-
-  if ( index >= capabilities.maxVertexAttribs ) {
-    return;
-  }
-  if ( stride < 0 ) {
-    return;
-  }
-
-  vao->generic.SetAttribSource( index, size, type, normalized == GL_TRUE, false, 0 );
-  vao->generic.SetAttribBinding( index, index );
-  vao->generic.SetBuffer( index, vas.arrayBufferBinding, reinterpret_cast<GLintptr>( pointer ), EffectiveStride ( stride, size, type ) );
-}
-
-void Ppca::ShadowVertexIAttribPointer( GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid* pointer ) {
-  VertexArrayObjectState* vao = vas.GetVertexArrayObject();
-  if ( vao == NULL ) {
-    return;
-  }
-
-  // Validate the arguments. Return silently if invalid.
-
-  switch ( size ) {
-    default:
-      return;
-    case 1:
-    case 2:
-    case 3:
-    case 4:
-      break;
-  }
-
-  switch ( type ) {
-    default:
-      return;
-    case GL_BYTE:
-    case GL_UNSIGNED_BYTE:
-    case GL_SHORT:
-    case GL_UNSIGNED_SHORT:
-    case GL_INT:
-    case GL_UNSIGNED_INT:
-      break;
-  }
-
-  if ( index >= capabilities.maxVertexAttribs ) {
-    return;
-  }
-  if ( stride < 0 ) {
-    return;
-  }
-
-  vao->generic.SetAttribSource( index, size, type, false, true, 0 );
-  vao->generic.SetAttribBinding( index, index );
-  vao->generic.SetBuffer( index, vas.arrayBufferBinding, reinterpret_cast<GLintptr>( pointer ), EffectiveStride ( stride, size, type ) );
-}
-
-void Ppca::ShadowVertexLAttribPointer( GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid* pointer ) {
-  VertexArrayObjectState* vao = vas.GetVertexArrayObject();
-  if ( vao == NULL ) {
-    return;
-  }
-
-  // Validate the arguments. Return silently if invalid.
-
-  switch ( size ) {
-    default:
-      return;
-    case 1:
-    case 2:
-    case 3:
-    case 4:
-      break;
-  }
-
-  switch ( type ) {
-    default:
-      return;
-    case GL_DOUBLE:
-      break;
-  }
-
-  if ( index >= capabilities.maxVertexAttribs ) {
-    return;
-  }
-  if ( stride < 0 ) {
-    return;
-  }
-
-  vao->generic.SetAttribSource( index, size, type, false, false, 0 );
-  vao->generic.SetAttribBinding( index, index );
-  vao->generic.SetBuffer( index, vas.arrayBufferBinding, reinterpret_cast<GLintptr>( pointer ), EffectiveStride ( stride, size, type ) );
-}
-
-void Ppca::ShadowEnableVertexAttribArray( GLuint index ) {
-  VertexArrayObjectState* vao = vas.GetVertexArrayObject();
-  if ( vao == NULL ) {
-    return;
-  }
-
-  // Validate the arguments. Return silently if invalid.
-
-  if ( index >= capabilities.maxVertexAttribs ) {
-    return;
-  }
-
-  vao->generic.SetEnable( index, true );
-}
-
-void Ppca::ShadowDisableVertexAttribArray( GLuint index ) {
-  VertexArrayObjectState* vao = vas.GetVertexArrayObject();
-  if ( vao == NULL ) {
-    return;
-  }
-
-  // Validate the arguments. Return silently if invalid.
-
-  if ( index >= capabilities.maxVertexAttribs ) {
-    return;
-  }
-
-  vao->generic.SetEnable( index, false );
-}
-
-
-
-void Ppca::ShadowVertexPointer( GLint size, GLenum type, GLsizei stride, const GLvoid* pointer ) {
-  VertexArrayObjectState* vao = vas.GetVertexArrayObject();
-  if ( vao == NULL ) {
-    return;
-  }
-
-  // Validate the arguments. Return silently if invalid.
-
-  switch ( size ) {
-    default:
-      return;
-    case 2:
-    case 3:
-    case 4:
-      break;
-  }
-
-  switch ( type ) {
-    default:
-      return;
-    case GL_SHORT:
-    case GL_INT:
-    case GL_HALF_FLOAT:
-    case GL_FLOAT:
-    case GL_DOUBLE:
-      break;
-    case GL_INT_2_10_10_10_REV:
-    case GL_UNSIGNED_INT_2_10_10_10_REV:
-      if ( ( size != 4 ) || ( size != GL_BGRA ) ) {
-        return;
-      }
-      break;
-  }
-
-  if ( stride < 0 ) {
-    return;
-  }
-
-  vao->fixed.SetData( ArrayNameToAttribIndex( GL_VERTEX_ARRAY ), vas.arrayBufferBinding, size, type, stride, reinterpret_cast<GLintptr>( pointer ) );
-}
-
-void Ppca::ShadowNormalPointer( GLenum type, GLsizei stride, const GLvoid* pointer ) {
-  VertexArrayObjectState* vao = vas.GetVertexArrayObject();
-  if ( vao == NULL ) {
-    return;
-  }
-
-  // Validate the arguments. Return silently if invalid.
-
-  switch ( type ) {
-    default:
-      return;
-    case GL_BYTE:
-    case GL_SHORT:
-    case GL_INT:
-    case GL_HALF_FLOAT:
-    case GL_FLOAT:
-    case GL_DOUBLE:
-      break;
-    case GL_INT_2_10_10_10_REV:
-    case GL_UNSIGNED_INT_2_10_10_10_REV:
-      break;
-  }
-
-  if ( stride < 0 ) {
-    return;
-  }
-
-  vao->fixed.SetData( ArrayNameToAttribIndex( GL_NORMAL_ARRAY ), vas.arrayBufferBinding, 3, type, stride, reinterpret_cast<GLintptr>( pointer ) );
-}
-
-void Ppca::ShadowColorPointer( GLint size, GLenum type, GLsizei stride, const GLvoid* pointer ) {
-  VertexArrayObjectState* vao = vas.GetVertexArrayObject();
-  if ( vao == NULL ) {
-    return;
-  }
-
-  // Validate the arguments. Return silently if invalid.
-
-  switch ( size ) {
-    default:
-      return;
-    case 3:
-    case 4:
-      break;
-    case GL_BGRA:
-      if ( ( type != GL_UNSIGNED_BYTE ) || ( type != GL_INT_2_10_10_10_REV ) || ( type != GL_UNSIGNED_INT_2_10_10_10_REV ) ) {
-        return;
-      }
-      break;
-  }
-
-  switch ( type ) {
-    default:
-      return;
-    case GL_BYTE:
-    case GL_UNSIGNED_BYTE:
-    case GL_SHORT:
-    case GL_UNSIGNED_SHORT:
-    case GL_INT:
-    case GL_UNSIGNED_INT:
-    case GL_HALF_FLOAT:
-    case GL_FLOAT:
-    case GL_DOUBLE:
-      break;
-    case GL_INT_2_10_10_10_REV:
-    case GL_UNSIGNED_INT_2_10_10_10_REV:
-      if ( ( size != 4 ) || ( size != GL_BGRA ) ) {
-        return;
-      }
-      break;
-  }
-
-  if ( stride < 0 ) {
-    return;
-  }
-
-  vao->fixed.SetData( ArrayNameToAttribIndex( GL_COLOR_ARRAY ), vas.arrayBufferBinding, size, type, stride, reinterpret_cast<GLintptr>( pointer ) );
-}
-
-void Ppca::ShadowSecondaryColorPointer( GLint size, GLenum type, GLsizei stride, const GLvoid* pointer ) {
-  VertexArrayObjectState* vao = vas.GetVertexArrayObject();
-  if ( vao == NULL ) {
-    return;
-  }
-
-  // Validate the arguments. Return silently if invalid.
-
-  switch ( size ) {
-    default:
-      return;
-    case 3:
-      break;
-    case GL_BGRA:
-      if ( ( type != GL_UNSIGNED_BYTE ) || ( type != GL_INT_2_10_10_10_REV ) || ( type != GL_UNSIGNED_INT_2_10_10_10_REV ) ) {
-        return;
-      }
-      break;
-  }
-
-  switch ( type ) {
-    default:
-      return;
-    case GL_BYTE:
-    case GL_UNSIGNED_BYTE:
-    case GL_SHORT:
-    case GL_UNSIGNED_SHORT:
-    case GL_INT:
-    case GL_UNSIGNED_INT:
-    case GL_HALF_FLOAT:
-    case GL_FLOAT:
-    case GL_DOUBLE:
-      break;
-    case GL_INT_2_10_10_10_REV:
-    case GL_UNSIGNED_INT_2_10_10_10_REV:
-      if ( ( size != 4 ) || ( size != GL_BGRA ) ) {
-        return;
-      }
-      break;
-  }
-
-  if ( stride < 0 ) {
-    return;
-  }
-
-  vao->fixed.SetData( ArrayNameToAttribIndex( GL_SECONDARY_COLOR_ARRAY ), vas.arrayBufferBinding, size, type, stride, reinterpret_cast<GLintptr>( pointer ) );
-}
-
-void Ppca::ShadowIndexPointer( GLenum type, GLsizei stride, const GLvoid* pointer ) {
-  VertexArrayObjectState* vao = vas.GetVertexArrayObject();
-  if ( vao == NULL ) {
-    return;
-  }
-
-  // Validate the arguments. Return silently if invalid.
-
-  switch ( type ) {
-    default:
-      return;
-    case GL_UNSIGNED_BYTE:
-    case GL_SHORT:
-    case GL_INT:
-    case GL_FLOAT:
-    case GL_DOUBLE:
-      break;
-  }
-
-  if ( stride < 0 ) {
-    return;
-  }
-
-  vao->fixed.SetData( ArrayNameToAttribIndex( GL_INDEX_ARRAY ), vas.arrayBufferBinding, 1, type, stride, reinterpret_cast<GLintptr>( pointer ) );
-}
-
-void Ppca::ShadowEdgeFlagPointer( GLsizei stride, const GLvoid* pointer ) {
-  VertexArrayObjectState* vao = vas.GetVertexArrayObject();
-  if ( vao == NULL ) {
-    return;
-  }
-
-  // Validate the arguments. Return silently if invalid.
-
-  if ( stride < 0 ) {
-    return;
-  }
-
-  vao->fixed.SetData( ArrayNameToAttribIndex( GL_EDGE_FLAG_ARRAY ), vas.arrayBufferBinding, 1, GL_BOOL, stride, reinterpret_cast<GLintptr>( pointer ) );
-}
-
-void Ppca::ShadowFogCoordPointer( GLenum type, GLsizei stride, const GLvoid* pointer ) {
-  VertexArrayObjectState* vao = vas.GetVertexArrayObject();
-  if ( vao == NULL ) {
-    return;
-  }
-
-  // Validate the arguments. Return silently if invalid.
-
-  switch ( type ) {
-    default:
-      return;
-    case GL_HALF_FLOAT:
-    case GL_FLOAT:
-    case GL_DOUBLE:
-      break;
-  }
-
-  if ( stride < 0 ) {
-    return;
-  }
-
-  vao->fixed.SetData( ArrayNameToAttribIndex( GL_FOG_COORD_ARRAY ), vas.arrayBufferBinding, 1, type, stride, reinterpret_cast<GLintptr>( pointer ) );
-}
-
-void Ppca::ShadowTexCoordPointer( GLint size, GLenum type, GLsizei stride, const GLvoid* pointer ) {
-  VertexArrayObjectState* vao = vas.GetVertexArrayObject();
-  if ( vao == NULL ) {
-    return;
-  }
-
-  // Validate the arguments. Return silently if invalid.
-
-  switch ( size ) {
-    default:
-      return;
-    case 1:
-    case 2:
-    case 3:
-    case 4:
-      break;
-  }
-
-  switch ( type ) {
-    default:
-      return;
-    case GL_SHORT:
-    case GL_INT:
-    case GL_HALF_FLOAT:
-    case GL_FLOAT:
-    case GL_DOUBLE:
-      break;
-    case GL_INT_2_10_10_10_REV:
-    case GL_UNSIGNED_INT_2_10_10_10_REV:
-      if ( ( size != 4 ) || ( size != GL_BGRA ) ) {
-        return;
-      }
-      break;
-  }
-
-  if ( stride < 0 ) {
-    return;
-  }
-
-  vao->fixed.SetData( ArrayNameToAttribIndex( GL_TEXTURE_COORD_ARRAY, vas.clientActiveTexture ), vas.arrayBufferBinding, size, type, stride, reinterpret_cast<GLintptr>( pointer ) );
-}
-
-
-void Ppca::ShadowEnableClientState( GLenum cap ) {
-  VertexArrayObjectState* vao = vas.GetVertexArrayObject();
-  if ( vao == NULL ) {
-    return;
-  }
-  vao->fixed.SetEnable( ArrayNameToAttribIndex( cap, vas.clientActiveTexture ), true );
-}
-
-void Ppca::ShadowDisableClientState( GLenum cap ) {
-  VertexArrayObjectState* vao = vas.GetVertexArrayObject();
-  if ( vao == NULL ) {
-    return;
-  }
-  vao->fixed.SetEnable( ArrayNameToAttribIndex( cap, vas.clientActiveTexture ), false );
-}
-
-void Ppca::ShadowClientActiveTexture( GLenum texture ) {
-  // Validate the arguments. Return silently if invalid.
-
-  if ( ( texture < GL_TEXTURE0 ) || ( texture >= GL_TEXTURE0 + capabilities.maxVertexTextureImageUnits ) ) {
-    return;
-  }
-
-  vas.clientActiveTexture = texture;
-}
-
-
-
-void Ppca::ShadowVertexBindingDivisor( GLuint bindingindex, GLuint divisor ) {
-  VertexArrayObjectState* vao = vas.GetVertexArrayObject();
-  if ( vao == NULL ) {
-    return;
-  }
-
-  // Validate the arguments. Return silently if invalid.
-
-  if ( bindingindex >= capabilities.maxVertexAttribBindings ) {
-    return;
-  }
-
-  vao->generic.SetBufferDivisor( bindingindex, divisor );
-}
-
-void Ppca::ShadowVertexAttribDivisor( GLuint index, GLuint divisor ) {
-  VertexArrayObjectState* vao = vas.GetVertexArrayObject();
-  if ( vao == NULL ) {
-    return;
-  }
-
-  // Validate the arguments. Return silently if invalid.
-
-  if ( index >= capabilities.maxVertexAttribs ) {
-    return;
-  }
-
-  vao->generic.SetAttribBinding( index, index );
-  vao->generic.SetBufferDivisor( index, divisor );
-}
-
-void Ppca::ShadowEnableDisable_( GLenum target, bool enable ) {
-  switch ( target ) {
-    default:
-      break;
-    case GL_PRIMITIVE_RESTART:
-      vas.primitiveRestartEnabled = enable;
-      break;
-    case GL_PRIMITIVE_RESTART_FIXED_INDEX:
-      vas.primitiveRestartFixedIndexEnabled = enable;
-      break;
-  }
-}
-
-void Ppca::ShadowEnable( GLenum target ) {
-  ShadowEnableDisable_( target, true );
-}
-
-void Ppca::ShadowDisable( GLenum target ) {
-  ShadowEnableDisable_( target, false );
-}
-
-void Ppca::ShadowPrimitiveRestartIndex( GLuint index ) {
-  vas.primitiveRestartIndex = index;
-}
-
-void Ppca::ShadowBindBuffer( GLenum target, GLuint buffer ) {
-  // TODO: If buffer was not allocated or was deleted, it should be ignored (a
-  // real GL backend implementation would set an error).
-
-  switch ( target ) {
-    case GL_PIXEL_PACK_BUFFER_BINDING:
-      pss.pixelPackBufferBinding = buffer;
-      break;
-    case GL_PIXEL_UNPACK_BUFFER_BINDING:
-      pss.pixelUnpackBufferBinding = buffer;
-      break;
-    case GL_ARRAY_BUFFER:
-      vas.arrayBufferBinding = buffer;
-      break;
-    case GL_DRAW_INDIRECT_BUFFER:
-      vas.drawIndirectBufferBinding = buffer;
-      break;
-    case GL_ELEMENT_ARRAY_BUFFER:
-      VertexArrayObjectState* vao = vas.GetVertexArrayObject();
-      if ( vao != NULL ) {
-        vao->elementArrayBufferBinding = buffer;
-      }
-      break;
-  }
-}
-
-void Ppca::ShadowBindVertexArray( GLuint vertexArray ) {
-  // TODO: If vertexArray was not allocated or was deleted, it should be
-  // ignored (a real GL backend implementation would set an error).
-
-  vas.vertexArrayBinding = vertexArray;
-}
-
-
-
-void Ppca::ShadowInterleavedArrays( GLenum format, GLsizei stride, const GLvoid* pointer ) {
-  VertexArrayObjectState* vao = vas.GetVertexArrayObject();
-  if ( vao == NULL ) {
-    return;
-  }
-
-  GLintptr data = reinterpret_cast<GLintptr>( pointer );
-
-  GLint vsize = 0;
-  GLint nsize = 0;
-  GLint csize = 0;
-  GLenum ctype = GL_FLOAT;
-  GLint tsize = 0;
-
-  // Validate the arguments. Return silently if invalid.
-
-  if ( stride < 0 ) {
-    return;
-  }
-
-  switch ( format ) {
-    default:
-      return;
-    case GL_V2F:
-      vsize = 2;
-      break;
-    case GL_V3F:
-      vsize = 3;
-      break;
-    case GL_C4UB_V2F:
-      vsize = 2;
-      csize = 4; ctype=GL_UNSIGNED_BYTE;
-      break;
-    case GL_C4UB_V3F:
-      vsize = 3;
-      csize = 4; ctype=GL_UNSIGNED_BYTE;
-      break;
-    case GL_C3F_V3F:
-      vsize = 3;
-      csize = 3; ctype=GL_FLOAT;
-      break;
-    case GL_N3F_V3F:
-      vsize = 3;
-      nsize = 3;
-      break;
-    case GL_C4F_N3F_V3F:
-      vsize = 3;
-      nsize = 3;
-      csize = 4; ctype=GL_FLOAT;
-      break;
-    case GL_T2F_V3F:
-      vsize = 3;
-      tsize = 2;
-      break;
-    case GL_T4F_V4F:
-      vsize = 4;
-      tsize = 4;
-      break;
-    case GL_T2F_C4UB_V3F:
-      vsize = 3;
-      csize = 4; ctype=GL_UNSIGNED_BYTE;
-      tsize = 2;
-      break;
-    case GL_T2F_C3F_V3F:
-      vsize = 3;
-      csize = 3; ctype=GL_FLOAT;
-      tsize = 2;
-      break;
-    case GL_T2F_N3F_V3F:
-      vsize = 3;
-      nsize = 3;
-      tsize = 2;
-      break;
-    case GL_T2F_C4F_N3F_V3F:
-      vsize = 3;
-      nsize = 3;
-      csize = 4; ctype=GL_FLOAT;
-      tsize = 2;
-      break;
-    case GL_T4F_C4F_N3F_V4F:
-      vsize = 4;
-      nsize = 3;
-      csize = 4; ctype=GL_FLOAT;
-      tsize = 4;
-      break;
-  }
-
-  if ( stride == 0 ) {
-    stride += vsize * sizeof( GLfloat );
-    if ( nsize != 0 ) {
-      stride += nsize * sizeof( GLfloat );
-    }
-    if ( csize != 0 ) {
-      if ( ctype == GL_FLOAT ) {
-        stride += csize * sizeof( GLfloat );
-      } else {
-        stride += csize * sizeof( GLubyte );
-      }
-    }
-    if ( tsize != 0 ) {
-      stride += tsize * sizeof( GLfloat );
-    }
-  }
-
-  if ( tsize != 0 ) {
-    vao->fixed.SetEnable( ArrayNameToAttribIndex( GL_TEXTURE_COORD_ARRAY, vas.clientActiveTexture ), true );
-    vao->fixed.SetData  ( ArrayNameToAttribIndex( GL_TEXTURE_COORD_ARRAY, vas.clientActiveTexture ), vas.arrayBufferBinding, tsize, GL_FLOAT, stride, data );
-    data += tsize * sizeof( GLfloat );
-  } else {
-    vao->fixed.SetEnable( ArrayNameToAttribIndex( GL_TEXTURE_COORD_ARRAY, vas.clientActiveTexture ), false );
-  }
-
-  if ( csize != 0 ) {
-    vao->fixed.SetEnable( ArrayNameToAttribIndex( GL_COLOR_ARRAY ), true );
-    vao->fixed.SetData  ( ArrayNameToAttribIndex( GL_COLOR_ARRAY ), vas.arrayBufferBinding, csize, ctype, stride, data );
-    if ( ctype == GL_FLOAT ) {
-      data += csize * sizeof( GLfloat );
-    } else {
-      data += csize * sizeof( GLubyte );
-    }
-  } else {
-    vao->fixed.SetEnable( ArrayNameToAttribIndex( GL_COLOR_ARRAY ), false );
-  }
-
-  if ( nsize != 0 ) {
-    vao->fixed.SetEnable( ArrayNameToAttribIndex( GL_NORMAL_ARRAY ), true );
-    vao->fixed.SetData  ( ArrayNameToAttribIndex( GL_NORMAL_ARRAY ), vas.arrayBufferBinding, 3, GL_FLOAT, stride, data );
-    data += nsize * sizeof( GLfloat );
-  } else {
-    vao->fixed.SetEnable( ArrayNameToAttribIndex( GL_NORMAL_ARRAY ), false );
-  }
-
-  vao->fixed.SetEnable( ArrayNameToAttribIndex( GL_VERTEX_ARRAY ), true );
-  vao->fixed.SetData  ( ArrayNameToAttribIndex( GL_VERTEX_ARRAY ), vas.arrayBufferBinding, vsize, GL_FLOAT, stride, data );
-  data += vsize * sizeof( GLfloat );
-
-  // Disable all other non-texture coordinate fixed-function arrays.
-  vao->fixed.SetEnable( ArrayNameToAttribIndex( GL_SECONDARY_COLOR_ARRAY ), false );
-  vao->fixed.SetEnable( ArrayNameToAttribIndex( GL_INDEX_ARRAY ), false );
-  vao->fixed.SetEnable( ArrayNameToAttribIndex( GL_EDGE_FLAG_ARRAY ), false );
-  vao->fixed.SetEnable( ArrayNameToAttribIndex( GL_FOG_COORD_ARRAY ), false );
-}
-
-
-
-void Ppca::ClientAttribDefaultDSA( RegalContext* ctx, GLbitfield mask ) {
-  if ( mask & GL_CLIENT_PIXEL_STORE_BIT ) {
-    ClientState::PixelStore::State tmp;
-    tmp.Reset();
-    Transition( capabilities, ctx->dispatcher.emulation, pss, tmp );
-    swap( pss, tmp );
-    mask &= ~GL_CLIENT_PIXEL_STORE_BIT;
-  }
-
-  if ( mask & GL_CLIENT_VERTEX_ARRAY_BIT ) {
-    ClientState::VertexArray::State tmp;
-    tmp.Reset();
-    Transition( capabilities, ctx->dispatcher.emulation, vas, tmp );
-    swap( vas, tmp );
-    mask &= ~GL_CLIENT_VERTEX_ARRAY_BIT;
-  }
-
-  if ( ctx->info->core || ctx->info->es2 )
-    return;
-
-  if ( mask )
-    ctx->dispatcher.emulation.glClientAttribDefaultEXT( mask );
-}
-
-void Ppca::PushClientAttribDefaultDSA( RegalContext* ctx, GLbitfield mask ) {
-  PushClientAttrib( ctx, mask );
-  ClientAttribDefaultDSA( ctx, mask );
-}
-
-void Ppca::ShadowMultiTexCoordPointerDSA( GLenum texunit, GLint size, GLenum type, GLsizei stride, const GLvoid* pointer ) {
-  VertexArrayObjectState* vao = vas.GetVertexArrayObject();
-  if ( vao == NULL ) {
-    return;
-  }
-
-  // Validate the arguments. Return silently if invalid.
-
-  if ( ( texunit < GL_TEXTURE0 ) || ( texunit >= GL_TEXTURE0 + capabilities.maxVertexTextureImageUnits ) ) {
-    return;
-  }
-
-  switch ( size ) {
-    default:
-      return;
-    case 1:
-    case 2:
-    case 3:
-    case 4:
-      break;
-  }
-
-  switch ( type ) {
-    default:
-      return;
-    case GL_SHORT:
-    case GL_INT:
-    case GL_HALF_FLOAT:
-    case GL_FLOAT:
-    case GL_DOUBLE:
-      break;
-    case GL_INT_2_10_10_10_REV:
-    case GL_UNSIGNED_INT_2_10_10_10_REV:
-      if ( ( size != 4 ) || ( size != GL_BGRA ) ) {
-        return;
-      }
-      break;
-  }
-
-  if ( stride < 0 ) {
-    return;
-  }
-
-  vao->fixed.SetData( ArrayNameToAttribIndex( GL_TEXTURE_COORD_ARRAY, texunit ), vas.arrayBufferBinding, size, type, stride, reinterpret_cast<GLintptr>( pointer ) );
-}
-
-void Ppca::ShadowEnableClientStateIndexedDSA( GLenum cap, GLuint index ) {
-  VertexArrayObjectState* vao = vas.GetVertexArrayObject();
-  if ( vao == NULL ) {
-    return;
-  }
-  vao->fixed.SetEnable( IndexedArrayNameToAttribIndex( cap , index ), true );
-}
-
-void Ppca::ShadowDisableClientStateIndexedDSA( GLenum cap, GLuint index ) {
-  VertexArrayObjectState* vao = vas.GetVertexArrayObject();
-  if ( vao == NULL ) {
-    return;
-  }
-  vao->fixed.SetEnable( IndexedArrayNameToAttribIndex( cap, index ), false );
-}
-
-
-void Ppca::ShadowVertexArrayVertexOffsetDSA( GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset ) {
-  VertexArrayObjectState* vao = vas.GetVertexArrayObject( vaobj );
-  if ( vao == NULL ) {
-    return;
-  }
-
-  // Validate the arguments. Return silently if invalid.
-
-  switch ( size ) {
-    default:
-      return;
-    case 2:
-    case 3:
-    case 4:
-      break;
-  }
-
-  switch ( type ) {
-    default:
-      return;
-    case GL_SHORT:
-    case GL_INT:
-    case GL_HALF_FLOAT:
-    case GL_FLOAT:
-    case GL_DOUBLE:
-      break;
-    case GL_INT_2_10_10_10_REV:
-    case GL_UNSIGNED_INT_2_10_10_10_REV:
-      if ( ( size != 4 ) || ( size != GL_BGRA ) ) {
-        return;
-      }
-      break;
-  }
-
-  if ( stride < 0 ) {
-    return;
-  }
-
-  vao->fixed.SetData( ArrayNameToAttribIndex( GL_VERTEX_ARRAY ), buffer, size, type, stride, offset );
-}
-
-void Ppca::ShadowVertexArrayColorOffsetDSA( GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset ) {
-  VertexArrayObjectState* vao = vas.GetVertexArrayObject( vaobj );
-  if ( vao == NULL ) {
-    return;
-  }
-
-  // Validate the arguments. Return silently if invalid.
-
-  switch ( size ) {
-    default:
-      return;
-    case 3:
-    case 4:
-      break;
-    case GL_BGRA:
-      if ( ( type != GL_UNSIGNED_BYTE ) || ( type != GL_INT_2_10_10_10_REV ) || ( type != GL_UNSIGNED_INT_2_10_10_10_REV ) ) {
-        return;
-      }
-      break;
-  }
-
-  switch ( type ) {
-    default:
-      return;
-    case GL_BYTE:
-    case GL_UNSIGNED_BYTE:
-    case GL_SHORT:
-    case GL_UNSIGNED_SHORT:
-    case GL_INT:
-    case GL_UNSIGNED_INT:
-    case GL_HALF_FLOAT:
-    case GL_FLOAT:
-    case GL_DOUBLE:
-      break;
-    case GL_INT_2_10_10_10_REV:
-    case GL_UNSIGNED_INT_2_10_10_10_REV:
-      if ( ( size != 4 ) || ( size != GL_BGRA ) ) {
-        return;
-      }
-      break;
-  }
-
-  if ( stride < 0 ) {
-    return;
-  }
-
-  vao->fixed.SetData( ArrayNameToAttribIndex( GL_COLOR_ARRAY ), buffer, size, type, stride, offset );
-}
-
-void Ppca::ShadowVertexArrayEdgeFlagOffsetDSA( GLuint vaobj, GLuint buffer, GLsizei stride, GLintptr offset ) {
-  VertexArrayObjectState* vao = vas.GetVertexArrayObject( vaobj );
-  if ( vao == NULL ) {
-    return;
-  }
-
-  // Validate the arguments. Return silently if invalid.
-
-  if ( stride < 0 ) {
-    return;
-  }
-
-  vao->fixed.SetData( ArrayNameToAttribIndex( GL_EDGE_FLAG_ARRAY ), buffer, 1, GL_BOOL, stride, offset );
-}
-
-void Ppca::ShadowVertexArrayIndexOffsetDSA( GLuint vaobj, GLuint buffer, GLenum type, GLsizei stride, GLintptr offset ) {
-  VertexArrayObjectState* vao = vas.GetVertexArrayObject( vaobj );
-  if ( vao == NULL ) {
-    return;
-  }
-
-  // Validate the arguments. Return silently if invalid.
-
-  switch ( type ) {
-    default:
-      return;
-    case GL_UNSIGNED_BYTE:
-    case GL_SHORT:
-    case GL_INT:
-    case GL_FLOAT:
-    case GL_DOUBLE:
-      break;
-  }
-
-  if ( stride < 0 ) {
-    return;
-  }
-
-  vao->fixed.SetData( ArrayNameToAttribIndex( GL_INDEX_ARRAY ), buffer, 1, type, stride, offset );
-}
-
-void Ppca::ShadowVertexArrayNormalOffsetDSA( GLuint vaobj, GLuint buffer, GLenum type, GLsizei stride, GLintptr offset ) {
-  VertexArrayObjectState* vao = vas.GetVertexArrayObject( vaobj );
-  if ( vao == NULL ) {
-    return;
-  }
-
-  // Validate the arguments. Return silently if invalid.
-
-  switch ( type ) {
-    default:
-      return;
-    case GL_BYTE:
-    case GL_SHORT:
-    case GL_INT:
-    case GL_HALF_FLOAT:
-    case GL_FLOAT:
-    case GL_DOUBLE:
-      break;
-    case GL_INT_2_10_10_10_REV:
-    case GL_UNSIGNED_INT_2_10_10_10_REV:
-      break;
-  }
-
-  if ( stride < 0 ) {
-    return;
-  }
-
-  vao->fixed.SetData( ArrayNameToAttribIndex( GL_NORMAL_ARRAY ), buffer, 3, type, stride, offset );
-}
-
-void Ppca::ShadowVertexArrayTexCoordOffsetDSA( GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset ) {
-  VertexArrayObjectState* vao = vas.GetVertexArrayObject( vaobj );
-  if ( vao == NULL ) {
-    return;
-  }
-
-  // Validate the arguments. Return silently if invalid.
-
-  switch ( size ) {
-    default:
-      return;
-    case 1:
-    case 2:
-    case 3:
-    case 4:
-      break;
-  }
-
-  switch ( type ) {
-    default:
-      return;
-    case GL_SHORT:
-    case GL_INT:
-    case GL_HALF_FLOAT:
-    case GL_FLOAT:
-    case GL_DOUBLE:
-      break;
-    case GL_INT_2_10_10_10_REV:
-    case GL_UNSIGNED_INT_2_10_10_10_REV:
-      if ( ( size != 4 ) || ( size != GL_BGRA ) ) {
-        return;
-      }
-      break;
-  }
-
-  if ( stride < 0 ) {
-    return;
-  }
-
-  vao->fixed.SetData( ArrayNameToAttribIndex( GL_TEXTURE_COORD_ARRAY, vas.clientActiveTexture ), buffer, size, type, stride, offset );
-}
-
-void Ppca::ShadowVertexArrayMultiTexCoordOffsetDSA( GLuint vaobj, GLuint buffer, GLenum texunit, GLint size, GLenum type, GLsizei stride, GLintptr offset ) {
-  VertexArrayObjectState* vao = vas.GetVertexArrayObject( vaobj );
-  if ( vao == NULL ) {
-    return;
-  }
-
-  // Validate the arguments. Return silently if invalid.
-
-  if ( ( texunit < GL_TEXTURE0 ) || ( texunit >= GL_TEXTURE0 + capabilities.maxVertexTextureImageUnits ) ) {
-    return;
-  }
-
-  switch ( size ) {
-    default:
-      return;
-    case 1:
-    case 2:
-    case 3:
-    case 4:
-      break;
-  }
-
-  switch ( type ) {
-    default:
-      return;
-    case GL_SHORT:
-    case GL_INT:
-    case GL_HALF_FLOAT:
-    case GL_FLOAT:
-    case GL_DOUBLE:
-      break;
-    case GL_INT_2_10_10_10_REV:
-    case GL_UNSIGNED_INT_2_10_10_10_REV:
-      if ( ( size != 4 ) || ( size != GL_BGRA ) ) {
-        return;
-      }
-      break;
-  }
-
-  if ( stride < 0 ) {
-    return;
-  }
-
-  vao->fixed.SetData( ArrayNameToAttribIndex( GL_TEXTURE_COORD_ARRAY, texunit ), buffer, size, type, stride, offset );
-}
-
-void Ppca::ShadowVertexArrayFogCoordOffsetDSA( GLuint vaobj, GLuint buffer, GLenum type, GLsizei stride, GLintptr offset ) {
-  VertexArrayObjectState* vao = vas.GetVertexArrayObject( vaobj );
-  if ( vao == NULL ) {
-    return;
-  }
-
-  // Validate the arguments. Return silently if invalid.
-
-  switch ( type ) {
-    default:
-      return;
-    case GL_HALF_FLOAT:
-    case GL_FLOAT:
-    case GL_DOUBLE:
-      break;
-  }
-
-  if ( stride < 0 ) {
-    return;
-  }
-
-  vao->fixed.SetData( ArrayNameToAttribIndex( GL_FOG_COORD_ARRAY ), buffer, 1, type, stride, offset );
-}
-
-void Ppca::ShadowVertexArraySecondaryColorOffsetDSA( GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset ) {
-  VertexArrayObjectState* vao = vas.GetVertexArrayObject( vaobj );
-  if ( vao == NULL ) {
-    return;
-  }
-
-  // Validate the arguments. Return silently if invalid.
-
-  switch ( size ) {
-    default:
-      return;
-    case 3:
-      break;
-    case GL_BGRA:
-      if ( ( type != GL_UNSIGNED_BYTE ) || ( type != GL_INT_2_10_10_10_REV ) || ( type != GL_UNSIGNED_INT_2_10_10_10_REV ) ) {
-        return;
-      }
-      break;
-  }
-
-  switch ( type ) {
-    default:
-      return;
-    case GL_BYTE:
-    case GL_UNSIGNED_BYTE:
-    case GL_SHORT:
-    case GL_UNSIGNED_SHORT:
-    case GL_INT:
-    case GL_UNSIGNED_INT:
-    case GL_HALF_FLOAT:
-    case GL_FLOAT:
-    case GL_DOUBLE:
-      break;
-    case GL_INT_2_10_10_10_REV:
-    case GL_UNSIGNED_INT_2_10_10_10_REV:
-      if ( ( size != 4 ) || ( size != GL_BGRA ) ) {
-        return;
-      }
-      break;
-  }
-
-  if ( stride < 0 ) {
-    return;
-  }
-
-  vao->fixed.SetData( ArrayNameToAttribIndex( GL_SECONDARY_COLOR_ARRAY ), buffer, size, type, stride, offset );
-}
-
-void Ppca::ShadowVertexArrayVertexAttribOffsetDSA( GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLintptr offset ) {
-  VertexArrayObjectState* vao = vas.GetVertexArrayObject( vaobj );
-  if ( vao == NULL ) {
-    return;
-  }
-
-  // Validate the arguments. Return silently if invalid.
-
-  switch ( size ) {
-    default:
-      return;
-    case 1:
-    case 2:
-    case 3:
-    case 4:
-      break;
-    case GL_BGRA:
-      if ( ( type != GL_UNSIGNED_BYTE ) || ( type != GL_INT_2_10_10_10_REV ) || ( type != GL_UNSIGNED_INT_2_10_10_10_REV ) ) {
-        return;
-      }
-      if ( normalized == GL_FALSE ) {
-        return;
-      }
-      break;
-  }
-
-  switch ( type ) {
-    default:
-      return;
-    case GL_BYTE:
-    case GL_UNSIGNED_BYTE:
-    case GL_SHORT:
-    case GL_UNSIGNED_SHORT:
-    case GL_INT:
-    case GL_UNSIGNED_INT:
-    case GL_FIXED:
-    case GL_HALF_FLOAT:
-    case GL_FLOAT:
-    case GL_DOUBLE:
-      break;
-    case GL_INT_2_10_10_10_REV:
-    case GL_UNSIGNED_INT_2_10_10_10_REV:
-      if ( ( size != 4 ) || ( size != GL_BGRA ) ) {
-        return;
-      }
-      break;
-  }
-
-  if ( index >= capabilities.maxVertexAttribs ) {
-    return;
-  }
-  if ( stride < 0 ) {
-    return;
-  }
-
-  vao->generic.SetAttribSource( index, size, type, normalized == GL_TRUE, false, 0 );
-  vao->generic.SetAttribBinding( index, index );
-  vao->generic.SetBuffer( index, buffer, offset, EffectiveStride ( stride, size, type ) );
-}
-
-void Ppca::ShadowVertexArrayVertexAttribIOffsetDSA( GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLsizei stride, GLintptr offset ) {
-  VertexArrayObjectState* vao = vas.GetVertexArrayObject( vaobj );
-  if ( vao == NULL ) {
-    return;
-  }
-
-  // Validate the arguments. Return silently if invalid.
-
-  switch ( size ) {
-    default:
-      return;
-    case 1:
-    case 2:
-    case 3:
-    case 4:
-      break;
-  }
-
-  switch ( type ) {
-    default:
-      return;
-    case GL_BYTE:
-    case GL_UNSIGNED_BYTE:
-    case GL_SHORT:
-    case GL_UNSIGNED_SHORT:
-    case GL_INT:
-    case GL_UNSIGNED_INT:
-      break;
-  }
-
-  if ( index >= capabilities.maxVertexAttribs ) {
-    return;
-  }
-  if ( stride < 0 ) {
-    return;
-  }
-
-  vao->generic.SetAttribSource( index, size, type, false, true, 0 );
-  vao->generic.SetAttribBinding( index, index );
-  vao->generic.SetBuffer( index, buffer, offset, EffectiveStride ( stride, size, type ) );
-}
-
-void Ppca::ShadowEnableVertexArrayDSA( GLuint vaobj, GLenum array ) {
-  VertexArrayObjectState* vao = vas.GetVertexArrayObject( vaobj );
-  if ( vao == NULL ) {
-    return;
-  }
-  vao->fixed.SetEnable( ArrayNameToAttribIndex( array, vas.clientActiveTexture ), true );
-}
-
-void Ppca::ShadowDisableVertexArrayDSA( GLuint vaobj, GLenum array ) {
-  VertexArrayObjectState* vao = vas.GetVertexArrayObject( vaobj );
-  if ( vao == NULL ) {
-    return;
-  }
-  vao->fixed.SetEnable( ArrayNameToAttribIndex( array, vas.clientActiveTexture ), false );
-}
-
-void Ppca::ShadowEnableVertexArrayAttribDSA( GLuint vaobj, GLuint index ) {
-  VertexArrayObjectState* vao = vas.GetVertexArrayObject( vaobj );
-  if ( vao == NULL ) {
-    return;
-  }
-
-  // Validate the arguments. Return silently if invalid.
-
-  if ( index >= capabilities.maxVertexAttribs ) {
-    return;
-  }
-
-  vao->generic.SetEnable( index, true  );
-}
-
-void Ppca::ShadowDisableVertexArrayAttribDSA( GLuint vaobj, GLuint index ) {
-  VertexArrayObjectState* vao = vas.GetVertexArrayObject( vaobj );
-  if ( vao == NULL ) {
-    return;
-  }
-
-  // Validate the arguments. Return silently if invalid.
-
-  if ( index >= capabilities.maxVertexAttribs ) {
-    return;
-  }
-
-  vao->generic.SetEnable( index, false );
-}
-
-void Ppca::ShadowDeleteBuffer_( GLuint buffer ) {
-  if ( pss.pixelPackBufferBinding == buffer ) {
-    pss.pixelPackBufferBinding = 0;
-  }
-  if ( pss.pixelUnpackBufferBinding == buffer ) {
-    pss.pixelUnpackBufferBinding = 0;
-  }
-
-  for ( size_t i = 0; i < ClientState::VertexArray::Generic::COUNT_BUFFERS; ++i ) {
-    ClientState::VertexArray::Generic::State::Buffer& gsbuffer = vas.vertexArrayObjectZero.generic.buffer[ i ];
-    if ( gsbuffer.buffer == buffer ) {
-      gsbuffer.buffer = 0;
-    }
-  }
-  if ( vas.vertexArrayObjectZero.elementArrayBufferBinding == buffer ) {
-    vas.vertexArrayObjectZero.elementArrayBufferBinding = 0;
-  }
-  if ( vas.arrayBufferBinding == buffer ) {
-    vas.arrayBufferBinding = 0;
-  }
-  if ( vas.drawIndirectBufferBinding == buffer ) {
-    vas.drawIndirectBufferBinding = 0;
-  }
-}
-
-void Ppca::ShadowDeleteVertexArray_( GLuint array ) {
-  if ( vas.vertexArrayBinding == array ) {
-    vas.vertexArrayBinding = 0;
-  }
-}
-
-void Ppca::ShadowDeleteBuffers( GLsizei n, const GLuint* buffers ) {
-  while ( n-- ) {
-    GLuint buffer = *buffers++;
-    if ( buffer != 0 ) {
-      ShadowDeleteBuffer_( buffer );
-    }
-  }
-}
-
-void Ppca::ShadowDeleteVertexArrays( GLsizei n, const GLuint* arrays ) {
-  while ( n-- ) {
-    GLuint array = *arrays++;
-    if ( array != 0 ) {
-      ShadowDeleteVertexArray_( array );
-    }
-  }
-}
-
-
-
-void Ppca::PushClientAttrib( RegalContext* ctx, GLbitfield mask ) {
-  clientAttribMaskStack_.push_back( mask );
-
-  if ( mask & GL_CLIENT_PIXEL_STORE_BIT ) {
-    pixelStoreStateStack_.push_back( pss );
-    mask &= ~GL_CLIENT_PIXEL_STORE_BIT;
-  }
-
-  if ( mask & GL_CLIENT_VERTEX_ARRAY_BIT ) {
-    vertexArrayStateStack_.push_back( vas );
-    mask &= ~GL_CLIENT_VERTEX_ARRAY_BIT;
-  }
-
-  if ( ctx->info->core || ctx->info->es2 )
-    return;
-
-  if ( mask )
-    ctx->dispatcher.emulation.glPushClientAttrib( mask );
-}
-
-void Ppca::PopClientAttrib( RegalContext* ctx ) {
-  RegalAssert( ctx );
-  RegalAssert( clientAttribMaskStack_.size() );
-
-  GLbitfield mask = 0;
-  if ( !clientAttribMaskStack_.empty() ) {
-    mask = clientAttribMaskStack_.back();
-    clientAttribMaskStack_.pop_back();
-  }
-
-  if ( mask & GL_CLIENT_PIXEL_STORE_BIT ) {
-    Transition( capabilities, ctx->dispatcher.emulation, pss, pixelStoreStateStack_.back() );
-    swap( pss, pixelStoreStateStack_.back() );
-    pixelStoreStateStack_.pop_back();
-    mask &= ~GL_CLIENT_PIXEL_STORE_BIT;
-  }
-
-  if ( mask & GL_CLIENT_VERTEX_ARRAY_BIT ) {
-    Transition( capabilities, ctx->dispatcher.emulation, vas, vertexArrayStateStack_.back() );
-    swap( vas, vertexArrayStateStack_.back() );
-    vertexArrayStateStack_.pop_back();
-    mask &= ~GL_CLIENT_VERTEX_ARRAY_BIT;
-  }
-
-  if ( ctx->info->core || ctx->info->es2 )
-    return;
-
-  if ( mask )
-    ctx->dispatcher.emulation.glPopClientAttrib();
-}
-
-
-
-template <typename T>
-bool GetImpl( const Ppca& ppca, RegalContext* ctx, GLenum pname, T *params ) {
-  RegalAssert( ctx );
-
-  if ( ctx->info->core || ctx->info->es2 )
-  {
-    switch ( pname )
-    {
-      case GL_MAX_CLIENT_ATTRIB_STACK_DEPTH:
-        if ( params )
-          params[ 0 ] = static_cast<T>(ppca.capabilities.maxClientAttribStackDepth);
-        return true;
-      case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS:
-        if ( params )
-          params[ 0 ] = static_cast<T>(ppca.capabilities.maxVertexTextureImageUnits);
-        return true;
-      case GL_MAX_VERTEX_ATTRIBS:
-        if ( params )
-          params[ 0 ] = static_cast<T>(ppca.capabilities.maxVertexAttribs);
-        return true;
-      case GL_MAX_VERTEX_ATTRIB_BINDINGS:
-        if ( params )
-          params[ 0 ] = static_cast<T>(ppca.capabilities.maxVertexAttribBindings);
-        return true;
-      default:
-        return false;
-    }
-  }
-  return false;
-}
-
-bool Ppca::Get( RegalContext* ctx, GLenum pname, GLint* params ) {
-  return GetImpl( *this, ctx, pname, params );
-}
-
-bool Ppca::Get( RegalContext* ctx, GLenum pname, GLint64* params ) {
-  return GetImpl( *this, ctx, pname, params );
-}
-
-bool Ppca::Get( RegalContext* ctx, GLenum pname, GLfloat* params ) {
-  return GetImpl( *this, ctx, pname, params );
-}
-
-bool Ppca::Get( RegalContext* ctx, GLenum pname, GLdouble* params ) {
-  return GetImpl( *this, ctx, pname, params );
-}
-
-bool Ppca::Get( RegalContext* ctx, GLenum pname, GLboolean* params ) {
-  GLint paramsi[ 1 ];
-  if ( !GetImpl( *this, ctx, pname, paramsi ) ) {
-    return false;
-  }
-
-  if ( params ) {
-    params[ 0 ] = ( paramsi[ 0 ] != 0 ) ? GL_TRUE : GL_FALSE;
-  }
-  return true;
-}
-
-} // namespace Emu
-
-REGAL_NAMESPACE_END
-
-#endif // REGAL_EMULATION
diff --git a/src/regal/RegalPpca.h b/src/regal/RegalPpca.h
index c6a7e48..747f79a 100644
--- a/src/regal/RegalPpca.h
+++ b/src/regal/RegalPpca.h
@@ -33,7 +33,7 @@
 /*
 
  Regal Emulation of glPushClientAttrib/glPopClientAttrib
- Lloyd Pique
+ Lloyd Pique, Nigel Stewart, Scott Nations
 
  */
 
@@ -42,8 +42,6 @@
 
 #include "RegalUtil.h"
 
-#define REGAL_PPCA_MAX_CLIENT_ATTRIB_STACK_DEPTH 16
-
 #if REGAL_EMULATION
 
 REGAL_GLOBAL_BEGIN
@@ -52,353 +50,252 @@
 
 #include <GL/Regal.h>
 
+#include "RegalClientState.h"
 #include "RegalEmu.h"
+#include "RegalLog.h"
+#include "RegalToken.h"
 #include "RegalContext.h"
+#include "RegalContextInfo.h"
 
 REGAL_GLOBAL_END
 
 REGAL_NAMESPACE_BEGIN
 
-struct DispatchTableGL;
-
-// ====================================
-// ClientState::Capabilities
-// ====================================
-
-namespace ClientState {
-
-  struct Capabilities {
-    GLuint maxVertexAttribRelativeOffset;
-    GLuint maxVertexTextureImageUnits;
-    GLuint maxVertexAttribs;
-    GLuint maxVertexAttribBindings;
-    GLuint maxClientAttribStackDepth;
-
-    bool driverAllowsVertexAttributeArraysWithoutBoundBuffer;
-  };
-
-} // namespace ClientState
-
-// ====================================
-// ClientState::PixelStore
-// ====================================
-
-namespace ClientState {
-namespace PixelStore {
-
-const size_t STATE_COUNT   = 16;
-const size_t INVALID_INDEX = ~0u;
-
-struct State
+namespace Emu
 {
-  static const GLenum indexToPName[ STATE_COUNT ];
 
-  void Reset();
-  void Set( GLenum pname, GLint pvalue );
-  GLint Get( GLenum pname ) const;
-
-  GLint data[ STATE_COUNT ];
-  GLuint pixelPackBufferBinding;
-  GLuint pixelUnpackBufferBinding;
-};
-
-void swap( State& lhs, State& rhs );
-
-size_t PNameToIndex( GLenum pname );
-
-void Transition( const Capabilities& cap, const DispatchTableGL& dt, const State& current, const State& target );
-
-} // namespace PixelStore
-} // namespace ClientState
-
-// ====================================
-// ClientState::VertexArray::Fixed
-// ====================================
-
-namespace ClientState {
-namespace VertexArray {
-namespace Fixed {
-
-const size_t COUNT_NAMED_ATTRIBS = 7;
-const size_t COUNT_TEXTURE_COORD_ATTRIBS = 16;
-const size_t COUNT_ATTRIBS = COUNT_NAMED_ATTRIBS + COUNT_TEXTURE_COORD_ATTRIBS;
-
-const size_t BASE_NAMED_ATTRIBS = 0;
-const size_t BASE_TEXTURE_COORD_ATTRIBS = BASE_NAMED_ATTRIBS + COUNT_NAMED_ATTRIBS;
-
-const size_t INVALID_ATTRIB_INDEX = ~0u;
-
-struct State
+struct Ppca : public ClientState::VertexArray, ClientState::PixelStore
 {
-  struct Source {
-    GLuint buffer;
-    GLint size;
-    GLenum type;
-    GLsizei stride;
-    GLintptr offset;
-  };
+  void Init(RegalContext &ctx)
+  {
+    Reset(ctx);
+  }
 
-  struct Attrib {
-    bool enabled;
-    Source source;
-  };
+  void Reset(RegalContext &ctx)
+  {
+    ClientState::VertexArray::Reset();
+    ClientState::PixelStore::Reset();
 
-  void Reset();
+    maskStack.clear();
+    vertexArrayStack.clear();
+    pixelStoreStack.clear();
 
-  void SetEnable ( size_t attribIndex, bool enabled );
-  void SetData   ( size_t attribIndex, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset );
+    // Chromium/PepperAPI GLES generates an error (visible through glGetError) and
+    // logs a message if a call is made to glVertexAttribPointer and no
+    // GL_ARRAY_BUFFER is bound.
 
-  Attrib attrib[ COUNT_ATTRIBS ];
-};
+    driverAllowsVertexAttributeArraysWithoutBoundBuffer = ( !ctx.info->es2 || ctx.info->vendor != "Chromium" );
+  }
 
-void swap( State& lhs, State& rhs );
-
-size_t ArrayNameToAttribIndex( GLenum array, GLenum texunit=GL_TEXTURE0 );
-size_t IndexedArrayNameToAttribIndex( GLenum array, GLuint index );
-
-void Transition( const Capabilities& cap, const DispatchTableGL& dt, const State& current, const State& target, GLenum& inoutClientActiveTexture, GLuint& inoutArrayBufferBinding );
-
-} // namespace Fixed
-} // namespace VertexArray
-} // namespace ClientState
-
-// ====================================
-// ClientState::VertexArray::Generic
-// ====================================
-
-namespace ClientState {
-namespace VertexArray {
-namespace Generic {
-
-const size_t COUNT_ATTRIBS = 16;
-const size_t COUNT_BUFFERS = 16;
-const size_t INVALID_INDEX = ~0u;
-
-struct State
-{
-  struct Source {
-    GLint size;
-    GLenum type;
-    bool normalized;
-    bool pureInteger;
-    GLuint relativeOffset;
-  };
-
-  struct Attrib {
-    bool enabled;
-    GLuint bindingIndex;
-    Source source;
-  };
-
-  struct Buffer {
-    GLuint buffer;
-    GLintptr offset;
-    GLsizei stride;
-    GLuint divisor;
-  };
-
-  void Reset();
-
-  void SetAttribSource( GLuint attribIndex, GLint size, GLenum type, bool normalized, bool pureInteger, GLuint relativeOffset );
-  void SetBuffer( GLuint bindingIndex, GLuint buffer, GLintptr offset, GLsizei stride );
-  void SetBufferDivisor( GLuint bindingIndex, GLuint divisor );
-  void SetAttribBinding( GLuint attribIndex, GLuint bindingIndex );
-  void SetEnable( GLuint attribIndex, bool enabled );
-
-  Attrib attrib[ COUNT_ATTRIBS ];
-  Buffer buffer[ COUNT_BUFFERS ];
-};
-
-void swap( State& lhs, State& rhs );
-
-void Transition( const Capabilities& cap, const DispatchTableGL& dt, const State& current, const State& target );
-
-} // namespace Generic
-} // namespace VertexArray
-} // namespace ClientState
-
-// ====================================
-// Regal::ClientState::VertexArray
-// ====================================
-
-namespace ClientState {
-namespace VertexArray {
-
-struct VertexArrayObjectState {
-  Fixed::State fixed;
-  Generic::State generic;
-  GLuint elementArrayBufferBinding;
-};
-
-struct State {
-  void Reset();
-  VertexArrayObjectState* GetVertexArrayObject( GLuint vao );
-  VertexArrayObjectState* GetVertexArrayObject();
-
-  VertexArrayObjectState vertexArrayObjectZero;
-
-  GLenum clientActiveTexture;
-  GLuint arrayBufferBinding;
-  GLuint drawIndirectBufferBinding;
-  GLuint vertexArrayBinding;
-  bool primitiveRestartEnabled;
-  // NB: primitiveRestartFixedIndexEnabled is not included in the OpenGL 4.3
-  // Compatibility Profile Table 23.8 (20120806), but indicated by the textual
-  // description in section 10.7
-  bool primitiveRestartFixedIndexEnabled;
-  GLuint primitiveRestartIndex;
-};
-
-void swap( State& lhs, State& rhs );
-
-void Transition( const Capabilities& cap, const DispatchTableGL& dt, const State& current, const State& target );
-
-} // namespace VertexArray
-} // namespace ClientState
-
-// ====================================
-// Ppca
-// ====================================
-
-namespace Emu {
-
-struct Ppca {
-  typedef std::vector<GLbitfield> ClientAttribMaskStack;
-  typedef std::vector<ClientState::PixelStore::State> PixelStoreStateStack;
-  typedef std::vector<ClientState::VertexArray::State> VertexArrayStateStack;
-
-  Ppca();
-
-  void Init( RegalContext &ctx );
-  void Cleanup( RegalContext &ctx )
+  void Cleanup(RegalContext &ctx)
   {
     UNUSED_PARAMETER(ctx);
   }
 
-  void Reset();
-  void DetectVertexAttributeArrayWithoutBoundBufferSupport( RegalContext& ctx );
+  void glPushClientAttrib(RegalContext *ctx, GLbitfield mask)
+  {
+    // from glspec43.compatibility.20130214.withchanges.pdf Sec. 21.6, p. 622
+    //
+    // A STACK_OVERFLOW error is generated if PushClientAttrib is called
+    // and the client attribute stack depth is equal to the value of
+    // MAX_CLIENT_ATTRIB_STACK_DEPTH.
+    // 
+    // TODO: set correct GL error here
 
-  // Pixel Storage State
+    if (maskStack.size() >= REGAL_EMU_MAX_CLIENT_ATTRIB_STACK_DEPTH)
+      return;
 
-  void ShadowPixelStore( GLenum pname, GLint pvalue );
-  void ShadowPixelStore( GLenum pname, GLfloat pvalue );
+    maskStack.push_back(mask);
 
-  // Generic Vertex Attributes
+    if (mask&GL_CLIENT_VERTEX_ARRAY_BIT)
+    {
+      Internal("Regal::Ppca::PushClientAttrib GL_CLIENT_VERTEX_ARRAY_BIT ",ClientState::VertexArray::toString());
+      vertexArrayStack.push_back(ClientState::VertexArray());
+      vertexArrayStack.back() = *this;
+      mask &= ~GL_CLIENT_VERTEX_ARRAY_BIT;
+    }
 
-  void ShadowVertexAttribFormat( GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset );
-  void ShadowVertexAttribIFormat( GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset );
-  void ShadowVertexAttribLFormat( GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset );
+    if (mask&GL_CLIENT_PIXEL_STORE_BIT)
+    {
+      Internal("Regal::Ppca::PushClientAttrib GL_CLIENT_PIXEL_STORE_BIT ",ClientState::PixelStore::toString());
+      pixelStoreStack.push_back(ClientState::PixelStore());
+      pixelStoreStack.back() = *this;
+      mask &= ~GL_CLIENT_PIXEL_STORE_BIT;
+    }
 
-  void ShadowBindVertexBuffer( GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride );
+    // Pass the rest through, for now
 
+    RegalAssert(ctx);
 
-  void ShadowVertexAttribBinding( GLuint attribindex, GLuint bindingindex );
+    if (ctx->info->core || ctx->info->es1 || ctx->info->es2)
+      return;
 
-  void ShadowVertexAttribPointer( GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* pointer );
-  void ShadowVertexIAttribPointer( GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid* pointer );
-  void ShadowVertexLAttribPointer( GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid* pointer );
+    if (mask)
+      ctx->dispatcher.emulation.glPushClientAttrib(mask);
+  }
 
-  void ShadowEnableVertexAttribArray( GLuint index );
-  void ShadowDisableVertexAttribArray( GLuint index );
+  void glPopClientAttrib(RegalContext *ctx)
+  {
+    RegalAssert(ctx);
 
-  // Fixed-Function Attributes
+    // from glspec43.compatibility.20130214.withchanges.pdf Sec. 21.6, p. 622
+    //
+    // A STACK_UNDERFLOW error is generated if PopClientAttrib is called
+    // and the client attribute stack depth is zero.
+    // 
+    // TODO: set correct GL error here
 
-  void ShadowVertexPointer( GLint size, GLenum type, GLsizei stride, const GLvoid* pointer );
-  void ShadowNormalPointer( GLenum type, GLsizei stride, const GLvoid* pointer );
-  void ShadowColorPointer( GLint size, GLenum type, GLsizei stride, const GLvoid* pointer );
-  void ShadowSecondaryColorPointer( GLint size, GLenum type, GLsizei stride, const GLvoid* pointer );
-  void ShadowIndexPointer( GLenum type, GLsizei stride, const GLvoid* pointer );
-  void ShadowEdgeFlagPointer( GLsizei stride, const GLvoid* pointer );
-  void ShadowFogCoordPointer( GLenum type, GLsizei stride, const GLvoid* pointer );
-  void ShadowTexCoordPointer( GLint size, GLenum type, GLsizei stride, const GLvoid* pointer );
+    if (!maskStack.size())
+      return;
 
-  void ShadowEnableClientState( GLenum cap );
-  void ShadowDisableClientState( GLenum cap );
+    GLbitfield mask = maskStack.back();
+    maskStack.pop_back();
 
-  void ShadowClientActiveTexture( GLenum texture );
+    if (mask&GL_CLIENT_VERTEX_ARRAY_BIT)
+    {
+      RegalAssert(vertexArrayStack.size());
+      ClientState::VertexArray::transition(ctx->dispatcher.emulation, vertexArrayStack.back(), driverAllowsVertexAttributeArraysWithoutBoundBuffer);
+      vertexArrayStack.pop_back();
 
-  // Vertex Attribute Divisors
+      Internal("Regal::Ppca::PopClientAttrib GL_CLIENT_VERTEX_ARRAY_BIT ",ClientState::VertexArray::toString());
 
-  void ShadowVertexBindingDivisor( GLuint bindingindex, GLuint divisor );
-  void ShadowVertexAttribDivisor( GLuint index, GLuint divisor );
+      mask &= ~GL_CLIENT_VERTEX_ARRAY_BIT;
+    }
 
-  // Primitive Restart
+    if (mask&GL_CLIENT_PIXEL_STORE_BIT)
+    {
+      RegalAssert(pixelStoreStack.size());
+      ClientState::PixelStore::transition(ctx->dispatcher.emulation, pixelStoreStack.back());
+      pixelStoreStack.pop_back();
 
-  void ShadowEnableDisable_( GLenum target, bool enable );
-  void ShadowEnable( GLenum target );
-  void ShadowDisable( GLenum target );
+      Internal("Regal::Ppca::PopClientAttrib GL_CLIENT_PIXEL_STORE_BIT ",ClientState::PixelStore::toString());
 
-  void ShadowPrimitiveRestartIndex( GLuint index );
+      mask &= ~GL_CLIENT_PIXEL_STORE_BIT;
+    }
 
-  // Vertex Arrays in Buffer Objects
+    // Pass the rest through, for now
 
-  void ShadowBindBuffer( GLenum target, GLuint buffer );
+    if (ctx->info->core || ctx->info->es1 || ctx->info->es2)
+      return;
 
-  // Vertex Array Objects
+    if (mask)
+      ctx->dispatcher.emulation.glPopClientAttrib();
+  }
 
-  void ShadowBindVertexArray( GLuint array );
+  void glClientAttribDefaultEXT(RegalContext *ctx, GLbitfield mask)
+  {
+    if (mask&GL_CLIENT_VERTEX_ARRAY_BIT)
+    {
+      ClientState::VertexArray::Reset();
 
-  // Interleaved Arrays
+      Internal("Regal::Ppca::glClientAttribDefaultEXT GL_CLIENT_VERTEX_ARRAY_BIT ",ClientState::VertexArray::toString());
 
-  void ShadowInterleavedArrays( GLenum format, GLsizei stride, const GLvoid* pointer );
+      // Ideally we'd only set the state that has changed - revisit
 
-  // Direct State Access
+      ClientState::VertexArray::set(ctx->dispatcher.emulation,driverAllowsVertexAttributeArraysWithoutBoundBuffer);
 
-  void ClientAttribDefaultDSA( RegalContext* ctx, GLbitfield mask );
-  void PushClientAttribDefaultDSA( RegalContext* ctx, GLbitfield mask );
+      mask &= ~GL_CLIENT_VERTEX_ARRAY_BIT;
+    }
 
-  void ShadowMultiTexCoordPointerDSA( GLenum texunit, GLint size, GLenum type, GLsizei stride, const GLvoid* pointer );
+    if (mask&GL_CLIENT_PIXEL_STORE_BIT)
+    {
+      ClientState::PixelStore::Reset();
 
-  void ShadowEnableClientStateIndexedDSA( GLenum cap, GLuint index );
-  void ShadowDisableClientStateIndexedDSA( GLenum cap, GLuint index );
+      Internal("Regal::Ppca::PopClientAttrib GL_CLIENT_PIXEL_STORE_BIT ",ClientState::PixelStore::toString());
 
-  void ShadowVertexArrayVertexOffsetDSA( GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset );
-  void ShadowVertexArrayColorOffsetDSA( GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset );
-  void ShadowVertexArrayEdgeFlagOffsetDSA( GLuint vaobj, GLuint buffer, GLsizei stride, GLintptr offset );
-  void ShadowVertexArrayIndexOffsetDSA( GLuint vaobj, GLuint buffer, GLenum type, GLsizei stride, GLintptr offset );
-  void ShadowVertexArrayNormalOffsetDSA( GLuint vaobj, GLuint buffer, GLenum type, GLsizei stride, GLintptr offset );
-  void ShadowVertexArrayTexCoordOffsetDSA( GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset );
-  void ShadowVertexArrayMultiTexCoordOffsetDSA( GLuint vaobj, GLuint buffer, GLenum texunit, GLint size, GLenum type, GLsizei stride, GLintptr offset );
-  void ShadowVertexArrayFogCoordOffsetDSA( GLuint vaobj, GLuint buffer, GLenum type, GLsizei stride, GLintptr offset );
-  void ShadowVertexArraySecondaryColorOffsetDSA( GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset );
-  void ShadowVertexArrayVertexAttribOffsetDSA( GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLintptr offset );
-  void ShadowVertexArrayVertexAttribIOffsetDSA( GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLsizei stride, GLintptr offset );
+      // Ideally we'd only set the state that has changed - revisit
 
-  void ShadowEnableVertexArrayDSA( GLuint vaobj, GLenum array );
-  void ShadowDisableVertexArrayDSA( GLuint vaobj, GLenum array );
+      ClientState::PixelStore::set(ctx->dispatcher.emulation);
 
-  void ShadowEnableVertexArrayAttribDSA( GLuint vaobj, GLuint index );
-  void ShadowDisableVertexArrayAttribDSA( GLuint vaobj, GLuint index );
+      mask &= ~GL_CLIENT_PIXEL_STORE_BIT;
+    }
 
-  void ShadowDeleteBuffer_( GLuint buffer );
-  void ShadowDeleteVertexArray_( GLuint array );
-  void ShadowDeleteBuffers( GLsizei n, const GLuint* buffers );
-  void ShadowDeleteVertexArrays( GLsizei n, const GLuint* arrays );
+    // Pass the rest through, for now
 
-  // Push/Pop Client attribute state
+    if (ctx->info->core || ctx->info->es1 || ctx->info->es2)
+      return;
 
-  void PushClientAttrib( RegalContext* ctx, GLbitfield mask );
-  void PopClientAttrib( RegalContext* ctx );
+    if (mask)
+      ctx->dispatcher.emulation.glClientAttribDefaultEXT(mask);
+  }
 
-  // Get
+  void glPushClientAttribDefaultEXT(RegalContext *ctx, GLbitfield mask)
+  {
+    GLbitfield tmpMask = mask;
+    glPushClientAttrib(ctx, tmpMask);
+    glClientAttribDefaultEXT(ctx, mask);
+  }
 
-  bool Get( RegalContext* ctx, GLenum pname, GLint* params );
-  bool Get( RegalContext* ctx, GLenum pname, GLint64* params );
-  bool Get( RegalContext* ctx, GLenum pname, GLfloat* params );
-  bool Get( RegalContext* ctx, GLenum pname, GLdouble* params );
-  bool Get( RegalContext* ctx, GLenum pname, GLboolean* params );
+  void glBindBuffer( GLenum target, GLuint buffer )
+  {
+    ClientState::VertexArray::glBindBuffer(target,buffer);
+    ClientState::PixelStore::glBindBuffer(target,buffer);
+  }
 
-  ClientState::Capabilities capabilities;
+  void glDeleteBuffers( GLsizei n, const GLuint *buffers )
+  {
+    ClientState::VertexArray::glDeleteBuffers(n,buffers);
+    ClientState::PixelStore::glDeleteBuffers(n,buffers);
+  }
 
-  ClientState::PixelStore::State pss;
-  ClientState::VertexArray::State vas;
+  bool glGetv(RegalContext *ctx, GLenum pname, GLboolean *params)
+  {
+    UNUSED_PARAMETER(ctx);
 
-  ClientAttribMaskStack clientAttribMaskStack_;
-  PixelStoreStateStack pixelStoreStateStack_;
-  VertexArrayStateStack vertexArrayStateStack_;
+    switch (pname)
+    {
+      case GL_MAX_CLIENT_ATTRIB_STACK_DEPTH:
+        params[0] = GL_TRUE;
+        break;
+      case GL_CLIENT_ATTRIB_STACK_DEPTH:
+        params[0] = (maskStack.size() != 0);
+        break;
+
+      default:
+        return false;
+    }
+    return true;
+  }
+
+  template <typename T> bool glGetv(RegalContext *ctx, GLenum pname, T *params)
+  {
+    UNUSED_PARAMETER(ctx);
+
+    switch (pname)
+    {
+      case GL_MAX_CLIENT_ATTRIB_STACK_DEPTH:
+        params[0] = static_cast<T>(REGAL_EMU_MAX_CLIENT_ATTRIB_STACK_DEPTH);
+        break;
+      case GL_CLIENT_ATTRIB_STACK_DEPTH:
+        params[0] = static_cast<T>(maskStack.size());
+        break;
+
+      default:
+        return false;
+    }
+    return true;
+  }
+
+  Ppca &swap(Ppca &other)
+  {
+    std::swap(driverAllowsVertexAttributeArraysWithoutBoundBuffer,other.driverAllowsVertexAttributeArraysWithoutBoundBuffer);
+    std::swap(maskStack,other.maskStack);
+    std::swap(vertexArrayStack,other.vertexArrayStack);
+    std::swap(pixelStoreStack,other.pixelStoreStack);
+
+    VertexArray::swap(other);
+    PixelStore::swap(other);
+
+    return *this;
+  }
+
+  bool driverAllowsVertexAttributeArraysWithoutBoundBuffer;
+  std::vector<GLbitfield>                maskStack;
+  std::vector<ClientState::VertexArray>  vertexArrayStack;
+  std::vector<ClientState::PixelStore>   pixelStoreStack;
 };
 
-} // namespace Emu
+}
 
 REGAL_NAMESPACE_END
 
diff --git a/src/regal/RegalUtil.h b/src/regal/RegalUtil.h
old mode 100755
new mode 100644
diff --git a/src/regal/Regalm.def b/src/regal/Regalm.def
old mode 100755
new mode 100644
diff --git a/tests/testRegalPpca.cpp b/tests/testRegalPpca.cpp
index 85f430d..0cb6f78 100644
--- a/tests/testRegalPpca.cpp
+++ b/tests/testRegalPpca.cpp
@@ -43,1989 +43,2766 @@
 using namespace Regal::Emu;
 
 using ::testing::Mock;
+using ::testing::_;
+using ::testing::AnyNumber;
+
 
 template <typename T, size_t N> size_t arraysize( const T( & )[ N ] ) {
   return N;
 }
 
-// ====================================
-// ClientState::PixelStore::State
-// ====================================
+void checkNamedVertexArrayDefaults(ClientState::NamedVertexArray& nva, GLuint n)
+{
+  EXPECT_EQ( GLboolean(GL_FALSE),   nva.enabled );
+  EXPECT_EQ( reinterpret_cast<const GLvoid*>(NULL), nva.pointer );
+  EXPECT_EQ( GLuint(0),             nva.buffer );
+  EXPECT_EQ( GLint(0),              nva.stride );
 
-TEST( RegalClientStatePixelStore, SizesAndMappings ) {
-  using namespace ClientState::PixelStore;
-  using ClientState::PixelStore::State;
-  using ClientState::PixelStore::PNameToIndex;
+  if (n == ClientState::FOG_COORD ||
+      n == ClientState::INDEX ||
+      n == ClientState::EDGE_FLAG)
+    EXPECT_EQ( GLint(1), nva.size );
+  else if (n == ClientState::NORMAL ||
+           n == ClientState::SECONDARY_COLOR)
+    EXPECT_EQ( GLint(3), nva.size );
+  else
+    EXPECT_EQ( GLint(4), nva.size );
 
-  // The arrays for the state data and mapping must match the number of
-  // named attributes the state supports.
-  ASSERT_EQ( STATE_COUNT, arraysize( static_cast<const State *>( NULL )->data ) );
-  ASSERT_EQ( STATE_COUNT, arraysize( State::indexToPName ) );
-
-  // Test the round trip mapping from index to name and back)
-  for ( size_t i = 0; i < STATE_COUNT; ++i ) {
-    EXPECT_EQ( i, PNameToIndex( State::indexToPName[ i ] ) );
-  }
-
-  // Unexpected names should return an invalid index.
-  EXPECT_EQ( INVALID_INDEX, PNameToIndex( GL_PACK_SWAP_BYTES - 1 ) );
+  if (n == ClientState::EDGE_FLAG)
+    EXPECT_EQ( GLenum(GL_BOOL),  nva.type );
+  else
+    EXPECT_EQ( GLenum(GL_FLOAT), nva.type );
 }
 
-TEST( RegalClientStatePixelStore, BasicOperations ) {
-  using ClientState::PixelStore::State;
-  using ClientState::PixelStore::PNameToIndex;
-
-  State state;
-  state.Reset();
-
-  State other;
-  other.Reset();
-
-  // It should be possible to set each attribute in a state to a unique
-  // value.
-  other.Set( GL_PACK_SWAP_BYTES     , 11 );
-  other.Set( GL_PACK_LSB_FIRST      , 12 );
-  other.Set( GL_PACK_ROW_LENGTH     , 13 );
-  other.Set( GL_PACK_IMAGE_HEIGHT   , 14 );
-  other.Set( GL_PACK_SKIP_ROWS      , 15 );
-  other.Set( GL_PACK_SKIP_PIXELS    , 16 );
-  other.Set( GL_PACK_SKIP_IMAGES    , 17 );
-  other.Set( GL_PACK_ALIGNMENT      , 18 );
-  other.Set( GL_UNPACK_SWAP_BYTES   , 21 );
-  other.Set( GL_UNPACK_LSB_FIRST    , 22 );
-  other.Set( GL_UNPACK_ROW_LENGTH   , 23 );
-  other.Set( GL_UNPACK_IMAGE_HEIGHT , 24 );
-  other.Set( GL_UNPACK_SKIP_ROWS    , 25 );
-  other.Set( GL_UNPACK_SKIP_PIXELS  , 26 );
-  other.Set( GL_UNPACK_SKIP_IMAGES  , 27 );
-  other.Set( GL_UNPACK_ALIGNMENT    , 28 );
-  other.pixelPackBufferBinding   = 100;
-  other.pixelUnpackBufferBinding = 101;
-
-  // Setting with an invalid name should silenty do nothing
-  // This is done here so if we affect the explicitly set state it will be
-  // detected soon.
-  other.Set( GL_TEXTURE0, 0xdead );
-
-  // Getting with an invalid name should just return zero
-  EXPECT_EQ( 0, state.Get( GL_TEXTURE0 ) );
-
-  // Peform a swap, so that it is effectively tested too
-  swap( state, other );
-
-  // It should be possible to get the unique value set previously in the
-  // swapped state.
-  EXPECT_EQ( 11, state.Get( GL_PACK_SWAP_BYTES     ) );
-  EXPECT_EQ( 12, state.Get( GL_PACK_LSB_FIRST      ) );
-  EXPECT_EQ( 13, state.Get( GL_PACK_ROW_LENGTH     ) );
-  EXPECT_EQ( 14, state.Get( GL_PACK_IMAGE_HEIGHT   ) );
-  EXPECT_EQ( 15, state.Get( GL_PACK_SKIP_ROWS      ) );
-  EXPECT_EQ( 16, state.Get( GL_PACK_SKIP_PIXELS    ) );
-  EXPECT_EQ( 17, state.Get( GL_PACK_SKIP_IMAGES    ) );
-  EXPECT_EQ( 18, state.Get( GL_PACK_ALIGNMENT      ) );
-  EXPECT_EQ( 21, state.Get( GL_UNPACK_SWAP_BYTES   ) );
-  EXPECT_EQ( 22, state.Get( GL_UNPACK_LSB_FIRST    ) );
-  EXPECT_EQ( 23, state.Get( GL_UNPACK_ROW_LENGTH   ) );
-  EXPECT_EQ( 24, state.Get( GL_UNPACK_IMAGE_HEIGHT ) );
-  EXPECT_EQ( 25, state.Get( GL_UNPACK_SKIP_ROWS    ) );
-  EXPECT_EQ( 26, state.Get( GL_UNPACK_SKIP_PIXELS  ) );
-  EXPECT_EQ( 27, state.Get( GL_UNPACK_SKIP_IMAGES  ) );
-  EXPECT_EQ( 28, state.Get( GL_UNPACK_ALIGNMENT    ) );
-
-  EXPECT_EQ( 100u, state.pixelPackBufferBinding );
-  EXPECT_EQ( 101u, state.pixelUnpackBufferBinding );
-
-  // Verify the expected default state set previously ended up in the swapped
-  // state.
-  EXPECT_EQ( 0, other.Get( GL_PACK_SWAP_BYTES     ) );
-  EXPECT_EQ( 0, other.Get( GL_PACK_LSB_FIRST      ) );
-  EXPECT_EQ( 0, other.Get( GL_PACK_ROW_LENGTH     ) );
-  EXPECT_EQ( 0, other.Get( GL_PACK_IMAGE_HEIGHT   ) );
-  EXPECT_EQ( 0, other.Get( GL_PACK_SKIP_ROWS      ) );
-  EXPECT_EQ( 0, other.Get( GL_PACK_SKIP_PIXELS    ) );
-  EXPECT_EQ( 0, other.Get( GL_PACK_SKIP_IMAGES    ) );
-  EXPECT_EQ( 4, other.Get( GL_PACK_ALIGNMENT      ) );
-  EXPECT_EQ( 0, other.Get( GL_UNPACK_SWAP_BYTES   ) );
-  EXPECT_EQ( 0, other.Get( GL_UNPACK_LSB_FIRST    ) );
-  EXPECT_EQ( 0, other.Get( GL_UNPACK_ROW_LENGTH   ) );
-  EXPECT_EQ( 0, other.Get( GL_UNPACK_IMAGE_HEIGHT ) );
-  EXPECT_EQ( 0, other.Get( GL_UNPACK_SKIP_ROWS    ) );
-  EXPECT_EQ( 0, other.Get( GL_UNPACK_SKIP_PIXELS  ) );
-  EXPECT_EQ( 0, other.Get( GL_UNPACK_SKIP_IMAGES  ) );
-  EXPECT_EQ( 4, other.Get( GL_UNPACK_ALIGNMENT    ) );
-
-  EXPECT_EQ( 0u, other.pixelPackBufferBinding );
-  EXPECT_EQ( 0u, other.pixelUnpackBufferBinding );
+void checkVertexBufferBindPointDefaults(ClientState::VertexBufferBindPoint& vbbp)
+{
+  EXPECT_EQ( GLuint(0),   vbbp.buffer );
+  EXPECT_EQ( GLintptr(0), vbbp.offset );
+  EXPECT_EQ( GLsizei(16), vbbp.stride );
+  EXPECT_EQ( GLuint(0),   vbbp.divisor );
 }
 
-TEST( RegalClientStatePixelStore, Transition ) {
-  using ClientState::Capabilities;
-  using ClientState::PixelStore::State;
-  using ClientState::PixelStore::PNameToIndex;
-  using ClientState::PixelStore::Transition;
+void checkGenericVertexArrayDefaults(ClientState::GenericVertexArray& gva, GLuint index)
+{
+  EXPECT_EQ( GLboolean(GL_FALSE), gva.enabled );
+  EXPECT_EQ( GLuint(4),           gva.size );
+  EXPECT_EQ( GLenum(GL_FLOAT),    gva.type );
+  EXPECT_EQ( GLuint(0),           gva.relativeOffset );
+  EXPECT_EQ( GLboolean(GL_FALSE), gva.normalized );
+  EXPECT_EQ( GLboolean(GL_FALSE), gva.isInteger );
+  EXPECT_EQ( GLboolean(GL_FALSE), gva.isLong );
+  EXPECT_EQ( index,               gva.bindingIndex );
+}
 
+void checkVertexArrayDefaults(ClientState::VertexArray& va)
+{
+  EXPECT_EQ( GLuint(0),           va.elementArrayBufferBinding );
+  EXPECT_EQ( GLenum(GL_TEXTURE0), va.clientActiveTexture );
+  EXPECT_EQ( GLboolean(GL_FALSE), va.primitiveRestartFixedIndex );
+  EXPECT_EQ( GLboolean(GL_FALSE), va.primitiveRestart );
+  EXPECT_EQ( GLuint(0),           va.primitiveRestartIndex );
+  EXPECT_EQ( GLuint(0),           va.arrayBufferBinding );
+  EXPECT_EQ( GLuint(0),           va.vertexArrayBinding );
+
+  for (GLuint ii=0; ii<ClientState::nNamedArrays; ii++)
+    checkNamedVertexArrayDefaults( va.named[ii], ii );
+
+  for (GLuint ii=0; ii<REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS; ii++)
+    checkVertexBufferBindPointDefaults( va.bindings[ii] );
+
+  for (GLuint ii=0; ii<REGAL_EMU_MAX_VERTEX_ATTRIBS; ii++)
+    checkGenericVertexArrayDefaults( va.generic[ii], ii );
+}
+
+void checkPixelStoreDefaults(ClientState::PixelStore& ps)
+{
+  EXPECT_EQ( GLboolean(GL_FALSE), ps.unpackSwapBytes );
+  EXPECT_EQ( GLboolean(GL_FALSE), ps.unpackLsbFirst );
+  EXPECT_EQ( GLint(0),            ps.unpackImageHeight );
+  EXPECT_EQ( GLint(0),            ps.unpackSkipImages );
+  EXPECT_EQ( GLint(0),            ps.unpackRowLength );
+  EXPECT_EQ( GLint(0),            ps.unpackSkipRows );
+  EXPECT_EQ( GLint(0),            ps.unpackSkipPixels );
+  EXPECT_EQ( GLint(4),            ps.unpackAlignment );
+  EXPECT_EQ( GLboolean(GL_FALSE), ps.packSwapBytes );
+  EXPECT_EQ( GLboolean(GL_FALSE), ps.packLsbFirst );
+  EXPECT_EQ( GLint(0),            ps.packImageHeight );
+  EXPECT_EQ( GLint(0),            ps.packSkipImages );
+  EXPECT_EQ( GLint(0),            ps.packRowLength );
+  EXPECT_EQ( GLint(0),            ps.packSkipRows );
+  EXPECT_EQ( GLint(0),            ps.packSkipPixels );
+  EXPECT_EQ( GLint(4),            ps.packAlignment );
+  EXPECT_EQ( GLuint(0),           ps.pixelUnpackBufferBinding );
+  EXPECT_EQ( GLuint(0),           ps.pixelPackBufferBinding );
+}
+
+void checkPpcaDefaults(RegalContext& ctx, Ppca& ppca)
+{
+  GLint clientAttribStackDepth = 666;
+  EXPECT_EQ( GLboolean( GL_TRUE ), ppca.glGetv(&ctx, GL_CLIENT_ATTRIB_STACK_DEPTH, &clientAttribStackDepth));
+  EXPECT_EQ( clientAttribStackDepth, GLint(0) );
+
+  EXPECT_EQ( std::vector<GLbitfield>::size_type(0),               ppca.maskStack.size() );
+  EXPECT_EQ( std::vector<ClientState::VertexArray>::size_type(0), ppca.vertexArrayStack.size() );
+  EXPECT_EQ( std::vector<ClientState::PixelStore>::size_type(0),  ppca.pixelStoreStack.size() );
+
+  checkVertexArrayDefaults(ppca);
+  checkPixelStoreDefaults(ppca);
+}
+
+TEST ( RegalPpca, Ppca_Defaults )
+{
   RegalGMockInterface mock;
 
-  Capabilities cap;
-
-  DispatchTableGL dt;
-  ::memset(&dt,0,sizeof(DispatchTableGL));
-  dt._enabled = true;
-  InitDispatchTableGMock( dt );
-
-  State current;
-  current.Reset();
-
-  State target;
-  target.Reset();
-
-  // Set some of the named attributes, and expect that calls will be made
-  // appropriately to the backend to transition to those value.
-  target.Set( GL_UNPACK_SKIP_PIXELS, 123 );
-  target.Set( GL_UNPACK_ALIGNMENT  , 456 );
-  target.pixelPackBufferBinding   = 321;
-  target.pixelUnpackBufferBinding = 654;
-
-  EXPECT_CALL( mock, glPixelStorei( GL_UNPACK_SKIP_PIXELS         , 123 ) );
-  EXPECT_CALL( mock, glPixelStorei( GL_UNPACK_ALIGNMENT           , 456 ) );
-  EXPECT_CALL( mock, glBindBuffer ( GL_PIXEL_PACK_BUFFER_BINDING  , 321 ) );
-  EXPECT_CALL( mock, glBindBuffer ( GL_PIXEL_UNPACK_BUFFER_BINDING, 654 ) );
-
-  // Perform the state transition
-  Transition( cap, dt, current, target );
-  Mock::VerifyAndClear( &mock );
-
-  // A transition with no differences should make no calls.
-
-  current.Reset();
-  target.Reset();
-
-  target.Set( GL_UNPACK_SKIP_PIXELS, 123 );
-  target.Set( GL_UNPACK_ALIGNMENT  , 456 );
-  target.pixelPackBufferBinding   = 321;
-  target.pixelUnpackBufferBinding = 654;
-
-  current.Set( GL_UNPACK_SKIP_PIXELS, 123 );
-  current.Set( GL_UNPACK_ALIGNMENT  , 456 );
-  current.pixelPackBufferBinding   = 321;
-  current.pixelUnpackBufferBinding = 654;
-
-  // Perform the state transition
-  Transition( cap, dt, current, target );
-  Mock::VerifyAndClear( &mock );
-}
-
-// ====================================
-// ClientState::VertexArray::Fixed::State
-// ====================================
-
-TEST( RegalClientStateVertexArrayFixedState, SizesAndMappings ) {
-  using namespace ClientState::VertexArray::Fixed;
-  using ClientState::VertexArray::Fixed::State;
-  using ClientState::VertexArray::Fixed::ArrayNameToAttribIndex;
-  using ClientState::VertexArray::Fixed::IndexedArrayNameToAttribIndex;
-
-  ASSERT_EQ( COUNT_ATTRIBS, arraysize( static_cast<State *>( NULL )->attrib ) );
-
-  // An expected attribute name returns the expected index
-  // (note: the full range of names effectively tested elsewhere)
-  EXPECT_EQ( BASE_NAMED_ATTRIBS, ArrayNameToAttribIndex( GL_VERTEX_ARRAY ) );
-  // For most attributes that do not use it, passing in non-default texture unit makes no difference.
-  EXPECT_EQ( BASE_NAMED_ATTRIBS, ArrayNameToAttribIndex( GL_VERTEX_ARRAY, GL_TEXTURE5 ) );
-  // An unexpected name should give an invalid index
-  EXPECT_EQ( INVALID_ATTRIB_INDEX, ArrayNameToAttribIndex( GL_PACK_SWAP_BYTES ) );
-  EXPECT_EQ( INVALID_ATTRIB_INDEX, ArrayNameToAttribIndex( GL_PACK_SWAP_BYTES, GL_TEXTURE5 ) );
-  // Texture coordinate attributes do use the texture unit.
-  EXPECT_EQ( BASE_TEXTURE_COORD_ATTRIBS + 5u, ArrayNameToAttribIndex( GL_TEXTURE_COORD_ARRAY, GL_TEXTURE5 ) );
-  // Passing in a bad texture unit gives an invalid index
-  EXPECT_EQ( INVALID_ATTRIB_INDEX, ArrayNameToAttribIndex( GL_TEXTURE_COORD_ARRAY, GL_TEXTURE0 - 1 ) );
-  EXPECT_EQ( INVALID_ATTRIB_INDEX, ArrayNameToAttribIndex( GL_TEXTURE_COORD_ARRAY, GL_TEXTURE0 + COUNT_TEXTURE_COORD_ATTRIBS ) );
-  EXPECT_EQ( INVALID_ATTRIB_INDEX, ArrayNameToAttribIndex( GL_TEXTURE_COORD_ARRAY, 0 ) );
-
-  // Most attribute names are not indexed, and should return an invalid index.
-  EXPECT_EQ( INVALID_ATTRIB_INDEX, IndexedArrayNameToAttribIndex( GL_VERTEX_ARRAY, 0 ) );
-  // Unexpected names should also give an invalid index.
-  EXPECT_EQ( INVALID_ATTRIB_INDEX, IndexedArrayNameToAttribIndex( GL_PACK_SWAP_BYTES, 0 ) );
-  // Texture coordinates are indexed, and should return valid output indices for valid input indices.
-  EXPECT_EQ( BASE_TEXTURE_COORD_ATTRIBS, IndexedArrayNameToAttribIndex( GL_TEXTURE_COORD_ARRAY, 0 ) );
-  EXPECT_EQ( BASE_TEXTURE_COORD_ATTRIBS + COUNT_TEXTURE_COORD_ATTRIBS - 1, IndexedArrayNameToAttribIndex( GL_TEXTURE_COORD_ARRAY, COUNT_TEXTURE_COORD_ATTRIBS - 1 ) );
-  // But even for texture coordinates, input indices outside the valid range return an invalid index.
-  EXPECT_EQ( INVALID_ATTRIB_INDEX, IndexedArrayNameToAttribIndex( GL_TEXTURE_COORD_ARRAY, -1 ) );
-  EXPECT_EQ( INVALID_ATTRIB_INDEX, IndexedArrayNameToAttribIndex( GL_TEXTURE_COORD_ARRAY, COUNT_TEXTURE_COORD_ATTRIBS ) );
-}
-
-TEST( RegalClientStateVertexArrayFixedState, BasicOperations ) {
-  using namespace ClientState::VertexArray::Fixed;
-  using ClientState::VertexArray::Fixed::State;
-  using ClientState::VertexArray::Fixed::ArrayNameToAttribIndex;
-
-  const size_t normalAttribIndex         = ArrayNameToAttribIndex ( GL_NORMAL_ARRAY );
-  const size_t secondaryColorAttribIndex = ArrayNameToAttribIndex ( GL_SECONDARY_COLOR_ARRAY );
-  const size_t indexAttribIndex          = ArrayNameToAttribIndex ( GL_INDEX_ARRAY );
-  const size_t fogCoordAttribIndex       = ArrayNameToAttribIndex ( GL_FOG_COORD_ARRAY );
-  const size_t edgeFlagAttribIndex       = ArrayNameToAttribIndex ( GL_EDGE_FLAG_ARRAY );
-
-  State state;
-  state.Reset();
-
-  State other;
-  other.Reset();
-
-  // Enable a specific attribute array.
-  state.SetEnable( 4, true );
-
-  // Set unique data for the array source for all attributes.
-  for ( size_t i = 0; i < COUNT_ATTRIBS; ++i ) {
-    state.SetData( i, i * 10 + 1, i * 10 + 2, i * 10 + 3, i * 10 + 4, i * 10 + 5 );
-  }
-
-  // Calls with out-of-bound values should silently return as a no-op.
-  // This is done here so if we affect the explicitly set state it will be
-  // detected soon.
-  state.SetEnable( INVALID_ATTRIB_INDEX, true );
-  state.SetEnable( COUNT_ATTRIBS, true );
-  state.SetData( INVALID_ATTRIB_INDEX, 0xdead, 0xdead, 0xdead, 0xdead, 0xdead );
-  state.SetData( COUNT_ATTRIBS, 0xdead, 0xdead, 0xdead, 0xdead, 0xdead );
-
-  // Peform a swap, so that it is effectively tested too
-  swap( state, other );
-
-  // Verify the unique data that was set is in the swapped state.
-  for ( size_t i = 0; i < COUNT_ATTRIBS; ++i ) {
-    const State::Attrib& attrib = other.attrib[ i ];
-
-    if ( i == 4 ) {
-      EXPECT_TRUE( attrib.enabled );
-    } else {
-      EXPECT_FALSE( attrib.enabled );
-    }
-
-    EXPECT_EQ( static_cast<GLuint>( i * 10 + 1 ), attrib.source.buffer );
-    EXPECT_EQ( static_cast<GLint> ( i * 10 + 2 ), attrib.source.size   );
-    EXPECT_EQ( static_cast<GLenum>( i * 10 + 3 ), attrib.source.type   );
-    EXPECT_EQ( static_cast<GLint> ( i * 10 + 4 ), attrib.source.stride );
-    EXPECT_EQ( static_cast<GLint> ( i * 10 + 5 ), attrib.source.offset );
-  }
-
-  // Verify the expected default state set previously ended up in the swapped
-  // state.
-  for ( size_t i = 0; i < COUNT_ATTRIBS; ++i ) {
-    const State::Attrib& attrib = state.attrib[ i ];
-    EXPECT_FALSE( attrib.enabled ) << "index " << i;
-    EXPECT_EQ( 0u, attrib.source.buffer ) << "index " << i;
-    if ( ( i == indexAttribIndex ) || ( i == fogCoordAttribIndex ) || ( i == edgeFlagAttribIndex ) ) {
-      EXPECT_EQ( 1, attrib.source.size ) << "index " << i;
-    } else if ( ( i == secondaryColorAttribIndex ) || ( i == normalAttribIndex ) ) {
-      EXPECT_EQ( 3, attrib.source.size ) << "index " << i;
-    } else {
-      EXPECT_EQ( 4, attrib.source.size ) << "index " << i;
-    }
-    if ( i == edgeFlagAttribIndex ) {
-      EXPECT_EQ( static_cast<GLenum>( GL_BOOL ), attrib.source.type ) << "index " << i;
-    } else {
-      EXPECT_EQ( static_cast<GLenum>( GL_FLOAT ), attrib.source.type ) << "index " << i;
-    }
-    EXPECT_EQ( 0, attrib.source.stride ) << "index " << i;
-    EXPECT_EQ( 0, attrib.source.offset ) << "index " << i;
-  }
-}
-
-TEST( RegalClientStateVertexArrayFixedState, Transition ) {
-  using ClientState::Capabilities;
-  using ClientState::VertexArray::Fixed::State;
-  using ClientState::VertexArray::Fixed::ArrayNameToAttribIndex;
-  using ClientState::VertexArray::Fixed::IndexedArrayNameToAttribIndex;
-  using ClientState::VertexArray::Fixed::Transition;
-
-  RegalGMockInterface mock;
-
-  Capabilities cap;
-  cap.driverAllowsVertexAttributeArraysWithoutBoundBuffer = true;
-
-  DispatchTableGL dt;
-  ::memset(&dt,0,sizeof(DispatchTableGL));
-  dt._enabled = true;
-  InitDispatchTableGMock( dt );
-
-  State current;
-  current.Reset();
-
-  State target;
-  target.Reset();
-
-  // The mapping between named fixed vertex attributes and the function to set
-  // their attributes is messy. We explicitly test every one to ensure the
-  // correct behavior.
-
-  // The vertex position attribute array uses all the array state we have.
-  target.SetEnable ( ArrayNameToAttribIndex( GL_VERTEX_ARRAY ), true );
-  target.SetData   ( ArrayNameToAttribIndex( GL_VERTEX_ARRAY ), 10, 11, 12, 13, 14 );
-  EXPECT_CALL( mock, glEnableClientState( GL_VERTEX_ARRAY ) );
-  EXPECT_CALL( mock, glBindBuffer( GL_ARRAY_BUFFER, 10 ) );
-  EXPECT_CALL( mock, glVertexPointer    ( 11, 12, 13, reinterpret_cast<const GLvoid*>( 14 ) ) );
-
-  // The vertex normal attribute array does not need the first size argument.
-  target.SetEnable( ArrayNameToAttribIndex( GL_NORMAL_ARRAY ), true );
-  target.SetData  ( ArrayNameToAttribIndex( GL_NORMAL_ARRAY ), 20, 21, 22, 23, 24 );
-  EXPECT_CALL( mock, glEnableClientState( GL_NORMAL_ARRAY ) );
-  EXPECT_CALL( mock, glBindBuffer( GL_ARRAY_BUFFER, 20 ) );
-  EXPECT_CALL( mock, glNormalPointer    ( 22, 23, reinterpret_cast<const GLvoid*>( 24 ) ) );
-
-  // The color attribute array uses all the array state we have.
-  target.SetEnable( ArrayNameToAttribIndex( GL_COLOR_ARRAY ), true );
-  target.SetData  ( ArrayNameToAttribIndex( GL_COLOR_ARRAY ), 30, 31, 32, 33, 34 );
-  EXPECT_CALL( mock, glEnableClientState( GL_COLOR_ARRAY ) );
-  EXPECT_CALL( mock, glBindBuffer( GL_ARRAY_BUFFER, 30 ) );
-  EXPECT_CALL( mock, glColorPointer     ( 31, 32, 33, reinterpret_cast<const GLvoid*>( 34 ) ) );
-
-  // The secondary color attribute array uses all the array state we have.
-  target.SetEnable( ArrayNameToAttribIndex( GL_SECONDARY_COLOR_ARRAY ), true );
-  target.SetData  ( ArrayNameToAttribIndex( GL_SECONDARY_COLOR_ARRAY ), 40, 41, 42, 43, 44 );
-  EXPECT_CALL( mock, glEnableClientState    ( GL_SECONDARY_COLOR_ARRAY ) );
-  EXPECT_CALL( mock, glBindBuffer( GL_ARRAY_BUFFER, 40 ) );
-  EXPECT_CALL( mock, glSecondaryColorPointer( 41, 42, 43, reinterpret_cast<const GLvoid*>( 44 ) ) );
-
-  // The index attribute array does not need the first size argument.
-  target.SetEnable( ArrayNameToAttribIndex( GL_INDEX_ARRAY ), true );
-  target.SetData  ( ArrayNameToAttribIndex( GL_INDEX_ARRAY ), 50, 51, 52, 53, 54 );
-  EXPECT_CALL( mock, glEnableClientState( GL_INDEX_ARRAY ) );
-  EXPECT_CALL( mock, glBindBuffer( GL_ARRAY_BUFFER, 50 ) );
-  EXPECT_CALL( mock, glIndexPointer     ( 52, 53, reinterpret_cast<const GLvoid*>( 54 ) ) );
-
-  // The edge flag attribute array does not need the size or the type
-  // arguments.
-  target.SetEnable( ArrayNameToAttribIndex( GL_EDGE_FLAG_ARRAY ), true );
-  target.SetData  ( ArrayNameToAttribIndex( GL_EDGE_FLAG_ARRAY ), 60, 61, 62, 63, 64 );
-  EXPECT_CALL( mock, glEnableClientState( GL_EDGE_FLAG_ARRAY ) );
-  EXPECT_CALL( mock, glBindBuffer( GL_ARRAY_BUFFER, 60 ) );
-  EXPECT_CALL( mock, glEdgeFlagPointer  ( 63, reinterpret_cast<const GLvoid*>( 64 ) ) );
-
-  // The fog coordiante attribute array does not need the size argument.
-  target.SetEnable( ArrayNameToAttribIndex( GL_FOG_COORD_ARRAY ), true );
-  target.SetData  ( ArrayNameToAttribIndex( GL_FOG_COORD_ARRAY ), 70, 71, 72, 73, 74 );
-  EXPECT_CALL( mock, glEnableClientState( GL_FOG_COORD_ARRAY ) );
-  EXPECT_CALL( mock, glBindBuffer( GL_ARRAY_BUFFER, 70 ) );
-  EXPECT_CALL( mock, glFogCoordPointer  ( 72, 73, reinterpret_cast<const GLvoid*>( 74 ) ) );
-
-  // There are multiple texture coordinate arrays, one for each texture unit.
-  // They use all the array state we have.
-  // They need a call to glClientActiveTexture to select the texture unit, if
-  // not already seleced.
-  // Note below we indicate that GL_TEXTURE0 is already selected, so there
-  // should be no call to select it again.
-  target.SetEnable( ArrayNameToAttribIndex( GL_TEXTURE_COORD_ARRAY, GL_TEXTURE0 ), true );
-  target.SetData  ( ArrayNameToAttribIndex( GL_TEXTURE_COORD_ARRAY, GL_TEXTURE0 ), 80, 81, 82, 83, 84 );
-  target.SetEnable( ArrayNameToAttribIndex( GL_TEXTURE_COORD_ARRAY, GL_TEXTURE5 ), true );
-  target.SetData  ( ArrayNameToAttribIndex( GL_TEXTURE_COORD_ARRAY, GL_TEXTURE5 ), 90, 91, 92, 93, 94 );
-  EXPECT_CALL( mock, glEnableClientState  ( GL_TEXTURE_COORD_ARRAY ) ).Times( 2 );
-  EXPECT_CALL( mock, glClientActiveTexture( GL_TEXTURE5 ) );
-  EXPECT_CALL( mock, glBindBuffer( GL_ARRAY_BUFFER, 80 ) );
-  EXPECT_CALL( mock, glTexCoordPointer    ( 81, 82, 83, reinterpret_cast<const GLvoid*>( 84 ) ) );
-  EXPECT_CALL( mock, glBindBuffer( GL_ARRAY_BUFFER, 90 ) );
-  EXPECT_CALL( mock, glTexCoordPointer    ( 91, 92, 93, reinterpret_cast<const GLvoid*>( 94 ) ) );
-
-  // Perform the requested transition
-  GLenum clientActiveTexture = GL_TEXTURE0;
-  GLuint arrayBufferBinding = 0;
-  Transition( cap, dt, current, target, clientActiveTexture, arrayBufferBinding );
-  // Verify that we've updated the shadowed selected texture unit as expected.
-  EXPECT_EQ( static_cast<GLenum>( GL_TEXTURE5 ), clientActiveTexture );
-  EXPECT_EQ( static_cast<GLuint>( 90 ), arrayBufferBinding );
-  // Verify the call expectations, and reset for another test.
-  Mock::VerifyAndClear( &mock );
-  target.Reset();
-  current.Reset();
-
-  // Verify state gets disabled/reset to default from non-default.
-  current.SetEnable( ArrayNameToAttribIndex( GL_VERTEX_ARRAY ), true );
-  current.SetData  ( ArrayNameToAttribIndex( GL_VERTEX_ARRAY ), 1, 2, 3, 4, 5 );
-  current.SetEnable( ArrayNameToAttribIndex( GL_TEXTURE_COORD_ARRAY, GL_TEXTURE1 ), true );
-  current.SetData  ( ArrayNameToAttribIndex( GL_TEXTURE_COORD_ARRAY, GL_TEXTURE1 ), 80, 81, 82, 83, 84 );
-  EXPECT_CALL( mock, glDisableClientState ( GL_VERTEX_ARRAY ) );
-  EXPECT_CALL( mock, glVertexPointer      ( 4, GL_FLOAT, 0, NULL ) );
-  EXPECT_CALL( mock, glClientActiveTexture( GL_TEXTURE1 ) );
-  EXPECT_CALL( mock, glDisableClientState ( GL_TEXTURE_COORD_ARRAY ) );
-  EXPECT_CALL( mock, glTexCoordPointer    ( 4, GL_FLOAT, 0, NULL ) );
-
-  // Enabling/Disabling an array is a distinct operation.
-  current.SetEnable( ArrayNameToAttribIndex( GL_NORMAL_ARRAY ), true );
-  EXPECT_CALL( mock, glDisableClientState( GL_NORMAL_ARRAY ) );
-
-  // Setting array data is a distinct operation
-  current.SetData  ( ArrayNameToAttribIndex( GL_COLOR_ARRAY ), 30, 31, 32, 33, 34 );
-  EXPECT_CALL( mock, glColorPointer     ( 4, GL_FLOAT, 0, NULL ) );
-
-  // Perform the requested transition
-  clientActiveTexture = GL_TEXTURE0;
-  arrayBufferBinding = 0;
-  Transition( cap, dt, current, target, clientActiveTexture, arrayBufferBinding );
-  // Verify that we've updated the shadowed selected texture unit as expected.
-  EXPECT_EQ( static_cast<GLenum>( GL_TEXTURE1 ), clientActiveTexture );
-  EXPECT_EQ( static_cast<GLuint>( 0 ), arrayBufferBinding );
-  // Verify the call expectations, and reset for another test.
-  Mock::VerifyAndClear( &mock );
-  target.Reset();
-  current.Reset();
-
-  // Identical state is a no-op in terms of calls.
-  current.SetEnable( ArrayNameToAttribIndex( GL_VERTEX_ARRAY ), true );
-  current.SetData  ( ArrayNameToAttribIndex( GL_VERTEX_ARRAY ), 1, 2, 3, 4, 5 );
-  target.SetEnable ( ArrayNameToAttribIndex( GL_VERTEX_ARRAY ), true );
-  target.SetData   ( ArrayNameToAttribIndex( GL_VERTEX_ARRAY ), 1, 2, 3, 4, 5 );
-
-  clientActiveTexture = GL_TEXTURE4;
-  arrayBufferBinding = 123;
-  Transition( cap, dt, current, target, clientActiveTexture, arrayBufferBinding );
-  // Verify that the shadowed selected texture unit is not updated.
-  EXPECT_EQ( static_cast<GLenum>( GL_TEXTURE4 ), clientActiveTexture );
-  EXPECT_EQ( static_cast<GLuint>( 123 ), arrayBufferBinding );
-  // Verify the call expectations, and reset for another test.
-  Mock::VerifyAndClear( &mock );
-  target.Reset();
-  current.Reset();
-
-  // If the driver does not support vertex buffer arrays without a bound array
-  // buffer, then our code should not make the call to set the vertex attribute
-  // array if the target state use a buffer of zero for that attribute.
-  cap.driverAllowsVertexAttributeArraysWithoutBoundBuffer = false;
-  target.SetData  ( ArrayNameToAttribIndex( GL_VERTEX_ARRAY ), 0, 12, 13, 14, 15 );
-  target.SetData  ( ArrayNameToAttribIndex( GL_TEXTURE_COORD_ARRAY, GL_TEXTURE1 ), 21, 22, 23, 24, 25 );
-  EXPECT_CALL( mock, glClientActiveTexture( GL_TEXTURE1 ) );
-  EXPECT_CALL( mock, glBindBuffer( GL_ARRAY_BUFFER, 21 ) );
-  EXPECT_CALL( mock, glTexCoordPointer    ( 22, 23, 24, reinterpret_cast<const void*>( 25 ) ) );
-
-  // Perform the requested transition
-  clientActiveTexture = GL_TEXTURE0;
-  arrayBufferBinding = 0;
-  Transition( cap, dt, current, target, clientActiveTexture, arrayBufferBinding );
-
-  // Verify the call expectations, and reset for another test.
-  Mock::VerifyAndClear( &mock );
-  target.Reset();
-  current.Reset();
-}
-
-// ====================================
-// ClientState::VertexArray::Generic::State
-// ====================================
-
-TEST( RegalClientStateVertexArrayGenericState, Sizes ) {
-  using namespace ClientState::VertexArray::Generic;
-  using ClientState::VertexArray::Generic::State;
-
-  ASSERT_EQ( COUNT_ATTRIBS, arraysize( static_cast<State *>( NULL )->attrib ) );
-  ASSERT_EQ( COUNT_BUFFERS, arraysize( static_cast<State *>( NULL )->buffer ) );
-}
-
-TEST( RegalClientStateVertexArrayGenericState, BasicOperations ) {
-  using namespace ClientState::VertexArray::Generic;
-  using ClientState::VertexArray::Generic::State;
-
-  State state;
-  state.Reset();
-
-  State other;
-  other.Reset();
-
-  // Enable a specific attribute array.
-  state.SetEnable( 4, true );
-
-  // Set unique data for the array source and binding for all attributes.
-  for ( size_t i = 0; i < COUNT_ATTRIBS; ++i ) {
-    state.SetAttribSource( i, i * 10 + 1, i * 10 + 2, i == 1, i == 2, i * 10 + 3 );
-    state.SetAttribBinding( i, ( i + 1 ) % COUNT_BUFFERS );
-  }
-
-  // Set unique data for the array buffers.
-  for ( size_t i = 0; i < COUNT_BUFFERS; ++i ) {
-    state.SetBuffer( i, 1000 + i * 10 + 1, 1000 + i * 10 + 2, 1000 + i * 10 + 3 );
-    state.SetBufferDivisor( i, 1000 + i * 10 + 4 );
-  }
-
-  // Calls with out-of-bound values should silently return as a no-op.
-  // This is done here so if we affect the explicitly set state it will be
-  // detected soon.
-  state.SetEnable( INVALID_INDEX, true );
-  state.SetEnable( COUNT_ATTRIBS, true );
-
-  state.SetAttribSource( INVALID_INDEX, 0xdead, 0xdead, false, false, 0xdead );
-  state.SetAttribSource( COUNT_ATTRIBS, 0xdead, 0xdead, false, false, 0xdead );
-
-  state.SetAttribBinding( INVALID_INDEX, 5 );
-  state.SetAttribBinding( COUNT_ATTRIBS, 5 );
-  state.SetAttribBinding( 0, INVALID_INDEX );
-  state.SetAttribBinding( 0, COUNT_BUFFERS );
-
-  state.SetBuffer( INVALID_INDEX, 0xdead, 0xdead, 0xdead );
-  state.SetBuffer( COUNT_BUFFERS, 0xdead, 0xdead, 0xdead );
-
-  state.SetBufferDivisor( INVALID_INDEX, 0xdead );
-  state.SetBufferDivisor( COUNT_BUFFERS, 0xdead );
-
-  // Peform a swap, so that it is effectively tested too.
-  swap( state, other );
-
-  // Verify the unique data that was set is in the swapped state.
-  for ( size_t i = 0; i < COUNT_ATTRIBS; ++i ) {
-    const State::Attrib& attrib = other.attrib[ i ];
-
-    if ( i == 4 ) {
-      EXPECT_TRUE( attrib.enabled );
-    } else {
-      EXPECT_FALSE( attrib.enabled );
-    }
-
-    EXPECT_EQ( static_cast<GLint> ( i * 10 + 1 ),  attrib.source.size );
-    EXPECT_EQ( static_cast<GLenum>( i * 10 + 2 ), attrib.source.type );
-    EXPECT_EQ( i * 10 + 3,  attrib.source.relativeOffset );
-
-    if ( i == 1 ) {
-      EXPECT_TRUE( attrib.source.normalized );
-    } else {
-      EXPECT_FALSE( attrib.source.normalized );
-    }
-
-    if ( i == 2 ) {
-      EXPECT_TRUE( attrib.source.pureInteger );
-    } else {
-      EXPECT_FALSE( attrib.source.pureInteger );
-    }
-
-    EXPECT_EQ( ( i + 1 ) % COUNT_BUFFERS, attrib.bindingIndex );
-  }
-
-  for ( size_t i = 0; i < COUNT_BUFFERS; ++i ) {
-    const State::Buffer& buffer = other.buffer[ i ];
-    EXPECT_EQ( 1000 + i * 10 + 1, buffer.buffer );
-    EXPECT_EQ( static_cast<GLint> ( 1000 + i * 10 + 2 ), buffer.offset );
-    EXPECT_EQ( static_cast<GLint> ( 1000 + i * 10 + 3 ), buffer.stride );
-    EXPECT_EQ( 1000 + i * 10 + 4, buffer.divisor );
-  }
-
-  // Verify the expected default state set previously ended up in the swapped
-  // state.
-  for ( size_t i = 0; i < COUNT_ATTRIBS; ++i ) {
-    const State::Attrib& attrib = state.attrib[ i ];
-
-    EXPECT_FALSE( attrib.enabled ) << "index " << i;
-
-    EXPECT_EQ( 4, attrib.source.size ) << "index " << i;
-    EXPECT_EQ( static_cast<GLenum>( GL_FLOAT ), attrib.source.type ) << "index " << i;
-    EXPECT_EQ( 0u, attrib.source.relativeOffset ) << "index " << i;
-    EXPECT_FALSE( attrib.source.normalized ) << "index " << i;
-    EXPECT_FALSE( attrib.source.pureInteger ) << "index " << i;
-
-    EXPECT_EQ( i, attrib.bindingIndex ) << "index " << i;
-  }
-
-  for ( size_t i = 0; i < COUNT_BUFFERS; ++i ) {
-    const State::Buffer& buffer = state.buffer[ i ];
-    EXPECT_EQ( 0u, buffer.buffer );
-    EXPECT_EQ( 0, buffer.offset );
-    EXPECT_EQ( 16, buffer.stride );
-    EXPECT_EQ( 0u, buffer.divisor );
-  }
-}
-
-TEST( RegalClientStateVertexArrayGenericState, Transition ) {
-  using ClientState::Capabilities;
-  using ClientState::VertexArray::Generic::State;
-  using ClientState::VertexArray::Generic::Transition;
-
-  RegalGMockInterface mock;
-
-  Capabilities cap;
-
-  DispatchTableGL dt;
-  ::memset(&dt,0,sizeof(DispatchTableGL));
-  dt._enabled = true;
-  InitDispatchTableGMock( dt );
-
-  State current;
-  current.Reset();
-
-  State target;
-  target.Reset();
-
-  // An attribute array can be enabled.
-  target.SetEnable ( 0, true );
-  EXPECT_CALL( mock, glEnableVertexAttribArray( 0 ) );
-
-  // An attribute array can be configured.
-  target.SetAttribSource( 1, 11, 12, false, false, 13 );
-  target.SetAttribSource( 2, 21, 22, true, false, 23 );
-  target.SetAttribSource( 3, 31, 32, false, true, 33 );
-  EXPECT_CALL( mock, glVertexAttribFormat ( 1, 11, 12, GL_FALSE, 13 ) );
-  EXPECT_CALL( mock, glVertexAttribFormat ( 2, 21, 22, GL_TRUE, 23 ) );
-  EXPECT_CALL( mock, glVertexAttribIFormat( 3, 31, 32, 33 ) );
-
-  // An attribute buffer can be configured.
-  target.SetBuffer( 4, 41, 42, 43 );
-  EXPECT_CALL( mock, glBindVertexBuffer( 4, 41, 42, 43 ) );
-
-  // An attribute buffer divisor can be configured.
-  target.SetBufferDivisor( 5, 51 );
-  EXPECT_CALL( mock, glVertexBindingDivisor( 5, 51 ) );
-
-  target.SetAttribBinding( 6, 7 );
-  EXPECT_CALL( mock, glVertexAttribBinding( 6, 7 ) );
-
-  // An attribute can be disabled and all data reset to default.
-  current.SetEnable       ( 8, true );
-  current.SetAttribSource ( 8, 61, 62, false, false, 63 );
-  current.SetBuffer       ( 8, 64, 65, 66 );
-  current.SetBufferDivisor( 8, 67 );
-  current.SetAttribBinding( 8, 9 );
-  EXPECT_CALL( mock, glDisableVertexAttribArray ( 8 ) );
-  EXPECT_CALL( mock, glVertexAttribFormat ( 8, 4, GL_FLOAT, GL_FALSE, 0 ) );
-  EXPECT_CALL( mock, glBindVertexBuffer( 8, 0, 0, 16 ) );
-  EXPECT_CALL( mock, glVertexBindingDivisor( 8, 0 ) );
-  EXPECT_CALL( mock, glVertexAttribBinding( 8, 8 ) );
-
-  // Perform the requested state transition.
-  Transition( cap, dt, current, target );
-  // Verify the call expectations, and reset for another test.
-  Mock::VerifyAndClear( &mock );
-  target.Reset();
-  current.Reset();
-
-  // Identical state is a no-op in terms of calls.
-  current.SetEnable       ( 0, true );
-  current.SetAttribSource ( 0, 11, 12, false, false, 13 );
-  current.SetBuffer       ( 0, 14, 15, 16 );
-  current.SetBufferDivisor( 0, 17 );
-  current.SetAttribBinding( 0, 1 );
-  target.SetEnable        ( 0, true );
-  target.SetAttribSource  ( 0, 11, 12, false, false, 13 );
-  target.SetBuffer        ( 0, 14, 15, 16 );
-  target.SetBufferDivisor ( 0, 17 );
-  target.SetAttribBinding ( 0, 1 );
-
-  // Perform the requested state transition.
-  Transition( cap, dt, current, target );
-}
-
-// ====================================
-// Regal::ClientState::VertexArray::State
-// ====================================
-
-TEST( RegalClientStateVertexArrayState, ResetAndSwap ) {
-  using ClientState::VertexArray::State;
-
-  State state;
-  state.Reset();
-
-  State other;
-  other.Reset();
-
-  state.clientActiveTexture = 1;
-  state.arrayBufferBinding = 2;
-  state.drawIndirectBufferBinding = 3;
-  state.vertexArrayBinding = 4;
-  state.primitiveRestartEnabled = true;
-  state.primitiveRestartFixedIndexEnabled = true;
-  state.primitiveRestartIndex = 5;
-  state.vertexArrayObjectZero.elementArrayBufferBinding = 6;
-
-  swap( state, other );
-
-  EXPECT_EQ( static_cast<GLenum>( GL_TEXTURE0 ), state.clientActiveTexture );
-  EXPECT_EQ( 0u, state.arrayBufferBinding );
-  EXPECT_EQ( 0u, state.drawIndirectBufferBinding );
-  EXPECT_EQ( 0u, state.vertexArrayBinding );
-  EXPECT_FALSE( state.primitiveRestartEnabled );
-  EXPECT_FALSE( state.primitiveRestartFixedIndexEnabled );
-  EXPECT_EQ( 0u, state.primitiveRestartIndex );
-  EXPECT_EQ( 0u, state.vertexArrayObjectZero.elementArrayBufferBinding );
-
-  EXPECT_EQ( 1u, other.clientActiveTexture );
-  EXPECT_EQ( 2u, other.arrayBufferBinding );
-  EXPECT_EQ( 3u, other.drawIndirectBufferBinding );
-  EXPECT_EQ( 4u, other.vertexArrayBinding );
-  EXPECT_TRUE( other.primitiveRestartEnabled );
-  EXPECT_TRUE( other.primitiveRestartFixedIndexEnabled );
-  EXPECT_EQ( 5u, other.primitiveRestartIndex );
-  EXPECT_EQ( 6u, other.vertexArrayObjectZero.elementArrayBufferBinding );
-}
-
-TEST( RegalClientStateVertexArrayState, GetVertexArrayObject ) {
-  using ClientState::VertexArray::State;
-
-  State state;
-  state.Reset();
-
-  EXPECT_EQ( &state.vertexArrayObjectZero, state.GetVertexArrayObject( 0 ) );
-  EXPECT_EQ( NULL, state.GetVertexArrayObject( 1 ) );
-
-  state.vertexArrayBinding = 0;
-  EXPECT_EQ( &state.vertexArrayObjectZero, state.GetVertexArrayObject() );
-  state.vertexArrayBinding = 1;
-  EXPECT_EQ( NULL, state.GetVertexArrayObject() );
-}
-
-TEST( RegalClientStateVertexArrayState, Transition ) {
-  using ClientState::Capabilities;
-  using ClientState::VertexArray::State;
-  using ClientState::VertexArray::Transition;
-
-  RegalGMockInterface mock;
-
-  Capabilities cap;
-
-  DispatchTableGL dt;
-  ::memset(&dt,0,sizeof(DispatchTableGL));
-  dt._enabled = true;
-  InitDispatchTableGMock( dt );
-
-  State current;
-  current.Reset();
-
-  State target;
-  target.Reset();
-
-  // Set up a simple non-default state, focusing on state unique this structure.
-  target.clientActiveTexture = 1;
-  target.arrayBufferBinding = 2;
-  target.drawIndirectBufferBinding = 3;
-  target.vertexArrayBinding = 4;
-  target.primitiveRestartEnabled = true;
-  target.primitiveRestartFixedIndexEnabled = true;
-  target.primitiveRestartIndex = 5;
-  target.vertexArrayObjectZero.elementArrayBufferBinding = 6;
-
-  // Set up expectations.
-  EXPECT_CALL( mock, glClientActiveTexture( 1 ) );
-  EXPECT_CALL( mock, glBindBuffer( GL_ARRAY_BUFFER, 2 ) );
-  EXPECT_CALL( mock, glBindBuffer( GL_DRAW_INDIRECT_BUFFER, 3 ) );
-  EXPECT_CALL( mock, glBindVertexArray( 4 ) );
-  EXPECT_CALL( mock, glEnable( GL_PRIMITIVE_RESTART ) );
-  EXPECT_CALL( mock, glEnable( GL_PRIMITIVE_RESTART_FIXED_INDEX ) );
-  EXPECT_CALL( mock, glPrimitiveRestartIndex( 5 ) );
-  EXPECT_CALL( mock, glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 6 ) );
-
-  // Perform the requested state transition.
-  Transition( cap, dt, current, target );
-  // Verify the call expectations, and reset for another test.
-  Mock::VerifyAndClear( &mock );
-
-  // Reverse the transition.
-  swap( current, target );
-
-  // Set up expectations.
-  EXPECT_CALL( mock, glClientActiveTexture( GL_TEXTURE0 ) );
-  EXPECT_CALL( mock, glBindBuffer( GL_ARRAY_BUFFER, 0 ) );
-  EXPECT_CALL( mock, glBindBuffer( GL_DRAW_INDIRECT_BUFFER, 0 ) );
-  EXPECT_CALL( mock, glBindVertexArray( 0 ) );
-  EXPECT_CALL( mock, glDisable( GL_PRIMITIVE_RESTART ) );
-  EXPECT_CALL( mock, glDisable( GL_PRIMITIVE_RESTART_FIXED_INDEX ) );
-  EXPECT_CALL( mock, glPrimitiveRestartIndex( 0 ) );
-  EXPECT_CALL( mock, glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 ) );
-
-  // Perform the requested state transition.
-  Transition( cap, dt, current, target );
-  // Verify the call expectations, and reset for another test.
-  Mock::VerifyAndClear( &mock );
-}
-
-// ====================================
-// Regal::Ppca
-// ====================================
-
-TEST ( RegalPpca, ClientPixelStoreStateShadowing ) {
-  using ClientState::PixelStore::PNameToIndex;
-
-  Ppca ppca;
-  ppca.Reset();
-
-  // The value stored should be rounded to the nearest integer.
-
-  ppca.ShadowPixelStore( GL_UNPACK_SKIP_PIXELS, 123 );
-  EXPECT_EQ( 123, ppca.pss.Get( GL_UNPACK_SKIP_PIXELS ) );
-
-  ppca.ShadowPixelStore( GL_UNPACK_SKIP_PIXELS, 123 );
-  EXPECT_EQ( 123, ppca.pss.Get( GL_UNPACK_SKIP_PIXELS ) );
-
-  ppca.ShadowPixelStore( GL_UNPACK_SKIP_PIXELS, 123.1f );
-  EXPECT_EQ( 123, ppca.pss.Get( GL_UNPACK_SKIP_PIXELS ) );
-
-  ppca.ShadowPixelStore( GL_UNPACK_SKIP_PIXELS, 123.5f );
-  EXPECT_EQ( 124, ppca.pss.Get( GL_UNPACK_SKIP_PIXELS ) );
-
-  ppca.ShadowPixelStore( GL_UNPACK_SKIP_PIXELS, 123.9f );
-  EXPECT_EQ( 124, ppca.pss.Get( GL_UNPACK_SKIP_PIXELS ) );
-
-  ppca.ShadowPixelStore( GL_UNPACK_SKIP_PIXELS, -123.1f );
-  EXPECT_EQ( -123, ppca.pss.Get( GL_UNPACK_SKIP_PIXELS ) );
-
-  ppca.ShadowPixelStore( GL_UNPACK_SKIP_PIXELS, -123.5f );
-  EXPECT_EQ( -123, ppca.pss.Get( GL_UNPACK_SKIP_PIXELS ) );
-
-  ppca.ShadowPixelStore( GL_UNPACK_SKIP_PIXELS, -123.9f );
-  EXPECT_EQ( -124, ppca.pss.Get( GL_UNPACK_SKIP_PIXELS ) );
-}
-
-TEST ( RegalPpca, ClientVertexArrayStateGenericShadowing ) {
-  using ClientState::VertexArray::Generic::State;
-
-  Ppca ppca;
-  ppca.Reset();
-
-  State& state = ppca.vas.vertexArrayObjectZero.generic;
-
-  // VertexAttribFormat
-
-  state.Reset();
-  ppca.ShadowVertexAttribFormat ( 3, 4, GL_FLOAT, GL_TRUE, 123 );
-
-  EXPECT_EQ   ( 4, state.attrib[ 3 ].source.size );
-  EXPECT_EQ   ( static_cast<GLenum>( GL_FLOAT ), state.attrib[ 3 ].source.type );
-  EXPECT_TRUE ( state.attrib[ 3 ].source.normalized );
-  EXPECT_FALSE( state.attrib[ 3 ].source.pureInteger );
-  EXPECT_EQ   ( 123u, state.attrib[ 3 ].source.relativeOffset );
-
-  state.Reset();
-  ppca.ShadowVertexAttribFormat ( 3, 4, GL_FLOAT, GL_FALSE, 123 );
-
-  EXPECT_FALSE ( state.attrib[ 3 ].source.normalized );
-
-  state.Reset();
-  ppca.ShadowVertexAttribIFormat( 3, 1, GL_INT, 456 );
-
-  EXPECT_EQ   ( 1, state.attrib[ 3 ].source.size );
-  EXPECT_EQ   ( static_cast<GLenum>( GL_INT ), state.attrib[ 3 ].source.type );
-  EXPECT_FALSE( state.attrib[ 3 ].source.normalized );
-  EXPECT_TRUE ( state.attrib[ 3 ].source.pureInteger );
-  EXPECT_EQ   ( 456u, state.attrib[ 3 ].source.relativeOffset );
-
-  state.Reset();
-  ppca.ShadowVertexAttribLFormat( 3, 2, GL_DOUBLE, 789 );
-
-  EXPECT_EQ   ( 2, state.attrib[ 3 ].source.size );
-  EXPECT_EQ   ( static_cast<GLenum>( GL_DOUBLE ), state.attrib[ 3 ].source.type );
-  EXPECT_FALSE( state.attrib[ 3 ].source.normalized );
-  EXPECT_FALSE( state.attrib[ 3 ].source.pureInteger );
-  EXPECT_EQ   ( 789u, state.attrib[ 3 ].source.relativeOffset );
-
-  // BindVertexBuffer
-
-  state.Reset();
-  ppca.ShadowBindVertexBuffer( 4, 5, 6, 7 );
-
-  EXPECT_EQ   ( 5u, state.buffer[ 4 ].buffer );
-  EXPECT_EQ   ( static_cast<GLintptr>( 6 ), state.buffer[ 4 ].offset );
-  EXPECT_EQ   ( 7, state.buffer[ 4 ].stride );
-  EXPECT_EQ   ( 0u, state.buffer[ 4 ].divisor );
-
-  // VertexAttribBinding
-
-  state.Reset();
-  ppca.ShadowVertexAttribBinding( 3, 4 );
-
-  EXPECT_EQ   ( 4u, state.attrib[ 3 ].bindingIndex );
-
-  // VertexAttribPointer
-
-  state.Reset();
-  ppca.vas.arrayBufferBinding = 8888;
-  ppca.ShadowVertexAttribPointer ( 3, 1, GL_FLOAT,  GL_TRUE, 123, reinterpret_cast<GLvoid *>( 321 ) );
-
-  EXPECT_EQ   ( 1, state.attrib[ 3 ].source.size );
-  EXPECT_EQ   ( static_cast<GLenum>( GL_FLOAT ), state.attrib[ 3 ].source.type );
-  EXPECT_TRUE ( state.attrib[ 3 ].source.normalized );
-  EXPECT_FALSE( state.attrib[ 3 ].source.pureInteger );
-  EXPECT_EQ   ( 0u, state.attrib[ 3 ].source.relativeOffset );
-  EXPECT_EQ   ( 3u, state.attrib[ 3 ].bindingIndex );
-  EXPECT_EQ   ( 8888u, state.buffer[ 3 ].buffer );
-  EXPECT_EQ   ( static_cast<GLintptr>( 321 ), state.buffer[ 3 ].offset );
-  EXPECT_EQ   ( 123, state.buffer[ 3 ].stride );
-
-  state.Reset();
-  ppca.ShadowVertexAttribPointer ( 3, 1, GL_FLOAT,  GL_FALSE, 0, reinterpret_cast<GLvoid *>( 321 ) );
-
-  EXPECT_FALSE( state.attrib[ 3 ].source.normalized );
-  EXPECT_EQ   ( 4, state.buffer[ 3 ].stride );
-
-  state.Reset();
-  ppca.ShadowVertexIAttribPointer( 3, 2, GL_INT,    456, reinterpret_cast<GLvoid *>( 654 ) );
-
-  EXPECT_EQ   ( 2, state.attrib[ 3 ].source.size );
-  EXPECT_EQ   ( static_cast<GLenum>( GL_INT ), state.attrib[ 3 ].source.type );
-  EXPECT_FALSE( state.attrib[ 3 ].source.normalized );
-  EXPECT_TRUE ( state.attrib[ 3 ].source.pureInteger );
-  EXPECT_EQ   ( 0u, state.attrib[ 3 ].source.relativeOffset );
-  EXPECT_EQ   ( 3u, state.attrib[ 3 ].bindingIndex );
-  EXPECT_EQ   ( 8888u, state.buffer[ 3 ].buffer );
-  EXPECT_EQ   ( static_cast<GLintptr>( 654 ), state.buffer[ 3 ].offset );
-  EXPECT_EQ   ( 456, state.buffer[ 3 ].stride );
-
-  state.Reset();
-  ppca.ShadowVertexIAttribPointer( 3, 2, GL_INT, 0, reinterpret_cast<GLvoid *>( 654 ) );
-
-  EXPECT_EQ   ( 8, state.buffer[ 3 ].stride );
-
-  state.Reset();
-  ppca.ShadowVertexLAttribPointer( 3, 3, GL_DOUBLE, 789, reinterpret_cast<GLvoid *>( 987 ) );
-
-  EXPECT_EQ   ( 3, state.attrib[ 3 ].source.size );
-  EXPECT_EQ   ( static_cast<GLenum>( GL_DOUBLE ), state.attrib[ 3 ].source.type );
-  EXPECT_FALSE( state.attrib[ 3 ].source.normalized );
-  EXPECT_FALSE( state.attrib[ 3 ].source.pureInteger );
-  EXPECT_EQ   ( 0u, state.attrib[ 3 ].source.relativeOffset );
-  EXPECT_EQ   ( 3u, state.attrib[ 3 ].bindingIndex );
-  EXPECT_EQ   ( 8888u, state.buffer[ 3 ].buffer );
-  EXPECT_EQ   ( static_cast<GLintptr>( 987 ) , state.buffer[ 3 ].offset );
-  EXPECT_EQ   ( 789, state.buffer[ 3 ].stride );
-
-  state.Reset();
-  ppca.ShadowVertexLAttribPointer( 3, 3, GL_DOUBLE, 0, reinterpret_cast<GLvoid *>( 987 ) );
-
-  EXPECT_EQ   ( 24, state.buffer[ 3 ].stride );
-
-  // Enable/DisableVertexAttribArray
-
-  state.Reset();
-  ppca.ShadowEnableVertexAttribArray( 3 );
-
-  EXPECT_TRUE( state.attrib [ 3 ].enabled );
-
-  ppca.ShadowDisableVertexAttribArray( 3 );
-
-  EXPECT_FALSE( state.attrib [ 3 ].enabled );
-
-  // VertexBindingDivisor
-
-  state.Reset();
-  ppca.ShadowVertexBindingDivisor( 4, 123 );
-
-  EXPECT_EQ( 123u, state.buffer[ 4 ].divisor );
-
-  // VertexAttribDivisor
-
-  state.Reset();
-  ppca.ShadowVertexAttribDivisor( 3, 456 );
-
-  EXPECT_EQ( 3u, state.attrib[ 3 ].bindingIndex );
-  EXPECT_EQ( 456u, state.buffer[ 3 ].divisor );
-
-  // ShadowVertexArrayVertexAttribOffsetDSA
-
-  state.Reset();
-  ppca.ShadowVertexArrayVertexAttribOffsetDSA( 0, 987, 3, 1, GL_FLOAT, GL_TRUE, 123, 321 );
-
-  EXPECT_EQ   ( 1, state.attrib[ 3 ].source.size );
-  EXPECT_EQ   ( static_cast<GLenum>( GL_FLOAT ), state.attrib[ 3 ].source.type );
-  EXPECT_TRUE ( state.attrib[ 3 ].source.normalized );
-  EXPECT_FALSE( state.attrib[ 3 ].source.pureInteger );
-  EXPECT_EQ   ( 0u, state.attrib[ 3 ].source.relativeOffset );
-  EXPECT_EQ   ( 3u, state.attrib[ 3 ].bindingIndex );
-  EXPECT_EQ   ( 987u, state.buffer[ 3 ].buffer );
-  EXPECT_EQ   ( static_cast<GLintptr>( 321 ), state.buffer[ 3 ].offset );
-  EXPECT_EQ   ( 123, state.buffer[ 3 ].stride );
-
-  state.Reset();
-  ppca.ShadowVertexArrayVertexAttribOffsetDSA( 0, 987, 3, 1, GL_FLOAT, GL_FALSE, 0, 321 );
-
-  EXPECT_FALSE ( state.attrib[ 3 ].source.normalized );
-  EXPECT_EQ   ( 4, state.buffer[ 3 ].stride );
-
-  state.Reset();
-  ppca.ShadowVertexArrayVertexAttribIOffsetDSA( 0, 987, 3, 2, GL_INT, 456, 654 );
-
-  EXPECT_EQ   ( 2, state.attrib[ 3 ].source.size );
-  EXPECT_EQ   ( static_cast<GLenum>( GL_INT ), state.attrib[ 3 ].source.type );
-  EXPECT_FALSE( state.attrib[ 3 ].source.normalized );
-  EXPECT_TRUE ( state.attrib[ 3 ].source.pureInteger );
-  EXPECT_EQ   ( 0u, state.attrib[ 3 ].source.relativeOffset );
-  EXPECT_EQ   ( 3u, state.attrib[ 3 ].bindingIndex );
-  EXPECT_EQ   ( 987u, state.buffer[ 3 ].buffer );
-  EXPECT_EQ   ( static_cast<GLintptr>( 654 ), state.buffer[ 3 ].offset );
-  EXPECT_EQ   ( 456, state.buffer[ 3 ].stride );
-
-  state.Reset();
-  ppca.ShadowVertexArrayVertexAttribIOffsetDSA( 0, 987, 3, 2, GL_INT, 0, 654 );
-
-  EXPECT_EQ   ( 8, state.buffer[ 3 ].stride );
-
-  // EnableDisableVertexArrayAttribDSA
-
-  state.Reset();
-  ppca.ShadowEnableVertexArrayAttribDSA( 0, 3 );
-
-  EXPECT_TRUE( state.attrib [ 3 ].enabled );
-
-  ppca.ShadowDisableVertexArrayAttribDSA( 0, 3 );
-
-  EXPECT_FALSE( state.attrib [ 3 ].enabled );
-
-
-
-  // If the vertex array binding is nonzero, none of these calls should do
-  // anything (since we do not actually track internal state for vertex array
-  // objects.
-  state.Reset();
-  state.attrib[ 3 ].source.relativeOffset = 123;
-  state.attrib[ 3 ].bindingIndex = 4;
-  state.buffer[ 4 ].buffer = 456;
-  state.buffer[ 4 ].divisor = 789;
-
-  ppca.vas.vertexArrayBinding = 1;
-
-  ppca.ShadowVertexAttribFormat ( 3, 3, GL_FLOAT, GL_TRUE, 0 );
-  ppca.ShadowVertexAttribIFormat( 3, 3, GL_INT, 0 );
-  ppca.ShadowVertexAttribLFormat( 3, 3, GL_DOUBLE, 0 );
-
-  ppca.ShadowBindVertexBuffer( 4, 0, 0, 0 );
-
-  ppca.ShadowVertexAttribBinding( 3, 0 );
-
-  ppca.ShadowVertexAttribPointer ( 3, 1, GL_FLOAT,  GL_TRUE, 0, NULL );
-  ppca.ShadowVertexIAttribPointer( 3, 2, GL_INT,    0, NULL );
-  ppca.ShadowVertexLAttribPointer( 3, 3, GL_DOUBLE, 0, NULL );
-
-  ppca.ShadowVertexBindingDivisor( 4, 0 );
-
-  ppca.ShadowVertexArrayVertexAttribOffsetDSA ( 1, 0, 3, 1, GL_FLOAT, GL_TRUE, 0, 0 );
-  ppca.ShadowVertexArrayVertexAttribIOffsetDSA( 1, 0, 3, 2, GL_INT, 0, 0 );
-
-  EXPECT_EQ   ( 123u, state.attrib[ 3 ].source.relativeOffset );
-  EXPECT_EQ   ( 4u,   state.attrib[ 3 ].bindingIndex );
-  EXPECT_EQ   ( 456u, state.buffer[ 4 ].buffer );
-  EXPECT_EQ   ( 789u, state.buffer[ 4 ].divisor );
-
-
-
-  state.attrib [ 3 ].enabled = false;
-  ppca.ShadowEnableVertexAttribArray( 3 );
-  ppca.ShadowEnableVertexArrayAttribDSA( 1, 3 );
-  EXPECT_FALSE( state.attrib [ 3 ].enabled );
-
-  state.attrib [ 3 ].enabled = true;
-  ppca.ShadowDisableVertexAttribArray( 3 );
-  ppca.ShadowDisableVertexArrayAttribDSA( 1, 3 );
-  EXPECT_TRUE( state.attrib [ 3 ].enabled );
-}
-
-TEST ( RegalPpca, ClientVertexArrayStateFFShadowing ) {
-  using namespace ClientState::VertexArray::Fixed;
-  using ClientState::VertexArray::Fixed::State;
-  using ClientState::VertexArray::Fixed::ArrayNameToAttribIndex;
-
-  Ppca ppca;
-  ppca.Reset();
-
-  const size_t colorAttribIndex          = ArrayNameToAttribIndex ( GL_COLOR_ARRAY );
-  const size_t edgeFlagAttribIndex       = ArrayNameToAttribIndex ( GL_EDGE_FLAG_ARRAY );
-  const size_t fogCoordAttribIndex       = ArrayNameToAttribIndex ( GL_FOG_COORD_ARRAY );
-  const size_t indexAttribIndex          = ArrayNameToAttribIndex ( GL_INDEX_ARRAY );
-  const size_t normalAttribIndex         = ArrayNameToAttribIndex ( GL_NORMAL_ARRAY );
-  const size_t secondaryColorAttribIndex = ArrayNameToAttribIndex ( GL_SECONDARY_COLOR_ARRAY );
-  const size_t vertexAttribIndex         = ArrayNameToAttribIndex ( GL_VERTEX_ARRAY );
-  const size_t texture0AttribIndex       = ArrayNameToAttribIndex ( GL_TEXTURE_COORD_ARRAY );
-
-  State& state = ppca.vas.vertexArrayObjectZero.fixed;
-
-  ppca.ShadowEnableClientState( GL_COLOR_ARRAY );
-  EXPECT_TRUE( state.attrib[ colorAttribIndex ].enabled );
-
-  ppca.ShadowDisableClientState( GL_COLOR_ARRAY );
-  EXPECT_FALSE( state.attrib[ colorAttribIndex ].enabled );
-
-  EXPECT_EQ( static_cast<GLenum>( GL_TEXTURE0 ), ppca.vas.clientActiveTexture );
-  ppca.ShadowClientActiveTexture( GL_TEXTURE2 );
-  EXPECT_EQ( static_cast<GLenum>( GL_TEXTURE2 ), ppca.vas.clientActiveTexture );
-
-  ppca.ShadowEnableClientState( GL_TEXTURE_COORD_ARRAY );
-  EXPECT_TRUE( state.attrib[ texture0AttribIndex + 2 ].enabled );
-
-  ppca.ShadowDisableClientState( GL_TEXTURE_COORD_ARRAY );
-  EXPECT_FALSE( state.attrib[ texture0AttribIndex + 2 ].enabled );
-
-  ppca.ShadowEnableVertexArrayDSA( 0, GL_TEXTURE_COORD_ARRAY );
-  EXPECT_TRUE( state.attrib[ texture0AttribIndex + 2 ].enabled );
-
-  ppca.ShadowDisableVertexArrayDSA( 0, GL_TEXTURE_COORD_ARRAY );
-  EXPECT_FALSE( state.attrib[ texture0AttribIndex + 2 ].enabled );
-
-  ppca.ShadowEnableVertexArrayDSA( 1, GL_TEXTURE_COORD_ARRAY );
-  EXPECT_FALSE( state.attrib[ texture0AttribIndex + 2 ].enabled );
-
-  ppca.ShadowDisableVertexArrayDSA( 1, GL_TEXTURE_COORD_ARRAY );
-  EXPECT_FALSE( state.attrib[ texture0AttribIndex + 2 ].enabled );
-
-  ppca.ShadowEnableClientStateIndexedDSA( GL_TEXTURE_COORD_ARRAY, 5 );
-  EXPECT_TRUE( state.attrib[ texture0AttribIndex + 5 ].enabled );
-
-  ppca.ShadowDisableClientStateIndexedDSA( GL_TEXTURE_COORD_ARRAY, 5 );
-  EXPECT_FALSE( state.attrib[ texture0AttribIndex + 5 ].enabled );
-
-  for ( size_t i = 0; i < COUNT_ATTRIBS; ++i ) {
-    state.attrib[ i ].source.buffer = 0;
-    state.attrib[ i ].source.size = 0;
-    state.attrib[ i ].source.type = 0;
-    state.attrib[ i ].source.stride = 0;
-  }
-
-  ppca.vas.arrayBufferBinding = 123;
-
-  ppca.ShadowVertexPointer( 4, GL_FLOAT, 1001, NULL );
-  EXPECT_EQ( 123u, state.attrib[ vertexAttribIndex ].source.buffer );
-  EXPECT_EQ( 4, state.attrib[ vertexAttribIndex ].source.size );
-  EXPECT_EQ( static_cast<GLenum>( GL_FLOAT ), state.attrib[ vertexAttribIndex ].source.type );
-  EXPECT_EQ( 1001, state.attrib[ vertexAttribIndex ].source.stride );
-
-  ppca.ShadowNormalPointer( GL_FLOAT, 1002, NULL );
-  EXPECT_EQ( 123u, state.attrib[ normalAttribIndex ].source.buffer );
-  EXPECT_EQ( 3, state.attrib[ normalAttribIndex ].source.size );
-  EXPECT_EQ( static_cast<GLenum>( GL_FLOAT ), state.attrib[ normalAttribIndex ].source.type );
-  EXPECT_EQ( 1002, state.attrib[ normalAttribIndex ].source.stride );
-
-  ppca.ShadowColorPointer( 4, GL_FLOAT, 1003, NULL );
-  EXPECT_EQ( 123u, state.attrib[ colorAttribIndex ].source.buffer );
-  EXPECT_EQ( 4, state.attrib[ colorAttribIndex ].source.size );
-  EXPECT_EQ( static_cast<GLenum>( GL_FLOAT ), state.attrib[ colorAttribIndex ].source.type );
-  EXPECT_EQ( 1003, state.attrib[ colorAttribIndex ].source.stride );
-
-  ppca.ShadowSecondaryColorPointer( 3, GL_FLOAT, 1004, NULL );
-  EXPECT_EQ( 123u, state.attrib[ secondaryColorAttribIndex ].source.buffer );
-  EXPECT_EQ( 3, state.attrib[ secondaryColorAttribIndex ].source.size );
-  EXPECT_EQ( static_cast<GLenum>( GL_FLOAT ), state.attrib[ secondaryColorAttribIndex ].source.type );
-  EXPECT_EQ( 1004, state.attrib[ secondaryColorAttribIndex ].source.stride );
-
-  ppca.ShadowIndexPointer( GL_INT, 1005, NULL );
-  EXPECT_EQ( 123u, state.attrib[ indexAttribIndex ].source.buffer );
-  EXPECT_EQ( 1, state.attrib[ indexAttribIndex ].source.size );
-  EXPECT_EQ( static_cast<GLenum>( GL_INT ), state.attrib[ indexAttribIndex ].source.type );
-  EXPECT_EQ( 1005, state.attrib[ indexAttribIndex ].source.stride );
-
-  ppca.ShadowEdgeFlagPointer( 1006, NULL );
-  EXPECT_EQ( 123u, state.attrib[ edgeFlagAttribIndex ].source.buffer );
-  EXPECT_EQ( 1, state.attrib[ edgeFlagAttribIndex ].source.size );
-  EXPECT_EQ( static_cast<GLenum>( GL_BOOL ), state.attrib[ edgeFlagAttribIndex ].source.type );
-  EXPECT_EQ( 1006, state.attrib[ edgeFlagAttribIndex ].source.stride );
-
-  ppca.ShadowFogCoordPointer( GL_FLOAT, 1007, NULL );
-  EXPECT_EQ( 123u, state.attrib[ fogCoordAttribIndex ].source.buffer );
-  EXPECT_EQ( 1, state.attrib[ fogCoordAttribIndex ].source.size );
-  EXPECT_EQ( static_cast<GLenum>( GL_FLOAT ), state.attrib[ fogCoordAttribIndex ].source.type );
-  EXPECT_EQ( 1007, state.attrib[ fogCoordAttribIndex ].source.stride );
-
-  ppca.ShadowTexCoordPointer( 2, GL_FLOAT, 1008, NULL );
-  EXPECT_EQ( 123u, state.attrib[ texture0AttribIndex + 2 ].source.buffer );
-  EXPECT_EQ( 2, state.attrib[ texture0AttribIndex + 2 ].source.size );
-  EXPECT_EQ( static_cast<GLenum>( GL_FLOAT ), state.attrib[ texture0AttribIndex + 2 ].source.type );
-  EXPECT_EQ( 1008, state.attrib[ texture0AttribIndex + 2 ].source.stride );
-
-
-
-  ppca.ShadowMultiTexCoordPointerDSA( GL_TEXTURE5, 2, GL_FLOAT, 2005, NULL );
-  EXPECT_EQ( 123u, state.attrib[ texture0AttribIndex + 5 ].source.buffer );
-  EXPECT_EQ( 2, state.attrib[ texture0AttribIndex + 5 ].source.size );
-  EXPECT_EQ( static_cast<GLenum>( GL_FLOAT ), state.attrib[ texture0AttribIndex + 5 ].source.type );
-  EXPECT_EQ( 2005, state.attrib[ texture0AttribIndex + 5 ].source.stride );
-
-
-
-  ppca.ShadowVertexArrayVertexOffsetDSA( 0, 3001, 3, GL_FLOAT, 3002, 0 );
-  EXPECT_EQ( 3001u, state.attrib[ vertexAttribIndex ].source.buffer );
-  EXPECT_EQ( 3, state.attrib[ vertexAttribIndex ].source.size );
-  EXPECT_EQ( static_cast<GLenum>( GL_FLOAT ), state.attrib[ vertexAttribIndex ].source.type );
-  EXPECT_EQ( 3002, state.attrib[ vertexAttribIndex ].source.stride );
-
-  ppca.ShadowVertexArrayColorOffsetDSA ( 0, 3003, 4, GL_FLOAT, 3004, 0 );
-  EXPECT_EQ( 3003u, state.attrib[ colorAttribIndex ].source.buffer );
-  EXPECT_EQ( 4, state.attrib[ colorAttribIndex ].source.size );
-  EXPECT_EQ( static_cast<GLenum>( GL_FLOAT ), state.attrib[ colorAttribIndex ].source.type );
-  EXPECT_EQ( 3004, state.attrib[ colorAttribIndex ].source.stride );
-
-  ppca.ShadowVertexArrayEdgeFlagOffsetDSA ( 0, 3005, 3006, 0 );
-  EXPECT_EQ( 3005u, state.attrib[ edgeFlagAttribIndex ].source.buffer );
-  EXPECT_EQ( 1, state.attrib[ edgeFlagAttribIndex ].source.size );
-  EXPECT_EQ( static_cast<GLenum>( GL_BOOL ), state.attrib[ edgeFlagAttribIndex ].source.type );
-  EXPECT_EQ( 3006, state.attrib[ edgeFlagAttribIndex ].source.stride );
-
-  ppca.ShadowVertexArrayIndexOffsetDSA ( 0, 3007, GL_INT, 3008, 0 );
-  EXPECT_EQ( 3007u, state.attrib[ indexAttribIndex ].source.buffer );
-  EXPECT_EQ( 1, state.attrib[ indexAttribIndex ].source.size );
-  EXPECT_EQ( static_cast<GLenum>( GL_INT ), state.attrib[ indexAttribIndex ].source.type );
-  EXPECT_EQ( 3008, state.attrib[ indexAttribIndex ].source.stride );
-
-  ppca.ShadowVertexArrayNormalOffsetDSA ( 0, 3009, GL_FLOAT, 3010, 0 );
-  EXPECT_EQ( 3009u, state.attrib[ normalAttribIndex ].source.buffer );
-  EXPECT_EQ( 3, state.attrib[ normalAttribIndex ].source.size );
-  EXPECT_EQ( static_cast<GLenum>( GL_FLOAT ), state.attrib[ normalAttribIndex ].source.type );
-  EXPECT_EQ( 3010, state.attrib[ normalAttribIndex ].source.stride );
-
-  ppca.ShadowVertexArrayTexCoordOffsetDSA( 0, 3011, 2, GL_FLOAT, 3012, 0 );
-  EXPECT_EQ( 3011u, state.attrib[ texture0AttribIndex + 2 ].source.buffer );
-  EXPECT_EQ( 2, state.attrib[ texture0AttribIndex + 2 ].source.size );
-  EXPECT_EQ( static_cast<GLenum>( GL_FLOAT ), state.attrib[ texture0AttribIndex + 2 ].source.type );
-  EXPECT_EQ( 3012, state.attrib[ texture0AttribIndex + 2 ].source.stride );
-
-  ppca.ShadowVertexArrayMultiTexCoordOffsetDSA( 0, 3013, GL_TEXTURE5, 2, GL_FLOAT, 3014, 0 );
-  EXPECT_EQ( 3013u, state.attrib[ texture0AttribIndex + 5 ].source.buffer );
-  EXPECT_EQ( 2, state.attrib[ texture0AttribIndex + 5 ].source.size );
-  EXPECT_EQ( static_cast<GLenum>( GL_FLOAT ), state.attrib[ texture0AttribIndex + 5 ].source.type );
-  EXPECT_EQ( 3014, state.attrib[ texture0AttribIndex + 5 ].source.stride );
-
-  ppca.ShadowVertexArrayFogCoordOffsetDSA ( 0, 3015, GL_FLOAT, 3016, 0 );
-  EXPECT_EQ( 3015u, state.attrib[ fogCoordAttribIndex ].source.buffer );
-  EXPECT_EQ( 1, state.attrib[ fogCoordAttribIndex ].source.size );
-  EXPECT_EQ( static_cast<GLenum>( GL_FLOAT ), state.attrib[ fogCoordAttribIndex ].source.type );
-  EXPECT_EQ( 3016, state.attrib[ fogCoordAttribIndex ].source.stride );
-
-  ppca.ShadowVertexArraySecondaryColorOffsetDSA ( 0, 3017, 3, GL_FLOAT, 3018, 0 );
-  EXPECT_EQ( 3017u, state.attrib[ secondaryColorAttribIndex ].source.buffer );
-  EXPECT_EQ( 3, state.attrib[ secondaryColorAttribIndex ].source.size );
-  EXPECT_EQ( static_cast<GLenum>( GL_FLOAT ), state.attrib[ secondaryColorAttribIndex ].source.type );
-  EXPECT_EQ( 3018, state.attrib[ secondaryColorAttribIndex ].source.stride );
-}
-
-TEST ( RegalPpca, ClientVertexArrayStatePrimitiveRestart ) {
-  Ppca ppca;
-  ppca.Reset();
-
-  EXPECT_FALSE( ppca.vas.primitiveRestartEnabled );
-  EXPECT_FALSE( ppca.vas.primitiveRestartFixedIndexEnabled );
-  EXPECT_EQ( 0u, ppca.vas.primitiveRestartIndex );
-
-  ppca.ShadowEnable( GL_PRIMITIVE_RESTART );
-  EXPECT_TRUE( ppca.vas.primitiveRestartEnabled );
-  ppca.ShadowDisable( GL_PRIMITIVE_RESTART );
-  EXPECT_FALSE( ppca.vas.primitiveRestartEnabled );
-
-  ppca.ShadowEnable( GL_PRIMITIVE_RESTART_FIXED_INDEX );
-  EXPECT_TRUE( ppca.vas.primitiveRestartFixedIndexEnabled );
-  ppca.ShadowDisable( GL_PRIMITIVE_RESTART_FIXED_INDEX );
-  EXPECT_FALSE( ppca.vas.primitiveRestartFixedIndexEnabled );
-
-  ppca.ShadowEnable( GL_TEXTURE_GEN_S );
-  EXPECT_FALSE( ppca.vas.primitiveRestartEnabled );
-  EXPECT_FALSE( ppca.vas.primitiveRestartFixedIndexEnabled );
-  ppca.ShadowDisable( GL_TEXTURE_GEN_S );
-
-  ppca.ShadowPrimitiveRestartIndex( ~0u );
-  EXPECT_EQ( ~0u, ppca.vas.primitiveRestartIndex );
-}
-
-TEST ( RegalPpca, ClientVertexArrayStateBindBuffer ) {
-  using ClientState::VertexArray::Generic::State;
-
-  Ppca ppca;
-  ppca.Reset();
-
-  ppca.ShadowBindBuffer( GL_ARRAY_BUFFER, 123 );
-  ppca.ShadowBindBuffer( GL_DRAW_INDIRECT_BUFFER, 456 );
-  ppca.ShadowBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 789 );
-  ppca.ShadowBindBuffer( GL_PIXEL_PACK_BUFFER_BINDING, 321 );
-  ppca.ShadowBindBuffer( GL_PIXEL_UNPACK_BUFFER_BINDING, 654 );
-
-  EXPECT_EQ( 123u, ppca.vas.arrayBufferBinding );
-  EXPECT_EQ( 456u, ppca.vas.drawIndirectBufferBinding );
-  EXPECT_EQ( 789u, ppca.vas.vertexArrayObjectZero.elementArrayBufferBinding );
-  EXPECT_EQ( 321u, ppca.pss.pixelPackBufferBinding );
-  EXPECT_EQ( 654u, ppca.pss.pixelUnpackBufferBinding );
-
-  ppca.Reset();
-  ppca.vas.vertexArrayBinding = 1;
-  ppca.ShadowBindBuffer( GL_ARRAY_BUFFER, 123 );
-  ppca.ShadowBindBuffer( GL_DRAW_INDIRECT_BUFFER, 456 );
-  ppca.ShadowBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 789 );
-  ppca.ShadowBindBuffer( GL_PIXEL_PACK_BUFFER_BINDING, 321 );
-  ppca.ShadowBindBuffer( GL_PIXEL_UNPACK_BUFFER_BINDING, 654 );
-
-  EXPECT_EQ( 123u, ppca.vas.arrayBufferBinding );
-  EXPECT_EQ( 456u, ppca.vas.drawIndirectBufferBinding );
-  EXPECT_EQ( 0u,   ppca.vas.vertexArrayObjectZero.elementArrayBufferBinding );
-  EXPECT_EQ( 321u, ppca.pss.pixelPackBufferBinding );
-  EXPECT_EQ( 654u, ppca.pss.pixelUnpackBufferBinding );
-}
-
-TEST ( RegalPpca, ClientVertexArrayStateInterleavedArrays ) {
-  using namespace ClientState::VertexArray::Fixed;
-  using ClientState::VertexArray::Fixed::State;
-  using ClientState::VertexArray::Fixed::ArrayNameToAttribIndex;
-
-  Ppca ppca;
-  ppca.Reset();
-
-  State& state = ppca.vas.vertexArrayObjectZero.fixed;
-
-  const size_t vertexAttribIndex         = ArrayNameToAttribIndex ( GL_VERTEX_ARRAY );
-  const size_t normalAttribIndex         = ArrayNameToAttribIndex ( GL_NORMAL_ARRAY );
-  const size_t colorAttribIndex          = ArrayNameToAttribIndex ( GL_COLOR_ARRAY );
-  const size_t texture0AttribIndex       = ArrayNameToAttribIndex ( GL_TEXTURE_COORD_ARRAY );
-
-  const size_t edgeFlagAttribIndex       = ArrayNameToAttribIndex ( GL_EDGE_FLAG_ARRAY );
-  const size_t fogCoordAttribIndex       = ArrayNameToAttribIndex ( GL_FOG_COORD_ARRAY );
-  const size_t indexAttribIndex          = ArrayNameToAttribIndex ( GL_INDEX_ARRAY );
-  const size_t secondaryColorAttribIndex = ArrayNameToAttribIndex ( GL_SECONDARY_COLOR_ARRAY );
-
-  // Do a comprehensive test on all settings for GL_T4F_C4F_N3F_V4F
-
-  state.Reset();
-  for ( size_t i = 0; i < COUNT_ATTRIBS; ++i ) {
-    state.attrib[ i ].enabled       = ( i & 1 ) == 0;
-    state.attrib[ i ].source.size   = 987;
-    state.attrib[ i ].source.type   = 987;
-    state.attrib[ i ].source.stride = 987;
-    state.attrib[ i ].source.offset = 987;
-  }
-
-  ppca.ShadowClientActiveTexture( GL_TEXTURE5 );
-  ppca.ShadowInterleavedArrays( GL_T4F_C4F_N3F_V4F, 0, NULL );
-  EXPECT_TRUE ( state.attrib[ vertexAttribIndex   ].enabled );
-  EXPECT_TRUE ( state.attrib[ normalAttribIndex   ].enabled );
-  EXPECT_TRUE ( state.attrib[ colorAttribIndex    ].enabled );
-  EXPECT_TRUE ( state.attrib[ texture0AttribIndex + 5 ].enabled );
-
-  EXPECT_EQ( 4,   state.attrib[ vertexAttribIndex ].source.size );
-  EXPECT_EQ( static_cast<GLenum>( GL_FLOAT ), state.attrib[ vertexAttribIndex ].source.type );
-  EXPECT_EQ( 60,  state.attrib[ vertexAttribIndex ].source.stride );
-  EXPECT_EQ( static_cast<GLintptr>( 44 ), state.attrib[ vertexAttribIndex ].source.offset );
-
-  EXPECT_EQ( 3,   state.attrib[ normalAttribIndex ].source.size );
-  EXPECT_EQ( static_cast<GLenum>( GL_FLOAT ), state.attrib[ normalAttribIndex ].source.type );
-  EXPECT_EQ( 60,  state.attrib[ normalAttribIndex ].source.stride );
-  EXPECT_EQ( static_cast<GLintptr>( 32 ), state.attrib[ normalAttribIndex ].source.offset );
-
-  EXPECT_EQ( 4,   state.attrib[ colorAttribIndex ].source.size );
-  EXPECT_EQ( static_cast<GLenum>( GL_FLOAT ), state.attrib[ colorAttribIndex ].source.type );
-  EXPECT_EQ( 60,  state.attrib[ colorAttribIndex ].source.stride );
-  EXPECT_EQ( static_cast<GLintptr>( 16 ), state.attrib[ colorAttribIndex ].source.offset );
-
-  EXPECT_EQ( 4,   state.attrib[ texture0AttribIndex + 5 ].source.size );
-  EXPECT_EQ( static_cast<GLenum>( GL_FLOAT ), state.attrib[ texture0AttribIndex + 5 ].source.type );
-  EXPECT_EQ( 60,  state.attrib[ texture0AttribIndex + 5 ].source.stride );
-  EXPECT_EQ( static_cast<GLintptr>( 0 ),  state.attrib[ texture0AttribIndex + 5 ].source.offset );
-
-  // The other non-texture coordinate arrays should be disabled
-
-  EXPECT_FALSE( state.attrib[ edgeFlagAttribIndex ].enabled );
-  EXPECT_FALSE( state.attrib[ fogCoordAttribIndex ].enabled );
-  EXPECT_FALSE( state.attrib[ indexAttribIndex ].enabled );
-  EXPECT_FALSE( state.attrib[ secondaryColorAttribIndex ].enabled );
-
-  // The other non-texture coordinate arrays should not otherwise be touched.
-
-  EXPECT_EQ( 987,  state.attrib[ edgeFlagAttribIndex ].source.size );
-  EXPECT_EQ( 987u, state.attrib[ edgeFlagAttribIndex ].source.type );
-  EXPECT_EQ( 987,  state.attrib[ edgeFlagAttribIndex ].source.stride );
-  EXPECT_EQ( static_cast<GLintptr>( 987 ), state.attrib[ edgeFlagAttribIndex ].source.offset );
-
-  EXPECT_EQ( 987,  state.attrib[ fogCoordAttribIndex ].source.size );
-  EXPECT_EQ( 987u, state.attrib[ fogCoordAttribIndex ].source.type );
-  EXPECT_EQ( 987,  state.attrib[ fogCoordAttribIndex ].source.stride );
-  EXPECT_EQ( static_cast<GLintptr>( 987 ), state.attrib[ fogCoordAttribIndex ].source.offset );
-
-  EXPECT_EQ( 987,  state.attrib[ indexAttribIndex ].source.size );
-  EXPECT_EQ( 987u, state.attrib[ indexAttribIndex ].source.type );
-  EXPECT_EQ( 987,  state.attrib[ indexAttribIndex ].source.stride );
-  EXPECT_EQ( static_cast<GLintptr>( 987 ), state.attrib[ indexAttribIndex ].source.offset );
-
-  EXPECT_EQ( 987,  state.attrib[ secondaryColorAttribIndex ].source.size );
-  EXPECT_EQ( 987u, state.attrib[ secondaryColorAttribIndex ].source.type );
-  EXPECT_EQ( 987,  state.attrib[ secondaryColorAttribIndex ].source.stride );
-  EXPECT_EQ( static_cast<GLintptr>( 987 ), state.attrib[ secondaryColorAttribIndex ].source.offset );
-
-  // Verify other texture coordinate settings unaffected.
-
-  for ( size_t i = 0; i < COUNT_TEXTURE_COORD_ATTRIBS; ++i ) {
-    if ( i == 5 ) continue;
-    State::Attrib& attrib = state.attrib[ BASE_TEXTURE_COORD_ATTRIBS + i ];
-    if ( ( ( BASE_TEXTURE_COORD_ATTRIBS + i ) & 1 ) == 0 ) {
-      EXPECT_TRUE( attrib.enabled ) << "Index " << i;
-    } else {
-      EXPECT_FALSE( attrib.enabled ) << "Index " << i;
-    }
-    EXPECT_EQ( 987,  attrib.source.size ) << "Index " << i;
-    EXPECT_EQ( 987u, attrib.source.type ) << "Index " << i;
-    EXPECT_EQ( 987,  attrib.source.stride ) << "Index " << i;
-    EXPECT_EQ( static_cast<GLintptr>( 987 ), attrib.source.offset ) << "Index " << i;
-  }
-
-  // Ensure if stride is nonzero, it is used as is, and ensure the pointer passed in is used as a base address.
-  state.Reset();
-  ppca.ShadowInterleavedArrays( GL_T4F_C4F_N3F_V4F, 321, reinterpret_cast<GLvoid *>( 5000 ) );
-
-  EXPECT_EQ( 321,   state.attrib[ vertexAttribIndex ].source.stride );
-  EXPECT_EQ( static_cast<GLintptr>( 5044 ), state.attrib[ vertexAttribIndex ].source.offset );
-  EXPECT_EQ( 321,   state.attrib[ normalAttribIndex ].source.stride );
-  EXPECT_EQ( static_cast<GLintptr>( 5032 ), state.attrib[ normalAttribIndex ].source.offset );
-  EXPECT_EQ( 321,   state.attrib[ colorAttribIndex ].source.stride );
-  EXPECT_EQ( static_cast<GLintptr>( 5016 ), state.attrib[ colorAttribIndex ].source.offset );
-  EXPECT_EQ( 321,   state.attrib[ texture0AttribIndex + 5 ].source.stride );
-  EXPECT_EQ( static_cast<GLintptr>( 5000 ), state.attrib[ texture0AttribIndex + 5 ].source.offset );
-
-  // Do a quick run through the remaining formats, and do some quick verifications.
-  ppca.Reset();
-
-  state.Reset();
-  ppca.ShadowInterleavedArrays( GL_V2F, 0, NULL );
-
-  EXPECT_TRUE ( state.attrib[ vertexAttribIndex   ].enabled );
-  EXPECT_FALSE( state.attrib[ normalAttribIndex   ].enabled );
-  EXPECT_FALSE( state.attrib[ colorAttribIndex    ].enabled );
-  EXPECT_FALSE( state.attrib[ texture0AttribIndex ].enabled );
-  EXPECT_EQ   ( 2,   state.attrib[ vertexAttribIndex   ].source.size );
-  EXPECT_EQ   ( 4,   state.attrib[ colorAttribIndex    ].source.size );
-  EXPECT_EQ   ( 4,   state.attrib[ texture0AttribIndex ].source.size );
-  EXPECT_EQ   ( static_cast<GLenum>( GL_FLOAT ), state.attrib[ colorAttribIndex    ].source.type );
-  EXPECT_EQ   ( 8,   state.attrib[ vertexAttribIndex   ].source.stride );
-  EXPECT_EQ   ( static_cast<GLintptr>( 0 ),  state.attrib[ vertexAttribIndex   ].source.offset );
-  EXPECT_EQ   ( static_cast<GLintptr>( 0 ),  state.attrib[ normalAttribIndex   ].source.offset );
-  EXPECT_EQ   ( static_cast<GLintptr>( 0 ),  state.attrib[ colorAttribIndex    ].source.offset );
-  EXPECT_EQ   ( static_cast<GLintptr>( 0 ),  state.attrib[ texture0AttribIndex ].source.offset );
-
-  state.Reset();
-  ppca.ShadowInterleavedArrays( GL_V3F, 0, NULL );
-
-  EXPECT_TRUE ( state.attrib[ vertexAttribIndex   ].enabled );
-  EXPECT_FALSE( state.attrib[ normalAttribIndex   ].enabled );
-  EXPECT_FALSE( state.attrib[ colorAttribIndex    ].enabled );
-  EXPECT_FALSE( state.attrib[ texture0AttribIndex ].enabled );
-  EXPECT_EQ   ( 3,   state.attrib[ vertexAttribIndex   ].source.size );
-  EXPECT_EQ   ( 4,   state.attrib[ colorAttribIndex    ].source.size );
-  EXPECT_EQ   ( 4,   state.attrib[ texture0AttribIndex ].source.size );
-  EXPECT_EQ   ( static_cast<GLenum>( GL_FLOAT ), state.attrib[ colorAttribIndex    ].source.type );
-  EXPECT_EQ   ( 12,  state.attrib[ vertexAttribIndex   ].source.stride );
-  EXPECT_EQ   ( static_cast<GLintptr>( 0 ),  state.attrib[ vertexAttribIndex   ].source.offset );
-  EXPECT_EQ   ( static_cast<GLintptr>( 0 ),  state.attrib[ normalAttribIndex   ].source.offset );
-  EXPECT_EQ   ( static_cast<GLintptr>( 0 ),  state.attrib[ colorAttribIndex    ].source.offset );
-  EXPECT_EQ   ( static_cast<GLintptr>( 0 ),  state.attrib[ texture0AttribIndex ].source.offset );
-
-  state.Reset();
-  ppca.ShadowInterleavedArrays( GL_C4UB_V2F, 0, NULL );
-
-  EXPECT_TRUE ( state.attrib[ vertexAttribIndex   ].enabled );
-  EXPECT_FALSE( state.attrib[ normalAttribIndex   ].enabled );
-  EXPECT_TRUE ( state.attrib[ colorAttribIndex    ].enabled );
-  EXPECT_FALSE( state.attrib[ texture0AttribIndex ].enabled );
-  EXPECT_EQ   ( 2,   state.attrib[ vertexAttribIndex   ].source.size );
-  EXPECT_EQ   ( 4,   state.attrib[ colorAttribIndex    ].source.size );
-  EXPECT_EQ   ( 4,   state.attrib[ texture0AttribIndex ].source.size );
-  EXPECT_EQ   ( static_cast<GLenum>( GL_UNSIGNED_BYTE ), state.attrib[ colorAttribIndex    ].source.type );
-  EXPECT_EQ   ( 12,  state.attrib[ vertexAttribIndex   ].source.stride );
-  EXPECT_EQ   ( static_cast<GLintptr>( 4 ),  state.attrib[ vertexAttribIndex   ].source.offset );
-  EXPECT_EQ   ( static_cast<GLintptr>( 0 ),  state.attrib[ normalAttribIndex   ].source.offset );
-  EXPECT_EQ   ( static_cast<GLintptr>( 0 ),  state.attrib[ colorAttribIndex    ].source.offset );
-  EXPECT_EQ   ( static_cast<GLintptr>( 0 ),  state.attrib[ texture0AttribIndex ].source.offset );
-
-  state.Reset();
-  ppca.ShadowInterleavedArrays( GL_C4UB_V3F, 0, NULL );
-
-  EXPECT_TRUE ( state.attrib[ vertexAttribIndex   ].enabled );
-  EXPECT_FALSE( state.attrib[ normalAttribIndex   ].enabled );
-  EXPECT_TRUE ( state.attrib[ colorAttribIndex    ].enabled );
-  EXPECT_FALSE( state.attrib[ texture0AttribIndex ].enabled );
-  EXPECT_EQ   ( 3,   state.attrib[ vertexAttribIndex   ].source.size );
-  EXPECT_EQ   ( 4,   state.attrib[ colorAttribIndex    ].source.size );
-  EXPECT_EQ   ( 4,   state.attrib[ texture0AttribIndex ].source.size );
-  EXPECT_EQ   ( static_cast<GLenum>( GL_UNSIGNED_BYTE ), state.attrib[ colorAttribIndex    ].source.type );
-  EXPECT_EQ   ( 16,  state.attrib[ vertexAttribIndex   ].source.stride );
-  EXPECT_EQ   ( static_cast<GLintptr>( 4 ),  state.attrib[ vertexAttribIndex   ].source.offset );
-  EXPECT_EQ   ( static_cast<GLintptr>( 0 ),  state.attrib[ normalAttribIndex   ].source.offset );
-  EXPECT_EQ   ( static_cast<GLintptr>( 0 ),  state.attrib[ colorAttribIndex    ].source.offset );
-  EXPECT_EQ   ( static_cast<GLintptr>( 0 ),  state.attrib[ texture0AttribIndex ].source.offset );
-
-  state.Reset();
-  ppca.ShadowInterleavedArrays( GL_C3F_V3F, 0, NULL );
-
-  EXPECT_TRUE ( state.attrib[ vertexAttribIndex   ].enabled );
-  EXPECT_FALSE( state.attrib[ normalAttribIndex   ].enabled );
-  EXPECT_TRUE( state.attrib[ colorAttribIndex    ].enabled );
-  EXPECT_FALSE( state.attrib[ texture0AttribIndex ].enabled );
-  EXPECT_EQ   ( 3,   state.attrib[ vertexAttribIndex   ].source.size );
-  EXPECT_EQ   ( 3,   state.attrib[ colorAttribIndex    ].source.size );
-  EXPECT_EQ   ( 4,   state.attrib[ texture0AttribIndex ].source.size );
-  EXPECT_EQ   ( static_cast<GLenum>( GL_FLOAT ), state.attrib[ colorAttribIndex    ].source.type );
-  EXPECT_EQ   ( 24,  state.attrib[ vertexAttribIndex   ].source.stride );
-  EXPECT_EQ   ( static_cast<GLintptr>( 12 ), state.attrib[ vertexAttribIndex   ].source.offset );
-  EXPECT_EQ   ( static_cast<GLintptr>( 0 ),  state.attrib[ normalAttribIndex   ].source.offset );
-  EXPECT_EQ   ( static_cast<GLintptr>( 0 ),  state.attrib[ colorAttribIndex    ].source.offset );
-  EXPECT_EQ   ( static_cast<GLintptr>( 0 ),  state.attrib[ texture0AttribIndex ].source.offset );
-
-  state.Reset();
-  ppca.ShadowInterleavedArrays( GL_N3F_V3F, 0, NULL );
-
-  EXPECT_TRUE ( state.attrib[ vertexAttribIndex   ].enabled );
-  EXPECT_TRUE ( state.attrib[ normalAttribIndex   ].enabled );
-  EXPECT_FALSE( state.attrib[ colorAttribIndex    ].enabled );
-  EXPECT_FALSE( state.attrib[ texture0AttribIndex ].enabled );
-  EXPECT_EQ   ( 3,   state.attrib[ vertexAttribIndex   ].source.size );
-  EXPECT_EQ   ( 4,   state.attrib[ colorAttribIndex    ].source.size );
-  EXPECT_EQ   ( 4,   state.attrib[ texture0AttribIndex ].source.size );
-  EXPECT_EQ   ( static_cast<GLenum>( GL_FLOAT ), state.attrib[ colorAttribIndex    ].source.type );
-  EXPECT_EQ   ( 24,  state.attrib[ vertexAttribIndex   ].source.stride );
-  EXPECT_EQ   ( static_cast<GLintptr>( 12 ), state.attrib[ vertexAttribIndex   ].source.offset );
-  EXPECT_EQ   ( static_cast<GLintptr>( 0 ),  state.attrib[ normalAttribIndex   ].source.offset );
-  EXPECT_EQ   ( static_cast<GLintptr>( 0 ),  state.attrib[ colorAttribIndex    ].source.offset );
-  EXPECT_EQ   ( static_cast<GLintptr>( 0 ),  state.attrib[ texture0AttribIndex ].source.offset );
-
-  state.Reset();
-  ppca.ShadowInterleavedArrays( GL_C4F_N3F_V3F, 0, NULL );
-
-  EXPECT_TRUE ( state.attrib[ vertexAttribIndex   ].enabled );
-  EXPECT_TRUE ( state.attrib[ normalAttribIndex   ].enabled );
-  EXPECT_TRUE ( state.attrib[ colorAttribIndex    ].enabled );
-  EXPECT_FALSE( state.attrib[ texture0AttribIndex ].enabled );
-  EXPECT_EQ   ( 3,   state.attrib[ vertexAttribIndex   ].source.size );
-  EXPECT_EQ   ( 4,   state.attrib[ colorAttribIndex    ].source.size );
-  EXPECT_EQ   ( 4,   state.attrib[ texture0AttribIndex ].source.size );
-  EXPECT_EQ   ( static_cast<GLenum>( GL_FLOAT ), state.attrib[ colorAttribIndex    ].source.type );
-  EXPECT_EQ   ( 40,  state.attrib[ vertexAttribIndex   ].source.stride );
-  EXPECT_EQ   ( static_cast<GLintptr>( 28 ), state.attrib[ vertexAttribIndex   ].source.offset );
-  EXPECT_EQ   ( static_cast<GLintptr>( 16 ), state.attrib[ normalAttribIndex   ].source.offset );
-  EXPECT_EQ   ( static_cast<GLintptr>( 0 ),  state.attrib[ colorAttribIndex    ].source.offset );
-  EXPECT_EQ   ( static_cast<GLintptr>( 0 ),  state.attrib[ texture0AttribIndex ].source.offset );
-
-  state.Reset();
-  ppca.ShadowInterleavedArrays( GL_T2F_V3F, 0, NULL );
-
-  EXPECT_TRUE ( state.attrib[ vertexAttribIndex   ].enabled );
-  EXPECT_FALSE( state.attrib[ normalAttribIndex   ].enabled );
-  EXPECT_FALSE( state.attrib[ colorAttribIndex    ].enabled );
-  EXPECT_TRUE( state.attrib[ texture0AttribIndex ].enabled );
-  EXPECT_EQ   ( 3,   state.attrib[ vertexAttribIndex   ].source.size );
-  EXPECT_EQ   ( 4,   state.attrib[ colorAttribIndex    ].source.size );
-  EXPECT_EQ   ( 2,   state.attrib[ texture0AttribIndex ].source.size );
-  EXPECT_EQ   ( static_cast<GLenum>( GL_FLOAT ), state.attrib[ colorAttribIndex    ].source.type );
-  EXPECT_EQ   ( 20,  state.attrib[ vertexAttribIndex   ].source.stride );
-  EXPECT_EQ   ( static_cast<GLintptr>( 8 ),  state.attrib[ vertexAttribIndex   ].source.offset );
-  EXPECT_EQ   ( static_cast<GLintptr>( 0 ),  state.attrib[ normalAttribIndex   ].source.offset );
-  EXPECT_EQ   ( static_cast<GLintptr>( 0 ),  state.attrib[ colorAttribIndex    ].source.offset );
-  EXPECT_EQ   ( static_cast<GLintptr>( 0 ),  state.attrib[ texture0AttribIndex ].source.offset );
-
-  state.Reset();
-  ppca.ShadowInterleavedArrays( GL_T4F_V4F, 0, NULL );
-
-  EXPECT_TRUE ( state.attrib[ vertexAttribIndex   ].enabled );
-  EXPECT_FALSE( state.attrib[ normalAttribIndex   ].enabled );
-  EXPECT_FALSE( state.attrib[ colorAttribIndex    ].enabled );
-  EXPECT_TRUE ( state.attrib[ texture0AttribIndex ].enabled );
-  EXPECT_EQ   ( 4,   state.attrib[ vertexAttribIndex   ].source.size );
-  EXPECT_EQ   ( 4,   state.attrib[ colorAttribIndex    ].source.size );
-  EXPECT_EQ   ( 4,   state.attrib[ texture0AttribIndex ].source.size );
-  EXPECT_EQ   ( static_cast<GLenum>( GL_FLOAT ), state.attrib[ colorAttribIndex    ].source.type );
-  EXPECT_EQ   ( 32,  state.attrib[ vertexAttribIndex   ].source.stride );
-  EXPECT_EQ   ( static_cast<GLintptr>( 16 ), state.attrib[ vertexAttribIndex   ].source.offset );
-  EXPECT_EQ   ( static_cast<GLintptr>( 0 ),  state.attrib[ normalAttribIndex   ].source.offset );
-  EXPECT_EQ   ( static_cast<GLintptr>( 0 ),  state.attrib[ colorAttribIndex    ].source.offset );
-  EXPECT_EQ   ( static_cast<GLintptr>( 0 ),  state.attrib[ texture0AttribIndex ].source.offset );
-
-  state.Reset();
-  ppca.ShadowInterleavedArrays( GL_T2F_C4UB_V3F, 0, NULL );
-
-  EXPECT_TRUE ( state.attrib[ vertexAttribIndex   ].enabled );
-  EXPECT_FALSE( state.attrib[ normalAttribIndex   ].enabled );
-  EXPECT_TRUE ( state.attrib[ colorAttribIndex    ].enabled );
-  EXPECT_TRUE ( state.attrib[ texture0AttribIndex ].enabled );
-  EXPECT_EQ   ( 3,   state.attrib[ vertexAttribIndex   ].source.size );
-  EXPECT_EQ   ( 4,   state.attrib[ colorAttribIndex    ].source.size );
-  EXPECT_EQ   ( 2,   state.attrib[ texture0AttribIndex ].source.size );
-  EXPECT_EQ   ( static_cast<GLenum>( GL_UNSIGNED_BYTE ), state.attrib[ colorAttribIndex    ].source.type );
-  EXPECT_EQ   ( 24,  state.attrib[ vertexAttribIndex   ].source.stride );
-  EXPECT_EQ   ( static_cast<GLintptr>( 12 ), state.attrib[ vertexAttribIndex   ].source.offset );
-  EXPECT_EQ   ( static_cast<GLintptr>( 0 ),  state.attrib[ normalAttribIndex   ].source.offset );
-  EXPECT_EQ   ( static_cast<GLintptr>( 8 ),  state.attrib[ colorAttribIndex    ].source.offset );
-  EXPECT_EQ   ( static_cast<GLintptr>( 0 ),  state.attrib[ texture0AttribIndex ].source.offset );
-
-  state.Reset();
-  ppca.ShadowInterleavedArrays( GL_T2F_C3F_V3F, 0, NULL );
-
-  EXPECT_TRUE ( state.attrib[ vertexAttribIndex   ].enabled );
-  EXPECT_FALSE( state.attrib[ normalAttribIndex   ].enabled );
-  EXPECT_TRUE ( state.attrib[ colorAttribIndex    ].enabled );
-  EXPECT_TRUE ( state.attrib[ texture0AttribIndex ].enabled );
-  EXPECT_EQ   ( 3,   state.attrib[ vertexAttribIndex   ].source.size );
-  EXPECT_EQ   ( 3,   state.attrib[ colorAttribIndex    ].source.size );
-  EXPECT_EQ   ( 2,   state.attrib[ texture0AttribIndex ].source.size );
-  EXPECT_EQ   ( static_cast<GLenum>( GL_FLOAT ), state.attrib[ colorAttribIndex    ].source.type );
-  EXPECT_EQ   ( 32,  state.attrib[ vertexAttribIndex   ].source.stride );
-  EXPECT_EQ   ( static_cast<GLintptr>( 20 ), state.attrib[ vertexAttribIndex   ].source.offset );
-  EXPECT_EQ   ( static_cast<GLintptr>( 0 ),  state.attrib[ normalAttribIndex   ].source.offset );
-  EXPECT_EQ   ( static_cast<GLintptr>( 8 ),  state.attrib[ colorAttribIndex    ].source.offset );
-  EXPECT_EQ   ( static_cast<GLintptr>( 0 ),  state.attrib[ texture0AttribIndex ].source.offset );
-
-  state.Reset();
-  ppca.ShadowInterleavedArrays( GL_T2F_N3F_V3F, 0, NULL );
-
-  EXPECT_TRUE ( state.attrib[ vertexAttribIndex   ].enabled );
-  EXPECT_TRUE ( state.attrib[ normalAttribIndex   ].enabled );
-  EXPECT_FALSE( state.attrib[ colorAttribIndex    ].enabled );
-  EXPECT_TRUE( state.attrib[ texture0AttribIndex ].enabled );
-  EXPECT_EQ   ( 3,   state.attrib[ vertexAttribIndex   ].source.size );
-  EXPECT_EQ   ( 4,   state.attrib[ colorAttribIndex    ].source.size );
-  EXPECT_EQ   ( 2,   state.attrib[ texture0AttribIndex ].source.size );
-  EXPECT_EQ   ( static_cast<GLenum>( GL_FLOAT ), state.attrib[ colorAttribIndex    ].source.type );
-  EXPECT_EQ   ( 32,  state.attrib[ vertexAttribIndex   ].source.stride );
-  EXPECT_EQ   ( static_cast<GLintptr>( 20 ), state.attrib[ vertexAttribIndex   ].source.offset );
-  EXPECT_EQ   ( static_cast<GLintptr>( 8 ),  state.attrib[ normalAttribIndex   ].source.offset );
-  EXPECT_EQ   ( static_cast<GLintptr>( 0 ),  state.attrib[ colorAttribIndex    ].source.offset );
-  EXPECT_EQ   ( static_cast<GLintptr>( 0 ),  state.attrib[ texture0AttribIndex ].source.offset );
-
-  state.Reset();
-  ppca.ShadowInterleavedArrays( GL_T2F_C4F_N3F_V3F, 0, NULL );
-
-  EXPECT_TRUE ( state.attrib[ vertexAttribIndex   ].enabled );
-  EXPECT_TRUE ( state.attrib[ normalAttribIndex   ].enabled );
-  EXPECT_TRUE ( state.attrib[ colorAttribIndex    ].enabled );
-  EXPECT_TRUE ( state.attrib[ texture0AttribIndex ].enabled );
-  EXPECT_EQ   ( 3,   state.attrib[ vertexAttribIndex   ].source.size );
-  EXPECT_EQ   ( 4,   state.attrib[ colorAttribIndex    ].source.size );
-  EXPECT_EQ   ( 2,   state.attrib[ texture0AttribIndex ].source.size );
-  EXPECT_EQ   ( static_cast<GLenum>( GL_FLOAT ), state.attrib[ colorAttribIndex    ].source.type );
-  EXPECT_EQ   ( 48,  state.attrib[ vertexAttribIndex   ].source.stride );
-  EXPECT_EQ   ( static_cast<GLintptr>( 36 ), state.attrib[ vertexAttribIndex   ].source.offset );
-  EXPECT_EQ   ( static_cast<GLintptr>( 24 ), state.attrib[ normalAttribIndex   ].source.offset );
-  EXPECT_EQ   ( static_cast<GLintptr>( 8 ),  state.attrib[ colorAttribIndex    ].source.offset );
-  EXPECT_EQ   ( static_cast<GLintptr>( 0 ),  state.attrib[ texture0AttribIndex ].source.offset );
-
-  // Pass in an unsupported "format", which should do nothing.
-
-  state.Reset();
-  for ( size_t i = 0; i < COUNT_ATTRIBS; ++i ) {
-    state.attrib[ i ].enabled       = ( i & 1 ) == 0;
-    state.attrib[ i ].source.size   = 987;
-    state.attrib[ i ].source.type   = 987;
-    state.attrib[ i ].source.stride = 987;
-    state.attrib[ i ].source.offset = 987;
-  }
-
-  ppca.ShadowInterleavedArrays( GL_RGBA, 0, NULL );
-
-  for ( size_t i = 0; i < COUNT_ATTRIBS; ++i ) {
-    if ( i == 5 ) continue;
-    State::Attrib& attrib = state.attrib[ i ];
-    if ( ( i & 1 ) == 0 ) {
-      EXPECT_TRUE( attrib.enabled ) << "Index " << i;
-    } else {
-      EXPECT_FALSE( attrib.enabled ) << "Index " << i;
-    }
-    EXPECT_EQ( 987,  attrib.source.size ) << "Index " << i;
-    EXPECT_EQ( 987u, attrib.source.type ) << "Index " << i;
-    EXPECT_EQ( 987,  attrib.source.stride ) << "Index " << i;
-    EXPECT_EQ( static_cast<GLintptr>( 987 ), attrib.source.offset ) << "Index " << i;
-  }
-}
-
-
-
-TEST ( RegalPpca, ShadowDeleteBuffers ) {
-  Ppca ppca;
-  ppca.Reset();
-
-  GLuint buffers[ 2 ] = { 0, 123 };
-
-  for ( size_t i = 0; i < ClientState::VertexArray::Generic::COUNT_BUFFERS; ++i ) {
-    ppca.vas.vertexArrayObjectZero.generic.buffer[ i ].buffer = 123;
-  }
-  ppca.vas.vertexArrayObjectZero.elementArrayBufferBinding = 123;
-  ppca.vas.arrayBufferBinding = 123;
-  ppca.vas.drawIndirectBufferBinding = 123;
-  ppca.pss.pixelPackBufferBinding = 123;
-  ppca.pss.pixelUnpackBufferBinding = 123;
-
-  ppca.ShadowDeleteBuffers( 2, buffers );
-
-  for ( size_t i = 0; i < ClientState::VertexArray::Generic::COUNT_BUFFERS; ++i ) {
-    EXPECT_EQ( 0u, ppca.vas.vertexArrayObjectZero.generic.buffer[ i ].buffer ) << "Index " << i;
-  }
-  EXPECT_EQ( 0u, ppca.vas.vertexArrayObjectZero.elementArrayBufferBinding );
-  EXPECT_EQ( 0u, ppca.vas.arrayBufferBinding );
-  EXPECT_EQ( 0u, ppca.vas.drawIndirectBufferBinding );
-  EXPECT_EQ( 0u, ppca.pss.pixelPackBufferBinding );
-  EXPECT_EQ( 0u, ppca.pss.pixelUnpackBufferBinding );
-
-  for ( size_t i = 0; i < ClientState::VertexArray::Generic::COUNT_BUFFERS; ++i ) {
-    ppca.vas.vertexArrayObjectZero.generic.buffer[ i ].buffer = 456;
-  }
-  ppca.vas.vertexArrayObjectZero.elementArrayBufferBinding = 456;
-  ppca.vas.arrayBufferBinding = 456;
-  ppca.vas.drawIndirectBufferBinding = 456;
-  ppca.pss.pixelPackBufferBinding = 456;
-  ppca.pss.pixelUnpackBufferBinding = 456;
-
-  ppca.ShadowDeleteBuffers( 2, buffers );
-
-  for ( size_t i = 0; i < ClientState::VertexArray::Generic::COUNT_BUFFERS; ++i ) {
-    EXPECT_EQ( 456u, ppca.vas.vertexArrayObjectZero.generic.buffer[ i ].buffer ) << "Index " << i;
-  }
-  EXPECT_EQ( 456u, ppca.vas.vertexArrayObjectZero.elementArrayBufferBinding );
-  EXPECT_EQ( 456u, ppca.vas.arrayBufferBinding );
-  EXPECT_EQ( 456u, ppca.vas.drawIndirectBufferBinding );
-  EXPECT_EQ( 456u, ppca.pss.pixelPackBufferBinding );
-  EXPECT_EQ( 456u, ppca.pss.pixelUnpackBufferBinding );
-}
-
-TEST ( RegalPpca, ShadowDeleteVertexArrays ) {
-  Ppca ppca;
-  ppca.Reset();
-
-  GLuint buffers[ 2 ] = { 0, 123 };
-
-  ppca.vas.vertexArrayBinding = 123;
-
-  ppca.ShadowDeleteVertexArrays( 2, buffers );
-
-  EXPECT_EQ( 0u, ppca.vas.vertexArrayBinding );
-
-  ppca.vas.vertexArrayBinding = 456;
-
-  ppca.ShadowDeleteVertexArrays( 2, buffers );
-
-  EXPECT_EQ( 456u, ppca.vas.vertexArrayBinding );
-}
-
-
-
-TEST ( RegalPpca, ClientAttribStackPixelState ) {
-  using ClientState::PixelStore::PNameToIndex;
-
-  RegalGMockInterface mock;
-
-  Ppca ppca;
-  ppca.Reset();
-
-  RegalContext ctx;
-  ctx.info = new ContextInfo();
-  InitDispatchTableGMock( ctx.dispatcher.emulation );
-
-  EXPECT_EQ( 4, ppca.pss.Get( GL_UNPACK_ALIGNMENT ) );
-  EXPECT_EQ( 0u, ppca.pixelStoreStateStack_.size() );
-
-  ppca.ShadowPixelStore( GL_UNPACK_ALIGNMENT, 100 );
-  ppca.PushClientAttrib( &ctx, 0 );
-
-  EXPECT_EQ( 100, ppca.pss.Get( GL_UNPACK_ALIGNMENT ) );
-  EXPECT_EQ( 0u, ppca.pixelStoreStateStack_.size() );
-
-  ppca.ShadowPixelStore( GL_UNPACK_ALIGNMENT, 101 );
-  ppca.PushClientAttrib( &ctx, GL_CLIENT_PIXEL_STORE_BIT );
-
-  EXPECT_EQ( 101, ppca.pss.Get( GL_UNPACK_ALIGNMENT ) );
-  EXPECT_EQ( 1u, ppca.pixelStoreStateStack_.size() );
-
-  EXPECT_CALL( mock, glPixelStorei( GL_UNPACK_ALIGNMENT, 4 ) );
-  ppca.ClientAttribDefaultDSA( &ctx, GL_CLIENT_PIXEL_STORE_BIT );
-  Mock::VerifyAndClear( &mock );
-
-  EXPECT_EQ( 4, ppca.pss.Get( GL_UNPACK_ALIGNMENT ) );
-  EXPECT_EQ( 1u, ppca.pixelStoreStateStack_.size() );
-
-  ppca.ShadowPixelStore( GL_UNPACK_ALIGNMENT, 102 );
-
-  EXPECT_CALL( mock, glPixelStorei( GL_UNPACK_ALIGNMENT, 4 ) );
-
-  ppca.PushClientAttribDefaultDSA( &ctx, GL_CLIENT_PIXEL_STORE_BIT );
-  Mock::VerifyAndClear( &mock );
-
-  EXPECT_EQ( 4, ppca.pss.Get( GL_UNPACK_ALIGNMENT ) );
-  EXPECT_EQ( 2u, ppca.pixelStoreStateStack_.size() );
-
-  EXPECT_CALL( mock, glPixelStorei( GL_UNPACK_ALIGNMENT, 102 ) );
-
-  ppca.PopClientAttrib( &ctx );
-  Mock::VerifyAndClear( &mock );
-
-  EXPECT_EQ( 102, ppca.pss.Get( GL_UNPACK_ALIGNMENT ) );
-  EXPECT_EQ( 1u, ppca.pixelStoreStateStack_.size() );
-
-  EXPECT_CALL( mock, glPixelStorei( GL_UNPACK_ALIGNMENT, 101 ) );
-
-  ppca.PopClientAttrib( &ctx );
-  Mock::VerifyAndClear( &mock );
-
-  EXPECT_EQ( 101, ppca.pss.Get( GL_UNPACK_ALIGNMENT ) );
-  EXPECT_EQ( 0u, ppca.pixelStoreStateStack_.size() );
-
-  ppca.PopClientAttrib( &ctx );
-  Mock::VerifyAndClear( &mock );
-
-  EXPECT_EQ( 101, ppca.pss.Get( GL_UNPACK_ALIGNMENT ) );
-  EXPECT_EQ( 0u, ppca.pixelStoreStateStack_.size() );
-
-  ppca.PopClientAttrib( &ctx );
-  Mock::VerifyAndClear( &mock );
-
-  EXPECT_EQ( 101, ppca.pss.Get( GL_UNPACK_ALIGNMENT ) );
-  EXPECT_EQ( 0u, ppca.pixelStoreStateStack_.size() );
-}
-
-TEST ( RegalPpca, ClientAttribStackVertexState ) {
-  using ClientState::VertexArray::Fixed::ArrayNameToAttribIndex;
-
-  RegalGMockInterface mock;
-
-  Ppca ppca;
-  ppca.Reset();
-
-  RegalContext ctx;
-  ctx.info = new ContextInfo();
-  InitDispatchTableGMock( ctx.dispatcher.emulation );
-
-  GLint& stride = ppca.vas.vertexArrayObjectZero.fixed.attrib [ ArrayNameToAttribIndex( GL_COLOR_ARRAY ) ].source.stride;
-
-  EXPECT_EQ( 0, stride );
-  EXPECT_EQ( 0u, ppca.vertexArrayStateStack_.size() );
-
-  ppca.ShadowColorPointer ( 4, GL_FLOAT, 100, NULL );
-  ppca.PushClientAttrib( &ctx, 0 );
-
-  EXPECT_EQ( 100, stride );
-  EXPECT_EQ( 0u, ppca.vertexArrayStateStack_.size() );
-
-  ppca.ShadowColorPointer ( 4, GL_FLOAT, 101, NULL );
-  ppca.PushClientAttrib( &ctx, GL_CLIENT_VERTEX_ARRAY_BIT );
-
-  EXPECT_EQ( 101, stride );
-  EXPECT_EQ( 1u, ppca.vertexArrayStateStack_.size() );
-
-  EXPECT_CALL( mock, glColorPointer( 4, GL_FLOAT, 0, NULL ) );
-  ppca.ClientAttribDefaultDSA( &ctx, GL_CLIENT_VERTEX_ARRAY_BIT );
-  Mock::VerifyAndClear( &mock );
-
-  EXPECT_EQ( 0, stride );
-  EXPECT_EQ( 1u, ppca.vertexArrayStateStack_.size() );
-
-  ppca.ShadowColorPointer ( 4, GL_FLOAT, 102, NULL );
-
-  EXPECT_CALL( mock, glColorPointer( 4, GL_FLOAT, 0, NULL ) );
-
-  ppca.PushClientAttribDefaultDSA( &ctx, GL_CLIENT_VERTEX_ARRAY_BIT );
-  Mock::VerifyAndClear( &mock );
-
-  EXPECT_EQ( 0, stride );
-  EXPECT_EQ( 2u, ppca.vertexArrayStateStack_.size() );
-
-  EXPECT_CALL( mock, glColorPointer( 4, GL_FLOAT, 102, NULL ) );
-
-  ppca.PopClientAttrib( &ctx );
-  Mock::VerifyAndClear( &mock );
-
-  EXPECT_EQ( 102, stride );
-  EXPECT_EQ( 1u, ppca.vertexArrayStateStack_.size() );
-
-  EXPECT_CALL( mock, glColorPointer( 4, GL_FLOAT, 101, NULL ) );
-
-  ppca.PopClientAttrib( &ctx );
-  Mock::VerifyAndClear( &mock );
-
-  EXPECT_EQ( 101, stride );
-  EXPECT_EQ( 0u, ppca.vertexArrayStateStack_.size() );
-
-  ppca.PopClientAttrib( &ctx );
-  Mock::VerifyAndClear( &mock );
-
-  EXPECT_EQ( 101, stride );
-  EXPECT_EQ( 0u, ppca.vertexArrayStateStack_.size() );
-
-  ppca.PopClientAttrib( &ctx );
-  Mock::VerifyAndClear( &mock );
-
-  EXPECT_EQ( 101, stride );
-  EXPECT_EQ( 0u, ppca.vertexArrayStateStack_.size() );
-}
-
-TEST ( RegalPpca, ClientAttribStackGeneral ) {
-  RegalGMockInterface mock;
-
-  Ppca ppca;
-  ppca.Reset();
-
   RegalContext ctx;
   ctx.info = new ContextInfo();
   ctx.info->core = false;
+  ctx.info->es1 = false;
   ctx.info->es2 = false;
   InitDispatchTableGMock( ctx.dispatcher.emulation );
 
+  Ppca ppca;
+  checkPpcaDefaults(ctx, ppca);
+
+  GLint maxClientAttribStackDepth = 0;
+  EXPECT_EQ( GLboolean( GL_TRUE ), ppca.glGetv( &ctx, GL_MAX_CLIENT_ATTRIB_STACK_DEPTH, &maxClientAttribStackDepth ) );
+  EXPECT_GE( maxClientAttribStackDepth, GLint(16) );
+
   const GLbitfield remainder = ~( GL_CLIENT_PIXEL_STORE_BIT | GL_CLIENT_VERTEX_ARRAY_BIT );
-
-  EXPECT_EQ( 0u, ppca.pixelStoreStateStack_.size() );
-  EXPECT_EQ( 0u, ppca.vertexArrayStateStack_.size() );
-
-  ppca.PushClientAttrib( &ctx, GL_CLIENT_PIXEL_STORE_BIT );
-
-  EXPECT_EQ( 1u, ppca.pixelStoreStateStack_.size() );
-  EXPECT_EQ( 0u, ppca.vertexArrayStateStack_.size() );
-
-  ppca.PushClientAttrib( &ctx, GL_CLIENT_VERTEX_ARRAY_BIT );
-
-  EXPECT_EQ( 1u, ppca.pixelStoreStateStack_.size() );
-  EXPECT_EQ( 1u, ppca.vertexArrayStateStack_.size() );
-
   EXPECT_CALL( mock, glPushClientAttrib( remainder ) );
 
-  ppca.PushClientAttrib( &ctx, GL_CLIENT_ALL_ATTRIB_BITS );
+  ppca.glPushClientAttrib( &ctx, GL_CLIENT_ALL_ATTRIB_BITS );
   Mock::VerifyAndClear( &mock );
 
-  EXPECT_EQ( 2u, ppca.pixelStoreStateStack_.size() );
-  EXPECT_EQ( 2u, ppca.vertexArrayStateStack_.size() );
+  GLint clientAttribStackDepth = 666;
+  EXPECT_EQ( GLboolean( GL_TRUE ), ppca.glGetv(&ctx, GL_CLIENT_ATTRIB_STACK_DEPTH, &clientAttribStackDepth));
+  EXPECT_EQ( GLint(1), clientAttribStackDepth );
 
-  EXPECT_CALL( mock, glClientAttribDefaultEXT( remainder ) );
+  EXPECT_EQ( std::vector<GLbitfield>::size_type(1),               ppca.maskStack.size() );
+  EXPECT_EQ( std::vector<ClientState::VertexArray>::size_type(1), ppca.vertexArrayStack.size() );
+  EXPECT_EQ( std::vector<ClientState::PixelStore>::size_type(1),  ppca.pixelStoreStack.size() );
 
-  ppca.ClientAttribDefaultDSA( &ctx, GL_CLIENT_ALL_ATTRIB_BITS );
-  Mock::VerifyAndClear( &mock );
-
-  EXPECT_EQ( 2u, ppca.pixelStoreStateStack_.size() );
-  EXPECT_EQ( 2u, ppca.vertexArrayStateStack_.size() );
-
-  EXPECT_CALL( mock, glClientAttribDefaultEXT( remainder ) );
-  EXPECT_CALL( mock, glPushClientAttrib( remainder ) );
-
-  ppca.PushClientAttribDefaultDSA( &ctx, GL_CLIENT_ALL_ATTRIB_BITS );
-  Mock::VerifyAndClear( &mock );
-
-  EXPECT_EQ( 3u, ppca.pixelStoreStateStack_.size() );
-  EXPECT_EQ( 3u, ppca.vertexArrayStateStack_.size() );
-
-  ctx.info->es2 = true;
-  ppca.PushClientAttrib( &ctx, GL_CLIENT_ALL_ATTRIB_BITS );
-  ppca.PopClientAttrib( &ctx );
-  ctx.info->es2 = false;
-  Mock::VerifyAndClear( &mock );
-
-  EXPECT_CALL( mock, glPopClientAttrib() );
-
-  ppca.PopClientAttrib( &ctx );
-  Mock::VerifyAndClear( &mock );
-
-  EXPECT_EQ( 2u, ppca.pixelStoreStateStack_.size() );
-  EXPECT_EQ( 2u, ppca.vertexArrayStateStack_.size() );
-
-  EXPECT_CALL( mock, glPopClientAttrib() );
-
-  ppca.PopClientAttrib( &ctx );
-  Mock::VerifyAndClear( &mock );
-
-  EXPECT_EQ( 1u, ppca.pixelStoreStateStack_.size() );
-  EXPECT_EQ( 1u, ppca.vertexArrayStateStack_.size() );
-
-  ppca.PopClientAttrib( &ctx );
-  Mock::VerifyAndClear( &mock );
-
-  EXPECT_EQ( 1u, ppca.pixelStoreStateStack_.size() );
-  EXPECT_EQ( 0u, ppca.vertexArrayStateStack_.size() );
-
-  ppca.PopClientAttrib( &ctx );
-  Mock::VerifyAndClear( &mock );
-
-  EXPECT_EQ( 0u, ppca.pixelStoreStateStack_.size() );
-  EXPECT_EQ( 0u, ppca.vertexArrayStateStack_.size() );
-
-  ppca.PopClientAttrib( &ctx );
-  Mock::VerifyAndClear( &mock );
-
-  EXPECT_EQ( 0u, ppca.pixelStoreStateStack_.size() );
-  EXPECT_EQ( 0u, ppca.vertexArrayStateStack_.size() );
+  ppca.Reset(ctx);
+  checkPpcaDefaults(ctx, ppca);
 }
 
-TEST ( RegalPpca, Get ) {
+TEST ( RegalPpca, VertexArray_Defaults )
+{
+  RegalContext ctx;
+  ctx.info = new ContextInfo();
+
   Ppca ppca;
-  ppca.Reset();
+  checkPpcaDefaults(ctx, ppca);
+
+  ppca.VertexArray::elementArrayBufferBinding = GLuint(6);
+  ppca.VertexArray::clientActiveTexture = GLenum(6);
+  ppca.VertexArray::primitiveRestartFixedIndex = GLboolean(GL_TRUE);
+  ppca.VertexArray::primitiveRestart = GLboolean(GL_TRUE);
+  ppca.VertexArray::primitiveRestartIndex = GLuint(6);
+  ppca.VertexArray::arrayBufferBinding = GLuint(6);
+  ppca.VertexArray::vertexArrayBinding = GLuint(6);
+
+  for (GLuint ii=0; ii<ClientState::nNamedArrays; ii++)
+  {
+    ppca.VertexArray::named[ii].enabled = GLboolean(GL_TRUE);
+    ppca.VertexArray::named[ii].pointer = reinterpret_cast<const GLvoid*>(77);
+    ppca.VertexArray::named[ii].buffer  = GLuint(77);
+    ppca.VertexArray::named[ii].size    = GLint(77);
+    ppca.VertexArray::named[ii].type    = GLenum(77);
+    ppca.VertexArray::named[ii].stride  = GLuint(77);
+  }
+
+  for (GLuint ii=0; ii<REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS; ii++)
+  {
+    ppca.VertexArray::bindings[ii].buffer  = GLuint(888);
+    ppca.VertexArray::bindings[ii].offset  = GLintptr(888);
+    ppca.VertexArray::bindings[ii].stride  = GLsizei(888);
+    ppca.VertexArray::bindings[ii].divisor = GLuint(888);
+  }
+
+  for (GLuint ii=0; ii<REGAL_EMU_MAX_VERTEX_ATTRIBS; ii++)
+  {
+    ppca.VertexArray::generic[ii].enabled        = GLboolean(9999);
+    ppca.VertexArray::generic[ii].size           = GLuint(9999);
+    ppca.VertexArray::generic[ii].type           = GLenum(9999);
+    ppca.VertexArray::generic[ii].relativeOffset = GLuint(9999);
+    ppca.VertexArray::generic[ii].normalized     = GLboolean(9999);
+    ppca.VertexArray::generic[ii].isInteger      = GLboolean(9999);
+    ppca.VertexArray::generic[ii].isLong         = GLboolean(9999);
+    ppca.VertexArray::generic[ii].bindingIndex   = GLuint(9999);
+  }
+
+  ppca.Reset(ctx);
+  checkPpcaDefaults(ctx, ppca);
+}
+
+TEST ( RegalPpca, PixelStore_Defaults )
+{
+  RegalContext ctx;
+  ctx.info = new ContextInfo();
+
+  Ppca ppca;
+  checkPpcaDefaults(ctx, ppca);
+
+  ppca.PixelStore::unpackSwapBytes = GL_TRUE;
+  ppca.PixelStore::unpackLsbFirst = GL_TRUE;
+  ppca.PixelStore::unpackImageHeight = 1;
+  ppca.PixelStore::unpackSkipImages = 2;
+  ppca.PixelStore::unpackRowLength = 3;
+  ppca.PixelStore::unpackSkipRows = 4;
+  ppca.PixelStore::unpackSkipPixels = 5;
+  ppca.PixelStore::unpackAlignment = 6;
+  ppca.PixelStore::packSwapBytes = GL_TRUE;
+  ppca.PixelStore::packLsbFirst = GL_TRUE;
+  ppca.PixelStore::packImageHeight = 7;
+  ppca.PixelStore::packSkipImages = 8;
+  ppca.PixelStore::packRowLength = 9;
+  ppca.PixelStore::packSkipRows = 10;
+  ppca.PixelStore::packSkipPixels = 11;
+  ppca.PixelStore::packAlignment = 12;
+  ppca.PixelStore::pixelUnpackBufferBinding = 13;
+  ppca.PixelStore::pixelPackBufferBinding = 14;
+
+  ppca.Reset(ctx);
+  checkPpcaDefaults(ctx, ppca);
+}
+
+TEST ( RegalPpca, VertexArray_Swap )
+{
+  RegalContext ctx;
+  ctx.info = new ContextInfo();
+
+  Ppca state;
+  checkPpcaDefaults(ctx, state);
+
+  state.VertexArray::elementArrayBufferBinding = GLuint(1);
+  state.VertexArray::clientActiveTexture = GLenum(2);
+  state.VertexArray::primitiveRestartFixedIndex = GLboolean(GL_TRUE);
+  state.VertexArray::primitiveRestart = GLboolean(GL_TRUE);
+  state.VertexArray::primitiveRestartIndex = GLuint(3);
+  state.VertexArray::arrayBufferBinding = GLuint(4);
+  state.VertexArray::vertexArrayBinding = GLuint(5);
+
+  for (GLuint ii=0; ii<ClientState::nNamedArrays; ii++)
+  {
+    state.VertexArray::named[ii].enabled = GLboolean(GL_TRUE);
+    state.VertexArray::named[ii].pointer = reinterpret_cast<const GLvoid*>(77);
+    state.VertexArray::named[ii].buffer  = GLuint(77);
+    state.VertexArray::named[ii].size    = GLint(77);
+    state.VertexArray::named[ii].type    = GLenum(77);
+    state.VertexArray::named[ii].stride  = GLuint(77);
+  }
+
+  for (GLuint ii=0; ii<REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS; ii++)
+  {
+    state.VertexArray::bindings[ii].buffer  = GLuint(888);
+    state.VertexArray::bindings[ii].offset  = GLintptr(888);
+    state.VertexArray::bindings[ii].stride  = GLsizei(888);
+    state.VertexArray::bindings[ii].divisor = GLuint(888);
+  }
+
+  for (GLuint ii=0; ii<REGAL_EMU_MAX_VERTEX_ATTRIBS; ii++)
+  {
+    state.VertexArray::generic[ii].enabled        = GLboolean(9999);
+    state.VertexArray::generic[ii].size           = GLuint(9999);
+    state.VertexArray::generic[ii].type           = GLenum(9999);
+    state.VertexArray::generic[ii].relativeOffset = GLuint(9999);
+    state.VertexArray::generic[ii].normalized     = GLboolean(9999);
+    state.VertexArray::generic[ii].isInteger      = GLboolean(9999);
+    state.VertexArray::generic[ii].isLong         = GLboolean(9999);
+    state.VertexArray::generic[ii].bindingIndex   = GLuint(9999);
+  }
+
+  Ppca other;
+  checkPpcaDefaults(ctx, other);
+
+  other.VertexArray::swap( state );
+
+  checkPpcaDefaults(ctx, state);
+
+  EXPECT_EQ( GLuint( 1 ),        other.VertexArray::elementArrayBufferBinding );
+  EXPECT_EQ( GLenum( 2 ),        other.VertexArray::clientActiveTexture );
+  EXPECT_EQ( GLboolean(GL_TRUE), other.VertexArray::primitiveRestartFixedIndex );
+  EXPECT_EQ( GLboolean(GL_TRUE), other.VertexArray::primitiveRestart );
+  EXPECT_EQ( GLuint(3),          other.VertexArray::primitiveRestartIndex );
+  EXPECT_EQ( GLuint(4),          other.VertexArray::arrayBufferBinding );
+  EXPECT_EQ( GLuint(5),          other.VertexArray::vertexArrayBinding );
+
+  for (GLuint ii=0; ii<ClientState::nNamedArrays; ii++)
+  {
+    EXPECT_EQ( GLboolean(GL_TRUE), other.VertexArray::named[ii].enabled );
+    EXPECT_EQ( reinterpret_cast<const GLvoid*>(77), other.VertexArray::named[ii].pointer );
+    EXPECT_EQ( GLuint(77),         other.VertexArray::named[ii].buffer );
+    EXPECT_EQ( GLint(77),          other.VertexArray::named[ii].size );
+    EXPECT_EQ( GLenum(77),         other.VertexArray::named[ii].type );
+    EXPECT_EQ( GLuint(77),         other.VertexArray::named[ii].stride );
+  }
+
+  for (GLuint ii=0; ii<REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS; ii++)
+  {
+    EXPECT_EQ( GLuint(888),   other.VertexArray::bindings[ii].buffer );
+    EXPECT_EQ( GLintptr(888), other.VertexArray::bindings[ii].offset );
+    EXPECT_EQ( GLsizei(888),  other.VertexArray::bindings[ii].stride );
+    EXPECT_EQ( GLuint(888),   other.VertexArray::bindings[ii].divisor );
+  }
+
+  for (GLuint ii=0; ii<REGAL_EMU_MAX_VERTEX_ATTRIBS; ii++)
+  {
+    EXPECT_EQ( GLboolean(9999), other.VertexArray::generic[ii].enabled );
+    EXPECT_EQ( GLuint(9999),    other.VertexArray::generic[ii].size );
+    EXPECT_EQ( GLenum(9999),    other.VertexArray::generic[ii].type );
+    EXPECT_EQ( GLuint(9999),    other.VertexArray::generic[ii].relativeOffset );
+    EXPECT_EQ( GLboolean(9999), other.VertexArray::generic[ii].normalized );
+    EXPECT_EQ( GLboolean(9999), other.VertexArray::generic[ii].isInteger );
+    EXPECT_EQ( GLboolean(9999), other.VertexArray::generic[ii].isLong );
+    EXPECT_EQ( GLuint(9999),    other.VertexArray::generic[ii].bindingIndex );
+  }
+}
+
+TEST ( RegalPpca, PixelStore_Swap )
+{
+  RegalContext ctx;
+  ctx.info = new ContextInfo();
+
+  Ppca state;
+  checkPpcaDefaults(ctx, state);
+
+  Ppca other;
+  checkPpcaDefaults(ctx, other);
+
+  // Set each attribute in other to a unique value
+
+  other.PixelStore::unpackSwapBytes = GL_TRUE;
+  other.PixelStore::unpackLsbFirst = GL_TRUE;
+  other.PixelStore::unpackImageHeight = 11;
+  other.PixelStore::unpackSkipImages = 12;
+  other.PixelStore::unpackRowLength = 13;
+  other.PixelStore::unpackSkipRows = 14;
+  other.PixelStore::unpackSkipPixels = 15;
+  other.PixelStore::unpackAlignment = 16;
+  other.PixelStore::packSwapBytes = GL_TRUE;
+  other.PixelStore::packLsbFirst = GL_TRUE;
+  other.PixelStore::packImageHeight = 27;
+  other.PixelStore::packSkipImages = 28;
+  other.PixelStore::packRowLength = 29;
+  other.PixelStore::packSkipRows = 30;
+  other.PixelStore::packSkipPixels = 31;
+  other.PixelStore::packAlignment = 32;
+  other.PixelStore::pixelUnpackBufferBinding = 123;
+  other.PixelStore::pixelPackBufferBinding = 456;
+
+  // Peform a swap then check these values are now in state
+
+  other.PixelStore::swap( state );
+
+  EXPECT_EQ( GLboolean(GL_TRUE), state.PixelStore::unpackSwapBytes );
+  EXPECT_EQ( GLboolean(GL_TRUE), state.PixelStore::unpackLsbFirst );
+  EXPECT_EQ( GLint(11),          state.PixelStore::unpackImageHeight );
+  EXPECT_EQ( GLint(12),          state.PixelStore::unpackSkipImages );
+  EXPECT_EQ( GLint(13),          state.PixelStore::unpackRowLength );
+  EXPECT_EQ( GLint(14),          state.PixelStore::unpackSkipRows );
+  EXPECT_EQ( GLint(15),          state.PixelStore::unpackSkipPixels );
+  EXPECT_EQ( GLint(16),          state.PixelStore::unpackAlignment );
+  EXPECT_EQ( GLboolean(GL_TRUE), state.PixelStore::packSwapBytes );
+  EXPECT_EQ( GLboolean(GL_TRUE), state.PixelStore::packLsbFirst );
+  EXPECT_EQ( GLint(27),          state.PixelStore::packImageHeight );
+  EXPECT_EQ( GLint(28),          state.PixelStore::packSkipImages );
+  EXPECT_EQ( GLint(29),          state.PixelStore::packRowLength );
+  EXPECT_EQ( GLint(30),          state.PixelStore::packSkipRows );
+  EXPECT_EQ( GLint(31),          state.PixelStore::packSkipPixels );
+  EXPECT_EQ( GLint(32),          state.PixelStore::packAlignment );
+  EXPECT_EQ( GLuint(123),        state.PixelStore::pixelUnpackBufferBinding );
+  EXPECT_EQ( GLuint(456),        state.PixelStore::pixelPackBufferBinding );
+
+  // Verify other contains all default values from state
+
+  checkPixelStoreDefaults(other);
+}
+
+TEST ( RegalPpca, PixelStore_PushPop )
+{
+  RegalGMockInterface mock;
 
   RegalContext ctx;
   ctx.info = new ContextInfo();
+  InitDispatchTableGMock( ctx.dispatcher.emulation );
+
+  Ppca ppca;
+  checkPpcaDefaults(ctx, ppca);
+
+  EXPECT_EQ( GLint(4), ppca.PixelStore::unpackAlignment );
+  EXPECT_EQ( std::vector<ClientState::PixelStore>::size_type(0),  ppca.pixelStoreStack.size() );
+
+  ppca.glPixelStore( GL_UNPACK_ALIGNMENT, 100 );
+  ppca.glPushClientAttrib( &ctx, 0 );
+
+  EXPECT_EQ( GLint(100), ppca.PixelStore::unpackAlignment );
+  EXPECT_EQ( std::vector<ClientState::PixelStore>::size_type(0),  ppca.pixelStoreStack.size() );
+
+  ppca.glPixelStore( GL_UNPACK_ALIGNMENT, 101 );
+  ppca.glPushClientAttrib( &ctx, GL_CLIENT_PIXEL_STORE_BIT );
+
+  EXPECT_EQ( GLint(101), ppca.PixelStore::unpackAlignment );
+  EXPECT_EQ( std::vector<ClientState::PixelStore>::size_type(1),  ppca.pixelStoreStack.size() );
+
+  EXPECT_CALL( mock, glBindBuffer(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glBindVertexArray(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glBindVertexBuffer(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glClientActiveTexture(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glColorPointer(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glDisableClientState(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glDisableClientStateiEXT(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glDisableVertexAttribArray(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glEdgeFlagPointer(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glEnableClientState(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glEnableVertexAttribArray(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glFogCoordPointer(_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glIndexPointer(_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glMultiTexCoordPointerEXT(_,_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glNormalPointer(_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glPixelStorei(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glPrimitiveRestartIndex(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glSecondaryColorPointer(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexAttribBinding(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexAttribFormat(_,_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexAttribIFormat(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexAttribLFormat(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexBindingDivisor(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexPointer(_,_,_,_) ).Times(AnyNumber());
+
+  ppca.glClientAttribDefaultEXT( &ctx, GL_CLIENT_PIXEL_STORE_BIT );
+
+  Mock::VerifyAndClear( &mock );
+
+  EXPECT_EQ( GLint(4), ppca.PixelStore::unpackAlignment );
+  EXPECT_EQ( std::vector<ClientState::PixelStore>::size_type(1), ppca.pixelStoreStack.size() );
+
+  ppca.glPixelStore( GL_UNPACK_ALIGNMENT, 102 );
+
+  EXPECT_EQ( GLint(102), ppca.PixelStore::unpackAlignment );
+
+  EXPECT_CALL( mock, glBindBuffer(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glBindVertexArray(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glBindVertexBuffer(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glClientActiveTexture(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glColorPointer(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glDisableClientState(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glDisableClientStateiEXT(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glDisableVertexAttribArray(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glEdgeFlagPointer(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glEnableClientState(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glEnableVertexAttribArray(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glFogCoordPointer(_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glIndexPointer(_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glMultiTexCoordPointerEXT(_,_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glNormalPointer(_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glPixelStorei(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glPrimitiveRestartIndex(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glSecondaryColorPointer(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexAttribBinding(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexAttribFormat(_,_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexAttribIFormat(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexAttribLFormat(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexBindingDivisor(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexPointer(_,_,_,_) ).Times(AnyNumber());
+
+  ppca.glPushClientAttribDefaultEXT( &ctx, GL_CLIENT_PIXEL_STORE_BIT );
+
+  Mock::VerifyAndClear( &mock );
+
+  EXPECT_EQ( GLint(4), ppca.PixelStore::unpackAlignment );
+  EXPECT_EQ( std::vector<ClientState::PixelStore>::size_type(2),  ppca.pixelStoreStack.size() );
+
+  EXPECT_CALL( mock, glBindBuffer(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glBindVertexArray(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glBindVertexBuffer(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glClientActiveTexture(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glColorPointer(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glDisableClientState(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glDisableClientStateiEXT(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glDisableVertexAttribArray(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glEdgeFlagPointer(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glEnableClientState(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glEnableVertexAttribArray(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glFogCoordPointer(_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glIndexPointer(_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glMultiTexCoordPointerEXT(_,_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glNormalPointer(_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glPixelStorei(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glPrimitiveRestartIndex(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glSecondaryColorPointer(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexAttribBinding(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexAttribFormat(_,_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexAttribIFormat(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexAttribLFormat(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexBindingDivisor(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexPointer(_,_,_,_) ).Times(AnyNumber());
+
+  ppca.glPopClientAttrib( &ctx );
+
+  Mock::VerifyAndClear( &mock );
+
+  EXPECT_EQ( GLint(102), ppca.PixelStore::unpackAlignment );
+  EXPECT_EQ( std::vector<ClientState::PixelStore>::size_type(1),  ppca.pixelStoreStack.size() );
+
+  EXPECT_CALL( mock, glBindBuffer(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glBindVertexArray(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glBindVertexBuffer(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glClientActiveTexture(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glColorPointer(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glDisableClientState(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glDisableClientStateiEXT(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glDisableVertexAttribArray(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glEdgeFlagPointer(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glEnableClientState(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glEnableVertexAttribArray(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glFogCoordPointer(_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glIndexPointer(_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glMultiTexCoordPointerEXT(_,_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glNormalPointer(_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glPixelStorei(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glPrimitiveRestartIndex(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glSecondaryColorPointer(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexAttribBinding(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexAttribFormat(_,_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexAttribIFormat(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexAttribLFormat(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexBindingDivisor(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexPointer(_,_,_,_) ).Times(AnyNumber());
+
+  ppca.glPopClientAttrib( &ctx );
+
+  Mock::VerifyAndClear( &mock );
+
+  EXPECT_EQ( GLint(101), ppca.PixelStore::unpackAlignment );
+  EXPECT_EQ( std::vector<ClientState::PixelStore>::size_type(0),  ppca.pixelStoreStack.size() );
+
+  EXPECT_CALL( mock, glBindBuffer(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glBindVertexArray(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glBindVertexBuffer(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glClientActiveTexture(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glColorPointer(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glDisableClientState(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glDisableClientStateiEXT(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glDisableVertexAttribArray(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glEdgeFlagPointer(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glEnableClientState(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glEnableVertexAttribArray(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glFogCoordPointer(_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glIndexPointer(_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glMultiTexCoordPointerEXT(_,_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glNormalPointer(_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glPixelStorei(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glPrimitiveRestartIndex(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glSecondaryColorPointer(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexAttribBinding(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexAttribFormat(_,_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexAttribIFormat(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexAttribLFormat(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexBindingDivisor(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexPointer(_,_,_,_) ).Times(AnyNumber());
+
+  ppca.glPopClientAttrib( &ctx );
+
+  Mock::VerifyAndClear( &mock );
+
+  EXPECT_EQ( GLint(101), ppca.PixelStore::unpackAlignment );
+  EXPECT_EQ( std::vector<ClientState::PixelStore>::size_type(0),  ppca.pixelStoreStack.size() );
+
+  EXPECT_CALL( mock, glBindBuffer(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glBindVertexArray(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glBindVertexBuffer(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glClientActiveTexture(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glColorPointer(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glDisableClientState(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glDisableClientStateiEXT(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glDisableVertexAttribArray(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glEdgeFlagPointer(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glEnableClientState(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glEnableVertexAttribArray(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glFogCoordPointer(_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glIndexPointer(_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glMultiTexCoordPointerEXT(_,_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glNormalPointer(_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glPixelStorei(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glPrimitiveRestartIndex(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glSecondaryColorPointer(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexAttribBinding(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexAttribFormat(_,_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexAttribIFormat(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexAttribLFormat(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexBindingDivisor(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexPointer(_,_,_,_) ).Times(AnyNumber());
+
+  ppca.glPopClientAttrib( &ctx );
+  Mock::VerifyAndClear( &mock );
+
+  EXPECT_EQ( GLint(101), ppca.PixelStore::unpackAlignment );
+  EXPECT_EQ( std::vector<ClientState::PixelStore>::size_type(0),  ppca.pixelStoreStack.size() );
+}
+
+TEST ( RegalPpca, VertexArray_PushPop )
+{
+  RegalGMockInterface mock;
+
+  RegalContext ctx;
+  ctx.info = new ContextInfo();
+  ctx.info = new ContextInfo();
+  InitDispatchTableGMock( ctx.dispatcher.emulation );
+
+  Ppca ppca;
+  checkPpcaDefaults(ctx, ppca);
+
+  EXPECT_EQ( GLint( 0 ), ppca.VertexArray::named[ ClientState::COLOR ].stride );
+  EXPECT_EQ( std::vector<ClientState::VertexArray>::size_type(0), ppca.vertexArrayStack.size() );
+
+  ppca.glColorPointer ( 4, GL_FLOAT, 100, NULL );
+  ppca.glPushClientAttrib( &ctx, 0 );
+
+  EXPECT_EQ( GLint( 100 ), ppca.VertexArray::named[ ClientState::COLOR ].stride );
+  EXPECT_EQ( std::vector<ClientState::VertexArray>::size_type(0), ppca.vertexArrayStack.size() );
+
+  ppca.glColorPointer ( 4, GL_FLOAT, 101, NULL );
+  ppca.glPushClientAttrib( &ctx, GL_CLIENT_VERTEX_ARRAY_BIT );
+
+  EXPECT_EQ( GLint( 101 ), ppca.VertexArray::named[ ClientState::COLOR ].stride );
+  EXPECT_EQ( std::vector<ClientState::VertexArray>::size_type(1), ppca.vertexArrayStack.size() );
+
+  EXPECT_CALL( mock, glBindBuffer(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glBindVertexArray(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glBindVertexBuffer(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glClientActiveTexture(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glColorPointer(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glDisable(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glDisableClientState(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glDisableClientStateiEXT(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glDisableVertexAttribArray(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glEdgeFlagPointer(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glEnable(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glEnableClientState(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glEnableVertexAttribArray(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glFogCoordPointer(_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glIndexPointer(_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glMultiTexCoordPointerEXT(_,_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glNormalPointer(_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glPixelStorei(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glPrimitiveRestartIndex(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glSecondaryColorPointer(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexAttribBinding(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexAttribFormat(_,_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexAttribIFormat(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexAttribLFormat(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexBindingDivisor(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexPointer(_,_,_,_) ).Times(AnyNumber());
+
+  ppca.glClientAttribDefaultEXT( &ctx, GL_CLIENT_VERTEX_ARRAY_BIT );
+
+  Mock::VerifyAndClear( &mock );
+
+  EXPECT_EQ( GLint( 0 ), ppca.VertexArray::named[ ClientState::COLOR ].stride );
+  EXPECT_EQ( std::vector<ClientState::VertexArray>::size_type(1), ppca.vertexArrayStack.size() );
+
+  ppca.glColorPointer ( 4, GL_FLOAT, 102, NULL );
+
+  EXPECT_CALL( mock, glBindBuffer(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glBindVertexArray(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glBindVertexBuffer(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glClientActiveTexture(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glColorPointer(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glDisable(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glDisableClientState(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glDisableClientStateiEXT(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glDisableVertexAttribArray(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glEdgeFlagPointer(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glEnable(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glEnableClientState(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glEnableVertexAttribArray(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glFogCoordPointer(_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glIndexPointer(_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glMultiTexCoordPointerEXT(_,_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glNormalPointer(_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glPixelStorei(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glPrimitiveRestartIndex(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glSecondaryColorPointer(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexAttribBinding(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexAttribFormat(_,_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexAttribIFormat(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexAttribLFormat(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexBindingDivisor(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexPointer(_,_,_,_) ).Times(AnyNumber());
+
+  ppca.glPushClientAttribDefaultEXT( &ctx, GL_CLIENT_VERTEX_ARRAY_BIT );
+
+  Mock::VerifyAndClear( &mock );
+
+  EXPECT_EQ( GLint( 0 ), ppca.VertexArray::named[ ClientState::COLOR ].stride );
+  EXPECT_EQ( std::vector<ClientState::VertexArray>::size_type(2), ppca.vertexArrayStack.size() );
+
+  EXPECT_CALL( mock, glBindBuffer(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glBindVertexArray(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glBindVertexBuffer(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glClientActiveTexture(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glColorPointer(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glDisable(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glDisableClientState(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glDisableClientStateiEXT(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glDisableVertexAttribArray(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glEdgeFlagPointer(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glEnable(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glEnableClientState(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glEnableVertexAttribArray(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glFogCoordPointer(_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glIndexPointer(_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glMultiTexCoordPointerEXT(_,_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glNormalPointer(_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glPixelStorei(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glPrimitiveRestartIndex(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glSecondaryColorPointer(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexAttribBinding(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexAttribFormat(_,_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexAttribIFormat(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexAttribLFormat(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexBindingDivisor(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexPointer(_,_,_,_) ).Times(AnyNumber());
+
+  ppca.glPopClientAttrib( &ctx );
+
+  Mock::VerifyAndClear( &mock );
+
+  EXPECT_EQ( GLint( 102 ), ppca.VertexArray::named[ ClientState::COLOR ].stride );
+  EXPECT_EQ( std::vector<ClientState::VertexArray>::size_type(1), ppca.vertexArrayStack.size() );
+
+  EXPECT_CALL( mock, glBindBuffer(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glBindVertexArray(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glBindVertexBuffer(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glClientActiveTexture(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glColorPointer(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glDisable(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glDisableClientState(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glDisableClientStateiEXT(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glDisableVertexAttribArray(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glEdgeFlagPointer(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glEnable(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glEnableClientState(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glEnableVertexAttribArray(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glFogCoordPointer(_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glIndexPointer(_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glMultiTexCoordPointerEXT(_,_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glNormalPointer(_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glPixelStorei(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glPrimitiveRestartIndex(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glSecondaryColorPointer(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexAttribBinding(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexAttribFormat(_,_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexAttribIFormat(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexAttribLFormat(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexBindingDivisor(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexPointer(_,_,_,_) ).Times(AnyNumber());
+
+  ppca.glPopClientAttrib( &ctx );
+
+  Mock::VerifyAndClear( &mock );
+
+  EXPECT_EQ( GLint( 101 ), ppca.VertexArray::named[ ClientState::COLOR ].stride );
+  EXPECT_EQ( std::vector<ClientState::VertexArray>::size_type(0), ppca.vertexArrayStack.size() );
+
+  ppca.glPopClientAttrib( &ctx );
+
+  Mock::VerifyAndClear( &mock );
+
+  EXPECT_EQ( GLint( 101 ), ppca.VertexArray::named[ ClientState::COLOR ].stride );
+  EXPECT_EQ( std::vector<ClientState::VertexArray>::size_type(0), ppca.vertexArrayStack.size() );
+
+  ppca.glPopClientAttrib( &ctx );
+
+  Mock::VerifyAndClear( &mock );
+
+  EXPECT_EQ( GLint( 101 ), ppca.VertexArray::named[ ClientState::COLOR ].stride );
+  EXPECT_EQ( std::vector<ClientState::VertexArray>::size_type(0), ppca.vertexArrayStack.size() );
+}
+
+TEST ( RegalPpca, ClientAttrib_PushPop )
+{
+  RegalGMockInterface mock;
+
+  RegalContext ctx;
+  ctx.info = new ContextInfo();
+  ctx.info->core = false;
+  ctx.info->es1 = false;
+  ctx.info->es2 = false;
+  InitDispatchTableGMock( ctx.dispatcher.emulation );
+
+  Ppca ppca;
+  checkPpcaDefaults(ctx, ppca);
+
+  const GLbitfield remainder = ~( GL_CLIENT_PIXEL_STORE_BIT | GL_CLIENT_VERTEX_ARRAY_BIT );
+
+  GLint clientAttribStackDepth = 666;
+  EXPECT_EQ( GLboolean( GL_TRUE ), ppca.glGetv(&ctx, GL_CLIENT_ATTRIB_STACK_DEPTH, &clientAttribStackDepth));
+  EXPECT_EQ( clientAttribStackDepth, GLint(0) );
+
+  EXPECT_EQ( std::vector<GLbitfield>::size_type(0),               ppca.maskStack.size() );
+  EXPECT_EQ( std::vector<ClientState::VertexArray>::size_type(0), ppca.vertexArrayStack.size() );
+  EXPECT_EQ( std::vector<ClientState::PixelStore>::size_type(0),  ppca.pixelStoreStack.size() );
+
+  ppca.glPushClientAttrib( &ctx, GL_CLIENT_PIXEL_STORE_BIT );
+
+  EXPECT_EQ( GLboolean( GL_TRUE ), ppca.glGetv(&ctx, GL_CLIENT_ATTRIB_STACK_DEPTH, &clientAttribStackDepth));
+  EXPECT_EQ( clientAttribStackDepth, GLint(1) );
+
+  EXPECT_EQ( std::vector<GLbitfield>::size_type(1),               ppca.maskStack.size() );
+  EXPECT_EQ( std::vector<ClientState::VertexArray>::size_type(0), ppca.vertexArrayStack.size() );
+  EXPECT_EQ( std::vector<ClientState::PixelStore>::size_type(1),  ppca.pixelStoreStack.size() );
+
+  ppca.glPushClientAttrib( &ctx, GL_CLIENT_VERTEX_ARRAY_BIT );
+
+  EXPECT_EQ( GLboolean( GL_TRUE ), ppca.glGetv(&ctx, GL_CLIENT_ATTRIB_STACK_DEPTH, &clientAttribStackDepth));
+  EXPECT_EQ( clientAttribStackDepth, GLint(2) );
+
+  EXPECT_EQ( std::vector<GLbitfield>::size_type(2),               ppca.maskStack.size() );
+  EXPECT_EQ( std::vector<ClientState::VertexArray>::size_type(1), ppca.vertexArrayStack.size() );
+  EXPECT_EQ( std::vector<ClientState::PixelStore>::size_type(1),  ppca.pixelStoreStack.size() );
+
+  EXPECT_CALL( mock, glPushClientAttrib( remainder ) );
+
+  ppca.glPushClientAttrib( &ctx, GL_CLIENT_ALL_ATTRIB_BITS );
+  Mock::VerifyAndClear( &mock );
+
+  EXPECT_EQ( GLboolean( GL_TRUE ), ppca.glGetv(&ctx, GL_CLIENT_ATTRIB_STACK_DEPTH, &clientAttribStackDepth));
+  EXPECT_EQ( clientAttribStackDepth, GLint(3) );
+
+  EXPECT_EQ( std::vector<GLbitfield>::size_type(3),               ppca.maskStack.size() );
+  EXPECT_EQ( std::vector<ClientState::VertexArray>::size_type(2), ppca.vertexArrayStack.size() );
+  EXPECT_EQ( std::vector<ClientState::PixelStore>::size_type(2),  ppca.pixelStoreStack.size() );
+
+  EXPECT_CALL( mock, glBindBuffer(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glBindVertexArray(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glBindVertexBuffer(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glClientActiveTexture(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glColorPointer(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glDisable(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glDisableClientState(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glDisableClientStateiEXT(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glDisableVertexAttribArray(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glEdgeFlagPointer(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glEnable(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glEnableClientState(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glEnableVertexAttribArray(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glFogCoordPointer(_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glIndexPointer(_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glMultiTexCoordPointerEXT(_,_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glNormalPointer(_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glPixelStorei(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glPrimitiveRestartIndex(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glSecondaryColorPointer(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexAttribBinding(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexAttribFormat(_,_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexAttribIFormat(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexAttribLFormat(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexBindingDivisor(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexPointer(_,_,_,_) ).Times(AnyNumber());
+
   ctx.info->es2 = true;
+  ppca.glPushClientAttrib( &ctx, GL_CLIENT_ALL_ATTRIB_BITS );
+  ppca.glPopClientAttrib( &ctx );
+  ctx.info->es2 = false;
+  Mock::VerifyAndClear( &mock );
+
+  EXPECT_EQ( GLboolean( GL_TRUE ), ppca.glGetv(&ctx, GL_CLIENT_ATTRIB_STACK_DEPTH, &clientAttribStackDepth));
+  EXPECT_EQ( clientAttribStackDepth, GLint(3) );
+
+  EXPECT_EQ( std::vector<GLbitfield>::size_type(3),               ppca.maskStack.size() );
+  EXPECT_EQ( std::vector<ClientState::VertexArray>::size_type(2), ppca.vertexArrayStack.size() );
+  EXPECT_EQ( std::vector<ClientState::PixelStore>::size_type(2),  ppca.pixelStoreStack.size() );
+
+  EXPECT_CALL( mock, glBindBuffer(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glBindVertexArray(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glBindVertexBuffer(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glClientActiveTexture(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glColorPointer(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glDisable(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glDisableClientState(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glDisableClientStateiEXT(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glDisableVertexAttribArray(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glEdgeFlagPointer(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glEnable(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glEnableClientState(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glEnableVertexAttribArray(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glFogCoordPointer(_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glIndexPointer(_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glMultiTexCoordPointerEXT(_,_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glNormalPointer(_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glPixelStorei(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glPrimitiveRestartIndex(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glSecondaryColorPointer(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexAttribBinding(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexAttribFormat(_,_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexAttribIFormat(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexAttribLFormat(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexBindingDivisor(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexPointer(_,_,_,_) ).Times(AnyNumber());
+
+  EXPECT_CALL( mock, glPopClientAttrib() );
+
+  EXPECT_CALL( mock, glBindBuffer(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glBindVertexArray(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glBindVertexBuffer(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glClientActiveTexture(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glColorPointer(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glDisable(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glDisableClientState(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glDisableClientStateiEXT(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glDisableVertexAttribArray(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glEdgeFlagPointer(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glEnable(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glEnableClientState(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glEnableVertexAttribArray(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glFogCoordPointer(_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glIndexPointer(_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glMultiTexCoordPointerEXT(_,_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glNormalPointer(_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glPixelStorei(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glPrimitiveRestartIndex(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glSecondaryColorPointer(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexAttribBinding(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexAttribFormat(_,_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexAttribIFormat(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexAttribLFormat(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexBindingDivisor(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexPointer(_,_,_,_) ).Times(AnyNumber());
+
+  ppca.glPopClientAttrib( &ctx );
+  Mock::VerifyAndClear( &mock );
+
+  EXPECT_EQ( GLboolean( GL_TRUE ), ppca.glGetv(&ctx, GL_CLIENT_ATTRIB_STACK_DEPTH, &clientAttribStackDepth));
+  EXPECT_EQ( clientAttribStackDepth, GLint(2) );
+
+  EXPECT_EQ( std::vector<GLbitfield>::size_type(2),               ppca.maskStack.size() );
+  EXPECT_EQ( std::vector<ClientState::VertexArray>::size_type(1), ppca.vertexArrayStack.size() );
+  EXPECT_EQ( std::vector<ClientState::PixelStore>::size_type(1),  ppca.pixelStoreStack.size() );
+
+  EXPECT_CALL( mock, glBindBuffer(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glBindVertexArray(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glBindVertexBuffer(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glClientActiveTexture(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glColorPointer(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glDisable(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glDisableClientState(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glDisableClientStateiEXT(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glDisableVertexAttribArray(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glEdgeFlagPointer(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glEnable(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glEnableClientState(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glEnableVertexAttribArray(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glFogCoordPointer(_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glIndexPointer(_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glMultiTexCoordPointerEXT(_,_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glNormalPointer(_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glPixelStorei(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glPrimitiveRestartIndex(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glSecondaryColorPointer(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexAttribBinding(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexAttribFormat(_,_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexAttribIFormat(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexAttribLFormat(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexBindingDivisor(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexPointer(_,_,_,_) ).Times(AnyNumber());
+
+  ppca.glPopClientAttrib( &ctx );
+  Mock::VerifyAndClear( &mock );
+
+  EXPECT_EQ( GLboolean( GL_TRUE ), ppca.glGetv(&ctx, GL_CLIENT_ATTRIB_STACK_DEPTH, &clientAttribStackDepth));
+  EXPECT_EQ( clientAttribStackDepth, GLint(1) );
+
+  EXPECT_EQ( std::vector<GLbitfield>::size_type(1),               ppca.maskStack.size() );
+  EXPECT_EQ( std::vector<ClientState::VertexArray>::size_type(0), ppca.vertexArrayStack.size() );
+  EXPECT_EQ( std::vector<ClientState::PixelStore>::size_type(1),  ppca.pixelStoreStack.size() );
+
+  EXPECT_CALL( mock, glBindBuffer(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glBindVertexArray(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glBindVertexBuffer(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glClientActiveTexture(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glColorPointer(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glDisable(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glDisableClientState(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glDisableClientStateiEXT(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glDisableVertexAttribArray(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glEdgeFlagPointer(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glEnable(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glEnableClientState(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glEnableVertexAttribArray(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glFogCoordPointer(_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glIndexPointer(_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glMultiTexCoordPointerEXT(_,_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glNormalPointer(_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glPixelStorei(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glPrimitiveRestartIndex(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glSecondaryColorPointer(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexAttribBinding(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexAttribFormat(_,_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexAttribIFormat(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexAttribLFormat(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexBindingDivisor(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexPointer(_,_,_,_) ).Times(AnyNumber());
+
+  ppca.glPopClientAttrib( &ctx );
+  Mock::VerifyAndClear( &mock );
+
+  EXPECT_EQ( GLboolean( GL_TRUE ), ppca.glGetv(&ctx, GL_CLIENT_ATTRIB_STACK_DEPTH, &clientAttribStackDepth));
+  EXPECT_EQ( clientAttribStackDepth, GLint(0) );
+
+  EXPECT_EQ( std::vector<GLbitfield>::size_type(0),               ppca.maskStack.size() );
+  EXPECT_EQ( std::vector<ClientState::VertexArray>::size_type(0), ppca.vertexArrayStack.size() );
+  EXPECT_EQ( std::vector<ClientState::PixelStore>::size_type(0),  ppca.pixelStoreStack.size() );
+
+  EXPECT_CALL( mock, glClientAttribDefaultEXT( remainder ) );
+  EXPECT_CALL( mock, glBindBuffer(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glBindVertexArray(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glBindVertexBuffer(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glClientActiveTexture(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glColorPointer(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glDisable(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glDisableClientState(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glDisableClientStateiEXT(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glDisableVertexAttribArray(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glEdgeFlagPointer(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glEnable(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glEnableClientState(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glEnableVertexAttribArray(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glFogCoordPointer(_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glIndexPointer(_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glMultiTexCoordPointerEXT(_,_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glNormalPointer(_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glPixelStorei(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glPrimitiveRestartIndex(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glSecondaryColorPointer(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexAttribBinding(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexAttribFormat(_,_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexAttribIFormat(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexAttribLFormat(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexBindingDivisor(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexPointer(_,_,_,_) ).Times(AnyNumber());
+
+  ppca.glClientAttribDefaultEXT( &ctx, GL_CLIENT_ALL_ATTRIB_BITS );
+
+  Mock::VerifyAndClear( &mock );
+
+  EXPECT_EQ( std::vector<GLbitfield>::size_type(0),               ppca.maskStack.size() );
+  EXPECT_EQ( std::vector<ClientState::VertexArray>::size_type(0), ppca.vertexArrayStack.size() );
+  EXPECT_EQ( std::vector<ClientState::PixelStore>::size_type(0),  ppca.pixelStoreStack.size() );
+
+  EXPECT_CALL( mock, glClientAttribDefaultEXT( remainder ) );
+  EXPECT_CALL( mock, glPushClientAttrib( remainder ) );
+  EXPECT_CALL( mock, glBindBuffer(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glBindVertexArray(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glBindVertexBuffer(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glClientActiveTexture(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glColorPointer(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glDisable(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glDisableClientState(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glDisableClientStateiEXT(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glDisableVertexAttribArray(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glEdgeFlagPointer(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glEnable(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glEnableClientState(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glEnableVertexAttribArray(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glFogCoordPointer(_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glIndexPointer(_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glMultiTexCoordPointerEXT(_,_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glNormalPointer(_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glPixelStorei(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glPrimitiveRestartIndex(_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glSecondaryColorPointer(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexAttribBinding(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexAttribFormat(_,_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexAttribIFormat(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexAttribLFormat(_,_,_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexBindingDivisor(_,_) ).Times(AnyNumber());
+  EXPECT_CALL( mock, glVertexPointer(_,_,_,_) ).Times(AnyNumber());
+
+  ppca.glPushClientAttribDefaultEXT( &ctx, GL_CLIENT_ALL_ATTRIB_BITS );
+
+  Mock::VerifyAndClear( &mock );
+
+  EXPECT_EQ( std::vector<GLbitfield>::size_type(1),               ppca.maskStack.size() );
+  EXPECT_EQ( std::vector<ClientState::VertexArray>::size_type(1), ppca.vertexArrayStack.size() );
+  EXPECT_EQ( std::vector<ClientState::PixelStore>::size_type(1),  ppca.pixelStoreStack.size() );
+}
+
+TEST ( RegalPpca, VertexArray_Named_BasicOperations )
+{
+  RegalContext ctx;
+  ctx.info = new ContextInfo();
+
+  Ppca state;
+  checkPpcaDefaults(ctx, state);
+
+  // Set unique data for the array source for all attributes.
+
+  for (GLuint ii=0; ii<ClientState::nNamedArrays; ii++)
+  {
+    if ( ii == 4 ) {
+      state.VertexArray::named[ii].enabled = GLboolean(GL_TRUE);
+    } else {
+      state.VertexArray::named[ii].enabled = GLboolean(GL_FALSE);
+    }
+    state.VertexArray::named[ii].pointer = reinterpret_cast<const GLvoid*>(ii * 10 + 5);
+    state.VertexArray::named[ii].buffer  = GLuint(ii * 10 + 1);
+    state.VertexArray::named[ii].size    = GLint( ii * 10 + 2);
+    state.VertexArray::named[ii].type    = GLenum(ii * 10 + 3);
+    state.VertexArray::named[ii].stride  = GLuint(ii * 10 + 4);
+  }
+
+  // Calls with out-of-bound values should silently return as a no-op.
+  // This is done here so if we affect the explicitly set state it will be
+  // detected soon.
+
+  state.glEnableClientState( GLenum(~0) );
+  state.glEnableClientStateiEXT( GL_TEXTURE_COORD_ARRAY, GLuint(~0) );
+
+  state.glDisableClientState( GLenum(~0) );
+  state.glDisableClientStateiEXT( GL_TEXTURE_COORD_ARRAY, GLuint(~0) );
+
+  state.glEnable( GLenum(~0) );
+  state.glEnable( GLenum(ClientState::nNamedArrays) );
+
+  state.glDisable( GLenum(~0) );
+  state.glDisable( GLenum(ClientState::nNamedArrays) );
+
+  // Peform a swap, so that it is effectively tested too
+
+  Ppca other;
+  checkPpcaDefaults(ctx, other);
+
+  state.VertexArray::swap( other );
+
+  // Verify the expected default state ended up in the original
+
+  checkPpcaDefaults(ctx, state);
+
+  // Verify the modified data ended up in the other state
+
+  for (GLuint ii=0; ii<ClientState::nNamedArrays; ii++)
+  {
+    if ( ii == 4 ) {
+      EXPECT_EQ( GLboolean(GL_TRUE),  other.VertexArray::named[ii].enabled );
+    } else {
+      EXPECT_EQ( GLboolean(GL_FALSE), other.VertexArray::named[ii].enabled );
+    }
+    EXPECT_EQ( reinterpret_cast<const GLvoid*>(ii * 10 + 5), other.VertexArray::named[ ii ].pointer );
+    EXPECT_EQ( GLuint(ii * 10 + 1), other.VertexArray::named[ ii ].buffer );
+    EXPECT_EQ( GLint( ii * 10 + 2), other.VertexArray::named[ ii ].size );
+    EXPECT_EQ( GLenum(ii * 10 + 3), other.VertexArray::named[ ii ].type );
+    EXPECT_EQ( GLuint(ii * 10 + 4), other.VertexArray::named[ ii ].stride );
+  }
+}
+
+TEST ( RegalPpca, VertexArray_Generic_BasicOperations )
+{
+  RegalContext ctx;
+  ctx.info = new ContextInfo();
+
+  Ppca state;
+  checkPpcaDefaults(ctx, state);
+
+  // Set unique data for the arrays
+
+  for (GLuint ii=0; ii<REGAL_EMU_MAX_VERTEX_ATTRIBS; ii++)
+  {
+    if ( ii == 4 ) {
+      state.VertexArray::generic[ii].enabled = GLboolean(GL_TRUE);
+    } else {
+      state.VertexArray::generic[ii].enabled = GLboolean(GL_FALSE);
+    }
+    state.VertexArray::generic[ii].size           = GLuint(ii * 100 + 1);
+    state.VertexArray::generic[ii].type           = GLenum(ii * 100 + 2);
+    state.VertexArray::generic[ii].relativeOffset = GLuint(ii * 100 + 3);
+    state.VertexArray::generic[ii].normalized     = GLboolean(ii * 100 + 4);
+    state.VertexArray::generic[ii].isInteger      = GLboolean(ii * 100 + 5);
+    state.VertexArray::generic[ii].isLong         = GLboolean(ii * 100 + 6);
+    state.VertexArray::generic[ii].bindingIndex   = GLuint(ii * 100 + 7);
+  }
+
+  // Set unique data for the bindings
+
+  for (GLuint ii=0; ii<REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS; ii++)
+  {
+    state.VertexArray::bindings[ii].buffer  = GLuint(ii * 1000 + 1);
+    state.VertexArray::bindings[ii].offset  = GLintptr(ii * 1000 + 2);
+    state.VertexArray::bindings[ii].stride  = GLsizei(ii * 1000 + 3);
+    state.VertexArray::bindings[ii].divisor = GLuint(ii * 1000 + 4);
+  }
+
+  // Calls with out-of-bound values should silently return as a no-op.
+  // This is done here so if we affect the explicitly set state it will be
+  // detected soon.
+
+  state.glEnableVertexArrayAttribEXT( 0, GLuint(~0) );
+  state.glDisableVertexArrayAttribEXT( 0, GLuint(~0) );
+  state.glVertexAttribFormat( GLuint(~0), 0, 0, GL_TRUE, 0 );
+  state.glVertexAttribFormat( GLuint(~0), 0, 0, GL_FALSE, 0 );
+  state.glVertexAttribLFormat( GLuint(~0), 0, 0, 0 );
+  state.glVertexAttribIFormat( GLuint(~0), 0, 0, 0 );
+  state.glVertexAttribBinding( GLuint(~0), 0 );
+  state.glEnableVertexAttribArray( GLuint(~0) );
+  state.glDisableVertexAttribArray( GLuint(~0) );
+
+  state.glEnableVertexArrayAttribEXT( 0, REGAL_EMU_MAX_VERTEX_ATTRIBS );
+  state.glDisableVertexArrayAttribEXT( 0, REGAL_EMU_MAX_VERTEX_ATTRIBS );
+  state.glVertexAttribFormat( REGAL_EMU_MAX_VERTEX_ATTRIBS, 0, 0, GL_TRUE, 0 );
+  state.glVertexAttribFormat( REGAL_EMU_MAX_VERTEX_ATTRIBS, 0, 0, GL_FALSE, 0 );
+  state.glVertexAttribLFormat( REGAL_EMU_MAX_VERTEX_ATTRIBS, 0, 0, 0 );
+  state.glVertexAttribIFormat( REGAL_EMU_MAX_VERTEX_ATTRIBS, 0, 0, 0 );
+  state.glVertexAttribBinding( REGAL_EMU_MAX_VERTEX_ATTRIBS, 0 );
+  state.glEnableVertexAttribArray( REGAL_EMU_MAX_VERTEX_ATTRIBS );
+  state.glDisableVertexAttribArray( REGAL_EMU_MAX_VERTEX_ATTRIBS );
+
+  state.glVertexAttribDivisor( GLuint(~0), 0 );
+  state.glVertexBindingDivisor( GLuint(~0), 0 );
+  state.glBindVertexBuffers( GLuint(~0), 0, 0, 0, 0);
+  state.glBindVertexBuffers( GLuint(~0), 0, (const GLuint*)(0xdead), 0, 0);
+  state.glBindVertexBuffers( 0, GLuint(~0), 0, 0, 0);
+  state.glBindVertexBuffers( 0, GLuint(~0), (const GLuint*)(0xdead), 0, 0);
+
+  state.glBindVertexBuffer( GLuint(GLuint(~0) - 1), 0, 0, 0);
+  state.glBindVertexBuffer( GLuint(~0), 0, 0, 0);
+
+  state.glVertexArrayMultiTexCoordOffsetEXT(0, 0, GLenum(~0), 0, GLenum(0), 0, GLintptr(0) );
+
+  state.glVertexAttribDivisor( REGAL_EMU_MAX_VERTEX_ATTRIBS, 0 );
+  state.glVertexAttribDivisor( REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS, 0 );
+  state.glVertexBindingDivisor( REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS, 0 );
+  state.glBindVertexBuffers( REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS, 0, 0, 0, 0);
+  state.glBindVertexBuffers( REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS, 0, (const GLuint*)(0xdead), 0, 0);
+
+  // don't change this 1 to a 0. if you do, among other things glBindVertexBuffer will try to access
+  // the bogus pointers being passed in here and you get what you deserve.
+
+  state.glBindVertexBuffers( 1, REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS, 0, 0, 0);
+  state.glBindVertexBuffers( 1, REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS, (const GLuint*)(0xdead), 0, 0);
+
+  state.glBindVertexBuffer( REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS, 0, 0, 0);
+
+  // Peform a swap, so that it is effectively tested too
+
+  Ppca other;
+  checkPpcaDefaults(ctx, other);
+
+  state.VertexArray::swap( other );
+
+  // Verify the expected default state ended up in the original
+
+  checkPpcaDefaults(ctx, state);
+
+  // Verify the modified array data ended up in the other state
+
+  for (GLuint ii=0; ii<REGAL_EMU_MAX_VERTEX_ATTRIBS; ii++)
+  {
+    if ( ii == 4 ) {
+      EXPECT_EQ( GLboolean(GL_TRUE),  other.VertexArray::generic[ ii ].enabled );
+    } else {
+      EXPECT_EQ( GLboolean(GL_FALSE), other.VertexArray::generic[ ii ].enabled );
+    }
+    EXPECT_EQ( GLuint(ii * 100 + 1),  other.VertexArray::generic[ ii ].size );
+    EXPECT_EQ( GLenum(ii * 100 + 2),  other.VertexArray::generic[ ii ].type );
+    EXPECT_EQ( GLuint(ii * 100 + 3),  other.VertexArray::generic[ ii ].relativeOffset );
+    EXPECT_EQ( GLboolean(ii * 100 + 4),  other.VertexArray::generic[ ii ].normalized );
+    EXPECT_EQ( GLboolean(ii * 100 + 5),  other.VertexArray::generic[ ii ].isInteger );
+    EXPECT_EQ( GLboolean(ii * 100 + 6),  other.VertexArray::generic[ ii ].isLong );
+    EXPECT_EQ( GLuint(ii * 100 + 7),  other.VertexArray::generic[ ii ].bindingIndex );
+  }
+
+  // Verify the modified bindings data ended up in the other state
+
+  for (GLuint ii=0; ii<REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS; ii++)
+  {
+    EXPECT_EQ( GLuint(ii * 1000 + 1),    other.VertexArray::bindings[ ii ].buffer );
+    EXPECT_EQ( GLintptr( ii * 1000 + 2), other.VertexArray::bindings[ ii ].offset );
+    EXPECT_EQ( GLsizei(ii * 1000 + 3),   other.VertexArray::bindings[ ii ].stride );
+    EXPECT_EQ( GLuint(ii * 1000 + 4),    other.VertexArray::bindings[ ii ].divisor );
+  }
+}
+
+TEST ( RegalPpca, VertexArrayGenericState_Transition )
+{
+  RegalGMockInterface mock;
+
+  DispatchTableGL dt;
+  ::memset(&dt,0,sizeof(DispatchTableGL));
+  dt._enabled = true;
+  InitDispatchTableGMock( dt );
+
+  RegalContext ctx;
+  ctx.info = new ContextInfo();
+
+  Ppca current;
+  checkPpcaDefaults(ctx, current);
+
+  Ppca target;
+  checkPpcaDefaults(ctx, target);
+
+  // An attribute array can be enabled.
+
+  target.glEnableVertexAttribArray( 0 );
+
+  EXPECT_CALL( mock, glEnableVertexAttribArray( 0 ) );
+
+  // An attribute array can be configured.
+
+  target.glVertexAttribFormat ( 1, 11, GLenum(12), GL_FALSE, 13 );
+  target.glVertexAttribFormat ( 2, 21, GLenum(22), GL_TRUE,  23 );
+  target.glVertexAttribIFormat( 3, 31, GLenum(32), 33 );
+
+  EXPECT_CALL( mock, glVertexAttribFormat ( 1, 11, 12, GL_FALSE, 13 ) );
+  EXPECT_CALL( mock, glVertexAttribFormat ( 2, 21, 22, GL_TRUE,  23 ) );
+  EXPECT_CALL( mock, glVertexAttribIFormat( 3, 31, 32, 33 ) );
+
+  // An attribute buffer can be configured.
+
+  target.glBindVertexBuffer( 4, 41, 42, 43 );
+
+  EXPECT_CALL( mock, glBindVertexBuffer( 4, 41, 42, 43 ) );
+
+  // An attribute buffer divisor can be configured.
+
+  target.glVertexBindingDivisor( 5, 51 );
+  EXPECT_CALL( mock, glVertexBindingDivisor( 5, 51 ) );
+
+  target.glVertexAttribBinding( 6, 7 );
+  EXPECT_CALL( mock, glVertexAttribBinding( 6, 7 ) );
+
+  target.glEnableVertexAttribArray( 8 );
+
+  EXPECT_CALL( mock, glEnableVertexAttribArray ( 8 ) );
+
+  // transition, verify, and reset
+
+  current.VertexArray::transition( dt, target, true );
+  Mock::VerifyAndClear( &mock );
+
+  // An attribute can be disabled and all data reset to default.
+
+  target.glDisableVertexAttribArray( 8 );
+  target.glVertexAttribFormat( 8, 61, 62, GL_FALSE, 63 );
+  target.glBindVertexBuffer( 8, 64, 65, 66 );
+  target.glVertexBindingDivisor( 8, 67 );
+  target.glVertexAttribBinding( 8, 9 );
+
+  EXPECT_CALL( mock, glDisableVertexAttribArray ( 8 ) );
+  EXPECT_CALL( mock, glVertexAttribFormat ( 8, 61, 62, GL_FALSE, 63 ) );
+  EXPECT_CALL( mock, glBindVertexBuffer( 8, 64, 65, 66 ) );
+  EXPECT_CALL( mock, glVertexBindingDivisor( 8, 67 ) );
+  EXPECT_CALL( mock, glVertexAttribBinding( 8, 9 ) );
+
+  // transition, verify, and reset
+
+  current.VertexArray::transition( dt, target, true );
+  Mock::VerifyAndClear( &mock );
+
+  // Identical state is a no-op in terms of calls.
+
+  current.VertexArray::transition( dt, target, true );
+  Mock::VerifyAndClear( &mock );
+
+  current.VertexArray::transition( dt, current, true );
+  Mock::VerifyAndClear( &mock );
+
+  target.VertexArray::transition( dt, target, true );
+  Mock::VerifyAndClear( &mock );
+
+  target.Reset(ctx);
+  current.Reset(ctx);
+
+  target.glEnableVertexAttribArray( 0 );
+  target.glVertexAttribFormat ( 0, 11, GLenum(12), GL_FALSE, 13 );
+  target.glBindVertexBuffer( 0, 14, 15, 16 );
+  target.glVertexBindingDivisor( 0, 17 );
+  target.glVertexAttribBinding( 0, 1 );
+
+  current.glEnableVertexAttribArray( 0 );
+  current.glVertexAttribFormat ( 0, 11, GLenum(12), GL_FALSE, 13 );
+  current.glBindVertexBuffer( 0, 14, 15, 16 );
+  current.glVertexBindingDivisor( 0, 17 );
+  current.glVertexAttribBinding( 0, 1 );
+
+  current.VertexArray::transition( dt, target, true );
+  Mock::VerifyAndClear( &mock );
+}
+
+TEST ( RegalPpca, VertexArray_Transition )
+{
+  RegalGMockInterface mock;
+
+  DispatchTableGL dt;
+  ::memset(&dt,0,sizeof(DispatchTableGL));
+  dt._enabled = true;
+  InitDispatchTableGMock( dt );
+
+  RegalContext ctx;
+  ctx.info = new ContextInfo();
+
+  Ppca current;
+  checkPpcaDefaults(ctx, current);
+
+  Ppca target;
+  checkPpcaDefaults(ctx, target);
+
+  // Set up a simple non-default state, focusing on state unique this structure.
+
+  target.elementArrayBufferBinding = GLuint(1);
+  target.clientActiveTexture = GLenum(2);
+  target.primitiveRestartFixedIndex = GLboolean(GL_TRUE);
+  target.primitiveRestart = GLboolean(GL_TRUE);
+  target.primitiveRestartIndex = GLuint(3);
+  target.arrayBufferBinding = GLuint(4);
+  target.vertexArrayBinding = GLuint(5);
+
+  // Set up expectations.
+
+  EXPECT_CALL( mock, glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 1 ) );
+  EXPECT_CALL( mock, glClientActiveTexture( 2 ) );
+  EXPECT_CALL( mock, glEnable( GL_PRIMITIVE_RESTART_FIXED_INDEX ) );
+  EXPECT_CALL( mock, glEnable( GL_PRIMITIVE_RESTART ) );
+  EXPECT_CALL( mock, glPrimitiveRestartIndex( 3 ) );
+  EXPECT_CALL( mock, glBindBuffer( GL_ARRAY_BUFFER, 4 ) );
+  EXPECT_CALL( mock, glBindVertexArray( 5 ) );
+
+  // Perform the requested state transition.
+
+  current.VertexArray::transition( dt, target, true );
+
+  // Verify the call expectations, and reset for another test.
+
+  Mock::VerifyAndClear( &mock );
+
+  // unfortunately even though this call to transition() won't actually
+  // do anything, the current implementation will clear the bound vertex
+  // array, do the changes (which turns out to be none), then bind back
+  // to the original vertex array
+
+  EXPECT_CALL( mock, glBindVertexArray( 0 ) );
+  EXPECT_CALL( mock, glBindVertexArray( 5 ) );
+
+  // Perform the requested state transition.
+
+  current.VertexArray::transition( dt, target, true );
+
+  // Verify the call expectations, and reset for another test.
+
+  Mock::VerifyAndClear( &mock );
+
+  // A transition with no differences should make no calls, but...
+  // see above comment.
+
+  EXPECT_CALL( mock, glBindVertexArray( 0 ) );
+  EXPECT_CALL( mock, glBindVertexArray( 5 ) );
+
+  current.VertexArray::transition( dt, current, true );
+  Mock::VerifyAndClear( &mock );
+
+  EXPECT_CALL( mock, glBindVertexArray( 0 ) );
+  EXPECT_CALL( mock, glBindVertexArray( 5 ) );
+
+  target.VertexArray::transition( dt, target, true );
+  Mock::VerifyAndClear( &mock );
+
+  current.Reset(ctx);
+  target.Reset(ctx);
+
+  // Now there really won't be any calls since both the
+  // current and target vertex array to bind is 0
+
+  current.VertexArray::transition( dt, target, true );
+  Mock::VerifyAndClear( &mock );
+
+  // set some state other than the vertex array binding
+
+  target.elementArrayBufferBinding = GLuint(1);
+  target.clientActiveTexture = GLenum(2);
+  target.primitiveRestartFixedIndex = GLboolean(GL_TRUE);
+  target.primitiveRestart = GLboolean(GL_TRUE);
+  target.primitiveRestartIndex = GLuint(3);
+  target.arrayBufferBinding = GLuint(4);
+
+  current.elementArrayBufferBinding = GLuint(1);
+  current.clientActiveTexture = GLenum(2);
+  current.primitiveRestartFixedIndex = GLboolean(GL_TRUE);
+  current.primitiveRestart = GLboolean(GL_TRUE);
+  current.primitiveRestartIndex = GLuint(3);
+  current.arrayBufferBinding = GLuint(4);
+
+  // and again no calls.
+
+  current.VertexArray::transition( dt, target, true );
+  Mock::VerifyAndClear( &mock );
+}
+
+TEST ( RegalPpca, PixelStore_Transition )
+{
+  RegalGMockInterface mock;
+
+  DispatchTableGL dt;
+  ::memset(&dt,0,sizeof(DispatchTableGL));
+  dt._enabled = true;
+  InitDispatchTableGMock( dt );
+
+  RegalContext ctx;
+  ctx.info = new ContextInfo();
+
+  Ppca current;
+  checkPpcaDefaults(ctx, current);
+
+  Ppca target;
+  checkPpcaDefaults(ctx, target);
+
+  // Set some of the named attributes, and expect that calls will be made
+  // appropriately to the backend to transition to those value.
+
+  current.PixelStore::unpackSkipPixels        = GLuint(123);
+  current.PixelStore::unpackAlignment         = GLuint(456);
+
+  target.PixelStore::pixelPackBufferBinding   = GLuint(321);
+  target.PixelStore::pixelUnpackBufferBinding = GLuint(654);
+
+  EXPECT_CALL( mock, glPixelStorei( GL_UNPACK_SKIP_PIXELS ,   0 ) );
+  EXPECT_CALL( mock, glPixelStorei( GL_UNPACK_ALIGNMENT   ,   4 ) );
+  EXPECT_CALL( mock, glBindBuffer ( GL_PIXEL_PACK_BUFFER  , 321 ) );
+  EXPECT_CALL( mock, glBindBuffer ( GL_PIXEL_UNPACK_BUFFER, 654 ) );
+
+  // Perform the state transition and verify expectations
+
+  current.PixelStore::transition( dt, target );
+  Mock::VerifyAndClear( &mock );
+
+  // A transition with no differences should make no calls.
+
+  current.PixelStore::transition( dt, current );
+  Mock::VerifyAndClear( &mock );
+
+  target.PixelStore::transition( dt, target );
+  Mock::VerifyAndClear( &mock );
+
+  current.Reset(ctx);
+  target.Reset(ctx);
+
+  current.PixelStore::transition( dt, target );
+  Mock::VerifyAndClear( &mock );
+
+  target.PixelStore::unpackSkipPixels          = GLuint(123);
+  target.PixelStore::unpackAlignment           = GLuint(456);
+  target.PixelStore::pixelPackBufferBinding    = GLuint(321);
+  target.PixelStore::pixelUnpackBufferBinding  = GLuint(654);
+
+  current.PixelStore::unpackSkipPixels         = GLuint(123);
+  current.PixelStore::unpackAlignment          = GLuint(456);
+  current.PixelStore::pixelPackBufferBinding   = GLuint(321);
+  current.PixelStore::pixelUnpackBufferBinding = GLuint(654);
+
+  current.PixelStore::transition( dt, target );
+  Mock::VerifyAndClear( &mock );
+}
+
+TEST ( RegalPpca, VertexArray_Generic )
+{
+  RegalContext ctx;
+  ctx.info = new ContextInfo();
+
+  Ppca ppca;
+  checkPpcaDefaults(ctx, ppca);
+
+  // VertexAttribFormat
+
+  ppca.glVertexAttribFormat ( 3, 4, GL_FLOAT, GL_TRUE, 123 );
+
+  EXPECT_EQ( GLuint(4),           ppca.VertexArray::generic[3].size );
+  EXPECT_EQ( GLenum(GL_FLOAT),    ppca.VertexArray::generic[3].type );
+  EXPECT_EQ( GLuint(123),         ppca.VertexArray::generic[3].relativeOffset );
+  EXPECT_EQ( GLboolean(GL_TRUE),  ppca.VertexArray::generic[3].normalized );
+  EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::generic[3].isInteger );
+  EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::generic[3].isLong );
+
+  ppca.Reset(ctx);
+  ppca.glVertexAttribFormat ( 3, 4, GL_FLOAT, GL_FALSE, 123 );
+
+  EXPECT_EQ( GLuint(4),           ppca.VertexArray::generic[3].size );
+  EXPECT_EQ( GLenum(GL_FLOAT),    ppca.VertexArray::generic[3].type );
+  EXPECT_EQ( GLuint(123),         ppca.VertexArray::generic[3].relativeOffset );
+  EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::generic[3].normalized );
+  EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::generic[3].isInteger );
+  EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::generic[3].isLong );
+
+  ppca.Reset(ctx);
+  ppca.glVertexAttribIFormat( 3, 1, GL_INT, 456 );
+
+  EXPECT_EQ( GLuint(1),           ppca.VertexArray::generic[3].size );
+  EXPECT_EQ( GLenum(GL_INT),      ppca.VertexArray::generic[3].type );
+  EXPECT_EQ( GLuint(456),         ppca.VertexArray::generic[3].relativeOffset );
+  EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::generic[3].normalized );
+  EXPECT_EQ( GLboolean(GL_TRUE),  ppca.VertexArray::generic[3].isInteger );
+  EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::generic[3].isLong );
+
+  ppca.Reset(ctx);
+  ppca.glVertexAttribLFormat( 3, 2, GL_DOUBLE, 789 );
+
+  EXPECT_EQ( GLuint(2),           ppca.VertexArray::generic[3].size );
+  EXPECT_EQ( GLenum(GL_DOUBLE),   ppca.VertexArray::generic[3].type );
+  EXPECT_EQ( GLuint(789),         ppca.VertexArray::generic[3].relativeOffset );
+  EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::generic[3].normalized );
+  EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::generic[3].isInteger );
+  EXPECT_EQ( GLboolean(GL_TRUE),  ppca.VertexArray::generic[3].isLong );
+
+  // BindVertexBuffer
+
+  ppca.Reset(ctx);
+  ppca.glBindVertexBuffer( 4, 5, 6, 7 );
+
+  EXPECT_EQ( GLuint(5),   ppca.VertexArray::bindings[4].buffer );
+  EXPECT_EQ( GLintptr(6), ppca.VertexArray::bindings[4].offset );
+  EXPECT_EQ( GLsizei(7),  ppca.VertexArray::bindings[4].stride );
+  EXPECT_EQ( GLuint(0),   ppca.VertexArray::bindings[4].divisor );
+
+  // VertexAttribBinding
+
+  ppca.Reset(ctx);
+  ppca.glVertexAttribBinding( 3, 4 );
+
+  EXPECT_EQ( GLuint(4), ppca.VertexArray::generic[3].bindingIndex );
+
+  // VertexAttribPointer
+
+  ppca.Reset(ctx);
+  ppca.VertexArray::arrayBufferBinding = 8888;
+  ppca.glVertexAttribPointer ( 3, 1, GL_FLOAT, GL_TRUE, 123, reinterpret_cast<const GLvoid *>( 321 ) );
+
+  EXPECT_EQ( GLuint(1),           ppca.VertexArray::generic[3].size );
+  EXPECT_EQ( GLenum(GL_FLOAT),    ppca.VertexArray::generic[3].type );
+  EXPECT_EQ( GLuint(0),           ppca.VertexArray::generic[3].relativeOffset );
+  EXPECT_EQ( GLboolean(GL_TRUE),  ppca.VertexArray::generic[3].normalized );
+  EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::generic[3].isInteger );
+  EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::generic[3].isLong );
+  EXPECT_EQ( GLuint(3),           ppca.VertexArray::generic[3].bindingIndex );
+
+  EXPECT_EQ( GLuint(8888),  ppca.VertexArray::bindings[3].buffer );
+  EXPECT_EQ( GLintptr(321), ppca.VertexArray::bindings[3].offset );
+  EXPECT_EQ( GLsizei(123),  ppca.VertexArray::bindings[3].stride );
+  EXPECT_EQ( GLuint(0),     ppca.VertexArray::bindings[3].divisor );
+
+  ppca.Reset(ctx);
+  ppca.VertexArray::arrayBufferBinding = 8888;
+  ppca.glVertexAttribPointer ( 3, 1, GL_FLOAT, GL_FALSE, 0, reinterpret_cast<GLvoid *>( 321 ) );
+
+  EXPECT_EQ( GLuint(1),           ppca.VertexArray::generic[3].size );
+  EXPECT_EQ( GLenum(GL_FLOAT),    ppca.VertexArray::generic[3].type );
+  EXPECT_EQ( GLuint(0),           ppca.VertexArray::generic[3].relativeOffset );
+  EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::generic[3].normalized );
+  EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::generic[3].isInteger );
+  EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::generic[3].isLong );
+  EXPECT_EQ( GLuint(3),           ppca.VertexArray::generic[3].bindingIndex );
+
+  EXPECT_EQ( GLuint(8888),  ppca.VertexArray::bindings[3].buffer );
+  EXPECT_EQ( GLintptr(321), ppca.VertexArray::bindings[3].offset );
+  EXPECT_EQ( GLsizei(4),    ppca.VertexArray::bindings[3].stride );
+  EXPECT_EQ( GLuint(0),     ppca.VertexArray::bindings[3].divisor );
+
+  ppca.Reset(ctx);
+  ppca.VertexArray::arrayBufferBinding = 8888;
+  ppca.glVertexAttribIPointer ( 3, 2, GL_INT, 456, reinterpret_cast<GLvoid *>( 654 ) );
+
+  EXPECT_EQ( GLuint(2),           ppca.VertexArray::generic[3].size );
+  EXPECT_EQ( GLenum(GL_INT),      ppca.VertexArray::generic[3].type );
+  EXPECT_EQ( GLuint(0),           ppca.VertexArray::generic[3].relativeOffset );
+  EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::generic[3].normalized );
+  EXPECT_EQ( GLboolean(GL_TRUE),  ppca.VertexArray::generic[3].isInteger );
+  EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::generic[3].isLong );
+  EXPECT_EQ( GLuint(3),           ppca.VertexArray::generic[3].bindingIndex );
+
+  EXPECT_EQ( GLuint(8888),  ppca.VertexArray::bindings[3].buffer );
+  EXPECT_EQ( GLintptr(654), ppca.VertexArray::bindings[3].offset );
+  EXPECT_EQ( GLsizei(456),  ppca.VertexArray::bindings[3].stride );
+  EXPECT_EQ( GLuint(0),     ppca.VertexArray::bindings[3].divisor );
+
+  ppca.Reset(ctx);
+  ppca.VertexArray::arrayBufferBinding = 8888;
+  ppca.glVertexAttribIPointer( 3, 2, GL_INT, 0, reinterpret_cast<GLvoid *>( 654 ) );
+
+  EXPECT_EQ( GLuint(2),           ppca.VertexArray::generic[3].size );
+  EXPECT_EQ( GLenum(GL_INT),      ppca.VertexArray::generic[3].type );
+  EXPECT_EQ( GLuint(0),           ppca.VertexArray::generic[3].relativeOffset );
+  EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::generic[3].normalized );
+  EXPECT_EQ( GLboolean(GL_TRUE),  ppca.VertexArray::generic[3].isInteger );
+  EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::generic[3].isLong );
+  EXPECT_EQ( GLuint(3),           ppca.VertexArray::generic[3].bindingIndex );
+
+  EXPECT_EQ( GLuint(8888),  ppca.VertexArray::bindings[3].buffer );
+  EXPECT_EQ( GLintptr(654), ppca.VertexArray::bindings[3].offset );
+  EXPECT_EQ( GLsizei(8),    ppca.VertexArray::bindings[3].stride );
+  EXPECT_EQ( GLuint(0),     ppca.VertexArray::bindings[3].divisor );
+
+  ppca.Reset(ctx);
+  ppca.VertexArray::arrayBufferBinding = 8888;
+  ppca.glVertexAttribLPointer( 3, 3, GL_DOUBLE, 789, reinterpret_cast<GLvoid *>( 987 ) );
+
+  EXPECT_EQ( GLuint(3),           ppca.VertexArray::generic[3].size );
+  EXPECT_EQ( GLenum(GL_DOUBLE),   ppca.VertexArray::generic[3].type );
+  EXPECT_EQ( GLuint(0),           ppca.VertexArray::generic[3].relativeOffset );
+  EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::generic[3].normalized );
+  EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::generic[3].isInteger );
+  EXPECT_EQ( GLboolean(GL_TRUE),  ppca.VertexArray::generic[3].isLong );
+  EXPECT_EQ( GLuint(3),           ppca.VertexArray::generic[3].bindingIndex );
+
+  EXPECT_EQ( GLuint(8888),  ppca.VertexArray::bindings[3].buffer );
+  EXPECT_EQ( GLintptr(987), ppca.VertexArray::bindings[3].offset );
+  EXPECT_EQ( GLsizei(789),  ppca.VertexArray::bindings[3].stride );
+  EXPECT_EQ( GLuint(0),     ppca.VertexArray::bindings[3].divisor );
+
+  ppca.VertexArray::arrayBufferBinding = 8888;
+  ppca.glVertexAttribLPointer( 3, 3, GL_DOUBLE, 0, reinterpret_cast<GLvoid *>( 987 ) );
+
+  EXPECT_EQ( GLuint(3),           ppca.VertexArray::generic[3].size );
+  EXPECT_EQ( GLenum(GL_DOUBLE),   ppca.VertexArray::generic[3].type );
+  EXPECT_EQ( GLuint(0),           ppca.VertexArray::generic[3].relativeOffset );
+  EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::generic[3].normalized );
+  EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::generic[3].isInteger );
+  EXPECT_EQ( GLboolean(GL_TRUE),  ppca.VertexArray::generic[3].isLong );
+  EXPECT_EQ( GLuint(3),           ppca.VertexArray::generic[3].bindingIndex );
+
+  EXPECT_EQ( GLuint(8888),  ppca.VertexArray::bindings[3].buffer );
+  EXPECT_EQ( GLintptr(987), ppca.VertexArray::bindings[3].offset );
+  EXPECT_EQ( GLsizei(24),   ppca.VertexArray::bindings[3].stride );
+  EXPECT_EQ( GLuint(0),     ppca.VertexArray::bindings[3].divisor );
+
+  // Enable/DisableVertexAttribArray
+
+  ppca.Reset(ctx);
+  ppca.glEnableVertexAttribArray( 3 );
+
+  EXPECT_EQ( GLboolean( GL_TRUE ), ppca.VertexArray::generic[ 3 ].enabled );
+
+  ppca.glDisableVertexAttribArray( 3 );
+
+  EXPECT_EQ( GLboolean( GL_FALSE ), ppca.VertexArray::generic[ 3 ].enabled );
+
+  // VertexBindingDivisor
+
+  ppca.Reset(ctx);
+  ppca.glVertexBindingDivisor( 4, 123 );
+
+  EXPECT_EQ( GLuint(123), ppca.VertexArray::bindings[4].divisor );
+
+  // VertexAttribDivisor
+
+  ppca.Reset(ctx);
+  ppca.glVertexAttribDivisor( 3, 456 );
+
+  EXPECT_EQ( GLuint(3),   ppca.VertexArray::generic[3].bindingIndex );
+  EXPECT_EQ( GLuint(456), ppca.VertexArray::bindings[3].divisor );
+
+  // ShadowVertexArrayVertexAttribOffsetEXT
+
+  ppca.Reset(ctx);
+  ppca.glVertexArrayVertexAttribOffsetEXT( 0, 987, 3, 1, GL_FLOAT, GL_TRUE, 123, 321 );
+
+  EXPECT_EQ( GLuint(1),           ppca.VertexArray::generic[3].size );
+  EXPECT_EQ( GLenum(GL_FLOAT),    ppca.VertexArray::generic[3].type );
+  EXPECT_EQ( GLuint( 0 ),         ppca.VertexArray::generic[3].relativeOffset );
+  EXPECT_EQ( GLboolean(GL_TRUE),  ppca.VertexArray::generic[3].normalized );
+  EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::generic[3].isInteger );
+  EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::generic[3].isLong );
+  EXPECT_EQ( GLuint(3),           ppca.VertexArray::generic[3].bindingIndex );
+
+  EXPECT_EQ( GLuint(987),   ppca.VertexArray::bindings[3].buffer );
+  EXPECT_EQ( GLintptr(321), ppca.VertexArray::bindings[3].offset );
+  EXPECT_EQ( GLsizei(123),  ppca.VertexArray::bindings[3].stride );
+  EXPECT_EQ( GLuint(0),     ppca.VertexArray::bindings[3].divisor );
+
+  ppca.Reset(ctx);
+  ppca.glVertexArrayVertexAttribOffsetEXT( 0, 987, 3, 1, GL_FLOAT, GL_FALSE, 0, 321 );
+
+  EXPECT_EQ( GLuint(1),           ppca.VertexArray::generic[3].size );
+  EXPECT_EQ( GLenum(GL_FLOAT),    ppca.VertexArray::generic[3].type );
+  EXPECT_EQ( GLuint( 0 ),         ppca.VertexArray::generic[3].relativeOffset );
+  EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::generic[3].normalized );
+  EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::generic[3].isInteger );
+  EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::generic[3].isLong );
+  EXPECT_EQ( GLuint(3),           ppca.VertexArray::generic[3].bindingIndex );
+
+  EXPECT_EQ( GLuint(987),   ppca.VertexArray::bindings[3].buffer );
+  EXPECT_EQ( GLintptr(321), ppca.VertexArray::bindings[3].offset );
+  EXPECT_EQ( GLsizei(4),    ppca.VertexArray::bindings[3].stride );
+  EXPECT_EQ( GLuint(0),     ppca.VertexArray::bindings[3].divisor );
+
+  ppca.Reset(ctx);
+  ppca.glVertexArrayVertexAttribIOffsetEXT( 0, 987, 3, 2, GL_INT, 456, 654 );
+
+  EXPECT_EQ( GLuint(2),           ppca.VertexArray::generic[3].size );
+  EXPECT_EQ( GLenum(GL_INT),      ppca.VertexArray::generic[3].type );
+  EXPECT_EQ( GLuint( 0 ),         ppca.VertexArray::generic[3].relativeOffset );
+  EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::generic[3].normalized );
+  EXPECT_EQ( GLboolean(GL_TRUE),  ppca.VertexArray::generic[3].isInteger );
+  EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::generic[3].isLong );
+  EXPECT_EQ( GLuint(3),           ppca.VertexArray::generic[3].bindingIndex );
+
+  EXPECT_EQ( GLuint(987),   ppca.VertexArray::bindings[3].buffer );
+  EXPECT_EQ( GLintptr(654), ppca.VertexArray::bindings[3].offset );
+  EXPECT_EQ( GLsizei(456),  ppca.VertexArray::bindings[3].stride );
+  EXPECT_EQ( GLuint(0),     ppca.VertexArray::bindings[3].divisor );
+
+  ppca.Reset(ctx);
+  ppca.glVertexArrayVertexAttribIOffsetEXT( 0, 987, 3, 2, GL_INT, 0, 654 );
+
+  EXPECT_EQ( GLuint(2),           ppca.VertexArray::generic[3].size );
+  EXPECT_EQ( GLenum(GL_INT),      ppca.VertexArray::generic[3].type );
+  EXPECT_EQ( GLuint( 0 ),         ppca.VertexArray::generic[3].relativeOffset );
+  EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::generic[3].normalized );
+  EXPECT_EQ( GLboolean(GL_TRUE),  ppca.VertexArray::generic[3].isInteger );
+  EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::generic[3].isLong );
+  EXPECT_EQ( GLuint(3),           ppca.VertexArray::generic[3].bindingIndex );
+
+  EXPECT_EQ( GLuint(987),   ppca.VertexArray::bindings[3].buffer );
+  EXPECT_EQ( GLintptr(654), ppca.VertexArray::bindings[3].offset );
+  EXPECT_EQ( GLsizei(8),    ppca.VertexArray::bindings[3].stride );
+  EXPECT_EQ( GLuint(0),     ppca.VertexArray::bindings[3].divisor );
+
+  // EnableDisableVertexArrayAttribEXT
+
+  ppca.Reset(ctx);
+  ppca.glEnableVertexArrayAttribEXT( 0, 3 );
+
+  EXPECT_EQ( GLboolean( GL_TRUE ), ppca.VertexArray::generic [ 3 ].enabled );
+
+  ppca.glDisableVertexArrayAttribEXT( 0, 3 );
+
+  EXPECT_EQ( GLboolean( GL_FALSE ), ppca.VertexArray::generic [ 3 ].enabled );
+
+  // If the vertex array binding is nonzero, none of these calls should do
+  // anything (since we do not actually track internal state for vertex array
+  // objects.
+
+  ppca.Reset(ctx);
+  ppca.VertexArray::generic[ 3 ].relativeOffset = GLuint(123);
+  ppca.VertexArray::generic[ 3 ].bindingIndex = 4;
+  ppca.VertexArray::bindings[ 4 ].buffer = 456;
+  ppca.VertexArray::bindings[ 4 ].divisor = 789;
+
+  ppca.VertexArray::vertexArrayBinding = 1;
+
+  ppca.glVertexAttribFormat ( 3, 3, GL_FLOAT, GL_TRUE, 0 );
+  ppca.glVertexAttribIFormat( 3, 3, GL_INT, 0 );
+  ppca.glVertexAttribLFormat( 3, 3, GL_DOUBLE, 0 );
+  ppca.glBindVertexBuffer( 4, 0, 0, 0 );
+  ppca.glVertexAttribBinding( 3, 0 );
+  ppca.glVertexAttribPointer ( 3, 1, GL_FLOAT,  GL_TRUE, 0, NULL );
+  ppca.glVertexAttribIPointer( 3, 2, GL_INT,    0, NULL );
+  ppca.glVertexAttribLPointer( 3, 3, GL_DOUBLE, 0, NULL );
+  ppca.glVertexBindingDivisor( 4, 0 );
+  ppca.glVertexArrayVertexAttribOffsetEXT ( 1, 0, 3, 1, GL_FLOAT, GL_TRUE, 0, 0 );
+  ppca.glVertexArrayVertexAttribIOffsetEXT( 1, 0, 3, 2, GL_INT, 0, 0 );
+
+  EXPECT_EQ( GLuint(123), ppca.VertexArray::generic[3].relativeOffset );
+  EXPECT_EQ( GLuint(4),   ppca.VertexArray::generic[3].bindingIndex );
+  EXPECT_EQ( GLuint(456), ppca.VertexArray::bindings[4].buffer );
+  EXPECT_EQ( GLuint(789), ppca.VertexArray::bindings[4].divisor );
+
+  ppca.VertexArray::generic [ 3 ].enabled = GL_FALSE;
+  ppca.glEnableVertexAttribArray( 3 );
+  ppca.glEnableVertexArrayAttribEXT( 1, 3 );
+  EXPECT_EQ( GLboolean( GL_FALSE ), ppca.VertexArray::generic [ 3 ].enabled );
+
+  ppca.VertexArray::generic [ 3 ].enabled = GL_TRUE;
+  ppca.glDisableVertexAttribArray( 3 );
+  ppca.glDisableVertexArrayAttribEXT( 1, 3 );
+  EXPECT_EQ( GLboolean( GL_TRUE ), ppca.VertexArray::generic [ 3 ].enabled );
+}
+
+TEST ( RegalPpca, VertexArray_Named )
+{
+  RegalContext ctx;
+  ctx.info = new ContextInfo();
+
+  Ppca ppca;
+  checkPpcaDefaults(ctx, ppca);
+
+  ppca.glEnableClientState( GL_COLOR_ARRAY );
+  EXPECT_EQ( GLboolean( GL_TRUE ),  ppca.VertexArray::named[ ClientState::COLOR     ].enabled );
+
+  ppca.glDisableClientState( GL_COLOR_ARRAY );
+  EXPECT_EQ( GLboolean( GL_FALSE ),  ppca.VertexArray::named[ ClientState::COLOR     ].enabled );
+
+  EXPECT_EQ( GLenum( GL_TEXTURE0 ), ppca.VertexArray::clientActiveTexture );
+
+  ppca.glClientActiveTexture( GL_TEXTURE2 );
+  EXPECT_EQ( GLenum( GL_TEXTURE2 ), ppca.VertexArray::clientActiveTexture );
+
+  ppca.glEnableClientState( GL_TEXTURE_COORD_ARRAY );
+  EXPECT_EQ( GLboolean( GL_TRUE ),   ppca.VertexArray::named[ ClientState::TEX_COORD + 2 ].enabled );
+
+  ppca.glDisableClientState( GL_TEXTURE_COORD_ARRAY );
+  EXPECT_EQ( GLboolean( GL_FALSE ),  ppca.VertexArray::named[ ClientState::TEX_COORD + 2 ].enabled );
+
+  ppca.glEnableVertexArrayEXT( 0, GL_TEXTURE_COORD_ARRAY );
+  EXPECT_EQ( GLboolean( GL_TRUE ),   ppca.VertexArray::named[ ClientState::TEX_COORD + 2 ].enabled );
+
+  ppca.glDisableVertexArrayEXT( 0, GL_TEXTURE_COORD_ARRAY );
+  EXPECT_EQ( GLboolean( GL_FALSE ),  ppca.VertexArray::named[ ClientState::TEX_COORD + 2 ].enabled );
+
+  ppca.glEnableVertexArrayEXT( 1, GL_TEXTURE_COORD_ARRAY );
+  EXPECT_EQ( GLboolean( GL_FALSE ),  ppca.VertexArray::named[ ClientState::TEX_COORD + 2 ].enabled );
+
+  ppca.glDisableVertexArrayEXT( 1, GL_TEXTURE_COORD_ARRAY );
+  EXPECT_EQ( GLboolean( GL_FALSE ),  ppca.VertexArray::named[ ClientState::TEX_COORD + 2 ].enabled );
+
+  ppca.glEnableClientStateIndexedEXT( GL_TEXTURE_COORD_ARRAY, 5 );
+  EXPECT_EQ( GLboolean( GL_TRUE ),   ppca.VertexArray::named[ ClientState::TEX_COORD + 5 ].enabled );
+
+  ppca.glDisableClientStateIndexedEXT( GL_TEXTURE_COORD_ARRAY, 5 );
+  EXPECT_EQ( GLboolean( GL_FALSE ),  ppca.VertexArray::named[ ClientState::TEX_COORD + 5 ].enabled );
+
+  for (GLuint ii=0; ii<ClientState::nNamedArrays; ii++)
+  {
+    ppca.VertexArray::named[ii].enabled = GLboolean(GL_FALSE);
+    ppca.VertexArray::named[ii].pointer = reinterpret_cast<const GLvoid*>(ii);
+    ppca.VertexArray::named[ii].buffer  = GLuint(ii);
+    ppca.VertexArray::named[ii].size    = GLint(ii);
+    ppca.VertexArray::named[ii].type    = GLenum(ii);
+    ppca.VertexArray::named[ii].stride  = GLuint(ii);
+  }
+
+  ppca.VertexArray::arrayBufferBinding = 123;
+
+  ppca.glVertexPointer( 4, GL_FLOAT, 1001, NULL );
+  EXPECT_EQ( GLuint(123),        ppca.VertexArray::named[ ClientState::VERTEX ].buffer );
+  EXPECT_EQ( GLint(4),           ppca.VertexArray::named[ ClientState::VERTEX ].size );
+  EXPECT_EQ( GLenum( GL_FLOAT ), ppca.VertexArray::named[ ClientState::VERTEX ].type );
+  EXPECT_EQ( GLint(1001),        ppca.VertexArray::named[ ClientState::VERTEX ].stride );
+
+  ppca.glNormalPointer( GL_FLOAT, 1002, NULL );
+  EXPECT_EQ( GLuint(123),        ppca.VertexArray::named[ ClientState::NORMAL ].buffer );
+  EXPECT_EQ( GLint(3),           ppca.VertexArray::named[ ClientState::NORMAL ].size );
+  EXPECT_EQ( GLenum( GL_FLOAT ), ppca.VertexArray::named[ ClientState::NORMAL ].type );
+  EXPECT_EQ( GLint(1002),        ppca.VertexArray::named[ ClientState::NORMAL ].stride );
+
+  ppca.glColorPointer( 4, GL_FLOAT, 1003, NULL );
+  EXPECT_EQ( GLuint(123),        ppca.VertexArray::named[ ClientState::COLOR ].buffer );
+  EXPECT_EQ( GLint(4),           ppca.VertexArray::named[ ClientState::COLOR ].size );
+  EXPECT_EQ( GLenum( GL_FLOAT ), ppca.VertexArray::named[ ClientState::COLOR ].type );
+  EXPECT_EQ( GLint(1003),        ppca.VertexArray::named[ ClientState::COLOR ].stride );
+
+  ppca.glSecondaryColorPointer( 3, GL_FLOAT, 1004, NULL );
+  EXPECT_EQ( GLuint(123),        ppca.VertexArray::named[ ClientState::SECONDARY_COLOR ].buffer );
+  EXPECT_EQ( GLint(3),           ppca.VertexArray::named[ ClientState::SECONDARY_COLOR ].size );
+  EXPECT_EQ( GLenum( GL_FLOAT ), ppca.VertexArray::named[ ClientState::SECONDARY_COLOR ].type );
+  EXPECT_EQ( GLint(1004),        ppca.VertexArray::named[ ClientState::SECONDARY_COLOR ].stride );
+
+  ppca.glIndexPointer( GL_INT, 1005, NULL );
+  EXPECT_EQ( GLuint(123),        ppca.VertexArray::named[ ClientState::INDEX ].buffer );
+  EXPECT_EQ( GLint(1),           ppca.VertexArray::named[ ClientState::INDEX ].size );
+  EXPECT_EQ( GLenum( GL_INT ),   ppca.VertexArray::named[ ClientState::INDEX ].type );
+  EXPECT_EQ( GLint(1005),        ppca.VertexArray::named[ ClientState::INDEX ].stride );
+
+  ppca.glEdgeFlagPointer( 1006, NULL );
+  EXPECT_EQ( GLuint(123),        ppca.VertexArray::named[ ClientState::EDGE_FLAG ].buffer );
+  EXPECT_EQ( GLint(1),           ppca.VertexArray::named[ ClientState::EDGE_FLAG ].size );
+  EXPECT_EQ( GLenum( GL_BOOL ),  ppca.VertexArray::named[ ClientState::EDGE_FLAG ].type );
+  EXPECT_EQ( GLint(1006),        ppca.VertexArray::named[ ClientState::EDGE_FLAG ].stride );
+
+  ppca.glFogCoordPointer( GL_FLOAT, 1007, NULL );
+  EXPECT_EQ( GLuint(123),        ppca.VertexArray::named[ ClientState::FOG_COORD ].buffer );
+  EXPECT_EQ( GLint(1),           ppca.VertexArray::named[ ClientState::FOG_COORD ].size );
+  EXPECT_EQ( GLenum( GL_FLOAT ), ppca.VertexArray::named[ ClientState::FOG_COORD ].type );
+  EXPECT_EQ( GLint(1007),        ppca.VertexArray::named[ ClientState::FOG_COORD ].stride );
+
+  ppca.glTexCoordPointer( 2, GL_FLOAT, 1008, NULL );
+  EXPECT_EQ( GLuint(123),        ppca.VertexArray::named[ ClientState::TEX_COORD + 2].buffer );
+  EXPECT_EQ( GLint(2),           ppca.VertexArray::named[ ClientState::TEX_COORD + 2].size );
+  EXPECT_EQ( GLenum( GL_FLOAT ), ppca.VertexArray::named[ ClientState::TEX_COORD + 2].type );
+  EXPECT_EQ( GLint(1008),        ppca.VertexArray::named[ ClientState::TEX_COORD + 2].stride );
+
+  ppca.glMultiTexCoordPointerEXT( GL_TEXTURE5, 2, GL_FLOAT, 2005, NULL );
+  EXPECT_EQ( GLuint(123),        ppca.VertexArray::named[ ClientState::TEX_COORD + 5].buffer );
+  EXPECT_EQ( GLint(2),           ppca.VertexArray::named[ ClientState::TEX_COORD + 5].size );
+  EXPECT_EQ( GLenum( GL_FLOAT ), ppca.VertexArray::named[ ClientState::TEX_COORD + 5].type );
+  EXPECT_EQ( GLint(2005),        ppca.VertexArray::named[ ClientState::TEX_COORD + 5].stride );
+
+  ppca.glVertexArrayVertexOffsetEXT( 0, 3001, 3, GL_FLOAT, 3002, 0 );
+  EXPECT_EQ( GLuint(3001),       ppca.VertexArray::named[ ClientState::VERTEX ].buffer );
+  EXPECT_EQ( GLint(3),           ppca.VertexArray::named[ ClientState::VERTEX ].size );
+  EXPECT_EQ( GLenum( GL_FLOAT ), ppca.VertexArray::named[ ClientState::VERTEX ].type );
+  EXPECT_EQ( GLint(3002),        ppca.VertexArray::named[ ClientState::VERTEX ].stride );
+
+  ppca.glVertexArrayColorOffsetEXT ( 0, 3003, 4, GL_FLOAT, 3004, 0 );
+  EXPECT_EQ( GLuint(3003),       ppca.VertexArray::named[ ClientState::COLOR ].buffer );
+  EXPECT_EQ( GLint(4),           ppca.VertexArray::named[ ClientState::COLOR ].size );
+  EXPECT_EQ( GLenum( GL_FLOAT ), ppca.VertexArray::named[ ClientState::COLOR ].type );
+  EXPECT_EQ( GLint(3004),        ppca.VertexArray::named[ ClientState::COLOR ].stride );
+
+  ppca.glVertexArrayEdgeFlagOffsetEXT ( 0, 3005, 3006, 0 );
+  EXPECT_EQ( GLuint(3005),       ppca.VertexArray::named[ ClientState::EDGE_FLAG ].buffer );
+  EXPECT_EQ( GLint(1),           ppca.VertexArray::named[ ClientState::EDGE_FLAG ].size );
+  EXPECT_EQ( GLenum( GL_BOOL ),  ppca.VertexArray::named[ ClientState::EDGE_FLAG ].type );
+  EXPECT_EQ( GLint(3006),        ppca.VertexArray::named[ ClientState::EDGE_FLAG ].stride );
+
+  ppca.glVertexArrayIndexOffsetEXT ( 0, 3007, GL_INT, 3008, 0 );
+  EXPECT_EQ( GLuint(3007),       ppca.VertexArray::named[ ClientState::INDEX ].buffer );
+  EXPECT_EQ( GLint(1),           ppca.VertexArray::named[ ClientState::INDEX ].size );
+  EXPECT_EQ( GLenum( GL_INT ),   ppca.VertexArray::named[ ClientState::INDEX ].type );
+  EXPECT_EQ( GLint(3008),        ppca.VertexArray::named[ ClientState::INDEX ].stride );
+
+  ppca.glVertexArrayNormalOffsetEXT ( 0, 3009, GL_FLOAT, 3010, 0 );
+  EXPECT_EQ( GLuint(3009),       ppca.VertexArray::named[ ClientState::NORMAL ].buffer );
+  EXPECT_EQ( GLint(3),           ppca.VertexArray::named[ ClientState::NORMAL ].size );
+  EXPECT_EQ( GLenum( GL_FLOAT ), ppca.VertexArray::named[ ClientState::NORMAL ].type );
+  EXPECT_EQ( GLint(3010),        ppca.VertexArray::named[ ClientState::NORMAL ].stride );
+
+  ppca.glVertexArrayTexCoordOffsetEXT( 0, 3011, 2, GL_FLOAT, 3012, 0 );
+  EXPECT_EQ( GLuint(3011),       ppca.VertexArray::named[ ClientState::TEX_COORD + 2 ].buffer );
+  EXPECT_EQ( GLint(2),           ppca.VertexArray::named[ ClientState::TEX_COORD + 2 ].size );
+  EXPECT_EQ( GLenum( GL_FLOAT ), ppca.VertexArray::named[ ClientState::TEX_COORD + 2 ].type );
+  EXPECT_EQ( GLint(3012),        ppca.VertexArray::named[ ClientState::TEX_COORD + 2 ].stride );
+
+  ppca.glVertexArrayMultiTexCoordOffsetEXT( 0, 3013, GL_TEXTURE5, 2, GL_FLOAT, 3014, 0 );
+  EXPECT_EQ( GLuint(3013),       ppca.VertexArray::named[ ClientState::TEX_COORD + 5 ].buffer );
+  EXPECT_EQ( GLint(2),           ppca.VertexArray::named[ ClientState::TEX_COORD + 5 ].size );
+  EXPECT_EQ( GLenum( GL_FLOAT ), ppca.VertexArray::named[ ClientState::TEX_COORD + 5 ].type );
+  EXPECT_EQ( GLint(3014),        ppca.VertexArray::named[ ClientState::TEX_COORD + 5 ].stride );
+
+  ppca.glVertexArrayFogCoordOffsetEXT ( 0, 3015, GL_FLOAT, 3016, 0 );
+  EXPECT_EQ( GLuint(3015),       ppca.VertexArray::named[ ClientState::FOG_COORD ].buffer );
+  EXPECT_EQ( GLint(1),           ppca.VertexArray::named[ ClientState::FOG_COORD ].size );
+  EXPECT_EQ( GLenum( GL_FLOAT ), ppca.VertexArray::named[ ClientState::FOG_COORD ].type );
+  EXPECT_EQ( GLint(3016),        ppca.VertexArray::named[ ClientState::FOG_COORD ].stride );
+
+  ppca.glVertexArraySecondaryColorOffsetEXT ( 0, 3017, 3, GL_FLOAT, 3018, 0 );
+  EXPECT_EQ( GLuint(3017),       ppca.VertexArray::named[ ClientState::SECONDARY_COLOR ].buffer );
+  EXPECT_EQ( GLint(3),           ppca.VertexArray::named[ ClientState::SECONDARY_COLOR ].size );
+  EXPECT_EQ( GLenum( GL_FLOAT ), ppca.VertexArray::named[ ClientState::SECONDARY_COLOR ].type );
+  EXPECT_EQ( GLint(3018),        ppca.VertexArray::named[ ClientState::SECONDARY_COLOR ].stride );
+}
+
+TEST ( RegalPpca, glDeleteBuffers_Shadowing )
+{
+  RegalContext ctx;
+  ctx.info = new ContextInfo();
+
+  Ppca ppca;
+  checkPpcaDefaults(ctx, ppca);
+
+  GLuint buffers[ 2 ] = { 0, 123 };
+
+  for (GLuint ii=0; ii<REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS; ii++)
+  {
+    ppca.VertexArray::bindings[ii].buffer  = GLuint(123);
+  }
+  ppca.VertexArray::elementArrayBufferBinding = GLuint(123);
+  ppca.VertexArray::arrayBufferBinding = GLuint(123);
+  ppca.PixelStore::pixelPackBufferBinding = GLuint(123);
+  ppca.PixelStore::pixelUnpackBufferBinding = GLuint(123);
+
+  ppca.glDeleteBuffers( 2, buffers );
+
+  checkPpcaDefaults(ctx, ppca);
+
+  for (GLuint ii=0; ii<REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS; ii++)
+  {
+    ppca.VertexArray::bindings[ii].buffer  = GLuint(456);
+  }
+  ppca.VertexArray::elementArrayBufferBinding = GLuint(456);
+  ppca.VertexArray::arrayBufferBinding = GLuint(456);
+  ppca.PixelStore::pixelPackBufferBinding = GLuint(456);
+  ppca.PixelStore::pixelUnpackBufferBinding = GLuint(456);
+
+  ppca.glDeleteBuffers( 2, buffers );
+
+  for (GLuint ii=0; ii<REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS; ii++)
+  {
+    EXPECT_EQ( GLuint(456), ppca.VertexArray::bindings[ii].buffer );
+  }
+  EXPECT_EQ( GLuint(456), ppca.VertexArray::elementArrayBufferBinding );
+  EXPECT_EQ( GLuint(456), ppca.VertexArray::arrayBufferBinding );
+  EXPECT_EQ( GLuint(456), ppca.PixelStore::pixelPackBufferBinding );
+  EXPECT_EQ( GLuint(456), ppca.PixelStore::pixelUnpackBufferBinding );
+}
+
+TEST ( RegalPpca, glDeleteVertexArrays_Shadowing )
+{
+  RegalContext ctx;
+  ctx.info = new ContextInfo();
+
+  Ppca ppca;
+  checkPpcaDefaults(ctx, ppca);
+
+  GLuint buffers[ 2 ] = { 0, 123 };
+
+  ppca.VertexArray::vertexArrayBinding = 123;
+
+  ppca.glDeleteVertexArrays( 2, buffers );
+
+  EXPECT_EQ( GLuint(0), ppca.VertexArray::vertexArrayBinding );
+
+  ppca.VertexArray::vertexArrayBinding = 456;
+
+  ppca.glDeleteVertexArrays( 2, buffers );
+
+  EXPECT_EQ( GLuint(456), ppca.VertexArray::vertexArrayBinding );
+}
+
+TEST ( RegalPpca, glPrimitiveRestart_Shadowing )
+{
+  RegalContext ctx;
+  ctx.info = new ContextInfo();
+
+  Ppca ppca;
+  checkPpcaDefaults(ctx, ppca);
+
+  EXPECT_EQ( GLboolean(GL_FALSE), ppca.primitiveRestart );
+  EXPECT_EQ( GLboolean(GL_FALSE), ppca.primitiveRestartFixedIndex );
+  EXPECT_EQ( GLuint(0),           ppca.VertexArray::primitiveRestartIndex );
+
+  // test glEnable & glDisable
+
+  ppca.glEnable( GL_PRIMITIVE_RESTART );
+  EXPECT_EQ( GLboolean(GL_TRUE), ppca.VertexArray::primitiveRestart );
+  EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::primitiveRestartFixedIndex );
+  ppca.glDisable( GL_PRIMITIVE_RESTART );
+  EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::primitiveRestart );
+  EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::primitiveRestartFixedIndex );
+  ppca.glEnable( GL_PRIMITIVE_RESTART_FIXED_INDEX );
+  EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::primitiveRestart );
+  EXPECT_EQ( GLboolean(GL_TRUE), ppca.VertexArray::primitiveRestartFixedIndex );
+  ppca.glDisable( GL_PRIMITIVE_RESTART_FIXED_INDEX );
+  EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::primitiveRestart );
+  EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::primitiveRestartFixedIndex );
+
+  ppca.glEnable( GL_TEXTURE_GEN_S );
+  EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::primitiveRestart );
+  EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::primitiveRestartFixedIndex );
+  ppca.glDisable( GL_TEXTURE_GEN_S );
+  EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::primitiveRestart );
+  EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::primitiveRestartFixedIndex );
+  ppca.VertexArray::primitiveRestart = GL_TRUE;
+  ppca.VertexArray::primitiveRestartFixedIndex = GL_TRUE;
+  ppca.glEnable( GL_TEXTURE_GEN_S );
+  EXPECT_EQ( GLboolean(GL_TRUE), ppca.VertexArray::primitiveRestart );
+  EXPECT_EQ( GLboolean(GL_TRUE), ppca.VertexArray::primitiveRestartFixedIndex );
+  ppca.glDisable( GL_TEXTURE_GEN_S );
+  EXPECT_EQ( GLboolean(GL_TRUE), ppca.VertexArray::primitiveRestart );
+  EXPECT_EQ( GLboolean(GL_TRUE), ppca.VertexArray::primitiveRestartFixedIndex );
+
+  // test glEnablei & glDisablei
+
+  ppca.Reset(ctx);
+  checkPpcaDefaults(ctx, ppca);
+
+  ppca.glEnablei( GL_PRIMITIVE_RESTART, 0 );
+  EXPECT_EQ( GLboolean(GL_TRUE), ppca.VertexArray::primitiveRestart );
+  EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::primitiveRestartFixedIndex );
+  ppca.glDisablei( GL_PRIMITIVE_RESTART, 0 );
+  EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::primitiveRestart );
+  EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::primitiveRestartFixedIndex );
+  ppca.glEnablei( GL_PRIMITIVE_RESTART_FIXED_INDEX, 0 );
+  EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::primitiveRestart );
+  EXPECT_EQ( GLboolean(GL_TRUE), ppca.VertexArray::primitiveRestartFixedIndex );
+  ppca.glDisablei( GL_PRIMITIVE_RESTART_FIXED_INDEX, 0 );
+  EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::primitiveRestart );
+  EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::primitiveRestartFixedIndex );
+
+  ppca.glEnablei( GL_TEXTURE_GEN_S, 0 );
+  EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::primitiveRestart );
+  EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::primitiveRestartFixedIndex );
+  ppca.glDisablei( GL_TEXTURE_GEN_S, 0 );
+  EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::primitiveRestart );
+  EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::primitiveRestartFixedIndex );
+  ppca.VertexArray::primitiveRestart = GL_TRUE;
+  ppca.VertexArray::primitiveRestartFixedIndex = GL_TRUE;
+  ppca.glEnablei( GL_TEXTURE_GEN_S, 0 );
+  EXPECT_EQ( GLboolean(GL_TRUE), ppca.VertexArray::primitiveRestart );
+  EXPECT_EQ( GLboolean(GL_TRUE), ppca.VertexArray::primitiveRestartFixedIndex );
+  ppca.glDisablei( GL_TEXTURE_GEN_S, 0 );
+  EXPECT_EQ( GLboolean(GL_TRUE), ppca.VertexArray::primitiveRestart );
+  EXPECT_EQ( GLboolean(GL_TRUE), ppca.VertexArray::primitiveRestartFixedIndex );
+
+  // test glEnableIndexedEXT & glDisableIndexedEXT
+
+  ppca.Reset(ctx);
+  checkPpcaDefaults(ctx, ppca);
+
+  ppca.glEnableIndexedEXT( GL_PRIMITIVE_RESTART, 0 );
+  EXPECT_EQ( GLboolean(GL_TRUE), ppca.VertexArray::primitiveRestart );
+  EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::primitiveRestartFixedIndex );
+  ppca.glDisableIndexedEXT( GL_PRIMITIVE_RESTART, 0 );
+  EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::primitiveRestart );
+  EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::primitiveRestartFixedIndex );
+  ppca.glEnableIndexedEXT( GL_PRIMITIVE_RESTART_FIXED_INDEX, 0 );
+  EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::primitiveRestart );
+  EXPECT_EQ( GLboolean(GL_TRUE), ppca.VertexArray::primitiveRestartFixedIndex );
+  ppca.glDisableIndexedEXT( GL_PRIMITIVE_RESTART_FIXED_INDEX, 0 );
+  EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::primitiveRestart );
+  EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::primitiveRestartFixedIndex );
+
+  ppca.glEnableIndexedEXT( GL_TEXTURE_GEN_S, 0 );
+  EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::primitiveRestart );
+  EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::primitiveRestartFixedIndex );
+  ppca.glDisableIndexedEXT( GL_TEXTURE_GEN_S, 0 );
+  EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::primitiveRestart );
+  EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::primitiveRestartFixedIndex );
+  ppca.VertexArray::primitiveRestart = GL_TRUE;
+  ppca.VertexArray::primitiveRestartFixedIndex = GL_TRUE;
+  ppca.glEnableIndexedEXT( GL_TEXTURE_GEN_S, 0 );
+  EXPECT_EQ( GLboolean(GL_TRUE), ppca.VertexArray::primitiveRestart );
+  EXPECT_EQ( GLboolean(GL_TRUE), ppca.VertexArray::primitiveRestartFixedIndex );
+  ppca.glDisableIndexedEXT( GL_TEXTURE_GEN_S, 0 );
+  EXPECT_EQ( GLboolean(GL_TRUE), ppca.VertexArray::primitiveRestart );
+  EXPECT_EQ( GLboolean(GL_TRUE), ppca.VertexArray::primitiveRestartFixedIndex );
+
+  // test glPrimitiveRestartIndex
+
+  ppca.Reset(ctx);
+  checkPpcaDefaults(ctx, ppca);
+
+  for (GLuint ii=0; ii<13; ii++)
+  {
+    ppca.glPrimitiveRestartIndex( ii );
+    EXPECT_EQ( GLuint(ii), ppca.VertexArray::primitiveRestartIndex );
+  }
+
+  ppca.glPrimitiveRestartIndex( GLuint(~0) );
+  EXPECT_EQ( GLuint(~0), ppca.VertexArray::primitiveRestartIndex );
+}
+
+TEST ( RegalPpca, glInterleavedArrays_Shadowing )
+{
+  RegalContext ctx;
+  ctx.info = new ContextInfo();
+
+  Ppca ppca;
+  checkPpcaDefaults(ctx, ppca);
+
+  // Do a comprehensive test on all settings for GL_T4F_C4F_N3F_V4F
+
+  for (GLuint ii=0; ii<ClientState::nNamedArrays; ii++)
+  {
+    ppca.VertexArray::named[ ii ].enabled = GLboolean( ( ii & 1 ) == 0 );
+    ppca.VertexArray::named[ ii ].size    = GLint( 987 );
+    ppca.VertexArray::named[ ii ].type    = GLenum( 987 );
+    ppca.VertexArray::named[ ii ].stride  = GLint( 987 );
+    ppca.VertexArray::named[ ii ].pointer = reinterpret_cast<const GLvoid*>( 987 );
+  }
+
+  ppca.glClientActiveTexture( GL_TEXTURE5 );
+  ppca.glInterleavedArrays( GL_T4F_C4F_N3F_V4F, 0, NULL );
+
+  EXPECT_EQ( GLboolean( GL_TRUE ),  ppca.VertexArray::named[ ClientState::VERTEX ].enabled );
+  EXPECT_EQ( GLint( 4 ),            ppca.VertexArray::named[ ClientState::VERTEX ].size );
+  EXPECT_EQ( GLenum( GL_FLOAT ),    ppca.VertexArray::named[ ClientState::VERTEX ].type );
+  EXPECT_EQ( GLint( 60 ),           ppca.VertexArray::named[ ClientState::VERTEX ].stride );
+  EXPECT_EQ( reinterpret_cast<const GLvoid*>( 44 ), ppca.VertexArray::named[ ClientState::VERTEX ].pointer );
+
+  EXPECT_EQ( GLboolean( GL_TRUE ),  ppca.VertexArray::named[ ClientState::NORMAL ].enabled );
+  EXPECT_EQ( GLint( 3 ),            ppca.VertexArray::named[ ClientState::NORMAL ].size );
+  EXPECT_EQ( GLenum( GL_FLOAT ),    ppca.VertexArray::named[ ClientState::NORMAL ].type );
+  EXPECT_EQ( GLint( 60 ),           ppca.VertexArray::named[ ClientState::NORMAL ].stride );
+  EXPECT_EQ( reinterpret_cast<const GLvoid*>( 32 ), ppca.VertexArray::named[ ClientState::NORMAL ].pointer );
+
+  EXPECT_EQ( GLboolean( GL_TRUE ),  ppca.VertexArray::named[ ClientState::COLOR ].enabled );
+  EXPECT_EQ( GLint( 4 ),            ppca.VertexArray::named[ ClientState::COLOR ].size );
+  EXPECT_EQ( GLenum( GL_FLOAT ),    ppca.VertexArray::named[ ClientState::COLOR ].type );
+  EXPECT_EQ( GLint( 60 ),           ppca.VertexArray::named[ ClientState::COLOR ].stride );
+  EXPECT_EQ( reinterpret_cast<const GLvoid*>( 16 ), ppca.VertexArray::named[ ClientState::COLOR ].pointer );
+
+  EXPECT_EQ( GLboolean( GL_TRUE ),  ppca.VertexArray::named[ ClientState::TEX_COORD + 5 ].enabled );
+  EXPECT_EQ( GLint( 4 ),            ppca.VertexArray::named[ ClientState::TEX_COORD + 5 ].size );
+  EXPECT_EQ( GLenum( GL_FLOAT ),    ppca.VertexArray::named[ ClientState::TEX_COORD + 5 ].type );
+  EXPECT_EQ( GLint( 60 ),           ppca.VertexArray::named[ ClientState::TEX_COORD + 5 ].stride );
+  EXPECT_EQ( reinterpret_cast<const GLvoid*>( 0 ),  ppca.VertexArray::named[ ClientState::TEX_COORD + 5 ].pointer );
+
+  // The other non-texture coordinate arrays should be disabled
+
+  EXPECT_EQ( GLboolean( GL_FALSE ), ppca.VertexArray::named[ ClientState::EDGE_FLAG       ].enabled );
+  EXPECT_EQ( GLboolean( GL_FALSE ), ppca.VertexArray::named[ ClientState::FOG_COORD       ].enabled );
+  EXPECT_EQ( GLboolean( GL_FALSE ), ppca.VertexArray::named[ ClientState::INDEX           ].enabled );
+  EXPECT_EQ( GLboolean( GL_FALSE ), ppca.VertexArray::named[ ClientState::SECONDARY_COLOR ].enabled );
+
+  // The other non-texture coordinate arrays should not otherwise be touched.
+
+  EXPECT_EQ( GLint( 987 ),           ppca.VertexArray::named[ ClientState::EDGE_FLAG       ].size );
+  EXPECT_EQ( GLenum( 987 ),          ppca.VertexArray::named[ ClientState::EDGE_FLAG       ].type );
+  EXPECT_EQ( GLint( 987 ),           ppca.VertexArray::named[ ClientState::EDGE_FLAG       ].stride );
+  EXPECT_EQ( reinterpret_cast<const GLvoid*>( 987 ), ppca.VertexArray::named[ ClientState::EDGE_FLAG       ].pointer );
+
+  EXPECT_EQ( GLint( 987 ),           ppca.VertexArray::named[ ClientState::FOG_COORD       ].size );
+  EXPECT_EQ( GLenum( 987 ),          ppca.VertexArray::named[ ClientState::FOG_COORD       ].type );
+  EXPECT_EQ( GLint( 987 ),           ppca.VertexArray::named[ ClientState::FOG_COORD       ].stride );
+  EXPECT_EQ( reinterpret_cast<const GLvoid*>( 987 ), ppca.VertexArray::named[ ClientState::FOG_COORD       ].pointer );
+
+  EXPECT_EQ( GLint( 987 ),           ppca.VertexArray::named[ ClientState::INDEX           ].size );
+  EXPECT_EQ( GLenum( 987 ),          ppca.VertexArray::named[ ClientState::INDEX           ].type );
+  EXPECT_EQ( GLint( 987 ),           ppca.VertexArray::named[ ClientState::INDEX           ].stride );
+  EXPECT_EQ( reinterpret_cast<const GLvoid*>( 987 ), ppca.VertexArray::named[ ClientState::INDEX           ].pointer );
+
+  EXPECT_EQ( GLint( 987 ),           ppca.VertexArray::named[ ClientState::SECONDARY_COLOR ].size );
+  EXPECT_EQ( GLenum( 987 ),          ppca.VertexArray::named[ ClientState::SECONDARY_COLOR ].type );
+  EXPECT_EQ( GLint( 987 ),           ppca.VertexArray::named[ ClientState::SECONDARY_COLOR ].stride );
+  EXPECT_EQ( reinterpret_cast<const GLvoid*>( 987 ), ppca.VertexArray::named[ ClientState::SECONDARY_COLOR ].pointer );
+
+  // Verify other texture coordinate settings unaffected.
+
+  for (GLuint ii=0; ii<REGAL_EMU_MAX_TEXTURE_COORDS; ii++)
+  {
+    if ( ii == 5 )
+      continue;
+
+    GLboolean b = ( ( ( ClientState::TEX_COORD + ii ) & 1 ) == 0 ) ? GL_TRUE : GL_FALSE;
+
+    EXPECT_EQ( GLboolean( b ),         ppca.VertexArray::named[ ClientState::TEX_COORD + ii ].enabled );
+    EXPECT_EQ( GLint( 987 ),           ppca.VertexArray::named[ ClientState::TEX_COORD + ii ].size );
+    EXPECT_EQ( GLenum( 987 ),          ppca.VertexArray::named[ ClientState::TEX_COORD + ii ].type );
+    EXPECT_EQ( GLint( 987 ),           ppca.VertexArray::named[ ClientState::TEX_COORD + ii ].stride );
+    EXPECT_EQ( reinterpret_cast<const GLvoid*>( 987 ), ppca.VertexArray::named[ ClientState::TEX_COORD + ii ].pointer );
+  }
+
+  // Ensure if stride is nonzero, it is used as is, and ensure the pointer passed in is used as a base address.
+
+  ppca.Reset(ctx);
+  checkPpcaDefaults(ctx, ppca);
+
+  ppca.glClientActiveTexture( GL_TEXTURE5 );
+  ppca.glInterleavedArrays( GL_T4F_C4F_N3F_V4F, 321, reinterpret_cast<GLvoid *>( 5000 ) );
+
+  EXPECT_EQ( GLint( 321 ),            ppca.VertexArray::named[ ClientState::VERTEX        ].stride );
+  EXPECT_EQ( reinterpret_cast<const GLvoid*>( 5044 ), ppca.VertexArray::named[ ClientState::VERTEX        ].pointer );
+  EXPECT_EQ( GLint( 321 ),            ppca.VertexArray::named[ ClientState::NORMAL        ].stride );
+  EXPECT_EQ( reinterpret_cast<const GLvoid*>( 5032 ), ppca.VertexArray::named[ ClientState::NORMAL        ].pointer );
+  EXPECT_EQ( GLint( 321 ),            ppca.VertexArray::named[ ClientState::COLOR         ].stride );
+  EXPECT_EQ( reinterpret_cast<const GLvoid*>( 5016 ), ppca.VertexArray::named[ ClientState::COLOR         ].pointer );
+  EXPECT_EQ( GLint( 321 ),            ppca.VertexArray::named[ ClientState::TEX_COORD + 5 ].stride );
+  EXPECT_EQ( reinterpret_cast<const GLvoid*>( 5000 ), ppca.VertexArray::named[ ClientState::TEX_COORD + 5 ].pointer );
+
+  // Do a quick run through the remaining formats, and do some quick verifications.
+
+  ppca.Reset(ctx);
+  checkPpcaDefaults(ctx, ppca);
+
+  ppca.glInterleavedArrays( GL_V2F, 0, NULL );
+
+  EXPECT_EQ( GLboolean( GL_TRUE ),  ppca.VertexArray::named[ ClientState::VERTEX    ].enabled );
+  EXPECT_EQ( GLboolean( GL_FALSE ), ppca.VertexArray::named[ ClientState::NORMAL    ].enabled );
+  EXPECT_EQ( GLboolean( GL_FALSE ), ppca.VertexArray::named[ ClientState::COLOR     ].enabled );
+  EXPECT_EQ( GLboolean( GL_FALSE ), ppca.VertexArray::named[ ClientState::TEX_COORD ].enabled );
+
+  EXPECT_EQ( GLint( 2 ),            ppca.VertexArray::named[ ClientState::VERTEX    ].size );
+  EXPECT_EQ( GLint( 3 ),            ppca.VertexArray::named[ ClientState::NORMAL    ].size );
+  EXPECT_EQ( GLint( 4 ),            ppca.VertexArray::named[ ClientState::COLOR     ].size );
+  EXPECT_EQ( GLint( 4 ),            ppca.VertexArray::named[ ClientState::TEX_COORD ].size );
+
+  EXPECT_EQ( GLenum( GL_FLOAT ),    ppca.VertexArray::named[ ClientState::VERTEX    ].type );
+  EXPECT_EQ( GLenum( GL_FLOAT ),    ppca.VertexArray::named[ ClientState::NORMAL    ].type );
+  EXPECT_EQ( GLenum( GL_FLOAT ),    ppca.VertexArray::named[ ClientState::COLOR     ].type );
+  EXPECT_EQ( GLenum( GL_FLOAT ),    ppca.VertexArray::named[ ClientState::TEX_COORD ].type );
+
+  EXPECT_EQ( GLint( 8 ),            ppca.VertexArray::named[ ClientState::VERTEX    ].stride );
+  EXPECT_EQ( GLint( 0 ),            ppca.VertexArray::named[ ClientState::NORMAL    ].stride );
+  EXPECT_EQ( GLint( 0 ),            ppca.VertexArray::named[ ClientState::COLOR     ].stride );
+  EXPECT_EQ( GLint( 0 ),            ppca.VertexArray::named[ ClientState::TEX_COORD ].stride );
+
+  EXPECT_EQ( reinterpret_cast<const GLvoid*>( 0 ),  ppca.VertexArray::named[ ClientState::VERTEX    ].pointer );
+  EXPECT_EQ( reinterpret_cast<const GLvoid*>( 0 ),  ppca.VertexArray::named[ ClientState::NORMAL    ].pointer );
+  EXPECT_EQ( reinterpret_cast<const GLvoid*>( 0 ),  ppca.VertexArray::named[ ClientState::COLOR     ].pointer );
+  EXPECT_EQ( reinterpret_cast<const GLvoid*>( 0 ),  ppca.VertexArray::named[ ClientState::TEX_COORD ].pointer );
+
+  ppca.Reset(ctx);
+  checkPpcaDefaults(ctx, ppca);
+
+  ppca.glInterleavedArrays( GL_V3F, 0, NULL );
+
+  EXPECT_EQ( GLboolean( GL_TRUE ),  ppca.VertexArray::named[ ClientState::VERTEX    ].enabled );
+  EXPECT_EQ( GLboolean( GL_FALSE ), ppca.VertexArray::named[ ClientState::NORMAL    ].enabled );
+  EXPECT_EQ( GLboolean( GL_FALSE ), ppca.VertexArray::named[ ClientState::COLOR     ].enabled );
+  EXPECT_EQ( GLboolean( GL_FALSE ), ppca.VertexArray::named[ ClientState::TEX_COORD ].enabled );
+
+  EXPECT_EQ( GLint( 3 ),            ppca.VertexArray::named[ ClientState::VERTEX    ].size );
+  EXPECT_EQ( GLint( 3 ),            ppca.VertexArray::named[ ClientState::NORMAL    ].size );
+  EXPECT_EQ( GLint( 4 ),            ppca.VertexArray::named[ ClientState::COLOR     ].size );
+  EXPECT_EQ( GLint( 4 ),            ppca.VertexArray::named[ ClientState::TEX_COORD ].size );
+
+  EXPECT_EQ( GLenum( GL_FLOAT ),    ppca.VertexArray::named[ ClientState::VERTEX    ].type );
+  EXPECT_EQ( GLenum( GL_FLOAT ),    ppca.VertexArray::named[ ClientState::NORMAL    ].type );
+  EXPECT_EQ( GLenum( GL_FLOAT ),    ppca.VertexArray::named[ ClientState::COLOR     ].type );
+  EXPECT_EQ( GLenum( GL_FLOAT ),    ppca.VertexArray::named[ ClientState::TEX_COORD ].type );
+
+  EXPECT_EQ( GLint( 12 ),           ppca.VertexArray::named[ ClientState::VERTEX    ].stride );
+  EXPECT_EQ( GLint( 0 ),            ppca.VertexArray::named[ ClientState::NORMAL    ].stride );
+  EXPECT_EQ( GLint( 0 ),            ppca.VertexArray::named[ ClientState::COLOR     ].stride );
+  EXPECT_EQ( GLint( 0 ),            ppca.VertexArray::named[ ClientState::TEX_COORD ].stride );
+
+  EXPECT_EQ( reinterpret_cast<const GLvoid*>( 0 ),  ppca.VertexArray::named[ ClientState::VERTEX    ].pointer );
+  EXPECT_EQ( reinterpret_cast<const GLvoid*>( 0 ),  ppca.VertexArray::named[ ClientState::NORMAL    ].pointer );
+  EXPECT_EQ( reinterpret_cast<const GLvoid*>( 0 ),  ppca.VertexArray::named[ ClientState::COLOR     ].pointer );
+  EXPECT_EQ( reinterpret_cast<const GLvoid*>( 0 ),  ppca.VertexArray::named[ ClientState::TEX_COORD ].pointer );
+
+  ppca.Reset(ctx);
+  checkPpcaDefaults(ctx, ppca);
+
+  ppca.glInterleavedArrays( GL_C4UB_V2F, 0, NULL );
+
+  EXPECT_EQ( GLboolean( GL_TRUE ),  ppca.VertexArray::named[ ClientState::VERTEX    ].enabled );
+  EXPECT_EQ( GLboolean( GL_FALSE ), ppca.VertexArray::named[ ClientState::NORMAL    ].enabled );
+  EXPECT_EQ( GLboolean( GL_TRUE ),  ppca.VertexArray::named[ ClientState::COLOR     ].enabled );
+  EXPECT_EQ( GLboolean( GL_FALSE ), ppca.VertexArray::named[ ClientState::TEX_COORD ].enabled );
+
+  EXPECT_EQ( GLint( 2 ),            ppca.VertexArray::named[ ClientState::VERTEX    ].size );
+  EXPECT_EQ( GLint( 3 ),            ppca.VertexArray::named[ ClientState::NORMAL    ].size );
+  EXPECT_EQ( GLint( 4 ),            ppca.VertexArray::named[ ClientState::COLOR     ].size );
+  EXPECT_EQ( GLint( 4 ),            ppca.VertexArray::named[ ClientState::TEX_COORD ].size );
+
+  EXPECT_EQ( GLenum( GL_FLOAT ),    ppca.VertexArray::named[ ClientState::VERTEX    ].type );
+  EXPECT_EQ( GLenum( GL_FLOAT ),    ppca.VertexArray::named[ ClientState::NORMAL    ].type );
+  EXPECT_EQ( GLenum( GL_UNSIGNED_BYTE ), ppca.VertexArray::named[ ClientState::COLOR     ].type );
+  EXPECT_EQ( GLenum( GL_FLOAT ),    ppca.VertexArray::named[ ClientState::TEX_COORD ].type );
+
+  EXPECT_EQ( GLint( 12 ),           ppca.VertexArray::named[ ClientState::VERTEX    ].stride );
+  EXPECT_EQ( GLint( 0 ),            ppca.VertexArray::named[ ClientState::NORMAL    ].stride );
+  EXPECT_EQ( GLint( 12 ),           ppca.VertexArray::named[ ClientState::COLOR     ].stride );
+  EXPECT_EQ( GLint( 0 ),            ppca.VertexArray::named[ ClientState::TEX_COORD ].stride );
+
+  EXPECT_EQ( reinterpret_cast<const GLvoid*>( 4 ),  ppca.VertexArray::named[ ClientState::VERTEX    ].pointer );
+  EXPECT_EQ( reinterpret_cast<const GLvoid*>( 0 ),  ppca.VertexArray::named[ ClientState::NORMAL    ].pointer );
+  EXPECT_EQ( reinterpret_cast<const GLvoid*>( 0 ),  ppca.VertexArray::named[ ClientState::COLOR     ].pointer );
+  EXPECT_EQ( reinterpret_cast<const GLvoid*>( 0 ),  ppca.VertexArray::named[ ClientState::TEX_COORD ].pointer );
+
+  ppca.Reset(ctx);
+  checkPpcaDefaults(ctx, ppca);
+
+  ppca.glInterleavedArrays( GL_C4UB_V3F, 0, NULL );
+
+  EXPECT_EQ( GLboolean( GL_TRUE ),  ppca.VertexArray::named[ ClientState::VERTEX    ].enabled );
+  EXPECT_EQ( GLboolean( GL_FALSE ), ppca.VertexArray::named[ ClientState::NORMAL    ].enabled );
+  EXPECT_EQ( GLboolean( GL_TRUE ),  ppca.VertexArray::named[ ClientState::COLOR     ].enabled );
+  EXPECT_EQ( GLboolean( GL_FALSE ), ppca.VertexArray::named[ ClientState::TEX_COORD ].enabled );
+
+  EXPECT_EQ( GLint( 3 ),            ppca.VertexArray::named[ ClientState::VERTEX    ].size );
+  EXPECT_EQ( GLint( 3 ),            ppca.VertexArray::named[ ClientState::NORMAL    ].size );
+  EXPECT_EQ( GLint( 4 ),            ppca.VertexArray::named[ ClientState::COLOR     ].size );
+  EXPECT_EQ( GLint( 4 ),            ppca.VertexArray::named[ ClientState::TEX_COORD ].size );
+
+  EXPECT_EQ( GLenum( GL_FLOAT ),    ppca.VertexArray::named[ ClientState::VERTEX    ].type );
+  EXPECT_EQ( GLenum( GL_FLOAT ),    ppca.VertexArray::named[ ClientState::NORMAL    ].type );
+  EXPECT_EQ( GLenum( GL_UNSIGNED_BYTE ), ppca.VertexArray::named[ ClientState::COLOR     ].type );
+  EXPECT_EQ( GLenum( GL_FLOAT ),    ppca.VertexArray::named[ ClientState::TEX_COORD ].type );
+
+  EXPECT_EQ( GLint( 16 ),           ppca.VertexArray::named[ ClientState::VERTEX    ].stride );
+  EXPECT_EQ( GLint( 0 ),            ppca.VertexArray::named[ ClientState::NORMAL    ].stride );
+  EXPECT_EQ( GLint( 16 ),           ppca.VertexArray::named[ ClientState::COLOR     ].stride );
+  EXPECT_EQ( GLint( 0 ),            ppca.VertexArray::named[ ClientState::TEX_COORD ].stride );
+
+  EXPECT_EQ( reinterpret_cast<const GLvoid*>( 4 ),  ppca.VertexArray::named[ ClientState::VERTEX    ].pointer );
+  EXPECT_EQ( reinterpret_cast<const GLvoid*>( 0 ),  ppca.VertexArray::named[ ClientState::NORMAL    ].pointer );
+  EXPECT_EQ( reinterpret_cast<const GLvoid*>( 0 ),  ppca.VertexArray::named[ ClientState::COLOR     ].pointer );
+  EXPECT_EQ( reinterpret_cast<const GLvoid*>( 0 ),  ppca.VertexArray::named[ ClientState::TEX_COORD ].pointer );
+
+  ppca.Reset(ctx);
+  checkPpcaDefaults(ctx, ppca);
+
+  ppca.glInterleavedArrays( GL_C3F_V3F, 0, NULL );
+
+  EXPECT_EQ( GLboolean( GL_TRUE ),  ppca.VertexArray::named[ ClientState::VERTEX    ].enabled );
+  EXPECT_EQ( GLboolean( GL_FALSE ), ppca.VertexArray::named[ ClientState::NORMAL    ].enabled );
+  EXPECT_EQ( GLboolean( GL_TRUE ),  ppca.VertexArray::named[ ClientState::COLOR     ].enabled );
+  EXPECT_EQ( GLboolean( GL_FALSE ), ppca.VertexArray::named[ ClientState::TEX_COORD ].enabled );
+
+  EXPECT_EQ( GLint( 3 ),            ppca.VertexArray::named[ ClientState::VERTEX    ].size );
+  EXPECT_EQ( GLint( 3 ),            ppca.VertexArray::named[ ClientState::NORMAL    ].size );
+  EXPECT_EQ( GLint( 3 ),            ppca.VertexArray::named[ ClientState::COLOR     ].size );
+  EXPECT_EQ( GLint( 4 ),            ppca.VertexArray::named[ ClientState::TEX_COORD ].size );
+
+  EXPECT_EQ( GLenum( GL_FLOAT ),    ppca.VertexArray::named[ ClientState::VERTEX    ].type );
+  EXPECT_EQ( GLenum( GL_FLOAT ),    ppca.VertexArray::named[ ClientState::NORMAL    ].type );
+  EXPECT_EQ( GLenum( GL_FLOAT ),    ppca.VertexArray::named[ ClientState::COLOR     ].type );
+  EXPECT_EQ( GLenum( GL_FLOAT ),    ppca.VertexArray::named[ ClientState::TEX_COORD ].type );
+
+  EXPECT_EQ( GLint( 24 ),           ppca.VertexArray::named[ ClientState::VERTEX    ].stride );
+  EXPECT_EQ( GLint( 0 ),            ppca.VertexArray::named[ ClientState::NORMAL    ].stride );
+  EXPECT_EQ( GLint( 24 ),           ppca.VertexArray::named[ ClientState::COLOR     ].stride );
+  EXPECT_EQ( GLint( 0 ),            ppca.VertexArray::named[ ClientState::TEX_COORD ].stride );
+
+  EXPECT_EQ( reinterpret_cast<const GLvoid*>( 12 ), ppca.VertexArray::named[ ClientState::VERTEX    ].pointer );
+  EXPECT_EQ( reinterpret_cast<const GLvoid*>( 0 ),  ppca.VertexArray::named[ ClientState::NORMAL    ].pointer );
+  EXPECT_EQ( reinterpret_cast<const GLvoid*>( 0 ),  ppca.VertexArray::named[ ClientState::COLOR     ].pointer );
+  EXPECT_EQ( reinterpret_cast<const GLvoid*>( 0 ),  ppca.VertexArray::named[ ClientState::TEX_COORD ].pointer );
+
+  ppca.Reset(ctx);
+  checkPpcaDefaults(ctx, ppca);
+
+  ppca.glInterleavedArrays( GL_N3F_V3F, 0, NULL );
+
+  EXPECT_EQ( GLboolean( GL_TRUE ),  ppca.VertexArray::named[ ClientState::VERTEX    ].enabled );
+  EXPECT_EQ( GLboolean( GL_TRUE ),  ppca.VertexArray::named[ ClientState::NORMAL    ].enabled );
+  EXPECT_EQ( GLboolean( GL_FALSE ), ppca.VertexArray::named[ ClientState::COLOR     ].enabled );
+  EXPECT_EQ( GLboolean( GL_FALSE ), ppca.VertexArray::named[ ClientState::TEX_COORD ].enabled );
+
+  EXPECT_EQ( GLint( 3 ),            ppca.VertexArray::named[ ClientState::VERTEX    ].size );
+  EXPECT_EQ( GLint( 3 ),            ppca.VertexArray::named[ ClientState::NORMAL    ].size );
+  EXPECT_EQ( GLint( 4 ),            ppca.VertexArray::named[ ClientState::COLOR     ].size );
+  EXPECT_EQ( GLint( 4 ),            ppca.VertexArray::named[ ClientState::TEX_COORD ].size );
+
+  EXPECT_EQ( GLenum( GL_FLOAT ),    ppca.VertexArray::named[ ClientState::VERTEX    ].type );
+  EXPECT_EQ( GLenum( GL_FLOAT ),    ppca.VertexArray::named[ ClientState::NORMAL    ].type );
+  EXPECT_EQ( GLenum( GL_FLOAT ),    ppca.VertexArray::named[ ClientState::COLOR     ].type );
+  EXPECT_EQ( GLenum( GL_FLOAT ),    ppca.VertexArray::named[ ClientState::TEX_COORD ].type );
+
+  EXPECT_EQ( GLint( 24 ),           ppca.VertexArray::named[ ClientState::VERTEX    ].stride );
+  EXPECT_EQ( GLint( 24 ),           ppca.VertexArray::named[ ClientState::NORMAL    ].stride );
+  EXPECT_EQ( GLint( 0 ),            ppca.VertexArray::named[ ClientState::COLOR     ].stride );
+  EXPECT_EQ( GLint( 0 ),            ppca.VertexArray::named[ ClientState::TEX_COORD ].stride );
+
+  EXPECT_EQ( reinterpret_cast<const GLvoid*>( 12 ), ppca.VertexArray::named[ ClientState::VERTEX    ].pointer );
+  EXPECT_EQ( reinterpret_cast<const GLvoid*>( 0 ),  ppca.VertexArray::named[ ClientState::NORMAL    ].pointer );
+  EXPECT_EQ( reinterpret_cast<const GLvoid*>( 0 ),  ppca.VertexArray::named[ ClientState::COLOR     ].pointer );
+  EXPECT_EQ( reinterpret_cast<const GLvoid*>( 0 ),  ppca.VertexArray::named[ ClientState::TEX_COORD ].pointer );
+
+  ppca.Reset(ctx);
+  checkPpcaDefaults(ctx, ppca);
+
+  ppca.glInterleavedArrays( GL_C4F_N3F_V3F, 0, NULL );
+
+  EXPECT_EQ( GLboolean( GL_TRUE ),  ppca.VertexArray::named[ ClientState::VERTEX    ].enabled );
+  EXPECT_EQ( GLboolean( GL_TRUE ),  ppca.VertexArray::named[ ClientState::NORMAL    ].enabled );
+  EXPECT_EQ( GLboolean( GL_TRUE ),  ppca.VertexArray::named[ ClientState::COLOR     ].enabled );
+  EXPECT_EQ( GLboolean( GL_FALSE ), ppca.VertexArray::named[ ClientState::TEX_COORD ].enabled );
+
+  EXPECT_EQ( GLint( 3 ),            ppca.VertexArray::named[ ClientState::VERTEX    ].size );
+  EXPECT_EQ( GLint( 3 ),            ppca.VertexArray::named[ ClientState::NORMAL    ].size );
+  EXPECT_EQ( GLint( 4 ),            ppca.VertexArray::named[ ClientState::COLOR     ].size );
+  EXPECT_EQ( GLint( 4 ),            ppca.VertexArray::named[ ClientState::TEX_COORD ].size );
+
+  EXPECT_EQ( GLenum( GL_FLOAT ),    ppca.VertexArray::named[ ClientState::VERTEX    ].type );
+  EXPECT_EQ( GLenum( GL_FLOAT ),    ppca.VertexArray::named[ ClientState::NORMAL    ].type );
+  EXPECT_EQ( GLenum( GL_FLOAT ),    ppca.VertexArray::named[ ClientState::COLOR     ].type );
+  EXPECT_EQ( GLenum( GL_FLOAT ),    ppca.VertexArray::named[ ClientState::TEX_COORD ].type );
+
+  EXPECT_EQ( GLint( 40 ),           ppca.VertexArray::named[ ClientState::VERTEX    ].stride );
+  EXPECT_EQ( GLint( 40 ),           ppca.VertexArray::named[ ClientState::NORMAL    ].stride );
+  EXPECT_EQ( GLint( 40 ),           ppca.VertexArray::named[ ClientState::COLOR     ].stride );
+  EXPECT_EQ( GLint( 0 ),            ppca.VertexArray::named[ ClientState::TEX_COORD ].stride );
+
+  EXPECT_EQ( reinterpret_cast<const GLvoid*>( 28 ), ppca.VertexArray::named[ ClientState::VERTEX    ].pointer );
+  EXPECT_EQ( reinterpret_cast<const GLvoid*>( 16 ), ppca.VertexArray::named[ ClientState::NORMAL    ].pointer );
+  EXPECT_EQ( reinterpret_cast<const GLvoid*>( 0 ),  ppca.VertexArray::named[ ClientState::COLOR     ].pointer );
+  EXPECT_EQ( reinterpret_cast<const GLvoid*>( 0 ),  ppca.VertexArray::named[ ClientState::TEX_COORD ].pointer );
+
+  ppca.Reset(ctx);
+  checkPpcaDefaults(ctx, ppca);
+
+  ppca.glInterleavedArrays( GL_T2F_V3F, 0, NULL );
+
+  EXPECT_EQ( GLboolean( GL_TRUE ),  ppca.VertexArray::named[ ClientState::VERTEX    ].enabled );
+  EXPECT_EQ( GLboolean( GL_FALSE ), ppca.VertexArray::named[ ClientState::NORMAL    ].enabled );
+  EXPECT_EQ( GLboolean( GL_FALSE ), ppca.VertexArray::named[ ClientState::COLOR     ].enabled );
+  EXPECT_EQ( GLboolean( GL_TRUE ),  ppca.VertexArray::named[ ClientState::TEX_COORD ].enabled );
+
+  EXPECT_EQ( GLint( 3 ),            ppca.VertexArray::named[ ClientState::VERTEX    ].size );
+  EXPECT_EQ( GLint( 3 ),            ppca.VertexArray::named[ ClientState::NORMAL    ].size );
+  EXPECT_EQ( GLint( 4 ),            ppca.VertexArray::named[ ClientState::COLOR     ].size );
+  EXPECT_EQ( GLint( 2 ),            ppca.VertexArray::named[ ClientState::TEX_COORD ].size );
+
+  EXPECT_EQ( GLenum( GL_FLOAT ),    ppca.VertexArray::named[ ClientState::VERTEX    ].type );
+  EXPECT_EQ( GLenum( GL_FLOAT ),    ppca.VertexArray::named[ ClientState::NORMAL    ].type );
+  EXPECT_EQ( GLenum( GL_FLOAT ),    ppca.VertexArray::named[ ClientState::COLOR     ].type );
+  EXPECT_EQ( GLenum( GL_FLOAT ),    ppca.VertexArray::named[ ClientState::TEX_COORD ].type );
+
+  EXPECT_EQ( GLint( 20 ),           ppca.VertexArray::named[ ClientState::VERTEX    ].stride );
+  EXPECT_EQ( GLint( 0 ),            ppca.VertexArray::named[ ClientState::NORMAL    ].stride );
+  EXPECT_EQ( GLint( 0 ),            ppca.VertexArray::named[ ClientState::COLOR     ].stride );
+  EXPECT_EQ( GLint( 20 ),           ppca.VertexArray::named[ ClientState::TEX_COORD ].stride );
+
+  EXPECT_EQ( reinterpret_cast<const GLvoid*>( 8 ),  ppca.VertexArray::named[ ClientState::VERTEX    ].pointer );
+  EXPECT_EQ( reinterpret_cast<const GLvoid*>( 0 ),  ppca.VertexArray::named[ ClientState::NORMAL    ].pointer );
+  EXPECT_EQ( reinterpret_cast<const GLvoid*>( 0 ),  ppca.VertexArray::named[ ClientState::COLOR     ].pointer );
+  EXPECT_EQ( reinterpret_cast<const GLvoid*>( 0 ),  ppca.VertexArray::named[ ClientState::TEX_COORD ].pointer );
+
+  ppca.Reset(ctx);
+  checkPpcaDefaults(ctx, ppca);
+
+  ppca.glInterleavedArrays( GL_T4F_V4F, 0, NULL );
+
+  EXPECT_EQ( GLboolean( GL_TRUE ),  ppca.VertexArray::named[ ClientState::VERTEX    ].enabled );
+  EXPECT_EQ( GLboolean( GL_FALSE ), ppca.VertexArray::named[ ClientState::NORMAL    ].enabled );
+  EXPECT_EQ( GLboolean( GL_FALSE ), ppca.VertexArray::named[ ClientState::COLOR     ].enabled );
+  EXPECT_EQ( GLboolean( GL_TRUE ),  ppca.VertexArray::named[ ClientState::TEX_COORD ].enabled );
+
+  EXPECT_EQ( GLint( 4 ),            ppca.VertexArray::named[ ClientState::VERTEX    ].size );
+  EXPECT_EQ( GLint( 3 ),            ppca.VertexArray::named[ ClientState::NORMAL    ].size );
+  EXPECT_EQ( GLint( 4 ),            ppca.VertexArray::named[ ClientState::COLOR     ].size );
+  EXPECT_EQ( GLint( 4 ),            ppca.VertexArray::named[ ClientState::TEX_COORD ].size );
+
+  EXPECT_EQ( GLenum( GL_FLOAT ),    ppca.VertexArray::named[ ClientState::VERTEX    ].type );
+  EXPECT_EQ( GLenum( GL_FLOAT ),    ppca.VertexArray::named[ ClientState::NORMAL    ].type );
+  EXPECT_EQ( GLenum( GL_FLOAT ),    ppca.VertexArray::named[ ClientState::COLOR     ].type );
+  EXPECT_EQ( GLenum( GL_FLOAT ),    ppca.VertexArray::named[ ClientState::TEX_COORD ].type );
+
+  EXPECT_EQ( GLint( 32 ),           ppca.VertexArray::named[ ClientState::VERTEX    ].stride );
+  EXPECT_EQ( GLint( 0 ),            ppca.VertexArray::named[ ClientState::NORMAL    ].stride );
+  EXPECT_EQ( GLint( 0 ),            ppca.VertexArray::named[ ClientState::COLOR     ].stride );
+  EXPECT_EQ( GLint( 32 ),           ppca.VertexArray::named[ ClientState::TEX_COORD ].stride );
+
+  EXPECT_EQ( reinterpret_cast<const GLvoid*>( 16 ), ppca.VertexArray::named[ ClientState::VERTEX    ].pointer );
+  EXPECT_EQ( reinterpret_cast<const GLvoid*>( 0 ),  ppca.VertexArray::named[ ClientState::NORMAL    ].pointer );
+  EXPECT_EQ( reinterpret_cast<const GLvoid*>( 0 ),  ppca.VertexArray::named[ ClientState::COLOR     ].pointer );
+  EXPECT_EQ( reinterpret_cast<const GLvoid*>( 0 ),  ppca.VertexArray::named[ ClientState::TEX_COORD ].pointer );
+
+  ppca.Reset(ctx);
+  checkPpcaDefaults(ctx, ppca);
+
+  ppca.glInterleavedArrays( GL_T2F_C4UB_V3F, 0, NULL );
+
+  EXPECT_EQ( GLboolean( GL_TRUE ),  ppca.VertexArray::named[ ClientState::VERTEX    ].enabled );
+  EXPECT_EQ( GLboolean( GL_FALSE ), ppca.VertexArray::named[ ClientState::NORMAL    ].enabled );
+  EXPECT_EQ( GLboolean( GL_TRUE ),  ppca.VertexArray::named[ ClientState::COLOR     ].enabled );
+  EXPECT_EQ( GLboolean( GL_TRUE ),  ppca.VertexArray::named[ ClientState::TEX_COORD ].enabled );
+
+  EXPECT_EQ( GLint( 3 ),            ppca.VertexArray::named[ ClientState::VERTEX    ].size );
+  EXPECT_EQ( GLint( 3 ),            ppca.VertexArray::named[ ClientState::NORMAL    ].size );
+  EXPECT_EQ( GLint( 4 ),            ppca.VertexArray::named[ ClientState::COLOR     ].size );
+  EXPECT_EQ( GLint( 2 ),            ppca.VertexArray::named[ ClientState::TEX_COORD ].size );
+
+  EXPECT_EQ( GLenum( GL_FLOAT ),    ppca.VertexArray::named[ ClientState::VERTEX    ].type );
+  EXPECT_EQ( GLenum( GL_FLOAT ),    ppca.VertexArray::named[ ClientState::NORMAL    ].type );
+  EXPECT_EQ( GLenum( GL_UNSIGNED_BYTE ),    ppca.VertexArray::named[ ClientState::COLOR     ].type );
+  EXPECT_EQ( GLenum( GL_FLOAT ),    ppca.VertexArray::named[ ClientState::TEX_COORD ].type );
+
+  EXPECT_EQ( GLint( 24 ),           ppca.VertexArray::named[ ClientState::VERTEX    ].stride );
+  EXPECT_EQ( GLint( 0 ),            ppca.VertexArray::named[ ClientState::NORMAL    ].stride );
+  EXPECT_EQ( GLint( 24 ),           ppca.VertexArray::named[ ClientState::COLOR     ].stride );
+  EXPECT_EQ( GLint( 24 ),           ppca.VertexArray::named[ ClientState::TEX_COORD ].stride );
+
+  EXPECT_EQ( reinterpret_cast<const GLvoid*>( 12 ), ppca.VertexArray::named[ ClientState::VERTEX    ].pointer );
+  EXPECT_EQ( reinterpret_cast<const GLvoid*>( 0 ),  ppca.VertexArray::named[ ClientState::NORMAL    ].pointer );
+  EXPECT_EQ( reinterpret_cast<const GLvoid*>( 8 ),  ppca.VertexArray::named[ ClientState::COLOR     ].pointer );
+  EXPECT_EQ( reinterpret_cast<const GLvoid*>( 0 ),  ppca.VertexArray::named[ ClientState::TEX_COORD ].pointer );
+
+  ppca.Reset(ctx);
+  checkPpcaDefaults(ctx, ppca);
+
+  ppca.glInterleavedArrays( GL_T2F_C3F_V3F, 0, NULL );
+
+  EXPECT_EQ( GLboolean( GL_TRUE ),  ppca.VertexArray::named[ ClientState::VERTEX    ].enabled );
+  EXPECT_EQ( GLboolean( GL_FALSE ), ppca.VertexArray::named[ ClientState::NORMAL    ].enabled );
+  EXPECT_EQ( GLboolean( GL_TRUE ),  ppca.VertexArray::named[ ClientState::COLOR     ].enabled );
+  EXPECT_EQ( GLboolean( GL_TRUE ),  ppca.VertexArray::named[ ClientState::TEX_COORD ].enabled );
+
+  EXPECT_EQ( GLint( 3 ),            ppca.VertexArray::named[ ClientState::VERTEX    ].size );
+  EXPECT_EQ( GLint( 3 ),            ppca.VertexArray::named[ ClientState::NORMAL    ].size );
+  EXPECT_EQ( GLint( 3 ),            ppca.VertexArray::named[ ClientState::COLOR     ].size );
+  EXPECT_EQ( GLint( 2 ),            ppca.VertexArray::named[ ClientState::TEX_COORD ].size );
+
+  EXPECT_EQ( GLenum( GL_FLOAT ),    ppca.VertexArray::named[ ClientState::VERTEX    ].type );
+  EXPECT_EQ( GLenum( GL_FLOAT ),    ppca.VertexArray::named[ ClientState::NORMAL    ].type );
+  EXPECT_EQ( GLenum( GL_FLOAT ),    ppca.VertexArray::named[ ClientState::COLOR     ].type );
+  EXPECT_EQ( GLenum( GL_FLOAT ),    ppca.VertexArray::named[ ClientState::TEX_COORD ].type );
+
+  EXPECT_EQ( GLint( 32 ),           ppca.VertexArray::named[ ClientState::VERTEX    ].stride );
+  EXPECT_EQ( GLint( 0 ),            ppca.VertexArray::named[ ClientState::NORMAL    ].stride );
+  EXPECT_EQ( GLint( 32 ),           ppca.VertexArray::named[ ClientState::COLOR     ].stride );
+  EXPECT_EQ( GLint( 32 ),           ppca.VertexArray::named[ ClientState::TEX_COORD ].stride );
+
+  EXPECT_EQ( reinterpret_cast<const GLvoid*>( 20 ), ppca.VertexArray::named[ ClientState::VERTEX    ].pointer );
+  EXPECT_EQ( reinterpret_cast<const GLvoid*>( 0 ),  ppca.VertexArray::named[ ClientState::NORMAL    ].pointer );
+  EXPECT_EQ( reinterpret_cast<const GLvoid*>( 8 ),  ppca.VertexArray::named[ ClientState::COLOR     ].pointer );
+  EXPECT_EQ( reinterpret_cast<const GLvoid*>( 0 ),  ppca.VertexArray::named[ ClientState::TEX_COORD ].pointer );
+
+  ppca.Reset(ctx);
+  checkPpcaDefaults(ctx, ppca);
+
+  ppca.glInterleavedArrays( GL_T2F_N3F_V3F, 0, NULL );
+
+  EXPECT_EQ( GLboolean( GL_TRUE ),  ppca.VertexArray::named[ ClientState::VERTEX    ].enabled );
+  EXPECT_EQ( GLboolean( GL_TRUE ),  ppca.VertexArray::named[ ClientState::NORMAL    ].enabled );
+  EXPECT_EQ( GLboolean( GL_FALSE ), ppca.VertexArray::named[ ClientState::COLOR     ].enabled );
+  EXPECT_EQ( GLboolean( GL_TRUE ),  ppca.VertexArray::named[ ClientState::TEX_COORD ].enabled );
+
+  EXPECT_EQ( GLint( 3 ),            ppca.VertexArray::named[ ClientState::VERTEX    ].size );
+  EXPECT_EQ( GLint( 3 ),            ppca.VertexArray::named[ ClientState::NORMAL    ].size );
+  EXPECT_EQ( GLint( 4 ),            ppca.VertexArray::named[ ClientState::COLOR     ].size );
+  EXPECT_EQ( GLint( 2 ),            ppca.VertexArray::named[ ClientState::TEX_COORD ].size );
+
+  EXPECT_EQ( GLenum( GL_FLOAT ),    ppca.VertexArray::named[ ClientState::VERTEX    ].type );
+  EXPECT_EQ( GLenum( GL_FLOAT ),    ppca.VertexArray::named[ ClientState::NORMAL    ].type );
+  EXPECT_EQ( GLenum( GL_FLOAT ),    ppca.VertexArray::named[ ClientState::COLOR     ].type );
+  EXPECT_EQ( GLenum( GL_FLOAT ),    ppca.VertexArray::named[ ClientState::TEX_COORD ].type );
+
+  EXPECT_EQ( GLint( 32 ),           ppca.VertexArray::named[ ClientState::VERTEX    ].stride );
+  EXPECT_EQ( GLint( 32 ),           ppca.VertexArray::named[ ClientState::NORMAL    ].stride );
+  EXPECT_EQ( GLint( 0 ),            ppca.VertexArray::named[ ClientState::COLOR     ].stride );
+  EXPECT_EQ( GLint( 32 ),           ppca.VertexArray::named[ ClientState::TEX_COORD ].stride );
+
+  EXPECT_EQ( reinterpret_cast<const GLvoid*>( 20 ), ppca.VertexArray::named[ ClientState::VERTEX    ].pointer );
+  EXPECT_EQ( reinterpret_cast<const GLvoid*>( 8 ),  ppca.VertexArray::named[ ClientState::NORMAL    ].pointer );
+  EXPECT_EQ( reinterpret_cast<const GLvoid*>( 0 ),  ppca.VertexArray::named[ ClientState::COLOR     ].pointer );
+  EXPECT_EQ( reinterpret_cast<const GLvoid*>( 0 ),  ppca.VertexArray::named[ ClientState::TEX_COORD ].pointer );
+
+  ppca.Reset(ctx);
+  checkPpcaDefaults(ctx, ppca);
+
+  ppca.glInterleavedArrays( GL_T2F_C4F_N3F_V3F, 0, NULL );
+
+  EXPECT_EQ( GLboolean( GL_TRUE ),  ppca.VertexArray::named[ ClientState::VERTEX    ].enabled );
+  EXPECT_EQ( GLboolean( GL_TRUE ),  ppca.VertexArray::named[ ClientState::NORMAL    ].enabled );
+  EXPECT_EQ( GLboolean( GL_TRUE ),  ppca.VertexArray::named[ ClientState::COLOR     ].enabled );
+  EXPECT_EQ( GLboolean( GL_TRUE ),  ppca.VertexArray::named[ ClientState::TEX_COORD ].enabled );
+
+  EXPECT_EQ( GLint( 3 ),            ppca.VertexArray::named[ ClientState::VERTEX    ].size );
+  EXPECT_EQ( GLint( 3 ),            ppca.VertexArray::named[ ClientState::NORMAL    ].size );
+  EXPECT_EQ( GLint( 4 ),            ppca.VertexArray::named[ ClientState::COLOR     ].size );
+  EXPECT_EQ( GLint( 2 ),            ppca.VertexArray::named[ ClientState::TEX_COORD ].size );
+
+  EXPECT_EQ( GLenum( GL_FLOAT ),    ppca.VertexArray::named[ ClientState::VERTEX    ].type );
+  EXPECT_EQ( GLenum( GL_FLOAT ),    ppca.VertexArray::named[ ClientState::NORMAL    ].type );
+  EXPECT_EQ( GLenum( GL_FLOAT ),    ppca.VertexArray::named[ ClientState::COLOR     ].type );
+  EXPECT_EQ( GLenum( GL_FLOAT ),    ppca.VertexArray::named[ ClientState::TEX_COORD ].type );
+
+  EXPECT_EQ( GLint( 48 ),           ppca.VertexArray::named[ ClientState::VERTEX    ].stride );
+  EXPECT_EQ( GLint( 48 ),           ppca.VertexArray::named[ ClientState::NORMAL    ].stride );
+  EXPECT_EQ( GLint( 48 ),           ppca.VertexArray::named[ ClientState::COLOR     ].stride );
+  EXPECT_EQ( GLint( 48 ),           ppca.VertexArray::named[ ClientState::TEX_COORD ].stride );
+
+  EXPECT_EQ( reinterpret_cast<const GLvoid*>( 36 ), ppca.VertexArray::named[ ClientState::VERTEX    ].pointer );
+  EXPECT_EQ( reinterpret_cast<const GLvoid*>( 24 ), ppca.VertexArray::named[ ClientState::NORMAL    ].pointer );
+  EXPECT_EQ( reinterpret_cast<const GLvoid*>( 8 ),  ppca.VertexArray::named[ ClientState::COLOR     ].pointer );
+  EXPECT_EQ( reinterpret_cast<const GLvoid*>( 0 ),  ppca.VertexArray::named[ ClientState::TEX_COORD ].pointer );
+
+  // Pass in an unsupported "format", which should do nothing.
+
+  ppca.Reset(ctx);
+  checkPpcaDefaults(ctx, ppca);
+
+  for (GLuint ii=0; ii<ClientState::nNamedArrays; ii++)
+  {
+    ppca.VertexArray::named[ ii ].enabled = GLboolean( ( ii & 1 ) == 0 );
+    ppca.VertexArray::named[ ii ].size    = GLint( 987 );
+    ppca.VertexArray::named[ ii ].type    = GLenum( 987 );
+    ppca.VertexArray::named[ ii ].stride  = GLint( 987 );
+    ppca.VertexArray::named[ ii ].pointer = reinterpret_cast<const GLvoid*>( 987 );
+  }
+
+  ppca.glInterleavedArrays( GL_RGBA, 0, NULL );
+
+  for (GLuint ii=0; ii<ClientState::nNamedArrays; ii++)
+  {
+    GLboolean b = ( ( ( ii ) & 1 ) == 0 ) ? GL_TRUE : GL_FALSE;
+
+    EXPECT_EQ( GLboolean( b ),         ppca.VertexArray::named[ ii ].enabled );
+    EXPECT_EQ( GLint( 987 ),           ppca.VertexArray::named[ ii ].size );
+    EXPECT_EQ( GLenum( 987 ),          ppca.VertexArray::named[ ii ].type );
+    EXPECT_EQ( GLint( 987 ),           ppca.VertexArray::named[ ii ].stride );
+    EXPECT_EQ( reinterpret_cast<const GLvoid*>( 987 ), ppca.VertexArray::named[ ii ].pointer );
+  }
+}
+
+TEST ( RegalPpca, glGet_Shadowing )
+{
+  RegalContext ctx;
+  ctx.info = new ContextInfo();
+
+  Ppca ppca;
+  checkPpcaDefaults(ctx, ppca);
 
   GLint resulti[ 1 ] = { 123 };
   GLint64 resulti64[ 1 ] = { 123 };
@@ -2035,43 +2812,2127 @@
 
   // First ensure getting an unimplemented value works (does nothing).
 
-  EXPECT_FALSE( ppca.Get( &ctx, GL_FLOAT, resulti ) );
+  EXPECT_EQ( GLboolean( GL_FALSE ), ppca.glGetv( &ctx, GL_FLOAT, resulti ) );
   EXPECT_EQ( 123, resulti[ 0 ] );
 
-  EXPECT_FALSE( ppca.Get( &ctx, GL_FLOAT, resulti64 ) );
+  EXPECT_EQ( GLboolean( GL_FALSE ), ppca.glGetv( &ctx, GL_FLOAT, resulti64 ) );
   EXPECT_EQ( 123, resulti64[ 0 ] );
 
-  EXPECT_FALSE( ppca.Get( &ctx, GL_FLOAT, resultf ) );
+  EXPECT_EQ( GLboolean( GL_FALSE ), ppca.glGetv( &ctx, GL_FLOAT, resultf ) );
   EXPECT_EQ( 123, resultf[ 0 ] );
 
-  EXPECT_FALSE( ppca.Get( &ctx, GL_FLOAT, resultd ) );
+  EXPECT_EQ( GLboolean( GL_FALSE ), ppca.glGetv( &ctx, GL_FLOAT, resultd ) );
   EXPECT_EQ( 123, resultd[ 0 ] );
 
-  EXPECT_FALSE( ppca.Get( &ctx, GL_FLOAT, resultb ) );
-  EXPECT_EQ( GL_FALSE, resultb[ 0 ] );
+  EXPECT_EQ( GLboolean( GL_FALSE ), ppca.glGetv( &ctx, GL_FLOAT, resultb ) );
+  EXPECT_EQ( GLboolean(GL_FALSE), resultb[ 0 ] );
 
   // Next verify that getting an implemented value gets the value.
 
-  EXPECT_TRUE( ppca.Get( &ctx, GL_MAX_CLIENT_ATTRIB_STACK_DEPTH, resulti ) );
-  EXPECT_EQ( REGAL_PPCA_MAX_CLIENT_ATTRIB_STACK_DEPTH, resulti[ 0 ] );
+  EXPECT_EQ( GLboolean( GL_TRUE ), ppca.glGetv( &ctx, GL_MAX_CLIENT_ATTRIB_STACK_DEPTH, resulti ) );
+  EXPECT_EQ( REGAL_EMU_MAX_CLIENT_ATTRIB_STACK_DEPTH, resulti[ 0 ] );
 
-  EXPECT_TRUE( ppca.Get( &ctx, GL_MAX_CLIENT_ATTRIB_STACK_DEPTH, resulti64 ) );
-  EXPECT_EQ( REGAL_PPCA_MAX_CLIENT_ATTRIB_STACK_DEPTH, resulti64[ 0 ] );
+  EXPECT_EQ( GLboolean( GL_TRUE ), ppca.glGetv( &ctx, GL_MAX_CLIENT_ATTRIB_STACK_DEPTH, resulti64 ) );
+  EXPECT_EQ( REGAL_EMU_MAX_CLIENT_ATTRIB_STACK_DEPTH, resulti64[ 0 ] );
 
-  EXPECT_TRUE( ppca.Get( &ctx, GL_MAX_CLIENT_ATTRIB_STACK_DEPTH, resultf ) );
-  EXPECT_EQ( REGAL_PPCA_MAX_CLIENT_ATTRIB_STACK_DEPTH, resultf[ 0 ] );
+  EXPECT_EQ( GLboolean( GL_TRUE ), ppca.glGetv( &ctx, GL_MAX_CLIENT_ATTRIB_STACK_DEPTH, resultf ) );
+  EXPECT_EQ( REGAL_EMU_MAX_CLIENT_ATTRIB_STACK_DEPTH, resultf[ 0 ] );
 
-  EXPECT_TRUE( ppca.Get( &ctx, GL_MAX_CLIENT_ATTRIB_STACK_DEPTH, resultd ) );
-  EXPECT_EQ( REGAL_PPCA_MAX_CLIENT_ATTRIB_STACK_DEPTH, resultd[ 0 ] );
+  EXPECT_EQ( GLboolean( GL_TRUE ), ppca.glGetv( &ctx, GL_MAX_CLIENT_ATTRIB_STACK_DEPTH, resultd ) );
+  EXPECT_EQ( REGAL_EMU_MAX_CLIENT_ATTRIB_STACK_DEPTH, resultd[ 0 ] );
 
-  EXPECT_TRUE( ppca.Get( &ctx, GL_MAX_CLIENT_ATTRIB_STACK_DEPTH, resultb ) );
-  EXPECT_EQ( GL_TRUE, resultb[ 0 ] );
+  EXPECT_EQ( GLboolean( GL_TRUE ), ppca.glGetv( &ctx, GL_MAX_CLIENT_ATTRIB_STACK_DEPTH, resultb ) );
+  EXPECT_EQ( GLboolean(GL_TRUE), resultb[ 0 ] );
+}
 
-  // If the backend appears to be compatible with the request, the emulation
-  // should just defer to the backend.
+TEST ( RegalPpca, glPixelStore_Shadowing )
+{
+  RegalContext ctx;
+  ctx.info = new ContextInfo();
 
-  ctx.info->es2 = ctx.info->core = false;
-  EXPECT_FALSE( ppca.Get( &ctx, GL_MAX_CLIENT_ATTRIB_STACK_DEPTH, resulti ) );
+  Ppca ppca;
+  checkPpcaDefaults(ctx, ppca);
+
+  // first test glPixelStorei
+
+  ppca.glPixelStore( GL_UNPACK_SWAP_BYTES, GLint(GL_TRUE) );
+  ppca.glPixelStore( GL_UNPACK_LSB_FIRST, GLint(GL_TRUE) );
+  ppca.glPixelStore( GL_UNPACK_IMAGE_HEIGHT, GLint(11) );
+  ppca.glPixelStore( GL_UNPACK_SKIP_IMAGES, GLint(12) );
+  ppca.glPixelStore( GL_UNPACK_ROW_LENGTH, GLint(13) );
+  ppca.glPixelStore( GL_UNPACK_SKIP_ROWS, GLint(14) );
+  ppca.glPixelStore( GL_UNPACK_SKIP_PIXELS, GLint(15) );
+  ppca.glPixelStore( GL_UNPACK_ALIGNMENT, GLint(16) );
+  ppca.glPixelStore( GL_PACK_SWAP_BYTES, GLint(GL_TRUE) );
+  ppca.glPixelStore( GL_PACK_LSB_FIRST, GLint(GL_TRUE) );
+  ppca.glPixelStore( GL_PACK_IMAGE_HEIGHT, GLint(27) );
+  ppca.glPixelStore( GL_PACK_SKIP_IMAGES, GLint(28) );
+  ppca.glPixelStore( GL_PACK_ROW_LENGTH, GLint(29) );
+  ppca.glPixelStore( GL_PACK_SKIP_ROWS, GLint(30) );
+  ppca.glPixelStore( GL_PACK_SKIP_PIXELS, GLint(31) );
+  ppca.glPixelStore( GL_PACK_ALIGNMENT, GLint(32) );
+
+  ppca.glBindBuffer( GL_PIXEL_UNPACK_BUFFER, GLuint(123) );
+  ppca.glBindBuffer( GL_PIXEL_PACK_BUFFER, GLuint(456) );
+
+  EXPECT_EQ( GLint(GL_TRUE), ppca.PixelStore::unpackSwapBytes );
+  EXPECT_EQ( GLint(GL_TRUE), ppca.PixelStore::unpackLsbFirst );
+  EXPECT_EQ( GLint(11),      ppca.PixelStore::unpackImageHeight );
+  EXPECT_EQ( GLint(12),      ppca.PixelStore::unpackSkipImages );
+  EXPECT_EQ( GLint(13),      ppca.PixelStore::unpackRowLength );
+  EXPECT_EQ( GLint(14),      ppca.PixelStore::unpackSkipRows );
+  EXPECT_EQ( GLint(15),      ppca.PixelStore::unpackSkipPixels );
+  EXPECT_EQ( GLint(16),      ppca.PixelStore::unpackAlignment );
+  EXPECT_EQ( GLint(GL_TRUE), ppca.PixelStore::packSwapBytes );
+  EXPECT_EQ( GLint(GL_TRUE), ppca.PixelStore::packLsbFirst );
+  EXPECT_EQ( GLint(27),      ppca.PixelStore::packImageHeight );
+  EXPECT_EQ( GLint(28),      ppca.PixelStore::packSkipImages );
+  EXPECT_EQ( GLint(29),      ppca.PixelStore::packRowLength );
+  EXPECT_EQ( GLint(30),      ppca.PixelStore::packSkipRows );
+  EXPECT_EQ( GLint(31),      ppca.PixelStore::packSkipPixels );
+  EXPECT_EQ( GLint(32),      ppca.PixelStore::packAlignment );
+  EXPECT_EQ( GLuint(123),    ppca.PixelStore::pixelUnpackBufferBinding );
+  EXPECT_EQ( GLuint(456),    ppca.PixelStore::pixelPackBufferBinding );
+
+  // reset just the pixel store state then verify that
+  // the entire ppca is now back to default state
+
+  ppca.PixelStore::Reset();
+  checkPpcaDefaults(ctx, ppca);
+
+  // now test glPixelStoref
+
+  ppca.glPixelStore( GL_UNPACK_SWAP_BYTES, GLfloat(1.11) );
+  ppca.glPixelStore( GL_UNPACK_LSB_FIRST, GLfloat(0) );
+  ppca.glPixelStore( GL_UNPACK_IMAGE_HEIGHT, GLfloat(11.0) );
+  ppca.glPixelStore( GL_UNPACK_SKIP_IMAGES, GLfloat(12.1) );
+  ppca.glPixelStore( GL_UNPACK_ROW_LENGTH, GLfloat(13.2) );
+  ppca.glPixelStore( GL_UNPACK_SKIP_ROWS, GLfloat(14.3) );
+  ppca.glPixelStore( GL_UNPACK_SKIP_PIXELS, GLfloat(15.4) );
+  ppca.glPixelStore( GL_UNPACK_ALIGNMENT, GLfloat(16.5) );
+  ppca.glPixelStore( GL_PACK_SWAP_BYTES, GLfloat(GL_TRUE) );
+  ppca.glPixelStore( GL_PACK_LSB_FIRST, GLfloat(GL_TRUE) );
+  ppca.glPixelStore( GL_PACK_IMAGE_HEIGHT, GLfloat(27.01) );
+  ppca.glPixelStore( GL_PACK_SKIP_IMAGES, GLfloat(28.02) );
+  ppca.glPixelStore( GL_PACK_ROW_LENGTH, GLfloat(29.03) );
+  ppca.glPixelStore( GL_PACK_SKIP_ROWS, GLfloat(30.04) );
+  ppca.glPixelStore( GL_PACK_SKIP_PIXELS, GLfloat(31.05) );
+  ppca.glPixelStore( GL_PACK_ALIGNMENT, GLfloat(32.06) );
+
+  ppca.glBindBuffer( GL_PIXEL_UNPACK_BUFFER, GLuint(123) );
+  ppca.glBindBuffer( GL_PIXEL_PACK_BUFFER, GLuint(456) );
+
+  EXPECT_EQ( GLfloat(GL_TRUE),  ppca.PixelStore::unpackSwapBytes );
+  EXPECT_EQ( GLfloat(GL_FALSE), ppca.PixelStore::unpackLsbFirst );
+  EXPECT_EQ( GLfloat(11),       ppca.PixelStore::unpackImageHeight );
+  EXPECT_EQ( GLfloat(12),       ppca.PixelStore::unpackSkipImages );
+  EXPECT_EQ( GLfloat(13),       ppca.PixelStore::unpackRowLength );
+  EXPECT_EQ( GLfloat(14),       ppca.PixelStore::unpackSkipRows );
+  EXPECT_EQ( GLfloat(15),       ppca.PixelStore::unpackSkipPixels );
+  EXPECT_EQ( GLfloat(16),       ppca.PixelStore::unpackAlignment );
+  EXPECT_EQ( GLfloat(GL_TRUE),  ppca.PixelStore::packSwapBytes );
+  EXPECT_EQ( GLfloat(GL_TRUE),  ppca.PixelStore::packLsbFirst );
+  EXPECT_EQ( GLfloat(27),       ppca.PixelStore::packImageHeight );
+  EXPECT_EQ( GLfloat(28),       ppca.PixelStore::packSkipImages );
+  EXPECT_EQ( GLfloat(29),       ppca.PixelStore::packRowLength );
+  EXPECT_EQ( GLfloat(30),       ppca.PixelStore::packSkipRows );
+  EXPECT_EQ( GLfloat(31),       ppca.PixelStore::packSkipPixels );
+  EXPECT_EQ( GLfloat(32),       ppca.PixelStore::packAlignment );
+  EXPECT_EQ( GLuint(123),       ppca.PixelStore::pixelUnpackBufferBinding );
+  EXPECT_EQ( GLuint(456),       ppca.PixelStore::pixelPackBufferBinding );
+}
+
+TEST ( RegalPpca, glBindBuffer_Shadowing )
+{
+  RegalContext ctx;
+  ctx.info = new ContextInfo();
+
+  Ppca ppca;
+  checkPpcaDefaults(ctx, ppca);
+
+  ppca.VertexArray::arrayBufferBinding = 0;
+  ppca.VertexArray::elementArrayBufferBinding = 0;
+  ppca.PixelStore::pixelUnpackBufferBinding = 0;
+  ppca.PixelStore::pixelPackBufferBinding = 0;
+
+  ppca.glBindBuffer( GL_ARRAY_BUFFER, GLuint(12) );
+  EXPECT_EQ( GLuint(12), ppca.VertexArray::arrayBufferBinding );
+  EXPECT_EQ( GLuint( 0), ppca.VertexArray::elementArrayBufferBinding );
+  EXPECT_EQ( GLuint( 0), ppca.PixelStore::pixelUnpackBufferBinding );
+  EXPECT_EQ( GLuint( 0), ppca.PixelStore::pixelPackBufferBinding );
+
+  ppca.glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, GLuint(34) );
+  EXPECT_EQ( GLuint(12), ppca.VertexArray::arrayBufferBinding );
+  EXPECT_EQ( GLuint(34), ppca.VertexArray::elementArrayBufferBinding );
+  EXPECT_EQ( GLuint( 0), ppca.PixelStore::pixelUnpackBufferBinding );
+  EXPECT_EQ( GLuint( 0), ppca.PixelStore::pixelPackBufferBinding );
+
+  ppca.glBindBuffer( GL_PIXEL_UNPACK_BUFFER, GLuint(21) );
+  EXPECT_EQ( GLuint(12), ppca.VertexArray::arrayBufferBinding );
+  EXPECT_EQ( GLuint(34), ppca.VertexArray::elementArrayBufferBinding );
+  EXPECT_EQ( GLuint(21), ppca.PixelStore::pixelUnpackBufferBinding );
+  EXPECT_EQ( GLuint( 0), ppca.PixelStore::pixelPackBufferBinding );
+
+  ppca.glBindBuffer( GL_PIXEL_PACK_BUFFER, GLuint(43) );
+  EXPECT_EQ( GLuint(12), ppca.VertexArray::arrayBufferBinding );
+  EXPECT_EQ( GLuint(34), ppca.VertexArray::elementArrayBufferBinding );
+  EXPECT_EQ( GLuint(21), ppca.PixelStore::pixelUnpackBufferBinding );
+  EXPECT_EQ( GLuint(43), ppca.PixelStore::pixelPackBufferBinding );
+
+  GLuint validBuffers[] = { GL_ATOMIC_COUNTER_BUFFER,
+                            GL_COPY_READ_BUFFER,
+                            GL_COPY_WRITE_BUFFER,
+                            GL_DRAW_INDIRECT_BUFFER,
+                            GL_DISPATCH_INDIRECT_BUFFER,
+                            GL_SHADER_STORAGE_BUFFER,
+                            GL_TEXTURE_BUFFER,
+                            GL_TRANSFORM_FEEDBACK_BUFFER,
+                            GL_UNIFORM_BUFFER };
+  GLuint nValidBuffers = sizeof(validBuffers)/sizeof(GLuint);
+
+  for (GLuint n=0; n<nValidBuffers; n++)
+  {
+    ppca.glBindBuffer( validBuffers[n], GLuint(56) );
+    EXPECT_EQ( GLuint(12), ppca.VertexArray::arrayBufferBinding );
+    EXPECT_EQ( GLuint(34), ppca.VertexArray::elementArrayBufferBinding );
+    EXPECT_EQ( GLuint(21), ppca.PixelStore::pixelUnpackBufferBinding );
+    EXPECT_EQ( GLuint(43), ppca.PixelStore::pixelPackBufferBinding );
+  }
+
+  GLuint invalidBuffers[] = { GL_ARRAY_BUFFER_BINDING,
+                              GL_ATOMIC_COUNTER_BUFFER_BINDING,
+                              GL_DRAW_INDIRECT_BUFFER_BINDING,
+                              GL_DISPATCH_INDIRECT_BUFFER_BINDING,
+                              GL_ELEMENT_ARRAY_BUFFER_BINDING,
+                              GL_PIXEL_PACK_BUFFER_BINDING,
+                              GL_PIXEL_UNPACK_BUFFER_BINDING,
+                              GL_SHADER_STORAGE_BUFFER_BINDING,
+                              GL_TEXTURE_BUFFER_DATA_STORE_BINDING,
+                              GL_TEXTURE_BUFFER_FORMAT,
+                              GL_TEXTURE_BUFFER_OFFSET,
+                              GL_TEXTURE_BUFFER_SIZE,
+                              GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT,
+                              GL_TRANSFORM_FEEDBACK_BUFFER_BINDING,
+                              GL_UNIFORM_BUFFER_BINDING };
+  GLuint nInvalidBuffers = sizeof(invalidBuffers)/sizeof(GLuint);
+
+  for (GLuint n=0; n<nInvalidBuffers; n++)
+  {
+    ppca.glBindBuffer( invalidBuffers[n], GLuint(78) );
+    EXPECT_EQ( GLuint(12), ppca.VertexArray::arrayBufferBinding );
+    EXPECT_EQ( GLuint(34), ppca.VertexArray::elementArrayBufferBinding );
+    EXPECT_EQ( GLuint(21), ppca.PixelStore::pixelUnpackBufferBinding );
+    EXPECT_EQ( GLuint(43), ppca.PixelStore::pixelPackBufferBinding );
+  }
+
+  ppca.Reset(ctx);
+  checkPpcaDefaults(ctx, ppca);
+
+  ppca.VertexArray::vertexArrayBinding = 1;
+  ppca.glBindBuffer( GL_ARRAY_BUFFER, GLuint(123) );
+  ppca.glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, GLuint(789) );
+  ppca.glBindBuffer( GL_PIXEL_PACK_BUFFER, GLuint(321) );
+  ppca.glBindBuffer( GL_PIXEL_UNPACK_BUFFER, GLuint(654) );
+
+  EXPECT_EQ( GLuint(123), ppca.VertexArray::arrayBufferBinding );
+  EXPECT_EQ( GLuint(  0), ppca.VertexArray::elementArrayBufferBinding );
+  EXPECT_EQ( GLuint(321), ppca.PixelStore::pixelPackBufferBinding );
+  EXPECT_EQ( GLuint(654), ppca.PixelStore::pixelUnpackBufferBinding );
+}
+
+TEST ( RegalPpca, glClientActiveTexture_Shadowing )
+{
+  RegalContext ctx;
+  ctx.info = new ContextInfo();
+
+  Ppca ppca;
+  checkPpcaDefaults(ctx, ppca);
+
+  for (GLuint ii=0; ii<(REGAL_EMU_MAX_TEXTURE_COORDS * 2); ii++)
+  {
+    GLenum test = GLenum(GL_TEXTURE0 + ii);
+
+    ppca.VertexArray::vertexArrayBinding = 0;
+    ppca.VertexArray::clientActiveTexture = GLenum(0);
+    ppca.glClientActiveTexture( test );
+
+    if (ii < REGAL_EMU_MAX_TEXTURE_COORDS)
+      EXPECT_EQ( test, ppca.VertexArray::clientActiveTexture );
+    else
+      EXPECT_EQ( GLenum(0), ppca.VertexArray::clientActiveTexture );
+
+    ppca.VertexArray::clientActiveTexture = GL_TEXTURE0;
+    checkPpcaDefaults(ctx, ppca);
+  }
+
+  for (GLuint ii=0; ii<(REGAL_EMU_MAX_TEXTURE_COORDS * 2); ii++)
+  {
+    GLenum test = GLenum(GL_TEXTURE0 + ii);
+
+    ppca.VertexArray::vertexArrayBinding = 1;
+    ppca.VertexArray::clientActiveTexture = GLenum(0);
+    ppca.glClientActiveTexture( test );
+
+    if (ii < REGAL_EMU_MAX_TEXTURE_COORDS)
+      EXPECT_EQ( test, ppca.VertexArray::clientActiveTexture );
+    else
+      EXPECT_EQ( GLenum(0), ppca.VertexArray::clientActiveTexture );
+
+    ppca.VertexArray::vertexArrayBinding = 0;
+    ppca.VertexArray::clientActiveTexture = GL_TEXTURE0;
+    checkPpcaDefaults(ctx, ppca);
+  }
+}
+
+TEST ( RegalPpca, glEnableDisableClientState_Shadowing )
+{
+  RegalContext ctx;
+  ctx.info = new ContextInfo();
+
+  Ppca ppca;
+  checkPpcaDefaults(ctx, ppca);
+
+  // test glEnableClientState & glDisableClientState with no vertex array bound
+
+  for (GLuint ii=0; ii<ClientState::nNamedArrays; ii++)
+  {
+    ppca.Reset(ctx);
+    checkPpcaDefaults(ctx, ppca);
+    ppca.VertexArray::vertexArrayBinding = 0;
+
+    if (ii < 7)
+    {
+      ppca.glEnableClientState( Regal::ClientState::vaEnum[ii][0] );
+      EXPECT_EQ( GLboolean(GL_TRUE), ppca.VertexArray::named[ii].enabled );
+      ppca.VertexArray::named[ii].enabled = GL_FALSE;
+      checkPpcaDefaults(ctx, ppca);
+      ppca.VertexArray::named[ii].enabled = GL_TRUE;
+      ppca.glDisableClientState( Regal::ClientState::vaEnum[ii][0] );
+      checkPpcaDefaults(ctx, ppca);
+    }
+    else
+    {
+      ppca.VertexArray::clientActiveTexture = GL_TEXTURE0 + ii - 7;
+      ppca.glEnableClientState( Regal::ClientState::vaEnum[7][0] );
+      EXPECT_EQ( GLboolean(GL_TRUE), ppca.VertexArray::named[ii].enabled );
+      ppca.VertexArray::named[ii].enabled = GL_FALSE;
+      ppca.VertexArray::clientActiveTexture = GL_TEXTURE0;
+      checkPpcaDefaults(ctx, ppca);
+      ppca.VertexArray::clientActiveTexture = GL_TEXTURE0 + ii - 7;
+      ppca.VertexArray::named[ii].enabled = GL_TRUE;
+      ppca.glDisableClientState( Regal::ClientState::vaEnum[7][0] );
+      ppca.VertexArray::clientActiveTexture = GL_TEXTURE0;
+      checkPpcaDefaults(ctx, ppca);
+    }
+  }
+
+  // test glEnableClientStateiEXT & glDisableClientStateiEXT with no vertex array bound
+
+  for (GLuint ii=0; ii<ClientState::nNamedArrays; ii++)
+  {
+    ppca.Reset(ctx);
+    checkPpcaDefaults(ctx, ppca);
+    ppca.VertexArray::vertexArrayBinding = 0;
+
+    if (ii < 7)
+    {
+      ppca.glEnableClientStateiEXT( Regal::ClientState::vaEnum[ii][0], 0 );
+      EXPECT_EQ( GLboolean(GL_TRUE), ppca.VertexArray::named[ii].enabled );
+      ppca.VertexArray::named[ii].enabled = GL_FALSE;
+      checkPpcaDefaults(ctx, ppca);
+      ppca.VertexArray::named[ii].enabled = GL_TRUE;
+      ppca.glDisableClientStateiEXT( Regal::ClientState::vaEnum[ii][0], 0 );
+      checkPpcaDefaults(ctx, ppca);
+    }
+    else
+    {
+      ppca.glEnableClientStateiEXT( Regal::ClientState::vaEnum[7][0], ii - 7 );
+      EXPECT_EQ( GLboolean(GL_TRUE), ppca.VertexArray::named[ii].enabled );
+      ppca.VertexArray::named[ii].enabled = GL_FALSE;
+      checkPpcaDefaults(ctx, ppca);
+      ppca.VertexArray::named[ii].enabled = GL_TRUE;
+      ppca.glDisableClientStateiEXT( Regal::ClientState::vaEnum[7][0], ii - 7 );
+      checkPpcaDefaults(ctx, ppca);
+    }
+  }
+
+  // test glEnableClientStateIndexedEXT & glDisableClientStateIndexedEXT with no vertex array bound
+
+  for (GLuint ii=0; ii<ClientState::nNamedArrays; ii++)
+  {
+    ppca.Reset(ctx);
+    checkPpcaDefaults(ctx, ppca);
+    ppca.VertexArray::vertexArrayBinding = 0;
+
+    if (ii < 7)
+    {
+      ppca.glEnableClientStateIndexedEXT( Regal::ClientState::vaEnum[ii][0], 0 );
+      EXPECT_EQ( GLboolean(GL_TRUE), ppca.VertexArray::named[ii].enabled );
+      ppca.VertexArray::named[ii].enabled = GL_FALSE;
+      checkPpcaDefaults(ctx, ppca);
+      ppca.VertexArray::named[ii].enabled = GL_TRUE;
+      ppca.glDisableClientStateIndexedEXT( Regal::ClientState::vaEnum[ii][0], 0 );
+      checkPpcaDefaults(ctx, ppca);
+    }
+    else
+    {
+      ppca.glEnableClientStateIndexedEXT( Regal::ClientState::vaEnum[7][0], ii - 7 );
+      EXPECT_EQ( GLboolean(GL_TRUE), ppca.VertexArray::named[ii].enabled );
+      ppca.VertexArray::named[ii].enabled = GL_FALSE;
+      checkPpcaDefaults(ctx, ppca);
+      ppca.VertexArray::named[ii].enabled = GL_TRUE;
+      ppca.glDisableClientStateIndexedEXT( Regal::ClientState::vaEnum[7][0], ii - 7 );
+      checkPpcaDefaults(ctx, ppca);
+    }
+  }
+
+  // test glEnableClientState & glDisableClientState with a vertex array bound
+
+  for (GLuint ii=0; ii<ClientState::nNamedArrays; ii++)
+  {
+    ppca.Reset(ctx);
+    checkPpcaDefaults(ctx, ppca);
+    ppca.VertexArray::vertexArrayBinding = 1;
+
+    if (ii < 7)
+    {
+      ppca.glEnableClientState( Regal::ClientState::vaEnum[ii][0] );
+      EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::named[ii].enabled );
+      ppca.VertexArray::vertexArrayBinding = 0;
+      checkPpcaDefaults(ctx, ppca);
+      ppca.VertexArray::vertexArrayBinding = 1;
+      ppca.VertexArray::named[ii].enabled = GL_TRUE;
+      ppca.glDisableClientState( Regal::ClientState::vaEnum[ii][0] );
+      EXPECT_EQ( GLboolean(GL_TRUE), ppca.VertexArray::named[ii].enabled );
+      ppca.VertexArray::named[ii].enabled = GL_FALSE;
+      ppca.VertexArray::vertexArrayBinding = 0;
+      checkPpcaDefaults(ctx, ppca);
+    }
+    else
+    {
+      ppca.VertexArray::clientActiveTexture = GL_TEXTURE0 + ii - 7;
+      ppca.glEnableClientState( Regal::ClientState::vaEnum[7][0] );
+      EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::named[ii].enabled );
+      ppca.VertexArray::clientActiveTexture = GL_TEXTURE0;
+      ppca.VertexArray::vertexArrayBinding = 0;
+      checkPpcaDefaults(ctx, ppca);
+      ppca.VertexArray::vertexArrayBinding = 1;
+      ppca.VertexArray::clientActiveTexture = GL_TEXTURE0 + ii - 7;
+      ppca.VertexArray::named[ii].enabled = GL_TRUE;
+      ppca.glDisableClientState( Regal::ClientState::vaEnum[7][0] );
+      EXPECT_EQ( GLboolean(GL_TRUE), ppca.VertexArray::named[ii].enabled );
+      ppca.VertexArray::named[ii].enabled = GL_FALSE;
+      ppca.VertexArray::clientActiveTexture = GL_TEXTURE0;
+      ppca.VertexArray::vertexArrayBinding = 0;
+      checkPpcaDefaults(ctx, ppca);
+    }
+  }
+
+  // test glEnableClientStateiEXT & glDisableClientStateiEXT with a vertex array bound
+
+  for (GLuint ii=0; ii<ClientState::nNamedArrays; ii++)
+  {
+    ppca.Reset(ctx);
+    checkPpcaDefaults(ctx, ppca);
+    ppca.VertexArray::vertexArrayBinding = 1;
+
+    if (ii < 7)
+    {
+      ppca.glEnableClientStateiEXT( Regal::ClientState::vaEnum[ii][0], 0 );
+      EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::named[ii].enabled );
+      ppca.VertexArray::vertexArrayBinding = 0;
+      checkPpcaDefaults(ctx, ppca);
+      ppca.VertexArray::vertexArrayBinding = 1;
+      ppca.VertexArray::named[ii].enabled = GL_TRUE;
+      ppca.glDisableClientStateiEXT( Regal::ClientState::vaEnum[ii][0], 0 );
+      EXPECT_EQ( GLboolean(GL_TRUE), ppca.VertexArray::named[ii].enabled );
+      ppca.VertexArray::named[ii].enabled = GL_FALSE;
+      ppca.VertexArray::vertexArrayBinding = 0;
+      checkPpcaDefaults(ctx, ppca);
+    }
+    else
+    {
+      ppca.glEnableClientStateiEXT( Regal::ClientState::vaEnum[7][0], ii - 7 );
+      EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::named[ii].enabled );
+      ppca.VertexArray::vertexArrayBinding = 0;
+      checkPpcaDefaults(ctx, ppca);
+      ppca.VertexArray::vertexArrayBinding = 1;
+      ppca.VertexArray::named[ii].enabled = GL_TRUE;
+      ppca.glDisableClientStateiEXT( Regal::ClientState::vaEnum[7][0], ii - 7 );
+      EXPECT_EQ( GLboolean(GL_TRUE), ppca.VertexArray::named[ii].enabled );
+      ppca.VertexArray::named[ii].enabled = GL_FALSE;
+      ppca.VertexArray::vertexArrayBinding = 0;
+      checkPpcaDefaults(ctx, ppca);
+    }
+  }
+
+  // test glEnableClientStateIndexedEXT & glDisableClientStateIndexedEXT with a vertex array bound
+
+  for (GLuint ii=0; ii<ClientState::nNamedArrays; ii++)
+  {
+    ppca.Reset(ctx);
+    checkPpcaDefaults(ctx, ppca);
+    ppca.VertexArray::vertexArrayBinding = 1;
+
+    if (ii < 7)
+    {
+      ppca.glEnableClientStateIndexedEXT( Regal::ClientState::vaEnum[ii][0], 0 );
+      EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::named[ii].enabled );
+      ppca.VertexArray::vertexArrayBinding = 0;
+      checkPpcaDefaults(ctx, ppca);
+      ppca.VertexArray::vertexArrayBinding = 1;
+      ppca.VertexArray::named[ii].enabled = GL_TRUE;
+      ppca.glDisableClientStateIndexedEXT( Regal::ClientState::vaEnum[ii][0], 0 );
+      EXPECT_EQ( GLboolean(GL_TRUE), ppca.VertexArray::named[ii].enabled );
+      ppca.VertexArray::named[ii].enabled = GL_FALSE;
+      ppca.VertexArray::vertexArrayBinding = 0;
+      checkPpcaDefaults(ctx, ppca);
+    }
+    else
+    {
+      ppca.glEnableClientStateIndexedEXT( Regal::ClientState::vaEnum[7][0], ii - 7 );
+      EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::named[ii].enabled );
+      ppca.VertexArray::vertexArrayBinding = 0;
+      checkPpcaDefaults(ctx, ppca);
+      ppca.VertexArray::vertexArrayBinding = 1;
+      ppca.VertexArray::named[ii].enabled = GL_TRUE;
+      ppca.glDisableClientStateIndexedEXT( Regal::ClientState::vaEnum[7][0], ii - 7 );
+      EXPECT_EQ( GLboolean(GL_TRUE), ppca.VertexArray::named[ii].enabled );
+      ppca.VertexArray::named[ii].enabled = GL_FALSE;
+      ppca.VertexArray::vertexArrayBinding = 0;
+      checkPpcaDefaults(ctx, ppca);
+    }
+  }
+}
+
+TEST ( RegalPpca, glBindVertexArray_Shadowing )
+{
+  RegalContext ctx;
+  ctx.info = new ContextInfo();
+
+  Ppca ppca;
+  checkPpcaDefaults(ctx, ppca);
+
+  ppca.glBindVertexArray( GLuint(13579) );
+  EXPECT_EQ( GLuint(13579), ppca.VertexArray::vertexArrayBinding );
+
+  ppca.VertexArray::vertexArrayBinding = 0;
+  checkPpcaDefaults(ctx, ppca);
+}
+
+TEST ( RegalPpca, glEnableDisableVertexAttribArray_Shadowing )
+{
+  RegalContext ctx;
+  ctx.info = new ContextInfo();
+
+  Ppca ppca;
+  checkPpcaDefaults(ctx, ppca);
+
+  // test glEnableVertexAttribArray & glDisableVertexAttribArray with no vertex array bound
+
+  for (GLuint ii=0; ii<REGAL_EMU_MAX_VERTEX_ATTRIBS; ii++)
+  {
+    ppca.Reset(ctx);
+    checkPpcaDefaults(ctx, ppca);
+    ppca.VertexArray::vertexArrayBinding = 0;
+
+    ppca.glEnableVertexAttribArray( ii );
+    EXPECT_EQ( GLboolean(GL_TRUE), ppca.VertexArray::generic[ii].enabled );
+    ppca.VertexArray::generic[ii].enabled = GL_FALSE;
+    checkPpcaDefaults(ctx, ppca);
+
+    ppca.VertexArray::generic[ii].enabled = GL_TRUE;
+    ppca.glDisableVertexAttribArray( ii );
+    checkPpcaDefaults(ctx, ppca);
+  }
+
+  // test glEnableVertexAttribArray & glDisableVertexAttribArray with a vertex array bound
+
+  for (GLuint ii=0; ii<REGAL_EMU_MAX_VERTEX_ATTRIBS; ii++)
+  {
+    ppca.Reset(ctx);
+    checkPpcaDefaults(ctx, ppca);
+    ppca.VertexArray::vertexArrayBinding = 1;
+
+    ppca.glEnableVertexAttribArray( ii );
+    EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::generic[ii].enabled );
+    ppca.VertexArray::vertexArrayBinding = 0;
+    checkPpcaDefaults(ctx, ppca);
+
+    ppca.VertexArray::vertexArrayBinding = 1;
+    ppca.VertexArray::generic[ii].enabled = GL_TRUE;
+    ppca.glDisableVertexAttribArray( ii );
+    EXPECT_EQ( GLboolean(GL_TRUE), ppca.VertexArray::generic[ii].enabled );
+    ppca.VertexArray::generic[ii].enabled = GL_FALSE;
+    ppca.VertexArray::vertexArrayBinding = 0;
+    checkPpcaDefaults(ctx, ppca);
+  }
+}
+
+TEST ( RegalPpca, glEnableDisableVertexArrayAttribEXT_Shadowing )
+{
+  RegalContext ctx;
+  ctx.info = new ContextInfo();
+
+  Ppca ppca;
+  checkPpcaDefaults(ctx, ppca);
+
+  // test glEnableVertexArrayAttribEXT & glDisableVertexArrayAttribEXT with no vertex array bound
+
+  for (GLuint ii=0; ii<REGAL_EMU_MAX_VERTEX_ATTRIBS; ii++)
+  {
+    ppca.Reset(ctx);
+    checkPpcaDefaults(ctx, ppca);
+
+    ppca.glEnableVertexArrayAttribEXT( 0, ii );
+    EXPECT_EQ( GLboolean(GL_TRUE), ppca.VertexArray::generic[ii].enabled );
+    ppca.VertexArray::generic[ii].enabled = GL_FALSE;
+    checkPpcaDefaults(ctx, ppca);
+
+    ppca.VertexArray::generic[ii].enabled = GL_TRUE;
+    ppca.glDisableVertexArrayAttribEXT( 0, ii );
+    checkPpcaDefaults(ctx, ppca);
+  }
+
+  // test glEnableVertexAttribArray & glDisableVertexAttribArray with a vertex array bound
+
+  for (GLuint ii=0; ii<REGAL_EMU_MAX_VERTEX_ATTRIBS; ii++)
+  {
+    ppca.Reset(ctx);
+    checkPpcaDefaults(ctx, ppca);
+
+    ppca.glEnableVertexArrayAttribEXT( ii+1, ii );
+    EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::generic[ii].enabled );
+    checkPpcaDefaults(ctx, ppca);
+
+    ppca.VertexArray::generic[ii].enabled = GL_TRUE;
+    ppca.glDisableVertexArrayAttribEXT( ii+1, ii );
+    EXPECT_EQ( GLboolean(GL_TRUE), ppca.VertexArray::generic[ii].enabled );
+    ppca.VertexArray::generic[ii].enabled = GL_FALSE;
+    checkPpcaDefaults(ctx, ppca);
+  }
+}
+
+TEST ( RegalPpca, glEnableDisableVertexArrayEXT_Shadowing )
+{
+  RegalContext ctx;
+  ctx.info = new ContextInfo();
+
+  Ppca ppca;
+  checkPpcaDefaults(ctx, ppca);
+
+  // test glEnableVertexArrayEXT & glDisableVertexArrayEXT with no vertex array object
+
+  for (GLuint ii=0; ii<ClientState::nNamedArrays; ii++)
+  {
+    ppca.Reset(ctx);
+    checkPpcaDefaults(ctx, ppca);
+
+    if (ii < 7)
+    {
+      ppca.glEnableVertexArrayEXT( 0, Regal::ClientState::vaEnum[ii][0] );
+      EXPECT_EQ( GLboolean(GL_TRUE), ppca.VertexArray::named[ii].enabled );
+      ppca.VertexArray::named[ii].enabled = GL_FALSE;
+      checkPpcaDefaults(ctx, ppca);
+      ppca.VertexArray::named[ii].enabled = GL_TRUE;
+      ppca.glDisableVertexArrayEXT( 0, Regal::ClientState::vaEnum[ii][0] );
+      checkPpcaDefaults(ctx, ppca);
+    }
+    else
+    {
+      ppca.VertexArray::clientActiveTexture = GL_TEXTURE0 + ii - 7;
+      ppca.glEnableVertexArrayEXT( 0, Regal::ClientState::vaEnum[7][0] );
+      EXPECT_EQ( GLboolean(GL_TRUE), ppca.VertexArray::named[ii].enabled );
+      ppca.VertexArray::named[ii].enabled = GL_FALSE;
+      ppca.VertexArray::clientActiveTexture = GL_TEXTURE0;
+      checkPpcaDefaults(ctx, ppca);
+      ppca.VertexArray::clientActiveTexture = GL_TEXTURE0 + ii - 7;
+      ppca.VertexArray::named[ii].enabled = GL_TRUE;
+      ppca.glDisableVertexArrayEXT( 0, Regal::ClientState::vaEnum[7][0] );
+      ppca.VertexArray::clientActiveTexture = GL_TEXTURE0;
+      checkPpcaDefaults(ctx, ppca);
+    }
+  }
+
+  // test glEnableVertexArrayEXT & glDisableVertexArrayEXT with a vertex array object
+
+  for (GLuint ii=0; ii<ClientState::nNamedArrays; ii++)
+  {
+    ppca.Reset(ctx);
+    checkPpcaDefaults(ctx, ppca);
+
+    if (ii < 7)
+    {
+      ppca.glEnableVertexArrayEXT( ii+1, Regal::ClientState::vaEnum[ii][0] );
+      checkPpcaDefaults(ctx, ppca);
+
+      ppca.VertexArray::named[ii].enabled = GL_TRUE;
+      ppca.glDisableVertexArrayEXT( ii+1, Regal::ClientState::vaEnum[ii][0] );
+      EXPECT_EQ( GLboolean(GL_TRUE), ppca.VertexArray::named[ii].enabled );
+      ppca.VertexArray::named[ii].enabled = GL_FALSE;
+      checkPpcaDefaults(ctx, ppca);
+    }
+    else
+    {
+      ppca.VertexArray::clientActiveTexture = GL_TEXTURE0 + ii - 7;
+      ppca.glEnableVertexArrayEXT( ii+1, Regal::ClientState::vaEnum[7][0] );
+      EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::named[ii].enabled );
+      ppca.VertexArray::clientActiveTexture = GL_TEXTURE0;
+      checkPpcaDefaults(ctx, ppca);
+
+      ppca.VertexArray::clientActiveTexture = GL_TEXTURE0 + ii - 7;
+      ppca.VertexArray::named[ii].enabled = GL_TRUE;
+      ppca.glDisableVertexArrayEXT( ii+1, Regal::ClientState::vaEnum[7][0] );
+      EXPECT_EQ( GLboolean(GL_TRUE), ppca.VertexArray::named[ii].enabled );
+      ppca.VertexArray::named[ii].enabled = GL_FALSE;
+      ppca.VertexArray::clientActiveTexture = GL_TEXTURE0;
+      checkPpcaDefaults(ctx, ppca);
+    }
+  }
+}
+
+TEST ( RegalPpca, glVertexAttribBinding_Shadowing )
+{
+  RegalContext ctx;
+  ctx.info = new ContextInfo();
+
+  Ppca ppca;
+  checkPpcaDefaults(ctx, ppca);
+
+  // test glVertexAttribBinding with no vertex array bound
+
+  for (GLuint ii=0; ii<REGAL_EMU_MAX_VERTEX_ATTRIBS; ii++)
+  {
+    ppca.Reset(ctx);
+    checkPpcaDefaults(ctx, ppca);
+    ppca.VertexArray::vertexArrayBinding = 0;
+
+    ppca.glVertexAttribBinding( ii, ii+1 );
+    EXPECT_EQ( GLuint(ii+1), ppca.VertexArray::generic[ii].bindingIndex );
+    ppca.VertexArray::generic[ii].bindingIndex = ii;
+    checkPpcaDefaults(ctx, ppca);
+  }
+
+  // test glVertexAttribBinding with a vertex array bound
+
+  for (GLuint ii=0; ii<REGAL_EMU_MAX_VERTEX_ATTRIBS; ii++)
+  {
+    ppca.Reset(ctx);
+    checkPpcaDefaults(ctx, ppca);
+    ppca.VertexArray::vertexArrayBinding = 1;
+
+    ppca.VertexArray::generic[ii].bindingIndex = ii+1;
+    ppca.glVertexAttribBinding( ii, 0 );
+    EXPECT_EQ( GLuint(ii+1), ppca.VertexArray::generic[ii].bindingIndex );
+    ppca.VertexArray::vertexArrayBinding = 0;
+    ppca.VertexArray::generic[ii].bindingIndex = ii;
+    checkPpcaDefaults(ctx, ppca);
+  }
+}
+
+TEST ( RegalPpca, glVertexBindingDivisor_Shadowing )
+{
+  RegalContext ctx;
+  ctx.info = new ContextInfo();
+
+  Ppca ppca;
+  checkPpcaDefaults(ctx, ppca);
+
+  // test glVertexBindingDivisor with no vertex array bound
+
+  for (GLuint ii=0; ii<REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS; ii++)
+  {
+    ppca.Reset(ctx);
+    checkPpcaDefaults(ctx, ppca);
+    ppca.VertexArray::vertexArrayBinding = 0;
+
+    ppca.glVertexBindingDivisor( ii, 333 );
+    EXPECT_EQ( GLuint(333), ppca.VertexArray::bindings[ii].divisor );
+    ppca.VertexArray::bindings[ii].divisor = 0;
+    checkPpcaDefaults(ctx, ppca);
+  }
+
+  // test glVertexBindingDivisor with a vertex array bound
+
+  for (GLuint ii=0; ii<REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS; ii++)
+  {
+    ppca.Reset(ctx);
+    checkPpcaDefaults(ctx, ppca);
+    ppca.VertexArray::vertexArrayBinding = 1;
+
+    ppca.VertexArray::bindings[ii].divisor = 333;
+    ppca.glVertexBindingDivisor( ii, 555 );
+    EXPECT_EQ( GLuint(333), ppca.VertexArray::bindings[ii].divisor );
+    ppca.VertexArray::bindings[ii].divisor = 0;
+    ppca.VertexArray::vertexArrayBinding = 0;
+    checkPpcaDefaults(ctx, ppca);
+  }
+
+  // test glVertexAttribDivisor with no vertex array bound
+
+  for (GLuint ii=0; ii<REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS; ii++)
+  {
+    ppca.Reset(ctx);
+    checkPpcaDefaults(ctx, ppca);
+    ppca.VertexArray::vertexArrayBinding = 0;
+
+    if (ii<REGAL_EMU_MAX_VERTEX_ATTRIBS)
+    {
+      ppca.glVertexAttribDivisor( ii, 555 );
+      EXPECT_EQ( GLuint(555), ppca.VertexArray::bindings[ii].divisor );
+      EXPECT_EQ( GLuint(ii), ppca.VertexArray::generic[ii].bindingIndex );
+      ppca.VertexArray::bindings[ii].divisor = 0;
+      ppca.VertexArray::generic[ii].bindingIndex = ii;
+    }
+    else
+    {
+      ppca.VertexArray::bindings[ii].divisor = 333;
+      ppca.glVertexAttribDivisor( ii, 555 );
+      EXPECT_EQ( GLuint(333), ppca.VertexArray::bindings[ii].divisor );
+      ppca.VertexArray::bindings[ii].divisor = 0;
+      ppca.VertexArray::vertexArrayBinding = 0;
+    }
+    checkPpcaDefaults(ctx, ppca);
+  }
+
+  // test glVertexAttribDivisor with a vertex array bound
+
+  for (GLuint ii=0; ii<REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS; ii++)
+  {
+    ppca.Reset(ctx);
+    checkPpcaDefaults(ctx, ppca);
+    ppca.VertexArray::vertexArrayBinding = 1;
+
+    if (ii<REGAL_EMU_MAX_VERTEX_ATTRIBS)
+    {
+      ppca.VertexArray::bindings[ii].divisor = 333;
+      ppca.VertexArray::generic[ii].bindingIndex = 333;
+      ppca.glVertexAttribDivisor( ii, 555 );
+      EXPECT_EQ( GLuint(333), ppca.VertexArray::bindings[ii].divisor );
+      EXPECT_EQ( GLuint(333), ppca.VertexArray::generic[ii].bindingIndex );
+      ppca.VertexArray::bindings[ii].divisor = 0;
+      ppca.VertexArray::generic[ii].bindingIndex = ii;
+      ppca.VertexArray::vertexArrayBinding = 0;
+    }
+    else
+    {
+      ppca.VertexArray::bindings[ii].divisor = 333;
+      ppca.glVertexAttribDivisor( ii, 555 );
+      EXPECT_EQ( GLuint(333), ppca.VertexArray::bindings[ii].divisor );
+      ppca.VertexArray::bindings[ii].divisor = 0;
+      ppca.VertexArray::vertexArrayBinding = 0;
+    }
+    checkPpcaDefaults(ctx, ppca);
+  }
+}
+
+TEST ( RegalPpca, glBindVertexBuffer_Shadowing )
+{
+  RegalContext ctx;
+  ctx.info = new ContextInfo();
+
+  Ppca ppca;
+  checkPpcaDefaults(ctx, ppca);
+
+  // test glBindVertexBuffer with no vertex array bound
+
+  for (GLuint ii=0; ii<REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS; ii++)
+  {
+    ppca.Reset(ctx);
+    checkPpcaDefaults(ctx, ppca);
+    ppca.VertexArray::vertexArrayBinding = 0;
+
+    ppca.glBindVertexBuffer( ii, GLuint(2 * ii + 1), GLintptr(0xbeef), ii+3 );
+
+    EXPECT_EQ( GLuint(2 * ii + 1), ppca.VertexArray::bindings[ii].buffer );
+    EXPECT_EQ( GLintptr( 0xbeef), ppca.VertexArray::bindings[ii].offset );
+    EXPECT_EQ( GLsizei(ii + 3), ppca.VertexArray::bindings[ii].stride );
+    ppca.VertexArray::bindings[ii].buffer = GLuint(0);
+    ppca.VertexArray::bindings[ii].offset = GLintptr(0);
+    ppca.VertexArray::bindings[ii].stride = GLsizei(16);
+    checkPpcaDefaults(ctx, ppca);
+  }
+
+  // test glBindVertexBuffer with a vertex array bound
+
+  for (GLuint ii=0; ii<REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS; ii++)
+  {
+    ppca.Reset(ctx);
+    checkPpcaDefaults(ctx, ppca);
+    ppca.VertexArray::vertexArrayBinding = 1;
+
+    ppca.VertexArray::bindings[ii].buffer = GLuint(333);
+    ppca.VertexArray::bindings[ii].offset = GLintptr(0xdead);
+    ppca.VertexArray::bindings[ii].stride = GLsizei(11);
+
+    ppca.glBindVertexBuffer( ii, 1, 1, 1 );
+
+    EXPECT_EQ( GLuint(333), ppca.VertexArray::bindings[ii].buffer );
+    EXPECT_EQ( GLintptr(0xdead), ppca.VertexArray::bindings[ii].offset );
+    EXPECT_EQ( GLsizei(11), ppca.VertexArray::bindings[ii].stride );
+
+    ppca.VertexArray::vertexArrayBinding = GLuint(0);
+    ppca.VertexArray::bindings[ii].buffer = GLuint(0);
+    ppca.VertexArray::bindings[ii].offset = GLintptr(0);
+    ppca.VertexArray::bindings[ii].stride = GLsizei(16);
+    checkPpcaDefaults(ctx, ppca);
+  }
+}
+
+TEST ( RegalPpca, glBindVertexBuffers_Shadowing )
+{
+  RegalContext ctx;
+  ctx.info = new ContextInfo();
+
+  Ppca ppca;
+  checkPpcaDefaults(ctx, ppca);
+
+  GLuint    buffers[REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS];
+  GLintptr  offsets[REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS];
+  GLsizei   strides[REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS];
+
+  for (GLuint ii=0; ii<REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS; ii++)
+  {
+    buffers[ii] = GLuint(2 * ii + 1);
+    offsets[ii] = GLintptr(0xbeef);
+    strides[ii] = GLsizei(ii+3);
+  }
+
+  // first test with "real" buffers, offsets, and strides
+
+  // test glBindVertexBuffers with no vertex array bound
+
+  ppca.Reset(ctx);
+  checkPpcaDefaults(ctx, ppca);
+
+  ppca.VertexArray::vertexArrayBinding = 0;
+  ppca.glBindVertexBuffers( 0, REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS, buffers, offsets, strides );
+
+  for (GLuint ii=0; ii<REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS; ii++)
+  {
+    EXPECT_EQ( GLuint(2 * ii + 1), ppca.VertexArray::bindings[ii].buffer );
+    EXPECT_EQ( GLintptr( 0xbeef), ppca.VertexArray::bindings[ii].offset );
+    EXPECT_EQ( GLsizei(ii + 3), ppca.VertexArray::bindings[ii].stride );
+    ppca.VertexArray::bindings[ii].buffer = GLuint(0);
+    ppca.VertexArray::bindings[ii].offset = GLintptr(0);
+    ppca.VertexArray::bindings[ii].stride = GLsizei(16);
+  }
+  checkPpcaDefaults(ctx, ppca);
+
+  // test glBindVertexBuffers with a vertex array bound
+
+  ppca.Reset(ctx);
+  checkPpcaDefaults(ctx, ppca);
+
+  for (GLuint ii=0; ii<REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS; ii++)
+  {
+    ppca.VertexArray::bindings[ii].buffer = GLuint(333);
+    ppca.VertexArray::bindings[ii].offset = GLintptr(0xdead);
+    ppca.VertexArray::bindings[ii].stride = GLsizei(11);
+  }
+
+  ppca.VertexArray::vertexArrayBinding = 1;
+  ppca.glBindVertexBuffers( 0, REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS, buffers, offsets, strides );
+
+  for (GLuint ii=0; ii<REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS; ii++)
+  {
+    EXPECT_EQ( GLuint(333),      ppca.VertexArray::bindings[ii].buffer );
+    EXPECT_EQ( GLintptr(0xdead), ppca.VertexArray::bindings[ii].offset );
+    EXPECT_EQ( GLsizei(11),      ppca.VertexArray::bindings[ii].stride );
+
+    ppca.VertexArray::bindings[ii].buffer = GLuint(0);
+    ppca.VertexArray::bindings[ii].offset = GLintptr(0);
+    ppca.VertexArray::bindings[ii].stride = GLsizei(16);
+  }
+  ppca.VertexArray::vertexArrayBinding = GLuint(0);
+  checkPpcaDefaults(ctx, ppca);
+
+  // test partial glBindVertexBuffers with no vertex array bound
+
+  ppca.Reset(ctx);
+  checkPpcaDefaults(ctx, ppca);
+
+  ppca.VertexArray::vertexArrayBinding = 0;
+  ppca.glBindVertexBuffers( 5, REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS-5, &(buffers[5]), &(offsets[5]), &(strides[5]) );
+
+  for (GLuint ii=5; ii<REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS; ii++)
+  {
+    EXPECT_EQ( GLuint(2 * ii + 1), ppca.VertexArray::bindings[ii].buffer );
+    EXPECT_EQ( GLintptr( 0xbeef), ppca.VertexArray::bindings[ii].offset );
+    EXPECT_EQ( GLsizei(ii + 3), ppca.VertexArray::bindings[ii].stride );
+    ppca.VertexArray::bindings[ii].buffer = GLuint(0);
+    ppca.VertexArray::bindings[ii].offset = GLintptr(0);
+    ppca.VertexArray::bindings[ii].stride = GLsizei(16);
+  }
+  checkPpcaDefaults(ctx, ppca);
+
+  // test partial glBindVertexBuffers with a vertex array bound
+
+  ppca.Reset(ctx);
+  checkPpcaDefaults(ctx, ppca);
+
+  for (GLuint ii=5; ii<REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS; ii++)
+  {
+    ppca.VertexArray::bindings[ii].buffer = GLuint(333);
+    ppca.VertexArray::bindings[ii].offset = GLintptr(0xdead);
+    ppca.VertexArray::bindings[ii].stride = GLsizei(11);
+  }
+
+  ppca.VertexArray::vertexArrayBinding = 1;
+  ppca.glBindVertexBuffers( 5, REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS-5, &(buffers[5]), &(offsets[5]), &(strides[5]) );
+
+  for (GLuint ii=5; ii<REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS; ii++)
+  {
+    EXPECT_EQ( GLuint(333),      ppca.VertexArray::bindings[ii].buffer );
+    EXPECT_EQ( GLintptr(0xdead), ppca.VertexArray::bindings[ii].offset );
+    EXPECT_EQ( GLsizei(11),      ppca.VertexArray::bindings[ii].stride );
+
+    ppca.VertexArray::bindings[ii].buffer = GLuint(0);
+    ppca.VertexArray::bindings[ii].offset = GLintptr(0);
+    ppca.VertexArray::bindings[ii].stride = GLsizei(16);
+  }
+  ppca.VertexArray::vertexArrayBinding = GLuint(0);
+  checkPpcaDefaults(ctx, ppca);
+
+  // a second partial test glBindVertexBuffers with no vertex array bound
+
+  ppca.Reset(ctx);
+  checkPpcaDefaults(ctx, ppca);
+
+  ppca.VertexArray::vertexArrayBinding = 0;
+  ppca.glBindVertexBuffers( 3, 3, &(buffers[3]), &(offsets[3]), &(strides[3]) );
+
+  for (GLuint ii=3; ii<6; ii++)
+  {
+    EXPECT_EQ( GLuint(2 * ii + 1), ppca.VertexArray::bindings[ii].buffer );
+    EXPECT_EQ( GLintptr( 0xbeef),  ppca.VertexArray::bindings[ii].offset );
+    EXPECT_EQ( GLsizei(ii + 3),    ppca.VertexArray::bindings[ii].stride );
+    ppca.VertexArray::bindings[ii].buffer = GLuint(0);
+    ppca.VertexArray::bindings[ii].offset = GLintptr(0);
+    ppca.VertexArray::bindings[ii].stride = GLsizei(16);
+  }
+  checkPpcaDefaults(ctx, ppca);
+
+  // a second partial test glBindVertexBuffers with a vertex array bound
+
+  ppca.Reset(ctx);
+  checkPpcaDefaults(ctx, ppca);
+
+  for (GLuint ii=3; ii<6; ii++)
+  {
+    ppca.VertexArray::bindings[ii].buffer = GLuint(333);
+    ppca.VertexArray::bindings[ii].offset = GLintptr(0xdead);
+    ppca.VertexArray::bindings[ii].stride = GLsizei(11);
+  }
+
+  ppca.VertexArray::vertexArrayBinding = 1;
+  ppca.glBindVertexBuffers( 3, 3, &(buffers[3]), &(offsets[3]), &(strides[3]) );
+
+  for (GLuint ii=3; ii<6; ii++)
+  {
+    EXPECT_EQ( GLuint(333),      ppca.VertexArray::bindings[ii].buffer );
+    EXPECT_EQ( GLintptr(0xdead), ppca.VertexArray::bindings[ii].offset );
+    EXPECT_EQ( GLsizei(11),      ppca.VertexArray::bindings[ii].stride );
+
+    ppca.VertexArray::bindings[ii].buffer = GLuint(0);
+    ppca.VertexArray::bindings[ii].offset = GLintptr(0);
+    ppca.VertexArray::bindings[ii].stride = GLsizei(16);
+  }
+  ppca.VertexArray::vertexArrayBinding = GLuint(0);
+  checkPpcaDefaults(ctx, ppca);
+
+  // a third partial test glBindVertexBuffers with no vertex array bound
+
+  ppca.Reset(ctx);
+  checkPpcaDefaults(ctx, ppca);
+
+  ppca.VertexArray::vertexArrayBinding = 0;
+  ppca.glBindVertexBuffers( 0, 4, buffers, offsets, strides );
+
+  for (GLuint ii=0; ii<4; ii++)
+  {
+    EXPECT_EQ( GLuint(2 * ii + 1), ppca.VertexArray::bindings[ii].buffer );
+    EXPECT_EQ( GLintptr( 0xbeef),  ppca.VertexArray::bindings[ii].offset );
+    EXPECT_EQ( GLsizei(ii + 3),    ppca.VertexArray::bindings[ii].stride );
+    ppca.VertexArray::bindings[ii].buffer = GLuint(0);
+    ppca.VertexArray::bindings[ii].offset = GLintptr(0);
+    ppca.VertexArray::bindings[ii].stride = GLsizei(16);
+  }
+  checkPpcaDefaults(ctx, ppca);
+
+  // a third partial test glBindVertexBuffers with a vertex array bound
+
+  ppca.Reset(ctx);
+  checkPpcaDefaults(ctx, ppca);
+
+  for (GLuint ii=0; ii<4; ii++)
+  {
+    ppca.VertexArray::bindings[ii].buffer = GLuint(333);
+    ppca.VertexArray::bindings[ii].offset = GLintptr(0xdead);
+    ppca.VertexArray::bindings[ii].stride = GLsizei(11);
+  }
+
+  ppca.VertexArray::vertexArrayBinding = 1;
+  ppca.glBindVertexBuffers( 0, 4, buffers, offsets, strides );
+
+  for (GLuint ii=0; ii<4; ii++)
+  {
+    EXPECT_EQ( GLuint(333),      ppca.VertexArray::bindings[ii].buffer );
+    EXPECT_EQ( GLintptr(0xdead), ppca.VertexArray::bindings[ii].offset );
+    EXPECT_EQ( GLsizei(11),      ppca.VertexArray::bindings[ii].stride );
+
+    ppca.VertexArray::bindings[ii].buffer = GLuint(0);
+    ppca.VertexArray::bindings[ii].offset = GLintptr(0);
+    ppca.VertexArray::bindings[ii].stride = GLsizei(16);
+  }
+  ppca.VertexArray::vertexArrayBinding = GLuint(0);
+  checkPpcaDefaults(ctx, ppca);
+
+  // now test passing NULL for buffers
+
+  // test glBindVertexBuffers with no vertex array bound
+
+  ppca.Reset(ctx);
+  checkPpcaDefaults(ctx, ppca);
+
+  for (GLuint ii=0; ii<REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS; ii++)
+  {
+    ppca.VertexArray::bindings[ii].buffer = GLuint(333);
+    ppca.VertexArray::bindings[ii].offset = GLintptr(0xdead);
+    ppca.VertexArray::bindings[ii].stride = GLsizei(11);
+  }
+
+  ppca.VertexArray::vertexArrayBinding = 0;
+  ppca.glBindVertexBuffers( 0, REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS, NULL, offsets, strides );
+
+  checkPpcaDefaults(ctx, ppca);
+
+  // test glBindVertexBuffers with a vertex array bound
+
+  ppca.Reset(ctx);
+  checkPpcaDefaults(ctx, ppca);
+
+  for (GLuint ii=0; ii<REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS; ii++)
+  {
+    ppca.VertexArray::bindings[ii].buffer = GLuint(333);
+    ppca.VertexArray::bindings[ii].offset = GLintptr(0xdead);
+    ppca.VertexArray::bindings[ii].stride = GLsizei(11);
+  }
+
+  ppca.VertexArray::vertexArrayBinding = 1;
+  ppca.glBindVertexBuffers( 0, REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS, NULL, offsets, strides );
+
+  for (GLuint ii=0; ii<REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS; ii++)
+  {
+    EXPECT_EQ( GLuint(333),      ppca.VertexArray::bindings[ii].buffer );
+    EXPECT_EQ( GLintptr(0xdead), ppca.VertexArray::bindings[ii].offset );
+    EXPECT_EQ( GLsizei(11),      ppca.VertexArray::bindings[ii].stride );
+
+    ppca.VertexArray::bindings[ii].buffer = GLuint(0);
+    ppca.VertexArray::bindings[ii].offset = GLintptr(0);
+    ppca.VertexArray::bindings[ii].stride = GLsizei(16);
+  }
+  ppca.VertexArray::vertexArrayBinding = GLuint(0);
+  checkPpcaDefaults(ctx, ppca);
+
+  // test partial glBindVertexBuffers with no vertex array bound
+
+  ppca.Reset(ctx);
+  checkPpcaDefaults(ctx, ppca);
+
+  for (GLuint ii=0; ii<REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS; ii++)
+  {
+    ppca.VertexArray::bindings[ii].buffer = GLuint(333);
+    ppca.VertexArray::bindings[ii].offset = GLintptr(0xdead);
+    ppca.VertexArray::bindings[ii].stride = GLsizei(11);
+  }
+
+  ppca.VertexArray::vertexArrayBinding = 0;
+  ppca.glBindVertexBuffers( 5, REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS-5, NULL, &(offsets[5]), &(strides[5]) );
+
+  for (GLuint ii=0; ii<REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS; ii++)
+  {
+    if (ii < 5)
+    {
+      EXPECT_EQ( GLuint(333),      ppca.VertexArray::bindings[ii].buffer );
+      EXPECT_EQ( GLintptr(0xdead), ppca.VertexArray::bindings[ii].offset );
+      EXPECT_EQ( GLsizei(11),      ppca.VertexArray::bindings[ii].stride );
+    }
+
+    ppca.VertexArray::bindings[ii].buffer = GLuint(0);
+    ppca.VertexArray::bindings[ii].offset = GLintptr(0);
+    ppca.VertexArray::bindings[ii].stride = GLsizei(16);
+  }
+  checkPpcaDefaults(ctx, ppca);
+
+  // test partial glBindVertexBuffers with a vertex array bound
+
+  ppca.Reset(ctx);
+  checkPpcaDefaults(ctx, ppca);
+
+  for (GLuint ii=0; ii<REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS; ii++)
+  {
+    ppca.VertexArray::bindings[ii].buffer = GLuint(333);
+    ppca.VertexArray::bindings[ii].offset = GLintptr(0xdead);
+    ppca.VertexArray::bindings[ii].stride = GLsizei(11);
+  }
+
+  ppca.VertexArray::vertexArrayBinding = 1;
+  ppca.glBindVertexBuffers( 5, REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS-5, NULL, &(offsets[5]), &(strides[5]) );
+
+  for (GLuint ii=0; ii<REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS; ii++)
+  {
+    EXPECT_EQ( GLuint(333),      ppca.VertexArray::bindings[ii].buffer );
+    EXPECT_EQ( GLintptr(0xdead), ppca.VertexArray::bindings[ii].offset );
+    EXPECT_EQ( GLsizei(11),      ppca.VertexArray::bindings[ii].stride );
+
+    ppca.VertexArray::bindings[ii].buffer = GLuint(0);
+    ppca.VertexArray::bindings[ii].offset = GLintptr(0);
+    ppca.VertexArray::bindings[ii].stride = GLsizei(16);
+  }
+  ppca.VertexArray::vertexArrayBinding = GLuint(0);
+  checkPpcaDefaults(ctx, ppca);
+
+  // a second partial test glBindVertexBuffers with no vertex array bound
+
+  ppca.Reset(ctx);
+  checkPpcaDefaults(ctx, ppca);
+
+  for (GLuint ii=0; ii<REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS; ii++)
+  {
+    ppca.VertexArray::bindings[ii].buffer = GLuint(333);
+    ppca.VertexArray::bindings[ii].offset = GLintptr(0xdead);
+    ppca.VertexArray::bindings[ii].stride = GLsizei(11);
+  }
+
+  ppca.VertexArray::vertexArrayBinding = 0;
+  ppca.glBindVertexBuffers( 3, 3, NULL, &(offsets[3]), &(strides[3]) );
+
+  for (GLuint ii=0; ii<REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS; ii++)
+  {
+    if (ii >= 3 && ii < 6)
+    {
+      EXPECT_EQ( GLuint(0),   ppca.VertexArray::bindings[ii].buffer );
+      EXPECT_EQ( GLintptr(0), ppca.VertexArray::bindings[ii].offset );
+      EXPECT_EQ( GLsizei(16), ppca.VertexArray::bindings[ii].stride );
+    }
+    else
+    {
+      EXPECT_EQ( GLuint(333),      ppca.VertexArray::bindings[ii].buffer );
+      EXPECT_EQ( GLintptr(0xdead), ppca.VertexArray::bindings[ii].offset );
+      EXPECT_EQ( GLsizei(11),      ppca.VertexArray::bindings[ii].stride );
+    }
+
+    ppca.VertexArray::bindings[ii].buffer = GLuint(0);
+    ppca.VertexArray::bindings[ii].offset = GLintptr(0);
+    ppca.VertexArray::bindings[ii].stride = GLsizei(16);
+  }
+  checkPpcaDefaults(ctx, ppca);
+
+  // a second partial test glBindVertexBuffers with a vertex array bound
+
+  ppca.Reset(ctx);
+  checkPpcaDefaults(ctx, ppca);
+
+  for (GLuint ii=0; ii<REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS; ii++)
+  {
+    ppca.VertexArray::bindings[ii].buffer = GLuint(333);
+    ppca.VertexArray::bindings[ii].offset = GLintptr(0xdead);
+    ppca.VertexArray::bindings[ii].stride = GLsizei(11);
+  }
+
+  ppca.VertexArray::vertexArrayBinding = 1;
+  ppca.glBindVertexBuffers( 3, 3, NULL, &(offsets[3]), &(strides[3]) );
+
+  for (GLuint ii=0; ii<REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS; ii++)
+  {
+    EXPECT_EQ( GLuint(333),      ppca.VertexArray::bindings[ii].buffer );
+    EXPECT_EQ( GLintptr(0xdead), ppca.VertexArray::bindings[ii].offset );
+    EXPECT_EQ( GLsizei(11),      ppca.VertexArray::bindings[ii].stride );
+
+    ppca.VertexArray::bindings[ii].buffer = GLuint(0);
+    ppca.VertexArray::bindings[ii].offset = GLintptr(0);
+    ppca.VertexArray::bindings[ii].stride = GLsizei(16);
+  }
+  ppca.VertexArray::vertexArrayBinding = GLuint(0);
+  checkPpcaDefaults(ctx, ppca);
+
+  // a third partial test glBindVertexBuffers with no vertex array bound
+
+  ppca.Reset(ctx);
+  checkPpcaDefaults(ctx, ppca);
+
+  for (GLuint ii=0; ii<REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS; ii++)
+  {
+    ppca.VertexArray::bindings[ii].buffer = GLuint(333);
+    ppca.VertexArray::bindings[ii].offset = GLintptr(0xdead);
+    ppca.VertexArray::bindings[ii].stride = GLsizei(11);
+  }
+
+  ppca.VertexArray::vertexArrayBinding = 0;
+  ppca.glBindVertexBuffers( 0, 4, NULL, offsets, strides );
+
+  for (GLuint ii=0; ii<REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS; ii++)
+  {
+    if (ii < 4)
+    {
+      EXPECT_EQ( GLuint(0),   ppca.VertexArray::bindings[ii].buffer );
+      EXPECT_EQ( GLintptr(0), ppca.VertexArray::bindings[ii].offset );
+      EXPECT_EQ( GLsizei(16), ppca.VertexArray::bindings[ii].stride );
+    }
+    else
+    {
+      EXPECT_EQ( GLuint(333),      ppca.VertexArray::bindings[ii].buffer );
+      EXPECT_EQ( GLintptr(0xdead), ppca.VertexArray::bindings[ii].offset );
+      EXPECT_EQ( GLsizei(11),      ppca.VertexArray::bindings[ii].stride );
+    }
+
+    ppca.VertexArray::bindings[ii].buffer = GLuint(0);
+    ppca.VertexArray::bindings[ii].offset = GLintptr(0);
+    ppca.VertexArray::bindings[ii].stride = GLsizei(16);
+  }
+
+  checkPpcaDefaults(ctx, ppca);
+
+  // a third partial test glBindVertexBuffers with a vertex array bound
+
+  ppca.Reset(ctx);
+  checkPpcaDefaults(ctx, ppca);
+
+  for (GLuint ii=0; ii<REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS; ii++)
+  {
+    ppca.VertexArray::bindings[ii].buffer = GLuint(333);
+    ppca.VertexArray::bindings[ii].offset = GLintptr(0xdead);
+    ppca.VertexArray::bindings[ii].stride = GLsizei(11);
+  }
+
+  ppca.VertexArray::vertexArrayBinding = 1;
+  ppca.glBindVertexBuffers( 0, 4, NULL, offsets, strides );
+
+  for (GLuint ii=0; ii<REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS; ii++)
+  {
+    EXPECT_EQ( GLuint(333),      ppca.VertexArray::bindings[ii].buffer );
+    EXPECT_EQ( GLintptr(0xdead), ppca.VertexArray::bindings[ii].offset );
+    EXPECT_EQ( GLsizei(11),      ppca.VertexArray::bindings[ii].stride );
+
+    ppca.VertexArray::bindings[ii].buffer = GLuint(0);
+    ppca.VertexArray::bindings[ii].offset = GLintptr(0);
+    ppca.VertexArray::bindings[ii].stride = GLsizei(16);
+  }
+  ppca.VertexArray::vertexArrayBinding = GLuint(0);
+  checkPpcaDefaults(ctx, ppca);
+}
+
+TEST ( RegalPpca, glVertexAttribFormat_Shadowing )
+{
+  RegalContext ctx;
+  ctx.info = new ContextInfo();
+
+  Ppca ppca;
+  checkPpcaDefaults(ctx, ppca);
+
+  // test glVertexAttrib(I|L|)Format with no vertex array bound
+
+  for (GLuint ii=0; ii<REGAL_EMU_MAX_VERTEX_ATTRIBS; ii++)
+  {
+    ppca.Reset(ctx);
+    checkPpcaDefaults(ctx, ppca);
+
+    ppca.VertexArray::vertexArrayBinding = 0;
+    ppca.glVertexAttribIFormat( ii, GLuint(2 * ii + 1), GLenum(ii), GLuint(ii + 3) );
+
+    EXPECT_EQ( GLuint(2 * ii + 1), ppca.VertexArray::generic[ii].size );
+    EXPECT_EQ( GLenum(ii), ppca.VertexArray::generic[ii].type );
+    EXPECT_EQ( GLuint(ii + 3), ppca.VertexArray::generic[ii].relativeOffset );
+    EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::generic[ii].normalized );
+    EXPECT_EQ( GLboolean(GL_TRUE), ppca.VertexArray::generic[ii].isInteger );
+    EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::generic[ii].isLong );
+
+    ppca.VertexArray::generic[ii].size = 4;
+    ppca.VertexArray::generic[ii].type = GL_FLOAT;
+    ppca.VertexArray::generic[ii].relativeOffset = GLuint(0);
+    ppca.VertexArray::generic[ii].isInteger = GL_FALSE;
+
+    checkPpcaDefaults(ctx, ppca);
+
+    ppca.VertexArray::vertexArrayBinding = 0;
+    ppca.glVertexAttribLFormat( ii, GLuint(2 * ii + 1), GLenum(ii), ii + 3 );
+
+    EXPECT_EQ( GLuint(2 * ii + 1), ppca.VertexArray::generic[ii].size );
+    EXPECT_EQ( GLenum(ii), ppca.VertexArray::generic[ii].type );
+    EXPECT_EQ( GLuint(ii + 3), ppca.VertexArray::generic[ii].relativeOffset );
+    EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::generic[ii].normalized );
+    EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::generic[ii].isInteger );
+    EXPECT_EQ( GLboolean(GL_TRUE), ppca.VertexArray::generic[ii].isLong );
+
+    ppca.VertexArray::generic[ii].size = 4;
+    ppca.VertexArray::generic[ii].type = GL_FLOAT;
+    ppca.VertexArray::generic[ii].relativeOffset = GLuint(0);
+    ppca.VertexArray::generic[ii].isLong = GL_FALSE;
+
+    checkPpcaDefaults(ctx, ppca);
+
+    ppca.VertexArray::vertexArrayBinding = 0;
+    ppca.VertexArray::generic[ii].normalized = GL_FALSE;
+    ppca.glVertexAttribFormat( ii, GLuint(2 * ii + 1), GLenum(ii), GL_TRUE, ii + 3 );
+
+    EXPECT_EQ( GLuint(2 * ii + 1), ppca.VertexArray::generic[ii].size );
+    EXPECT_EQ( GLenum(ii), ppca.VertexArray::generic[ii].type );
+    EXPECT_EQ( GLuint(ii + 3), ppca.VertexArray::generic[ii].relativeOffset );
+    EXPECT_EQ( GLboolean(GL_TRUE), ppca.VertexArray::generic[ii].normalized );
+    EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::generic[ii].isInteger );
+    EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::generic[ii].isLong );
+
+    ppca.VertexArray::generic[ii].size = 4;
+    ppca.VertexArray::generic[ii].type = GL_FLOAT;
+    ppca.VertexArray::generic[ii].relativeOffset = GLuint(0);
+    ppca.VertexArray::generic[ii].normalized = GL_FALSE;
+
+    checkPpcaDefaults(ctx, ppca);
+
+    ppca.VertexArray::vertexArrayBinding = 0;
+    ppca.VertexArray::generic[ii].normalized = GL_TRUE;
+    ppca.glVertexAttribFormat( ii, GLuint(2 * ii + 1), GLenum(ii), GL_FALSE, ii + 3 );
+
+    EXPECT_EQ( GLuint(2 * ii + 1), ppca.VertexArray::generic[ii].size );
+    EXPECT_EQ( GLenum(ii), ppca.VertexArray::generic[ii].type );
+    EXPECT_EQ( GLuint(ii + 3), ppca.VertexArray::generic[ii].relativeOffset );
+    EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::generic[ii].normalized );
+    EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::generic[ii].isInteger );
+    EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::generic[ii].isLong );
+
+    ppca.VertexArray::generic[ii].size = 4;
+    ppca.VertexArray::generic[ii].type = GL_FLOAT;
+    ppca.VertexArray::generic[ii].relativeOffset = GLuint(0);
+
+    checkPpcaDefaults(ctx, ppca);
+  }
+
+  // test glVertexAttrib(I|L|)Format with a vertex array bound
+
+  for (GLuint ii=0; ii<REGAL_EMU_MAX_VERTEX_ATTRIBS; ii++)
+  {
+    ppca.Reset(ctx);
+    checkPpcaDefaults(ctx, ppca);
+
+    ppca.VertexArray::generic[ii].size = 2 * ii + 3;
+    ppca.VertexArray::generic[ii].type = GLenum(2 * ii + 4);
+    ppca.VertexArray::generic[ii].relativeOffset = GLuint(2 * ii + 5);
+    ppca.VertexArray::generic[ii].normalized = GL_TRUE;
+    ppca.VertexArray::generic[ii].isInteger = GL_TRUE;
+    ppca.VertexArray::generic[ii].isLong = GL_TRUE;
+
+    ppca.VertexArray::vertexArrayBinding = 1;
+    ppca.glVertexAttribIFormat( ii, ii + 1, GLenum(ii + 2), ii + 3 );
+
+    EXPECT_EQ( GLuint(2 * ii + 3), ppca.VertexArray::generic[ii].size );
+    EXPECT_EQ( GLenum(2 * ii + 4), ppca.VertexArray::generic[ii].type );
+    EXPECT_EQ( GLuint(2 * ii + 5), ppca.VertexArray::generic[ii].relativeOffset );
+    EXPECT_EQ( GLboolean(GL_TRUE), ppca.VertexArray::generic[ii].normalized );
+    EXPECT_EQ( GLboolean(GL_TRUE), ppca.VertexArray::generic[ii].isInteger );
+    EXPECT_EQ( GLboolean(GL_TRUE), ppca.VertexArray::generic[ii].isLong );
+
+    ppca.VertexArray::generic[ii].size = 4;
+    ppca.VertexArray::generic[ii].type = GL_FLOAT;
+    ppca.VertexArray::generic[ii].relativeOffset = GLuint(0);
+    ppca.VertexArray::generic[ii].normalized = GL_FALSE;
+    ppca.VertexArray::generic[ii].isInteger = GL_FALSE;
+    ppca.VertexArray::generic[ii].isLong = GL_FALSE;
+    ppca.VertexArray::vertexArrayBinding = 0;
+
+    checkPpcaDefaults(ctx, ppca);
+
+    ppca.VertexArray::generic[ii].size = 2 * ii + 3;
+    ppca.VertexArray::generic[ii].type = GLenum(2 * ii + 4);
+    ppca.VertexArray::generic[ii].relativeOffset = GLuint(2 * ii + 5);
+    ppca.VertexArray::generic[ii].normalized = GL_TRUE;
+    ppca.VertexArray::generic[ii].isInteger = GL_TRUE;
+    ppca.VertexArray::generic[ii].isLong = GL_TRUE;
+
+    ppca.VertexArray::vertexArrayBinding = 1;
+    ppca.glVertexAttribLFormat( ii, ii + 1, GLenum(ii + 2), ii + 3 );
+
+    EXPECT_EQ( GLuint(2 * ii + 3), ppca.VertexArray::generic[ii].size );
+    EXPECT_EQ( GLenum(2 * ii + 4), ppca.VertexArray::generic[ii].type );
+    EXPECT_EQ( GLuint(2 * ii + 5), ppca.VertexArray::generic[ii].relativeOffset );
+    EXPECT_EQ( GLboolean(GL_TRUE), ppca.VertexArray::generic[ii].normalized );
+    EXPECT_EQ( GLboolean(GL_TRUE), ppca.VertexArray::generic[ii].isInteger );
+    EXPECT_EQ( GLboolean(GL_TRUE), ppca.VertexArray::generic[ii].isLong );
+
+    ppca.VertexArray::generic[ii].size = 4;
+    ppca.VertexArray::generic[ii].type = GL_FLOAT;
+    ppca.VertexArray::generic[ii].relativeOffset = GLuint(0);
+    ppca.VertexArray::generic[ii].normalized = GL_FALSE;
+    ppca.VertexArray::generic[ii].isInteger = GL_FALSE;
+    ppca.VertexArray::generic[ii].isLong = GL_FALSE;
+    ppca.VertexArray::vertexArrayBinding = 0;
+
+    checkPpcaDefaults(ctx, ppca);
+
+    ppca.VertexArray::generic[ii].size = 2 * ii + 3;
+    ppca.VertexArray::generic[ii].type = GLenum(2 * ii + 4);
+    ppca.VertexArray::generic[ii].relativeOffset = GLuint(2 * ii + 5);
+    ppca.VertexArray::generic[ii].normalized = GL_TRUE;
+    ppca.VertexArray::generic[ii].isInteger = GL_TRUE;
+    ppca.VertexArray::generic[ii].isLong = GL_TRUE;
+
+    ppca.VertexArray::vertexArrayBinding = 1;
+    ppca.glVertexAttribFormat( ii, ii + 1, GLenum(ii + 2), GL_FALSE, ii + 3 );
+
+    EXPECT_EQ( GLuint(2 * ii + 3), ppca.VertexArray::generic[ii].size );
+    EXPECT_EQ( GLenum(2 * ii + 4), ppca.VertexArray::generic[ii].type );
+    EXPECT_EQ( GLuint(2 * ii + 5), ppca.VertexArray::generic[ii].relativeOffset );
+    EXPECT_EQ( GLboolean(GL_TRUE), ppca.VertexArray::generic[ii].normalized );
+    EXPECT_EQ( GLboolean(GL_TRUE), ppca.VertexArray::generic[ii].isInteger );
+    EXPECT_EQ( GLboolean(GL_TRUE), ppca.VertexArray::generic[ii].isLong );
+
+    ppca.VertexArray::generic[ii].size = 4;
+    ppca.VertexArray::generic[ii].type = GL_FLOAT;
+    ppca.VertexArray::generic[ii].relativeOffset = GLuint(0);
+    ppca.VertexArray::generic[ii].normalized = GL_FALSE;
+    ppca.VertexArray::generic[ii].isInteger = GL_FALSE;
+    ppca.VertexArray::generic[ii].isLong = GL_FALSE;
+    ppca.VertexArray::vertexArrayBinding = 0;
+
+    checkPpcaDefaults(ctx, ppca);
+
+    ppca.VertexArray::generic[ii].size = 2 * ii + 3;
+    ppca.VertexArray::generic[ii].type = GLenum(2 * ii + 4);
+    ppca.VertexArray::generic[ii].relativeOffset = GLuint(2 * ii + 5);
+    ppca.VertexArray::generic[ii].normalized = GL_FALSE;
+    ppca.VertexArray::generic[ii].isInteger = GL_TRUE;
+    ppca.VertexArray::generic[ii].isLong = GL_TRUE;
+
+    ppca.VertexArray::vertexArrayBinding = 1;
+    ppca.glVertexAttribFormat( ii, ii + 1, GLenum(ii + 2), GL_TRUE, ii + 3 );
+
+    EXPECT_EQ( GLuint(2 * ii + 3), ppca.VertexArray::generic[ii].size );
+    EXPECT_EQ( GLenum(2 * ii + 4), ppca.VertexArray::generic[ii].type );
+    EXPECT_EQ( GLuint(2 * ii + 5), ppca.VertexArray::generic[ii].relativeOffset );
+    EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::generic[ii].normalized );
+    EXPECT_EQ( GLboolean(GL_TRUE), ppca.VertexArray::generic[ii].isInteger );
+    EXPECT_EQ( GLboolean(GL_TRUE), ppca.VertexArray::generic[ii].isLong );
+
+    ppca.VertexArray::generic[ii].size = 4;
+    ppca.VertexArray::generic[ii].type = GL_FLOAT;
+    ppca.VertexArray::generic[ii].relativeOffset = GLuint(0);
+    ppca.VertexArray::generic[ii].normalized = GL_FALSE;
+    ppca.VertexArray::generic[ii].isInteger = GL_FALSE;
+    ppca.VertexArray::generic[ii].isLong = GL_FALSE;
+    ppca.VertexArray::vertexArrayBinding = 0;
+
+    checkPpcaDefaults(ctx, ppca);
+  }
+}
+
+TEST ( RegalPpca, glVertexAttribPointer_Shadowing )
+{
+  RegalContext ctx;
+  ctx.info = new ContextInfo();
+
+  Ppca ppca;
+  checkPpcaDefaults(ctx, ppca);
+
+  // test glVertexAttrib(I|L|)Pointer with no vertex array bound
+
+  for (GLuint ii=0; ii<REGAL_EMU_MAX_VERTEX_ATTRIBS && ii<REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS; ii++)
+  {
+    ppca.Reset(ctx);
+    checkPpcaDefaults(ctx, ppca);
+
+    GLuint   testSize   = GLuint(2 * ii + 1);
+    GLenum   testType   = GLenum(ii);
+    GLsizei  testStride = GLsizei(ii + 3);
+    GLintptr testOffset = (GLintptr)(ii + 4);
+    GLuint   testBuffer = ppca.VertexArray::arrayBufferBinding;
+
+    ppca.VertexArray::generic[ii].relativeOffset = GLuint(1);
+    ppca.VertexArray::vertexArrayBinding = 0;
+    ppca.glVertexAttribIPointer( ii, testSize, testType, testStride, reinterpret_cast<const GLvoid*>(testOffset) );
+
+    EXPECT_EQ( testSize,    ppca.VertexArray::generic[ii].size );
+    EXPECT_EQ( testType,    ppca.VertexArray::generic[ii].type );
+    EXPECT_EQ( GLuint( 0 ), ppca.VertexArray::generic[ii].relativeOffset );
+    EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::generic[ii].normalized );
+    EXPECT_EQ( GLboolean(GL_TRUE),  ppca.VertexArray::generic[ii].isInteger );
+    EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::generic[ii].isLong );
+    EXPECT_EQ( ii,          ppca.VertexArray::generic[ii].bindingIndex );
+
+    EXPECT_EQ( testBuffer,  ppca.VertexArray::bindings[ii].buffer );
+    EXPECT_EQ( testOffset,  ppca.VertexArray::bindings[ii].offset );
+    EXPECT_EQ( testStride,  ppca.VertexArray::bindings[ii].stride );
+
+    ppca.VertexArray::generic[ii].size = 4;
+    ppca.VertexArray::generic[ii].type = GL_FLOAT;
+    ppca.VertexArray::generic[ii].relativeOffset = GLuint(0);
+    ppca.VertexArray::generic[ii].normalized = GL_FALSE;
+    ppca.VertexArray::generic[ii].isInteger = GL_FALSE;
+    ppca.VertexArray::generic[ii].isLong = GL_FALSE;
+    ppca.VertexArray::generic[ii].bindingIndex = ii;
+
+    ppca.VertexArray::bindings[ii].buffer = GLuint(0);
+    ppca.VertexArray::bindings[ii].offset = GLintptr(0);
+    ppca.VertexArray::bindings[ii].stride = GLsizei(16);
+
+    checkPpcaDefaults(ctx, ppca);
+
+    ppca.VertexArray::generic[ii].relativeOffset = GLuint(1);
+    ppca.VertexArray::vertexArrayBinding = 0;
+    ppca.glVertexAttribLPointer( ii, testSize, testType, testStride, reinterpret_cast<const GLvoid*>(testOffset) );
+
+    EXPECT_EQ( testSize,    ppca.VertexArray::generic[ii].size );
+    EXPECT_EQ( testType,    ppca.VertexArray::generic[ii].type );
+    EXPECT_EQ( GLuint( 0 ), ppca.VertexArray::generic[ii].relativeOffset );
+    EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::generic[ii].normalized );
+    EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::generic[ii].isInteger );
+    EXPECT_EQ( GLboolean(GL_TRUE),  ppca.VertexArray::generic[ii].isLong );
+    EXPECT_EQ( ii,          ppca.VertexArray::generic[ii].bindingIndex );
+
+    EXPECT_EQ( testBuffer,  ppca.VertexArray::bindings[ii].buffer );
+    EXPECT_EQ( testOffset,  ppca.VertexArray::bindings[ii].offset );
+    EXPECT_EQ( testStride,  ppca.VertexArray::bindings[ii].stride );
+
+    ppca.VertexArray::generic[ii].size = 4;
+    ppca.VertexArray::generic[ii].type = GL_FLOAT;
+    ppca.VertexArray::generic[ii].relativeOffset = GLuint(0);
+    ppca.VertexArray::generic[ii].normalized = GL_FALSE;
+    ppca.VertexArray::generic[ii].isInteger = GL_FALSE;
+    ppca.VertexArray::generic[ii].isLong = GL_FALSE;
+    ppca.VertexArray::generic[ii].bindingIndex = ii;
+
+    ppca.VertexArray::bindings[ii].buffer = GLuint(0);
+    ppca.VertexArray::bindings[ii].offset = GLintptr(0);
+    ppca.VertexArray::bindings[ii].stride = GLsizei(16);
+
+    checkPpcaDefaults(ctx, ppca);
+
+    ppca.VertexArray::generic[ii].relativeOffset = GLuint(1);
+    ppca.VertexArray::generic[ii].normalized = GL_TRUE;
+    ppca.VertexArray::vertexArrayBinding = 0;
+    ppca.glVertexAttribPointer( ii, testSize, testType, GL_FALSE, testStride, reinterpret_cast<const GLvoid*>(testOffset) );
+
+    EXPECT_EQ( testSize,    ppca.VertexArray::generic[ii].size );
+    EXPECT_EQ( testType,    ppca.VertexArray::generic[ii].type );
+    EXPECT_EQ( GLuint( 0 ), ppca.VertexArray::generic[ii].relativeOffset );
+    EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::generic[ii].normalized );
+    EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::generic[ii].isInteger );
+    EXPECT_EQ( GLboolean(GL_FALSE),  ppca.VertexArray::generic[ii].isLong );
+    EXPECT_EQ( ii,          ppca.VertexArray::generic[ii].bindingIndex );
+
+    EXPECT_EQ( testBuffer,  ppca.VertexArray::bindings[ii].buffer );
+    EXPECT_EQ( testOffset,  ppca.VertexArray::bindings[ii].offset );
+    EXPECT_EQ( testStride,  ppca.VertexArray::bindings[ii].stride );
+
+    ppca.VertexArray::generic[ii].size = 4;
+    ppca.VertexArray::generic[ii].type = GL_FLOAT;
+    ppca.VertexArray::generic[ii].relativeOffset = GLuint(0);
+    ppca.VertexArray::generic[ii].normalized = GL_FALSE;
+    ppca.VertexArray::generic[ii].isInteger = GL_FALSE;
+    ppca.VertexArray::generic[ii].isLong = GL_FALSE;
+    ppca.VertexArray::generic[ii].bindingIndex = ii;
+
+    ppca.VertexArray::bindings[ii].buffer = GLuint(0);
+    ppca.VertexArray::bindings[ii].offset = GLintptr(0);
+    ppca.VertexArray::bindings[ii].stride = GLsizei(16);
+
+    checkPpcaDefaults(ctx, ppca);
+
+    ppca.VertexArray::generic[ii].relativeOffset = GLuint(1);
+    ppca.VertexArray::generic[ii].normalized = GL_FALSE;
+    ppca.VertexArray::vertexArrayBinding = 0;
+    ppca.glVertexAttribPointer( ii, testSize, testType, GL_TRUE, testStride, reinterpret_cast<const GLvoid*>(testOffset) );
+
+    EXPECT_EQ( testSize,    ppca.VertexArray::generic[ii].size );
+    EXPECT_EQ( testType,    ppca.VertexArray::generic[ii].type );
+    EXPECT_EQ( GLuint( 0 ), ppca.VertexArray::generic[ii].relativeOffset );
+    EXPECT_EQ( GLboolean(GL_TRUE),  ppca.VertexArray::generic[ii].normalized );
+    EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::generic[ii].isInteger );
+    EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::generic[ii].isLong );
+    EXPECT_EQ( ii,          ppca.VertexArray::generic[ii].bindingIndex );
+
+    EXPECT_EQ( testBuffer,  ppca.VertexArray::bindings[ii].buffer );
+    EXPECT_EQ( testOffset,  ppca.VertexArray::bindings[ii].offset );
+    EXPECT_EQ( testStride,  ppca.VertexArray::bindings[ii].stride );
+
+    ppca.VertexArray::generic[ii].size = 4;
+    ppca.VertexArray::generic[ii].type = GL_FLOAT;
+    ppca.VertexArray::generic[ii].relativeOffset = GLuint(0);
+    ppca.VertexArray::generic[ii].normalized = GL_FALSE;
+    ppca.VertexArray::generic[ii].isInteger = GL_FALSE;
+    ppca.VertexArray::generic[ii].isLong = GL_FALSE;
+    ppca.VertexArray::generic[ii].bindingIndex = ii;
+
+    ppca.VertexArray::bindings[ii].buffer = GLuint(0);
+    ppca.VertexArray::bindings[ii].offset = GLintptr(0);
+    ppca.VertexArray::bindings[ii].stride = GLsizei(16);
+
+    checkPpcaDefaults(ctx, ppca);
+  }
+
+  // test glVertexAttrib(I|L|)Pointer with a vertex array bound
+
+  for (GLuint ii=0; ii<REGAL_EMU_MAX_VERTEX_ATTRIBS && ii<REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS; ii++)
+  {
+    ppca.Reset(ctx);
+    checkPpcaDefaults(ctx, ppca);
+
+    GLuint   testSize   = GLuint(2 * ii + 1);
+    GLenum   testType   = GLenum(ii);
+    GLsizei  testStride = GLsizei(ii + 3);
+    GLintptr testOffset = (GLintptr)(ii + 4);
+
+    ppca.VertexArray::generic[ii].normalized = GL_TRUE;
+    ppca.VertexArray::generic[ii].isInteger = GL_FALSE;
+    ppca.VertexArray::generic[ii].isLong = GL_TRUE;
+    ppca.VertexArray::generic[ii].relativeOffset = GLuint(1);
+
+    ppca.VertexArray::vertexArrayBinding = 1;
+    ppca.glVertexAttribIPointer( ii, testSize, testType, testStride, reinterpret_cast<const GLvoid*>(testOffset) );
+
+    EXPECT_EQ( GLuint( 1 ),         ppca.VertexArray::generic[ii].relativeOffset );
+    EXPECT_EQ( GLuint( 1 ),         ppca.VertexArray::vertexArrayBinding );
+    EXPECT_EQ( GLboolean(GL_TRUE),  ppca.VertexArray::generic[ii].normalized );
+    EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::generic[ii].isInteger );
+    EXPECT_EQ( GLboolean(GL_TRUE),  ppca.VertexArray::generic[ii].isLong );
+
+    ppca.VertexArray::generic[ii].normalized = GL_FALSE;
+    ppca.VertexArray::generic[ii].isInteger = GL_FALSE;
+    ppca.VertexArray::generic[ii].isLong = GL_FALSE;
+    ppca.VertexArray::generic[ii].relativeOffset = GLuint(0);
+    ppca.VertexArray::vertexArrayBinding = 0;
+
+    checkPpcaDefaults(ctx, ppca);
+
+    ppca.VertexArray::generic[ii].normalized = GL_TRUE;
+    ppca.VertexArray::generic[ii].isInteger = GL_TRUE;
+    ppca.VertexArray::generic[ii].isLong = GL_FALSE;
+    ppca.VertexArray::generic[ii].relativeOffset = GLuint(1);
+
+    ppca.VertexArray::vertexArrayBinding = 1;
+    ppca.glVertexAttribLPointer( ii, testSize, testType, testStride, reinterpret_cast<const GLvoid*>(testOffset) );
+
+    EXPECT_EQ( GLuint( 1 ),         ppca.VertexArray::generic[ii].relativeOffset );
+    EXPECT_EQ( GLuint( 1 ),         ppca.VertexArray::vertexArrayBinding );
+    EXPECT_EQ( GLboolean(GL_TRUE),  ppca.VertexArray::generic[ii].normalized );
+    EXPECT_EQ( GLboolean(GL_TRUE),  ppca.VertexArray::generic[ii].isInteger );
+    EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::generic[ii].isLong );
+
+    ppca.VertexArray::generic[ii].normalized = GL_FALSE;
+    ppca.VertexArray::generic[ii].isInteger = GL_FALSE;
+    ppca.VertexArray::generic[ii].isLong = GL_FALSE;
+    ppca.VertexArray::generic[ii].relativeOffset = GLuint(0);
+    ppca.VertexArray::vertexArrayBinding = 0;
+
+    checkPpcaDefaults(ctx, ppca);
+
+    ppca.VertexArray::generic[ii].normalized = GL_TRUE;
+    ppca.VertexArray::generic[ii].isInteger = GL_TRUE;
+    ppca.VertexArray::generic[ii].isLong = GL_TRUE;
+    ppca.VertexArray::generic[ii].relativeOffset = GLuint(1);
+
+    ppca.VertexArray::vertexArrayBinding = 1;
+    ppca.glVertexAttribPointer( ii, testSize, testType, GL_FALSE, testStride, reinterpret_cast<const GLvoid*>(testOffset) );
+
+    EXPECT_EQ( GLuint( 1 ),        ppca.VertexArray::generic[ii].relativeOffset );
+    EXPECT_EQ( GLuint( 1 ),        ppca.VertexArray::vertexArrayBinding );
+    EXPECT_EQ( GLboolean(GL_TRUE), ppca.VertexArray::generic[ii].normalized );
+    EXPECT_EQ( GLboolean(GL_TRUE), ppca.VertexArray::generic[ii].isInteger );
+    EXPECT_EQ( GLboolean(GL_TRUE), ppca.VertexArray::generic[ii].isLong );
+
+    ppca.VertexArray::generic[ii].normalized = GL_FALSE;
+    ppca.VertexArray::generic[ii].isInteger = GL_FALSE;
+    ppca.VertexArray::generic[ii].isLong = GL_FALSE;
+    ppca.VertexArray::generic[ii].relativeOffset = GLuint(0);
+    ppca.VertexArray::vertexArrayBinding = 0;
+
+    checkPpcaDefaults(ctx, ppca);
+
+    ppca.VertexArray::generic[ii].normalized = GL_FALSE;
+    ppca.VertexArray::generic[ii].isInteger = GL_TRUE;
+    ppca.VertexArray::generic[ii].isLong = GL_TRUE;
+    ppca.VertexArray::generic[ii].relativeOffset = GLuint(1);
+
+    ppca.VertexArray::vertexArrayBinding = 1;
+    ppca.glVertexAttribPointer( ii, testSize, testType, GL_TRUE, testStride, reinterpret_cast<const GLvoid*>(testOffset) );
+
+    EXPECT_EQ( GLuint( 1 ),         ppca.VertexArray::generic[ii].relativeOffset );
+    EXPECT_EQ( GLuint( 1 ),         ppca.VertexArray::vertexArrayBinding );
+    EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::generic[ii].normalized );
+    EXPECT_EQ( GLboolean(GL_TRUE),  ppca.VertexArray::generic[ii].isInteger );
+    EXPECT_EQ( GLboolean(GL_TRUE),  ppca.VertexArray::generic[ii].isLong );
+
+    ppca.VertexArray::generic[ii].normalized = GL_FALSE;
+    ppca.VertexArray::generic[ii].isInteger = GL_FALSE;
+    ppca.VertexArray::generic[ii].isLong = GL_FALSE;
+    ppca.VertexArray::generic[ii].relativeOffset = GLuint(0);
+    ppca.VertexArray::vertexArrayBinding = 0;
+
+    checkPpcaDefaults(ctx, ppca);
+  }
+}
+
+TEST ( RegalPpca, glVertexArrayVertexAttribOffsetEXT_Shadowing )
+{
+  RegalContext ctx;
+  ctx.info = new ContextInfo();
+
+  Ppca ppca;
+  checkPpcaDefaults(ctx, ppca);
+
+  // test glVertexArrayVertexAttrib(I|)OffsetEXT with no vertex array bound
+
+  for (GLuint ii=0; ii<REGAL_EMU_MAX_VERTEX_ATTRIBS && ii<REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS; ii++)
+  {
+    ppca.Reset(ctx);
+    checkPpcaDefaults(ctx, ppca);
+
+    GLuint   testSize   = GLuint(2 * ii + 1);
+    GLenum   testType   = GLenum(ii);
+    GLsizei  testStride = GLsizei(ii + 3);
+    GLintptr testOffset = (GLintptr)(ii + 4);
+    GLuint   testBuffer = ppca.VertexArray::arrayBufferBinding + 1;
+
+    // first test passing in 0 for vertex array object
+
+    ppca.VertexArray::generic[ii].relativeOffset = GLuint(1);
+    ppca.VertexArray::vertexArrayBinding = 0;
+    ppca.glVertexArrayVertexAttribIOffsetEXT( 0, testBuffer, ii, testSize, testType, testStride, testOffset );
+
+    EXPECT_EQ( testSize,    ppca.VertexArray::generic[ii].size );
+    EXPECT_EQ( testType,    ppca.VertexArray::generic[ii].type );
+    EXPECT_EQ( GLuint( 0 ), ppca.VertexArray::generic[ii].relativeOffset );
+    EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::generic[ii].normalized );
+    EXPECT_EQ( GLboolean(GL_TRUE),  ppca.VertexArray::generic[ii].isInteger );
+    EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::generic[ii].isLong );
+    EXPECT_EQ( ii,          ppca.VertexArray::generic[ii].bindingIndex );
+
+    EXPECT_EQ( testBuffer,  ppca.VertexArray::bindings[ii].buffer );
+    EXPECT_EQ( testOffset,  ppca.VertexArray::bindings[ii].offset );
+    EXPECT_EQ( testStride,  ppca.VertexArray::bindings[ii].stride );
+
+    ppca.VertexArray::generic[ii].size = 4;
+    ppca.VertexArray::generic[ii].type = GL_FLOAT;
+    ppca.VertexArray::generic[ii].relativeOffset = GLuint(0);
+    ppca.VertexArray::generic[ii].normalized = GL_FALSE;
+    ppca.VertexArray::generic[ii].isInteger = GL_FALSE;
+    ppca.VertexArray::generic[ii].isLong = GL_FALSE;
+    ppca.VertexArray::generic[ii].bindingIndex = ii;
+
+    ppca.VertexArray::bindings[ii].buffer = GLuint(0);
+    ppca.VertexArray::bindings[ii].offset = GLintptr(0);
+    ppca.VertexArray::bindings[ii].stride = GLsizei(16);
+
+    checkPpcaDefaults(ctx, ppca);
+
+    ppca.VertexArray::generic[ii].relativeOffset = GLuint(1);
+    ppca.VertexArray::generic[ii].normalized = GL_TRUE;
+    ppca.VertexArray::vertexArrayBinding = 0;
+    ppca.glVertexArrayVertexAttribOffsetEXT( 0, testBuffer, ii, testSize, testType, GL_FALSE, testStride, testOffset );
+
+    EXPECT_EQ( testSize,    ppca.VertexArray::generic[ii].size );
+    EXPECT_EQ( testType,    ppca.VertexArray::generic[ii].type );
+    EXPECT_EQ( GLuint( 0 ), ppca.VertexArray::generic[ii].relativeOffset );
+    EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::generic[ii].normalized );
+    EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::generic[ii].isInteger );
+    EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::generic[ii].isLong );
+    EXPECT_EQ( ii,          ppca.VertexArray::generic[ii].bindingIndex );
+
+    EXPECT_EQ( testBuffer,  ppca.VertexArray::bindings[ii].buffer );
+    EXPECT_EQ( testOffset,  ppca.VertexArray::bindings[ii].offset );
+    EXPECT_EQ( testStride,  ppca.VertexArray::bindings[ii].stride );
+
+    ppca.VertexArray::generic[ii].size = 4;
+    ppca.VertexArray::generic[ii].type = GL_FLOAT;
+    ppca.VertexArray::generic[ii].relativeOffset = GLuint(0);
+    ppca.VertexArray::generic[ii].normalized = GL_FALSE;
+    ppca.VertexArray::generic[ii].isInteger = GL_FALSE;
+    ppca.VertexArray::generic[ii].isLong = GL_FALSE;
+    ppca.VertexArray::generic[ii].bindingIndex = ii;
+
+    ppca.VertexArray::bindings[ii].buffer = GLuint(0);
+    ppca.VertexArray::bindings[ii].offset = GLintptr(0);
+    ppca.VertexArray::bindings[ii].stride = GLsizei(16);
+
+    checkPpcaDefaults(ctx, ppca);
+
+    ppca.VertexArray::generic[ii].relativeOffset = GLuint(1);
+    ppca.VertexArray::generic[ii].normalized = GL_FALSE;
+    ppca.VertexArray::vertexArrayBinding = 0;
+    ppca.glVertexArrayVertexAttribOffsetEXT( 0, testBuffer, ii, testSize, testType, GL_TRUE, testStride, testOffset );
+
+    EXPECT_EQ( testSize,    ppca.VertexArray::generic[ii].size );
+    EXPECT_EQ( testType,    ppca.VertexArray::generic[ii].type );
+    EXPECT_EQ( GLuint( 0 ), ppca.VertexArray::generic[ii].relativeOffset );
+    EXPECT_EQ( GLboolean(GL_TRUE),  ppca.VertexArray::generic[ii].normalized );
+    EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::generic[ii].isInteger );
+    EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::generic[ii].isLong );
+    EXPECT_EQ( ii,          ppca.VertexArray::generic[ii].bindingIndex );
+
+    EXPECT_EQ( testBuffer,  ppca.VertexArray::bindings[ii].buffer );
+    EXPECT_EQ( testOffset,  ppca.VertexArray::bindings[ii].offset );
+    EXPECT_EQ( testStride,  ppca.VertexArray::bindings[ii].stride );
+
+    ppca.VertexArray::generic[ii].size = 4;
+    ppca.VertexArray::generic[ii].type = GL_FLOAT;
+    ppca.VertexArray::generic[ii].relativeOffset = GLuint(0);
+    ppca.VertexArray::generic[ii].normalized = GL_FALSE;
+    ppca.VertexArray::generic[ii].isInteger = GL_FALSE;
+    ppca.VertexArray::generic[ii].isLong = GL_FALSE;
+    ppca.VertexArray::generic[ii].bindingIndex = ii;
+
+    ppca.VertexArray::bindings[ii].buffer = GLuint(0);
+    ppca.VertexArray::bindings[ii].offset = GLintptr(0);
+    ppca.VertexArray::bindings[ii].stride = GLsizei(16);
+
+    checkPpcaDefaults(ctx, ppca);
+
+    // now test passing in 1 for vertex array object
+
+    ppca.VertexArray::generic[ii].relativeOffset = GLuint(1);
+    ppca.VertexArray::vertexArrayBinding = 0;
+    ppca.glVertexArrayVertexAttribIOffsetEXT( 1, testBuffer, ii, testSize, testType, testStride, testOffset );
+
+    EXPECT_EQ( GLuint( 1 ), ppca.VertexArray::generic[ii].relativeOffset );
+
+    ppca.VertexArray::generic[ii].relativeOffset = 0;
+
+    checkPpcaDefaults(ctx, ppca);
+
+    ppca.VertexArray::generic[ii].relativeOffset = GLuint(1);
+    ppca.VertexArray::generic[ii].normalized = GL_TRUE;
+    ppca.VertexArray::vertexArrayBinding = 0;
+    ppca.glVertexArrayVertexAttribOffsetEXT( 1, testBuffer, ii, testSize, testType, GL_FALSE, testStride, testOffset );
+
+    EXPECT_EQ( GLuint( 1 ), ppca.VertexArray::generic[ii].relativeOffset );
+    EXPECT_EQ( GLboolean(GL_TRUE), ppca.VertexArray::generic[ii].normalized );
+
+    ppca.VertexArray::generic[ii].relativeOffset = GLuint(0);
+    ppca.VertexArray::generic[ii].normalized = GL_FALSE;
+
+    checkPpcaDefaults(ctx, ppca);
+
+    ppca.VertexArray::generic[ii].relativeOffset = GLuint(1);
+    ppca.VertexArray::generic[ii].normalized = GL_FALSE;
+    ppca.VertexArray::vertexArrayBinding = 0;
+    ppca.glVertexArrayVertexAttribOffsetEXT( 1, testBuffer, ii, testSize, testType, GL_TRUE, testStride, testOffset );
+
+    EXPECT_EQ( GLuint( 1 ), ppca.VertexArray::generic[ii].relativeOffset );
+    EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::generic[ii].normalized );
+
+    ppca.VertexArray::generic[ii].relativeOffset = GLuint(0);
+    ppca.VertexArray::generic[ii].normalized = GL_FALSE;
+
+    checkPpcaDefaults(ctx, ppca);
+  }
+
+  // test glVertexArrayVertexAttrib(I|)OffsetEXT with a vertex array bound
+
+  for (GLuint ii=0; ii<REGAL_EMU_MAX_VERTEX_ATTRIBS && ii<REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS; ii++)
+  {
+    ppca.Reset(ctx);
+    checkPpcaDefaults(ctx, ppca);
+
+    GLuint   testSize   = GLuint(2 * ii + 1);
+    GLenum   testType   = GLenum(ii);
+    GLsizei  testStride = GLsizei(ii + 3);
+    GLintptr testOffset = (GLintptr)(ii + 4);
+    GLuint   testBuffer = ppca.VertexArray::arrayBufferBinding + 1;
+
+    // first test passing in 0 for vertex array object
+
+    ppca.VertexArray::generic[ii].normalized = GL_TRUE;
+    ppca.VertexArray::generic[ii].isInteger = GL_FALSE;
+    ppca.VertexArray::generic[ii].isLong = GL_TRUE;
+    ppca.VertexArray::generic[ii].relativeOffset = GLuint(1);
+
+    ppca.VertexArray::vertexArrayBinding = 1;
+    ppca.glVertexArrayVertexAttribIOffsetEXT( 0, testBuffer, ii, testSize, testType, testStride, testOffset );
+
+    EXPECT_EQ( GLuint( 1 ),  ppca.VertexArray::vertexArrayBinding );
+
+    EXPECT_EQ( testSize,    ppca.VertexArray::generic[ii].size );
+    EXPECT_EQ( testType,    ppca.VertexArray::generic[ii].type );
+    EXPECT_EQ( GLuint( 0 ), ppca.VertexArray::generic[ii].relativeOffset );
+    EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::generic[ii].normalized );
+    EXPECT_EQ( GLboolean(GL_TRUE),  ppca.VertexArray::generic[ii].isInteger );
+    EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::generic[ii].isLong );
+    EXPECT_EQ( ii,          ppca.VertexArray::generic[ii].bindingIndex );
+
+    EXPECT_EQ( testBuffer,  ppca.VertexArray::bindings[ii].buffer );
+    EXPECT_EQ( testOffset,  ppca.VertexArray::bindings[ii].offset );
+    EXPECT_EQ( testStride,  ppca.VertexArray::bindings[ii].stride );
+
+    ppca.VertexArray::vertexArrayBinding = 0;
+
+    ppca.VertexArray::generic[ii].size = 4;
+    ppca.VertexArray::generic[ii].type = GL_FLOAT;
+    ppca.VertexArray::generic[ii].relativeOffset = GLuint(0);
+    ppca.VertexArray::generic[ii].normalized = GL_FALSE;
+    ppca.VertexArray::generic[ii].isInteger = GL_FALSE;
+    ppca.VertexArray::generic[ii].isLong = GL_FALSE;
+    ppca.VertexArray::generic[ii].bindingIndex = ii;
+
+    ppca.VertexArray::bindings[ii].buffer = GLuint(0);
+    ppca.VertexArray::bindings[ii].offset = GLintptr(0);
+    ppca.VertexArray::bindings[ii].stride = GLsizei(16);
+
+    checkPpcaDefaults(ctx, ppca);
+
+    ppca.VertexArray::generic[ii].normalized = GL_TRUE;
+    ppca.VertexArray::generic[ii].isInteger = GL_TRUE;
+    ppca.VertexArray::generic[ii].isLong = GL_TRUE;
+    ppca.VertexArray::generic[ii].relativeOffset = GLuint(1);
+
+    ppca.VertexArray::vertexArrayBinding = 1;
+    ppca.glVertexArrayVertexAttribOffsetEXT( 0, testBuffer, ii, testSize, testType, GL_FALSE, testStride, testOffset );
+
+    EXPECT_EQ( GLuint( 1 ), ppca.VertexArray::vertexArrayBinding );
+
+    EXPECT_EQ( testSize,    ppca.VertexArray::generic[ii].size );
+    EXPECT_EQ( testType,    ppca.VertexArray::generic[ii].type );
+    EXPECT_EQ( GLuint( 0 ), ppca.VertexArray::generic[ii].relativeOffset );
+    EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::generic[ii].normalized );
+    EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::generic[ii].isInteger );
+    EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::generic[ii].isLong );
+    EXPECT_EQ( ii,          ppca.VertexArray::generic[ii].bindingIndex );
+
+    EXPECT_EQ( testBuffer,  ppca.VertexArray::bindings[ii].buffer );
+    EXPECT_EQ( testOffset,  ppca.VertexArray::bindings[ii].offset );
+    EXPECT_EQ( testStride,  ppca.VertexArray::bindings[ii].stride );
+
+    ppca.VertexArray::vertexArrayBinding = 0;
+
+    ppca.VertexArray::generic[ii].size = 4;
+    ppca.VertexArray::generic[ii].type = GL_FLOAT;
+    ppca.VertexArray::generic[ii].relativeOffset = GLuint(0);
+    ppca.VertexArray::generic[ii].normalized = GL_FALSE;
+    ppca.VertexArray::generic[ii].isInteger = GL_FALSE;
+    ppca.VertexArray::generic[ii].isLong = GL_FALSE;
+    ppca.VertexArray::generic[ii].bindingIndex = ii;
+
+    ppca.VertexArray::bindings[ii].buffer = GLuint(0);
+    ppca.VertexArray::bindings[ii].offset = GLintptr(0);
+    ppca.VertexArray::bindings[ii].stride = GLsizei(16);
+
+    checkPpcaDefaults(ctx, ppca);
+
+    ppca.VertexArray::generic[ii].normalized = GL_FALSE;
+    ppca.VertexArray::generic[ii].isInteger = GL_TRUE;
+    ppca.VertexArray::generic[ii].isLong = GL_TRUE;
+    ppca.VertexArray::generic[ii].relativeOffset = GLuint(1);
+
+    ppca.VertexArray::vertexArrayBinding = 1;
+    ppca.glVertexArrayVertexAttribOffsetEXT( 0, testBuffer, ii, testSize, testType, GL_TRUE, testStride, testOffset );
+
+    EXPECT_EQ( GLuint( 1 ), ppca.VertexArray::vertexArrayBinding );
+
+    EXPECT_EQ( testSize,    ppca.VertexArray::generic[ii].size );
+    EXPECT_EQ( testType,    ppca.VertexArray::generic[ii].type );
+    EXPECT_EQ( GLuint( 0 ), ppca.VertexArray::generic[ii].relativeOffset );
+    EXPECT_EQ( GLboolean(GL_TRUE),  ppca.VertexArray::generic[ii].normalized );
+    EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::generic[ii].isInteger );
+    EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::generic[ii].isLong );
+    EXPECT_EQ( ii,          ppca.VertexArray::generic[ii].bindingIndex );
+
+    EXPECT_EQ( testBuffer,  ppca.VertexArray::bindings[ii].buffer );
+    EXPECT_EQ( testOffset,  ppca.VertexArray::bindings[ii].offset );
+    EXPECT_EQ( testStride,  ppca.VertexArray::bindings[ii].stride );
+
+    ppca.VertexArray::vertexArrayBinding = 0;
+
+    ppca.VertexArray::generic[ii].size = 4;
+    ppca.VertexArray::generic[ii].type = GL_FLOAT;
+    ppca.VertexArray::generic[ii].relativeOffset = GLuint(0);
+    ppca.VertexArray::generic[ii].normalized = GL_FALSE;
+    ppca.VertexArray::generic[ii].isInteger = GL_FALSE;
+    ppca.VertexArray::generic[ii].isLong = GL_FALSE;
+    ppca.VertexArray::generic[ii].bindingIndex = ii;
+
+    ppca.VertexArray::bindings[ii].buffer = GLuint(0);
+    ppca.VertexArray::bindings[ii].offset = GLintptr(0);
+    ppca.VertexArray::bindings[ii].stride = GLsizei(16);
+
+    checkPpcaDefaults(ctx, ppca);
+
+    // now test passing in 1 for vertex array object
+
+    ppca.VertexArray::generic[ii].normalized = GL_TRUE;
+    ppca.VertexArray::generic[ii].isInteger = GL_FALSE;
+    ppca.VertexArray::generic[ii].isLong = GL_TRUE;
+    ppca.VertexArray::generic[ii].relativeOffset = GLuint(1);
+
+    ppca.VertexArray::vertexArrayBinding = 1;
+    ppca.glVertexArrayVertexAttribIOffsetEXT( 1, testBuffer, ii, testSize, testType, testStride, testOffset );
+
+    EXPECT_EQ( GLuint( 1 ),  ppca.VertexArray::vertexArrayBinding );
+
+    EXPECT_EQ( GLuint( 1 ), ppca.VertexArray::generic[ii].relativeOffset );
+    EXPECT_EQ( GLboolean(GL_TRUE),  ppca.VertexArray::generic[ii].normalized );
+    EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::generic[ii].isInteger );
+    EXPECT_EQ( GLboolean(GL_TRUE),  ppca.VertexArray::generic[ii].isLong );
+
+    ppca.VertexArray::vertexArrayBinding = 0;
+
+    ppca.VertexArray::generic[ii].relativeOffset = GLuint(0);
+    ppca.VertexArray::generic[ii].normalized = GL_FALSE;
+    ppca.VertexArray::generic[ii].isInteger = GL_FALSE;
+    ppca.VertexArray::generic[ii].isLong = GL_FALSE;
+
+    checkPpcaDefaults(ctx, ppca);
+
+    ppca.VertexArray::generic[ii].normalized = GL_TRUE;
+    ppca.VertexArray::generic[ii].isInteger = GL_TRUE;
+    ppca.VertexArray::generic[ii].isLong = GL_TRUE;
+    ppca.VertexArray::generic[ii].relativeOffset = GLuint(1);
+
+    ppca.VertexArray::vertexArrayBinding = 1;
+    ppca.glVertexArrayVertexAttribOffsetEXT( 1, testBuffer, ii, testSize, testType, GL_FALSE, testStride, testOffset );
+
+    EXPECT_EQ( GLuint( 1 ), ppca.VertexArray::vertexArrayBinding );
+
+    EXPECT_EQ( GLuint( 1 ), ppca.VertexArray::generic[ii].relativeOffset );
+    EXPECT_EQ( GLboolean(GL_TRUE), ppca.VertexArray::generic[ii].normalized );
+    EXPECT_EQ( GLboolean(GL_TRUE), ppca.VertexArray::generic[ii].isInteger );
+    EXPECT_EQ( GLboolean(GL_TRUE), ppca.VertexArray::generic[ii].isLong );
+
+    ppca.VertexArray::vertexArrayBinding = 0;
+
+    ppca.VertexArray::generic[ii].relativeOffset = GLuint(0);
+    ppca.VertexArray::generic[ii].normalized = GL_FALSE;
+    ppca.VertexArray::generic[ii].isInteger = GL_FALSE;
+    ppca.VertexArray::generic[ii].isLong = GL_FALSE;
+
+    checkPpcaDefaults(ctx, ppca);
+
+    ppca.VertexArray::generic[ii].normalized = GL_FALSE;
+    ppca.VertexArray::generic[ii].isInteger = GL_TRUE;
+    ppca.VertexArray::generic[ii].isLong = GL_TRUE;
+    ppca.VertexArray::generic[ii].relativeOffset = GLuint(1);
+
+    ppca.VertexArray::vertexArrayBinding = 1;
+
+    ppca.glVertexArrayVertexAttribOffsetEXT( 1, testBuffer, ii, testSize, testType, GL_TRUE, testStride, testOffset );
+
+    EXPECT_EQ( GLuint( 1 ), ppca.VertexArray::vertexArrayBinding );
+
+    EXPECT_EQ( GLuint( 1 ), ppca.VertexArray::generic[ii].relativeOffset );
+    EXPECT_EQ( GLboolean(GL_FALSE), ppca.VertexArray::generic[ii].normalized );
+    EXPECT_EQ( GLboolean(GL_TRUE),  ppca.VertexArray::generic[ii].isInteger );
+    EXPECT_EQ( GLboolean(GL_TRUE),  ppca.VertexArray::generic[ii].isLong );
+
+    ppca.VertexArray::vertexArrayBinding = 0;
+
+    ppca.VertexArray::generic[ii].relativeOffset = GLuint(0);
+    ppca.VertexArray::generic[ii].normalized = GL_FALSE;
+    ppca.VertexArray::generic[ii].isInteger = GL_FALSE;
+    ppca.VertexArray::generic[ii].isLong = GL_FALSE;
+
+    checkPpcaDefaults(ctx, ppca);
+  }
 }
 
 }  // namespace
+
+/*
+glColorPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)
+*/