Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / angle / src / libGLESv2 / libGLESv2.cpp
index a33481e..a62e163 100644 (file)
@@ -1,6 +1,5 @@
-#include "precompiled.h"
 //
-// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved.
+// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 //
@@ -8,9 +7,10 @@
 // libGLESv2.cpp: Implements the exported OpenGL ES 2.0 functions.
 
 #include "common/version.h"
+#include "common/utilities.h"
 
 #include "libGLESv2/main.h"
-#include "libGLESv2/utilities.h"
+#include "libGLESv2/formatutils.h"
 #include "libGLESv2/Buffer.h"
 #include "libGLESv2/Fence.h"
 #include "libGLESv2/Framebuffer.h"
 #include "libGLESv2/Texture.h"
 #include "libGLESv2/Query.h"
 #include "libGLESv2/Context.h"
+#include "libGLESv2/VertexArray.h"
+#include "libGLESv2/VertexAttribute.h"
+#include "libGLESv2/TransformFeedback.h"
+#include "libGLESv2/FramebufferAttachment.h"
 
-bool validImageSize(GLint level, GLsizei width, GLsizei height)
-{
-    if (level < 0 || width < 0 || height < 0)
-    {
-        return false;
-    }
-
-    if (gl::getContext() && gl::getContext()->supportsNonPower2Texture())
-    {
-        return true;
-    }
-
-    if (level == 0)
-    {
-        return true;
-    }
-
-    if (gl::isPow2(width) && gl::isPow2(height))
-    {
-        return true;
-    }
-
-    return false;
-}
-
-// Verify that format/type are one of the combinations from table 3.4.
-bool checkTextureFormatType(GLenum format, GLenum type)
-{
-    // validate <format> by itself (used as secondary key below)
-    switch (format)
-    {
-      case GL_RGBA:
-      case GL_BGRA_EXT:
-      case GL_RGB:
-      case GL_ALPHA:
-      case GL_LUMINANCE:
-      case GL_LUMINANCE_ALPHA:
-      case GL_DEPTH_COMPONENT:
-      case GL_DEPTH_STENCIL_OES:
-        break;
-      default:
-        return gl::error(GL_INVALID_ENUM, false);
-    }
-
-    // invalid <type> -> sets INVALID_ENUM
-    // invalid <format>+<type> combination -> sets INVALID_OPERATION
-    switch (type)
-    {
-      case GL_UNSIGNED_BYTE:
-        switch (format)
-        {
-          case GL_RGBA:
-          case GL_BGRA_EXT:
-          case GL_RGB:
-          case GL_ALPHA:
-          case GL_LUMINANCE:
-          case GL_LUMINANCE_ALPHA:
-            return true;
-          default:
-            return gl::error(GL_INVALID_OPERATION, false);
-        }
-
-      case GL_FLOAT:
-      case GL_HALF_FLOAT_OES:
-        switch (format)
-        {
-          case GL_RGBA:
-          case GL_RGB:
-          case GL_ALPHA:
-          case GL_LUMINANCE:
-          case GL_LUMINANCE_ALPHA:
-            return true;
-          default:
-            return gl::error(GL_INVALID_OPERATION, false);
-        }
-
-      case GL_UNSIGNED_SHORT_4_4_4_4:
-      case GL_UNSIGNED_SHORT_5_5_5_1:
-        switch (format)
-        {
-          case GL_RGBA:
-            return true;
-          default:
-            return gl::error(GL_INVALID_OPERATION, false);
-        }
-
-      case GL_UNSIGNED_SHORT_5_6_5:
-        switch (format)
-        {
-          case GL_RGB:
-            return true;
-          default:
-            return gl::error(GL_INVALID_OPERATION, false);
-        }
-
-      case GL_UNSIGNED_SHORT:
-      case GL_UNSIGNED_INT:
-        switch (format)
-        {
-          case GL_DEPTH_COMPONENT:
-            return true;
-          default:
-            return gl::error(GL_INVALID_OPERATION, false);
-        }
-
-      case GL_UNSIGNED_INT_24_8_OES:
-        switch (format)
-        {
-          case GL_DEPTH_STENCIL_OES:
-            return true;
-          default:
-            return gl::error(GL_INVALID_OPERATION, false);
-        }
-
-      default:
-        return gl::error(GL_INVALID_ENUM, false);
-    }
-}
-
-bool validateSubImageParams2D(bool compressed, GLsizei width, GLsizei height,
-                              GLint xoffset, GLint yoffset, GLint level, GLenum format, GLenum type,
-                              gl::Texture2D *texture)
-{
-    if (!texture)
-    {
-        return gl::error(GL_INVALID_OPERATION, false);
-    }
-
-    if (compressed != texture->isCompressed(level))
-    {
-        return gl::error(GL_INVALID_OPERATION, false);
-    }
-
-    if (format != GL_NONE)
-    {
-        GLenum internalformat = gl::ConvertSizedInternalFormat(format, type);
-        if (internalformat != texture->getInternalFormat(level))
-        {
-            return gl::error(GL_INVALID_OPERATION, false);
-        }
-    }
-
-    if (compressed)
-    {
-        if ((width % 4 != 0 && width != texture->getWidth(0)) ||
-            (height % 4 != 0 && height != texture->getHeight(0)))
-        {
-            return gl::error(GL_INVALID_OPERATION, false);
-        }
-    }
-
-    if (xoffset + width > texture->getWidth(level) ||
-        yoffset + height > texture->getHeight(level))
-    {
-        return gl::error(GL_INVALID_VALUE, false);
-    }
-
-    return true;
-}
-
-bool validateSubImageParamsCube(bool compressed, GLsizei width, GLsizei height,
-                                GLint xoffset, GLint yoffset, GLenum target, GLint level, GLenum format, GLenum type,
-                                gl::TextureCubeMap *texture)
-{
-    if (!texture)
-    {
-        return gl::error(GL_INVALID_OPERATION, false);
-    }
-
-    if (compressed != texture->isCompressed(target, level))
-    {
-        return gl::error(GL_INVALID_OPERATION, false);
-    }
-
-    if (format != GL_NONE)
-    {
-        GLenum internalformat = gl::ConvertSizedInternalFormat(format, type);
-        if (internalformat != texture->getInternalFormat(target, level))
-        {
-            return gl::error(GL_INVALID_OPERATION, false);
-        }
-    }
-
-    if (compressed)
-    {
-        if ((width % 4 != 0 && width != texture->getWidth(target, 0)) ||
-            (height % 4 != 0 && height != texture->getHeight(target, 0)))
-        {
-            return gl::error(GL_INVALID_OPERATION, false);
-        }
-    }
-
-    if (xoffset + width > texture->getWidth(target, level) ||
-        yoffset + height > texture->getHeight(target, level))
-    {
-        return gl::error(GL_INVALID_VALUE, false);
-    }
-
-    return true;
-}
-
-// check for combinations of format and type that are valid for ReadPixels
-bool validReadFormatType(GLenum format, GLenum type)
-{
-    switch (format)
-    {
-      case GL_RGBA:
-        switch (type)
-        {
-          case GL_UNSIGNED_BYTE:
-            break;
-          default:
-            return false;
-        }
-        break;
-      case GL_BGRA_EXT:
-        switch (type)
-        {
-          case GL_UNSIGNED_BYTE:
-          case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT:
-          case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT:
-            break;
-          default:
-            return false;
-        }
-        break;
-      default:
-        return false;
-    }
-    return true;
-}
+#include "libGLESv2/validationES.h"
+#include "libGLESv2/validationES2.h"
+#include "libGLESv2/validationES3.h"
+#include "libGLESv2/queryconversions.h"
 
 extern "C"
 {
 
+// OpenGL ES 2.0 functions
+
 void __stdcall glActiveTexture(GLenum texture)
 {
     EVENT("(GLenum texture = 0x%X)", texture);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
+        if (texture < GL_TEXTURE0 || texture > GL_TEXTURE0 + context->getCaps().maxCombinedTextureImageUnits - 1)
         {
-            if (texture < GL_TEXTURE0 || texture > GL_TEXTURE0 + context->getMaximumCombinedTextureImageUnits() - 1)
-            {
-                return gl::error(GL_INVALID_ENUM);
-            }
-
-            context->setActiveSampler(texture - GL_TEXTURE0);
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
         }
-    }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
+
+        context->getState().setActiveSampler(texture - GL_TEXTURE0);
     }
 }
 
@@ -284,48 +56,45 @@ void __stdcall glAttachShader(GLuint program, GLuint shader)
 {
     EVENT("(GLuint program = %d, GLuint shader = %d)", program, shader);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        gl::Context *context = gl::getNonLostContext();
+        gl::Program *programObject = context->getProgram(program);
+        gl::Shader *shaderObject = context->getShader(shader);
 
-        if (context)
+        if (!programObject)
         {
-            gl::Program *programObject = context->getProgram(program);
-            gl::Shader *shaderObject = context->getShader(shader);
-
-            if (!programObject)
+            if (context->getShader(program))
             {
-                if (context->getShader(program))
-                {
-                    return gl::error(GL_INVALID_OPERATION);
-                }
-                else
-                {
-                    return gl::error(GL_INVALID_VALUE);
-                }
+                context->recordError(gl::Error(GL_INVALID_OPERATION));
+                return;
             }
-
-            if (!shaderObject)
+            else
             {
-                if (context->getProgram(shader))
-                {
-                    return gl::error(GL_INVALID_OPERATION);
-                }
-                else
-                {
-                    return gl::error(GL_INVALID_VALUE);
-                }
+                context->recordError(gl::Error(GL_INVALID_VALUE));
+                return;
             }
+        }
 
-            if (!programObject->attachShader(shaderObject))
+        if (!shaderObject)
+        {
+            if (context->getProgram(shader))
+            {
+                context->recordError(gl::Error(GL_INVALID_OPERATION));
+                return;
+            }
+            else
             {
-                return gl::error(GL_INVALID_OPERATION);
+                context->recordError(gl::Error(GL_INVALID_VALUE));
+                return;
             }
         }
-    }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
+
+        if (!programObject->attachShader(shaderObject))
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
     }
 }
 
@@ -333,75 +102,59 @@ void __stdcall glBeginQueryEXT(GLenum target, GLuint id)
 {
     EVENT("(GLenum target = 0x%X, GLuint %d)", target, id);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        switch (target)
-        {
-          case GL_ANY_SAMPLES_PASSED_EXT: 
-          case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT:
-              break;
-          default: 
-              return gl::error(GL_INVALID_ENUM);
-        }
-
-        if (id == 0)
+        if (!ValidateBeginQuery(context, target, id))
         {
-            return gl::error(GL_INVALID_OPERATION);
+            return;
         }
 
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
+        gl::Error error = context->beginQuery(target, id);
+        if (error.isError())
         {
-            context->beginQuery(target, id);
+            context->recordError(error);
+            return;
         }
     }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
-    }
 }
 
 void __stdcall glBindAttribLocation(GLuint program, GLuint index, const GLchar* name)
 {
     EVENT("(GLuint program = %d, GLuint index = %d, const GLchar* name = 0x%0.8p)", program, index, name);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
         if (index >= gl::MAX_VERTEX_ATTRIBS)
         {
-            return gl::error(GL_INVALID_VALUE);
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
         }
 
-        gl::Context *context = gl::getNonLostContext();
+        gl::Program *programObject = context->getProgram(program);
 
-        if (context)
+        if (!programObject)
         {
-            gl::Program *programObject = context->getProgram(program);
-
-            if (!programObject)
+            if (context->getShader(program))
             {
-                if (context->getShader(program))
-                {
-                    return gl::error(GL_INVALID_OPERATION);
-                }
-                else
-                {
-                    return gl::error(GL_INVALID_VALUE);
-                }
+                context->recordError(gl::Error(GL_INVALID_OPERATION));
+                return;
             }
-
-            if (strncmp(name, "gl_", 3) == 0)
+            else
             {
-                return gl::error(GL_INVALID_OPERATION);
+                context->recordError(gl::Error(GL_INVALID_VALUE));
+                return;
             }
+        }
 
-            programObject->bindAttributeLocation(index, name);
+        if (strncmp(name, "gl_", 3) == 0)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
         }
-    }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
+
+        programObject->bindAttributeLocation(index, name);
     }
 }
 
@@ -409,84 +162,88 @@ void __stdcall glBindBuffer(GLenum target, GLuint buffer)
 {
     EVENT("(GLenum target = 0x%X, GLuint buffer = %d)", target, buffer);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        gl::Context *context = gl::getNonLostContext();
+        if (!gl::ValidBufferTarget(context, target))
+        {
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
+        }
 
-        if (context)
+        switch (target)
         {
-            switch (target)
-            {
-              case GL_ARRAY_BUFFER:
-                context->bindArrayBuffer(buffer);
-                return;
-              case GL_ELEMENT_ARRAY_BUFFER:
-                context->bindElementArrayBuffer(buffer);
-                return;
-              default:
-                return gl::error(GL_INVALID_ENUM);
-            }
+          case GL_ARRAY_BUFFER:
+            context->bindArrayBuffer(buffer);
+            return;
+          case GL_ELEMENT_ARRAY_BUFFER:
+            context->bindElementArrayBuffer(buffer);
+            return;
+          case GL_COPY_READ_BUFFER:
+            context->bindCopyReadBuffer(buffer);
+            return;
+          case GL_COPY_WRITE_BUFFER:
+            context->bindCopyWriteBuffer(buffer);
+            return;
+          case GL_PIXEL_PACK_BUFFER:
+            context->bindPixelPackBuffer(buffer);
+            return;
+          case GL_PIXEL_UNPACK_BUFFER:
+            context->bindPixelUnpackBuffer(buffer);
+            return;
+          case GL_UNIFORM_BUFFER:
+            context->bindGenericUniformBuffer(buffer);
+            return;
+          case GL_TRANSFORM_FEEDBACK_BUFFER:
+            context->bindGenericTransformFeedbackBuffer(buffer);
+            return;
+
+          default:
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
         }
     }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
-    }
 }
 
 void __stdcall glBindFramebuffer(GLenum target, GLuint framebuffer)
 {
     EVENT("(GLenum target = 0x%X, GLuint framebuffer = %d)", target, framebuffer);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        if (target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER_ANGLE && target != GL_READ_FRAMEBUFFER_ANGLE)
+        if (!gl::ValidFramebufferTarget(target))
         {
-            return gl::error(GL_INVALID_ENUM);
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
         }
 
-        gl::Context *context = gl::getNonLostContext();
+        if (target == GL_READ_FRAMEBUFFER_ANGLE || target == GL_FRAMEBUFFER)
+        {
+            context->bindReadFramebuffer(framebuffer);
+        }
 
-        if (context)
+        if (target == GL_DRAW_FRAMEBUFFER_ANGLE || target == GL_FRAMEBUFFER)
         {
-            if (target == GL_READ_FRAMEBUFFER_ANGLE || target == GL_FRAMEBUFFER)
-            {
-                context->bindReadFramebuffer(framebuffer);
-            }
-            
-            if (target == GL_DRAW_FRAMEBUFFER_ANGLE || target == GL_FRAMEBUFFER)
-            {
-                context->bindDrawFramebuffer(framebuffer);
-            }
+            context->bindDrawFramebuffer(framebuffer);
         }
     }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
-    }
 }
 
 void __stdcall glBindRenderbuffer(GLenum target, GLuint renderbuffer)
 {
     EVENT("(GLenum target = 0x%X, GLuint renderbuffer = %d)", target, renderbuffer);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
         if (target != GL_RENDERBUFFER)
         {
-            return gl::error(GL_INVALID_ENUM);
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
         }
 
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
-        {
-            context->bindRenderbuffer(renderbuffer);
-        }
-    }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
+        context->bindRenderbuffer(renderbuffer);
     }
 }
 
@@ -494,35 +251,38 @@ void __stdcall glBindTexture(GLenum target, GLuint texture)
 {
     EVENT("(GLenum target = 0x%X, GLuint texture = %d)", target, texture);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        gl::Context *context = gl::getNonLostContext();
+        gl::Texture *textureObject = context->getTexture(texture);
 
-        if (context)
+        if (textureObject && textureObject->getTarget() != target && texture != 0)
         {
-            gl::Texture *textureObject = context->getTexture(texture);
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
 
-            if (textureObject && textureObject->getTarget() != target && texture != 0)
-            {
-                return gl::error(GL_INVALID_OPERATION);
-            }
+        switch (target)
+        {
+          case GL_TEXTURE_2D:
+          case GL_TEXTURE_CUBE_MAP:
+            break;
 
-            switch (target)
+          case GL_TEXTURE_3D:
+          case GL_TEXTURE_2D_ARRAY:
+            if (context->getClientVersion() < 3)
             {
-              case GL_TEXTURE_2D:
-                context->bindTexture2D(texture);
-                return;
-              case GL_TEXTURE_CUBE_MAP:
-                context->bindTextureCubeMap(texture);
+                context->recordError(gl::Error(GL_INVALID_ENUM));
                 return;
-              default:
-                return gl::error(GL_INVALID_ENUM);
             }
+            break;
+
+          default:
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
         }
-    }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
+
+        context->bindTexture(target, texture);
     }
 }
 
@@ -531,18 +291,11 @@ void __stdcall glBlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclamp
     EVENT("(GLclampf red = %f, GLclampf green = %f, GLclampf blue = %f, GLclampf alpha = %f)",
           red, green, blue, alpha);
 
-    try
-    {
-        gl::Context* context = gl::getNonLostContext();
+    gl::Context* context = gl::getNonLostContext();
 
-        if (context)
-        {
-            context->setBlendColor(gl::clamp01(red), gl::clamp01(green), gl::clamp01(blue), gl::clamp01(alpha));
-        }
-    }
-    catch(std::bad_alloc&)
+    if (context)
     {
-        return gl::error(GL_OUT_OF_MEMORY);
+        context->getState().setBlendColor(gl::clamp01(red), gl::clamp01(green), gl::clamp01(blue), gl::clamp01(alpha));
     }
 }
 
@@ -555,16 +308,21 @@ void __stdcall glBlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha)
 {
     EVENT("(GLenum modeRGB = 0x%X, GLenum modeAlpha = 0x%X)", modeRGB, modeAlpha);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
         switch (modeRGB)
         {
           case GL_FUNC_ADD:
           case GL_FUNC_SUBTRACT:
           case GL_FUNC_REVERSE_SUBTRACT:
+          case GL_MIN:
+          case GL_MAX:
             break;
+
           default:
-            return gl::error(GL_INVALID_ENUM);
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
         }
 
         switch (modeAlpha)
@@ -572,21 +330,16 @@ void __stdcall glBlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha)
           case GL_FUNC_ADD:
           case GL_FUNC_SUBTRACT:
           case GL_FUNC_REVERSE_SUBTRACT:
+          case GL_MIN:
+          case GL_MAX:
             break;
+
           default:
-            return gl::error(GL_INVALID_ENUM);
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
         }
 
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
-        {
-            context->setBlendEquation(modeRGB, modeAlpha);
-        }
-    }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
+        context->getState().setBlendEquation(modeRGB, modeAlpha);
     }
 }
 
@@ -600,7 +353,8 @@ void __stdcall glBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha
     EVENT("(GLenum srcRGB = 0x%X, GLenum dstRGB = 0x%X, GLenum srcAlpha = 0x%X, GLenum dstAlpha = 0x%X)",
           srcRGB, dstRGB, srcAlpha, dstAlpha);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
         switch (srcRGB)
         {
@@ -620,8 +374,10 @@ void __stdcall glBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha
           case GL_ONE_MINUS_CONSTANT_ALPHA:
           case GL_SRC_ALPHA_SATURATE:
             break;
+
           default:
-            return gl::error(GL_INVALID_ENUM);
+              context->recordError(gl::Error(GL_INVALID_ENUM));
+              return;
         }
 
         switch (dstRGB)
@@ -641,8 +397,18 @@ void __stdcall glBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha
           case GL_CONSTANT_ALPHA:
           case GL_ONE_MINUS_CONSTANT_ALPHA:
             break;
+
+          case GL_SRC_ALPHA_SATURATE:
+            if (context->getClientVersion() < 3)
+            {
+                context->recordError(gl::Error(GL_INVALID_ENUM));
+                return;
+            }
+            break;
+
           default:
-            return gl::error(GL_INVALID_ENUM);
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
         }
 
         switch (srcAlpha)
@@ -663,8 +429,10 @@ void __stdcall glBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha
           case GL_ONE_MINUS_CONSTANT_ALPHA:
           case GL_SRC_ALPHA_SATURATE:
             break;
+
           default:
-            return gl::error(GL_INVALID_ENUM);
+              context->recordError(gl::Error(GL_INVALID_ENUM));
+              return;
         }
 
         switch (dstAlpha)
@@ -684,8 +452,18 @@ void __stdcall glBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha
           case GL_CONSTANT_ALPHA:
           case GL_ONE_MINUS_CONSTANT_ALPHA:
             break;
+
+          case GL_SRC_ALPHA_SATURATE:
+            if (context->getClientVersion() < 3)
+            {
+                context->recordError(gl::Error(GL_INVALID_ENUM));
+                return;
+            }
+            break;
+
           default:
-            return gl::error(GL_INVALID_ENUM);
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
         }
 
         bool constantColorUsed = (srcRGB == GL_CONSTANT_COLOR || srcRGB == GL_ONE_MINUS_CONSTANT_COLOR ||
@@ -697,19 +475,11 @@ void __stdcall glBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha
         if (constantColorUsed && constantAlphaUsed)
         {
             ERR("Simultaneous use of GL_CONSTANT_ALPHA/GL_ONE_MINUS_CONSTANT_ALPHA and GL_CONSTANT_COLOR/GL_ONE_MINUS_CONSTANT_COLOR invalid under WebGL");
-            return gl::error(GL_INVALID_OPERATION);
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
         }
 
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
-        {
-            context->setBlendFactors(srcRGB, dstRGB, srcAlpha, dstAlpha);
-        }
-    }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
+        context->getState().setBlendFactors(srcRGB, dstRGB, srcAlpha, dstAlpha);
     }
 }
 
@@ -718,11 +488,13 @@ void __stdcall glBufferData(GLenum target, GLsizeiptr size, const GLvoid* data,
     EVENT("(GLenum target = 0x%X, GLsizeiptr size = %d, const GLvoid* data = 0x%0.8p, GLenum usage = %d)",
           target, size, data, usage);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
         if (size < 0)
         {
-            return gl::error(GL_INVALID_VALUE);
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
         }
 
         switch (usage)
@@ -731,40 +503,46 @@ void __stdcall glBufferData(GLenum target, GLsizeiptr size, const GLvoid* data,
           case GL_STATIC_DRAW:
           case GL_DYNAMIC_DRAW:
             break;
+
+          case GL_STREAM_READ:
+          case GL_STREAM_COPY:
+          case GL_STATIC_READ:
+          case GL_STATIC_COPY:
+          case GL_DYNAMIC_READ:
+          case GL_DYNAMIC_COPY:
+            if (context->getClientVersion() < 3)
+            {
+                context->recordError(gl::Error(GL_INVALID_ENUM));
+                return;
+            }
+            break;
+
           default:
-            return gl::error(GL_INVALID_ENUM);
+              context->recordError(gl::Error(GL_INVALID_ENUM));
+              return;
         }
 
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
+        if (!gl::ValidBufferTarget(context, target))
         {
-            gl::Buffer *buffer;
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
+        }
 
-            switch (target)
-            {
-              case GL_ARRAY_BUFFER:
-                buffer = context->getArrayBuffer();
-                break;
-              case GL_ELEMENT_ARRAY_BUFFER:
-                buffer = context->getElementArrayBuffer();
-                break;
-              default:
-                return gl::error(GL_INVALID_ENUM);
-            }
+        gl::Buffer *buffer = context->getState().getTargetBuffer(target);
 
-            if (!buffer)
-            {
-                return gl::error(GL_INVALID_OPERATION);
-            }
+        if (!buffer)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
 
-            buffer->bufferData(data, size, usage);
+        gl::Error error = buffer->bufferData(data, size, usage);
+        if (error.isError())
+        {
+            context->recordError(error);
+            return;
         }
     }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
-    }
 }
 
 void __stdcall glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data)
@@ -772,11 +550,13 @@ void __stdcall glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size,
     EVENT("(GLenum target = 0x%X, GLintptr offset = %d, GLsizeiptr size = %d, const GLvoid* data = 0x%0.8p)",
           target, offset, size, data);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
         if (size < 0 || offset < 0)
         {
-            return gl::error(GL_INVALID_VALUE);
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
         }
 
         if (data == NULL)
@@ -784,74 +564,64 @@ void __stdcall glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size,
             return;
         }
 
-        gl::Context *context = gl::getNonLostContext();
+        if (!gl::ValidBufferTarget(context, target))
+        {
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
+        }
+
+        gl::Buffer *buffer = context->getState().getTargetBuffer(target);
 
-        if (context)
+        if (!buffer)
         {
-            gl::Buffer *buffer;
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
 
-            switch (target)
-            {
-              case GL_ARRAY_BUFFER:
-                buffer = context->getArrayBuffer();
-                break;
-              case GL_ELEMENT_ARRAY_BUFFER:
-                buffer = context->getElementArrayBuffer();
-                break;
-              default:
-                return gl::error(GL_INVALID_ENUM);
-            }
+        if (buffer->isMapped())
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
 
-            if (!buffer)
-            {
-                return gl::error(GL_INVALID_OPERATION);
-            }
+        // Check for possible overflow of size + offset
+        if (!rx::IsUnsignedAdditionSafe<size_t>(size, offset))
+        {
+            context->recordError(gl::Error(GL_OUT_OF_MEMORY));
+            return;
+        }
 
-            if ((size_t)size + offset > buffer->size())
-            {
-                return gl::error(GL_INVALID_VALUE);
-            }
+        if (size + offset > buffer->getSize())
+        {
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
+        }
 
-            buffer->bufferSubData(data, size, offset);
+        gl::Error error = buffer->bufferSubData(data, size, offset);
+        if (error.isError())
+        {
+            context->recordError(error);
+            return;
         }
     }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
-    }
 }
 
 GLenum __stdcall glCheckFramebufferStatus(GLenum target)
 {
     EVENT("(GLenum target = 0x%X)", target);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        if (target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER_ANGLE && target != GL_READ_FRAMEBUFFER_ANGLE)
+        if (!gl::ValidFramebufferTarget(target))
         {
-            return gl::error(GL_INVALID_ENUM, 0);
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return 0;
         }
 
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
-        {
-            gl::Framebuffer *framebuffer = NULL;
-            if (target == GL_READ_FRAMEBUFFER_ANGLE)
-            {
-                framebuffer = context->getReadFramebuffer();
-            }
-            else
-            {
-                framebuffer = context->getDrawFramebuffer();
-            }
-
-            return framebuffer->completeness();
-        }
-    }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY, 0);
+        gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
+        ASSERT(framebuffer);
+        return framebuffer->completeness();
     }
 
     return 0;
@@ -859,20 +629,31 @@ GLenum __stdcall glCheckFramebufferStatus(GLenum target)
 
 void __stdcall glClear(GLbitfield mask)
 {
-    EVENT("(GLbitfield mask = %X)", mask);
+    EVENT("(GLbitfield mask = 0x%X)", mask);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        gl::Context *context = gl::getNonLostContext();
+        gl::Framebuffer *framebufferObject = context->getState().getDrawFramebuffer();
 
-        if (context)
+        if (!framebufferObject || framebufferObject->completeness() != GL_FRAMEBUFFER_COMPLETE)
         {
-            context->clear(mask);
+            context->recordError(gl::Error(GL_INVALID_FRAMEBUFFER_OPERATION));
+            return;
+        }
+
+        if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) != 0)
+        {
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
+        }
+
+        gl::Error error = context->clear(mask);
+        if (error.isError())
+        {
+            context->recordError(error);
+            return;
         }
-    }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
     }
 }
 
@@ -881,18 +662,10 @@ void __stdcall glClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclamp
     EVENT("(GLclampf red = %f, GLclampf green = %f, GLclampf blue = %f, GLclampf alpha = %f)",
           red, green, blue, alpha);
 
-    try
-    {
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
-        {
-            context->setClearColor(red, green, blue, alpha);
-        }
-    }
-    catch(std::bad_alloc&)
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        return gl::error(GL_OUT_OF_MEMORY);
+        context->getState().setClearColor(red, green, blue, alpha);
     }
 }
 
@@ -900,18 +673,10 @@ void __stdcall glClearDepthf(GLclampf depth)
 {
     EVENT("(GLclampf depth = %f)", depth);
 
-    try
-    {
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
-        {
-            context->setClearDepth(depth);
-        }
-    }
-    catch(std::bad_alloc&)
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        return gl::error(GL_OUT_OF_MEMORY);
+        context->getState().setClearDepth(depth);
     }
 }
 
@@ -919,38 +684,22 @@ void __stdcall glClearStencil(GLint s)
 {
     EVENT("(GLint s = %d)", s);
 
-    try
-    {
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
-        {
-            context->setClearStencil(s);
-        }
-    }
-    catch(std::bad_alloc&)
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        return gl::error(GL_OUT_OF_MEMORY);
+        context->getState().setClearStencil(s);
     }
 }
 
 void __stdcall glColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha)
 {
-    EVENT("(GLboolean red = %d, GLboolean green = %d, GLboolean blue = %d, GLboolean alpha = %d)",
+    EVENT("(GLboolean red = %d, GLboolean green = %u, GLboolean blue = %u, GLboolean alpha = %u)",
           red, green, blue, alpha);
 
-    try
-    {
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
-        {
-            context->setColorMask(red == GL_TRUE, green == GL_TRUE, blue == GL_TRUE, alpha == GL_TRUE);
-        }
-    }
-    catch(std::bad_alloc&)
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        return gl::error(GL_OUT_OF_MEMORY);
+        context->getState().setColorMask(red == GL_TRUE, green == GL_TRUE, blue == GL_TRUE, alpha == GL_TRUE);
     }
 }
 
@@ -958,191 +707,85 @@ void __stdcall glCompileShader(GLuint shader)
 {
     EVENT("(GLuint shader = %d)", shader);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        gl::Context *context = gl::getNonLostContext();
+        gl::Shader *shaderObject = context->getShader(shader);
 
-        if (context)
+        if (!shaderObject)
         {
-            gl::Shader *shaderObject = context->getShader(shader);
-
-            if (!shaderObject)
+            if (context->getProgram(shader))
             {
-                if (context->getProgram(shader))
-                {
-                    return gl::error(GL_INVALID_OPERATION);
-                }
-                else
-                {
-                    return gl::error(GL_INVALID_VALUE);
-                }
+                context->recordError(gl::Error(GL_INVALID_OPERATION));
+                return;
+            }
+            else
+            {
+                context->recordError(gl::Error(GL_INVALID_VALUE));
+                return;
             }
-
-            shaderObject->compile();
         }
-    }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
+
+        shaderObject->compile();
     }
 }
 
-void __stdcall glCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, 
+void __stdcall glCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height,
                                       GLint border, GLsizei imageSize, const GLvoid* data)
 {
-    EVENT("(GLenum target = 0x%X, GLint level = %d, GLenum internalformat = 0x%X, GLsizei width = %d, " 
+    EVENT("(GLenum target = 0x%X, GLint level = %d, GLenum internalformat = 0x%X, GLsizei width = %d, "
           "GLsizei height = %d, GLint border = %d, GLsizei imageSize = %d, const GLvoid* data = 0x%0.8p)",
           target, level, internalformat, width, height, border, imageSize, data);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        if (!validImageSize(level, width, height) || border != 0 || imageSize < 0)
-        {
-            return gl::error(GL_INVALID_VALUE);
-        }
-
-        switch (internalformat)
-        {
-          case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
-          case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
-          case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
-          case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
-            break;
-          default:
-            return gl::error(GL_INVALID_ENUM);
-        }
-
-        if (border != 0)
+        if (context->getClientVersion() < 3 &&
+            !ValidateES2TexImageParameters(context, target, level, internalformat, true, false,
+                                           0, 0, width, height, border, GL_NONE, GL_NONE, data))
         {
-            return gl::error(GL_INVALID_OPERATION);
+            return;
         }
 
-        if (width != 1 && width != 2 && width % 4 != 0)
+        if (context->getClientVersion() >= 3 &&
+            !ValidateES3TexImageParameters(context, target, level, internalformat, true, false,
+                                           0, 0, 0, width, height, 1, border, GL_NONE, GL_NONE, data))
         {
-            return gl::error(GL_INVALID_OPERATION);
+            return;
         }
 
-        if (height != 1 && height != 2 && height % 4 != 0)
+        const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
+        if (imageSize < 0 || static_cast<GLuint>(imageSize) != formatInfo.computeBlockSize(GL_UNSIGNED_BYTE, width, height))
         {
-            return gl::error(GL_INVALID_OPERATION);
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
         }
 
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
+        switch (target)
         {
-            if (level > context->getMaximumTextureLevel())
-            {
-                return gl::error(GL_INVALID_VALUE);
-            }
-
-            switch (target)
-            {
-              case GL_TEXTURE_2D:
-                if (width > (context->getMaximumTextureDimension() >> level) ||
-                    height > (context->getMaximumTextureDimension() >> level))
-                {
-                    return gl::error(GL_INVALID_VALUE);
-                }
-                break;
-              case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
-              case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
-              case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
-              case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
-              case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
-              case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
-                if (width != height)
-                {
-                    return gl::error(GL_INVALID_VALUE);
-                }
-
-                if (width > (context->getMaximumCubeTextureDimension() >> level) ||
-                    height > (context->getMaximumCubeTextureDimension() >> level))
-                {
-                    return gl::error(GL_INVALID_VALUE);
-                }
-                break;
-              default:
-                return gl::error(GL_INVALID_ENUM);
-            }
-
-            switch (internalformat) {
-              case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
-              case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
-                if (!context->supportsDXT1Textures())
-                {
-                    return gl::error(GL_INVALID_ENUM); // in this case, it's as though the internal format switch failed
-                }
-                break;
-              case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
-                if (!context->supportsDXT3Textures())
-                {
-                    return gl::error(GL_INVALID_ENUM); // in this case, it's as though the internal format switch failed
-                }
-                break;
-              case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
-                if (!context->supportsDXT5Textures())
-                {
-                    return gl::error(GL_INVALID_ENUM); // in this case, it's as though the internal format switch failed
-                }
-                break;
-              default: UNREACHABLE();
-            }
-
-            if (imageSize != gl::ComputeCompressedSize(width, height, internalformat))
-            {
-                return gl::error(GL_INVALID_VALUE);
-            }
-
-            if (target == GL_TEXTURE_2D)
+          case GL_TEXTURE_2D:
             {
                 gl::Texture2D *texture = context->getTexture2D();
-
-                if (!texture)
-                {
-                    return gl::error(GL_INVALID_OPERATION);
-                }
-
-                if (texture->isImmutable())
-                {
-                    return gl::error(GL_INVALID_OPERATION);
-                }
-
                 texture->setCompressedImage(level, internalformat, width, height, imageSize, data);
             }
-            else
+            break;
+
+          case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
+          case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
+          case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
+          case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
+          case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
+          case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
             {
                 gl::TextureCubeMap *texture = context->getTextureCubeMap();
-
-                if (!texture)
-                {
-                    return gl::error(GL_INVALID_OPERATION);
-                }
-
-                if (texture->isImmutable())
-                {
-                    return gl::error(GL_INVALID_OPERATION);
-                }
-
-                switch (target)
-                {
-                  case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
-                  case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
-                  case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
-                  case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
-                  case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
-                  case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
-                    texture->setCompressedImage(target, level, internalformat, width, height, imageSize, data);
-                    break;
-                  default: UNREACHABLE();
-                }
+                texture->setCompressedImage(target, level, internalformat, width, height, imageSize, data);
             }
-        }
+            break;
 
-    }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
+          default:
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
+        }
     }
 }
 
@@ -1154,103 +797,56 @@ void __stdcall glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffs
           "GLsizei imageSize = %d, const GLvoid* data = 0x%0.8p)",
           target, level, xoffset, yoffset, width, height, format, imageSize, data);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        if (!gl::IsInternalTextureTarget(target))
+        if (context->getClientVersion() < 3 &&
+            !ValidateES2TexImageParameters(context, target, level, GL_NONE, true, true,
+                                           xoffset, yoffset, width, height, 0, GL_NONE, GL_NONE, data))
         {
-            return gl::error(GL_INVALID_ENUM);
-        }
-
-        if (xoffset < 0 || yoffset < 0 || !validImageSize(level, width, height) || imageSize < 0)
-        {
-            return gl::error(GL_INVALID_VALUE);
+            return;
         }
 
-        switch (format)
+        if (context->getClientVersion() >= 3 &&
+            !ValidateES3TexImageParameters(context, target, level, GL_NONE, true, true,
+                                           xoffset, yoffset, 0, width, height, 1, 0, GL_NONE, GL_NONE, data))
         {
-          case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
-          case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
-          case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
-          case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
-            break;
-          default:
-            return gl::error(GL_INVALID_ENUM);
+            return;
         }
 
-        if (width == 0 || height == 0 || data == NULL)
+        const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
+        if (imageSize < 0 || static_cast<GLuint>(imageSize) != formatInfo.computeBlockSize(GL_UNSIGNED_BYTE, width, height))
         {
+            context->recordError(gl::Error(GL_INVALID_VALUE));
             return;
         }
 
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
+        switch (target)
         {
-            if (level > context->getMaximumTextureLevel())
+          case GL_TEXTURE_2D:
             {
-                return gl::error(GL_INVALID_VALUE);
+                gl::Texture2D *texture = context->getTexture2D();
+                texture->subImageCompressed(level, xoffset, yoffset, width, height, format, imageSize, data);
             }
+            break;
 
-            switch (format) {
-              case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
-              case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
-                if (!context->supportsDXT1Textures())
-                {
-                    return gl::error(GL_INVALID_ENUM); // in this case, it's as though the internal format switch failed
-                }
-                break;
-              case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
-                if (!context->supportsDXT3Textures())
-                {
-                    return gl::error(GL_INVALID_ENUM); // in this case, it's as though the internal format switch failed
-                }
-                break;
-              case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
-                if (!context->supportsDXT5Textures())
-                {
-                    return gl::error(GL_INVALID_ENUM); // in this case, it's as though the internal format switch failed
-                }
-                break;
-              default: UNREACHABLE();
-            }
-
-            if (imageSize != gl::ComputeCompressedSize(width, height, format))
-            {
-                return gl::error(GL_INVALID_VALUE);
-            }
-
-            if (xoffset % 4 != 0 || yoffset % 4 != 0)
-            {
-                return gl::error(GL_INVALID_OPERATION); // we wait to check the offsets until this point, because the multiple-of-four restriction
-                                                    // does not exist unless DXT textures are supported.
-            }
-
-            if (target == GL_TEXTURE_2D)
-            {
-                gl::Texture2D *texture = context->getTexture2D();
-                if (validateSubImageParams2D(true, width, height, xoffset, yoffset, level, format, GL_NONE, texture))
-                {
-                    texture->subImageCompressed(level, xoffset, yoffset, width, height, format, imageSize, data);
-                }
-            }
-            else if (gl::IsCubemapTextureTarget(target))
+          case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
+          case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
+          case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
+          case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
+          case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
+          case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
             {
                 gl::TextureCubeMap *texture = context->getTextureCubeMap();
-                if (validateSubImageParamsCube(true, width, height, xoffset, yoffset, target, level, format, GL_NONE, texture))
-                {
-                    texture->subImageCompressed(target, level, xoffset, yoffset, width, height, format, imageSize, data);
-                }
-            }
-            else
-            {
-                UNREACHABLE();
+                texture->subImageCompressed(target, level, xoffset, yoffset, width, height, format, imageSize, data);
             }
+            break;
+
+          default:
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
         }
     }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
-    }
 }
 
 void __stdcall glCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border)
@@ -1259,194 +855,51 @@ void __stdcall glCopyTexImage2D(GLenum target, GLint level, GLenum internalforma
           "GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d, GLint border = %d)",
           target, level, internalformat, x, y, width, height, border);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        if (!validImageSize(level, width, height))
+        if (context->getClientVersion() < 3 &&
+            !ValidateES2CopyTexImageParameters(context, target, level, internalformat, false,
+                                               0, 0, x, y, width, height, border))
         {
-            return gl::error(GL_INVALID_VALUE);
+            return;
         }
 
-        if (border != 0)
+        if (context->getClientVersion() >= 3 &&
+            !ValidateES3CopyTexImageParameters(context, target, level, internalformat, false,
+                                               0, 0, 0, x, y, width, height, border))
         {
-            return gl::error(GL_INVALID_VALUE);
+            return;
         }
 
-        gl::Context *context = gl::getNonLostContext();
+        gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
 
-        if (context)
+        switch (target)
         {
-            if (level > context->getMaximumTextureLevel())
-            {
-                return gl::error(GL_INVALID_VALUE);
-            }
-
-            switch (target)
-            {
-              case GL_TEXTURE_2D:
-                if (width > (context->getMaximumTextureDimension() >> level) ||
-                    height > (context->getMaximumTextureDimension() >> level))
-                {
-                    return gl::error(GL_INVALID_VALUE);
-                }
-                break;
-              case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
-              case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
-              case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
-              case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
-              case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
-              case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
-                if (width != height)
-                {
-                    return gl::error(GL_INVALID_VALUE);
-                }
-
-                if (width > (context->getMaximumCubeTextureDimension() >> level) ||
-                    height > (context->getMaximumCubeTextureDimension() >> level))
-                {
-                    return gl::error(GL_INVALID_VALUE);
-                }
-                break;
-              default:
-                return gl::error(GL_INVALID_ENUM);
-            }
-
-            gl::Framebuffer *framebuffer = context->getReadFramebuffer();
-
-            if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
-            {
-                return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION);
-            }
-
-            if (context->getReadFramebufferHandle() != 0 && framebuffer->getSamples() != 0)
-            {
-                return gl::error(GL_INVALID_OPERATION);
-            }
-
-            gl::Renderbuffer *source = framebuffer->getReadColorbuffer();
-            GLenum colorbufferFormat = source->getInternalFormat();
-
-            // [OpenGL ES 2.0.24] table 3.9
-            switch (internalformat)
-            {
-              case GL_ALPHA:
-                if (colorbufferFormat != GL_ALPHA8_EXT &&
-                    colorbufferFormat != GL_RGBA4 &&
-                    colorbufferFormat != GL_RGB5_A1 &&
-                    colorbufferFormat != GL_BGRA8_EXT &&
-                    colorbufferFormat != GL_RGBA8_OES)
-                {
-                    return gl::error(GL_INVALID_OPERATION);
-                }
-                break;
-              case GL_LUMINANCE:
-              case GL_RGB:
-                if (colorbufferFormat != GL_RGB565 &&
-                    colorbufferFormat != GL_RGB8_OES &&
-                    colorbufferFormat != GL_RGBA4 &&
-                    colorbufferFormat != GL_RGB5_A1 &&
-                    colorbufferFormat != GL_BGRA8_EXT &&
-                    colorbufferFormat != GL_RGBA8_OES)
-                {
-                    return gl::error(GL_INVALID_OPERATION);
-                }
-                break;
-              case GL_LUMINANCE_ALPHA:
-              case GL_RGBA:
-                if (colorbufferFormat != GL_RGBA4 &&
-                    colorbufferFormat != GL_RGB5_A1 &&
-                    colorbufferFormat != GL_BGRA8_EXT &&
-                    colorbufferFormat != GL_RGBA8_OES)
-                 {
-                     return gl::error(GL_INVALID_OPERATION);
-                 }
-                 break;
-              case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
-              case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
-                if (context->supportsDXT1Textures())
-                {
-                    return gl::error(GL_INVALID_OPERATION);
-                }
-                else
-                {
-                    return gl::error(GL_INVALID_ENUM);
-                }
-                break;
-              case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
-                if (context->supportsDXT3Textures())
-                {
-                    return gl::error(GL_INVALID_OPERATION);
-                }
-                else
-                {
-                    return gl::error(GL_INVALID_ENUM);
-                }
-                break;
-              case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
-                if (context->supportsDXT5Textures())
-                {
-                    return gl::error(GL_INVALID_OPERATION);
-                }
-                else
-                {
-                    return gl::error(GL_INVALID_ENUM);
-                }
-                break;
-              case GL_DEPTH_COMPONENT:
-              case GL_DEPTH_COMPONENT16:
-              case GL_DEPTH_COMPONENT32_OES:
-              case GL_DEPTH_STENCIL_OES:
-              case GL_DEPTH24_STENCIL8_OES:
-                  if (context->supportsDepthTextures())
-                  {
-                      return gl::error(GL_INVALID_OPERATION);
-                  }
-                  else
-                  {
-                      return gl::error(GL_INVALID_ENUM);
-                  }
-              default:
-                return gl::error(GL_INVALID_ENUM);
-            }
-
-            if (target == GL_TEXTURE_2D)
+          case GL_TEXTURE_2D:
             {
                 gl::Texture2D *texture = context->getTexture2D();
-
-                if (!texture)
-                {
-                    return gl::error(GL_INVALID_OPERATION);
-                }
-
-                if (texture->isImmutable())
-                {
-                    return gl::error(GL_INVALID_OPERATION);
-                }
-
                 texture->copyImage(level, internalformat, x, y, width, height, framebuffer);
             }
-            else if (gl::IsCubemapTextureTarget(target))
+            break;
+
+          case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
+          case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
+          case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
+          case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
+          case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
+          case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
             {
                 gl::TextureCubeMap *texture = context->getTextureCubeMap();
-
-                if (!texture)
-                {
-                    return gl::error(GL_INVALID_OPERATION);
-                }
-
-                if (texture->isImmutable())
-                {
-                    return gl::error(GL_INVALID_OPERATION);
-                }
-
                 texture->copyImage(target, level, internalformat, x, y, width, height, framebuffer);
             }
-            else UNREACHABLE();
+            break;
+
+          default:
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
         }
     }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
-    }
 }
 
 void __stdcall glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height)
@@ -1455,148 +908,61 @@ void __stdcall glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GL
           "GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d)",
           target, level, xoffset, yoffset, x, y, width, height);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        if (!gl::IsInternalTextureTarget(target))
-        {
-            return gl::error(GL_INVALID_ENUM);
-        }
-
-        if (level < 0 || xoffset < 0 || yoffset < 0 || width < 0 || height < 0)
-        {
-            return gl::error(GL_INVALID_VALUE);
-        }
-
-        if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
+        if (context->getClientVersion() < 3 &&
+            !ValidateES2CopyTexImageParameters(context, target, level, GL_NONE, true,
+                                               xoffset, yoffset, x, y, width, height, 0))
         {
-            return gl::error(GL_INVALID_VALUE);
+            return;
         }
 
-        if (width == 0 || height == 0)
+        if (context->getClientVersion() >= 3 &&
+            !ValidateES3CopyTexImageParameters(context, target, level, GL_NONE, true,
+                                               xoffset, yoffset, 0, x, y, width, height, 0))
         {
             return;
         }
 
-        gl::Context *context = gl::getNonLostContext();
+        gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
 
-        if (context)
+        switch (target)
         {
-            if (level > context->getMaximumTextureLevel())
-            {
-                return gl::error(GL_INVALID_VALUE);
-            }
-
-            gl::Framebuffer *framebuffer = context->getReadFramebuffer();
-
-            if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
-            {
-                return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION);
-            }
-
-            if (context->getReadFramebufferHandle() != 0 && framebuffer->getSamples() != 0)
-            {
-                return gl::error(GL_INVALID_OPERATION);
-            }
-
-            gl::Renderbuffer *source = framebuffer->getReadColorbuffer();
-            GLenum colorbufferFormat = source->getInternalFormat();
-            gl::Texture *texture = NULL;
-            GLenum textureFormat = GL_RGBA;
-
-            if (target == GL_TEXTURE_2D)
-            {
-                gl::Texture2D *tex2d = context->getTexture2D();
-
-                if (!validateSubImageParams2D(false, width, height, xoffset, yoffset, level, GL_NONE, GL_NONE, tex2d))
-                {
-                    return; // error already registered by validateSubImageParams
-                }
-                textureFormat = gl::ExtractFormat(tex2d->getInternalFormat(level));
-                texture = tex2d;
-            }
-            else if (gl::IsCubemapTextureTarget(target))
+          case GL_TEXTURE_2D:
             {
-                gl::TextureCubeMap *texcube = context->getTextureCubeMap();
-
-                if (!validateSubImageParamsCube(false, width, height, xoffset, yoffset, target, level, GL_NONE, GL_NONE, texcube))
-                {
-                    return; // error already registered by validateSubImageParams
-                }
-                textureFormat = gl::ExtractFormat(texcube->getInternalFormat(target, level));
-                texture = texcube;
+                gl::Texture2D *texture = context->getTexture2D();
+                texture->copySubImage(target, level, xoffset, yoffset, 0, x, y, width, height, framebuffer);
             }
-            else UNREACHABLE();
+            break;
 
-            // [OpenGL ES 2.0.24] table 3.9
-            switch (textureFormat)
+          case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
+          case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
+          case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
+          case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
+          case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
+          case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
             {
-              case GL_ALPHA:
-                if (colorbufferFormat != GL_ALPHA8_EXT &&
-                    colorbufferFormat != GL_RGBA4 &&
-                    colorbufferFormat != GL_RGB5_A1 &&
-                    colorbufferFormat != GL_RGBA8_OES)
-                {
-                    return gl::error(GL_INVALID_OPERATION);
-                }
-                break;
-              case GL_LUMINANCE:
-              case GL_RGB:
-                if (colorbufferFormat != GL_RGB565 &&
-                    colorbufferFormat != GL_RGB8_OES &&
-                    colorbufferFormat != GL_RGBA4 &&
-                    colorbufferFormat != GL_RGB5_A1 &&
-                    colorbufferFormat != GL_RGBA8_OES)
-                {
-                    return gl::error(GL_INVALID_OPERATION);
-                }
-                break;
-              case GL_LUMINANCE_ALPHA:
-              case GL_RGBA:
-                if (colorbufferFormat != GL_RGBA4 &&
-                    colorbufferFormat != GL_RGB5_A1 &&
-                    colorbufferFormat != GL_RGBA8_OES)
-                {
-                    return gl::error(GL_INVALID_OPERATION);
-                }
-                break;
-              case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
-              case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
-              case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
-              case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
-                return gl::error(GL_INVALID_OPERATION);
-              case GL_DEPTH_COMPONENT:
-              case GL_DEPTH_STENCIL_OES:
-                return gl::error(GL_INVALID_OPERATION);
-              default:
-                return gl::error(GL_INVALID_OPERATION);
+                gl::TextureCubeMap *texture = context->getTextureCubeMap();
+                texture->copySubImage(target, level, xoffset, yoffset, 0, x, y, width, height, framebuffer);
             }
+            break;
 
-            texture->copySubImage(target, level, xoffset, yoffset, x, y, width, height, framebuffer);
+          default:
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
         }
     }
-
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
-    }
 }
 
 GLuint __stdcall glCreateProgram(void)
 {
     EVENT("()");
 
-    try
-    {
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
-        {
-            return context->createProgram();
-        }
-    }
-    catch(std::bad_alloc&)
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        return gl::error(GL_OUT_OF_MEMORY, 0);
+        return context->createProgram();
     }
 
     return 0;
@@ -1606,26 +972,20 @@ GLuint __stdcall glCreateShader(GLenum type)
 {
     EVENT("(GLenum type = 0x%X)", type);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
+        switch (type)
         {
-            switch (type)
-            {
-              case GL_FRAGMENT_SHADER:
-              case GL_VERTEX_SHADER:
-                return context->createShader(type);
-              default:
-                return gl::error(GL_INVALID_ENUM, 0);
-            }
+          case GL_FRAGMENT_SHADER:
+          case GL_VERTEX_SHADER:
+            return context->createShader(type);
+
+          default:
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return 0;
         }
     }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY, 0);
-    }
 
     return 0;
 }
@@ -1634,29 +994,22 @@ void __stdcall glCullFace(GLenum mode)
 {
     EVENT("(GLenum mode = 0x%X)", mode);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
         switch (mode)
         {
           case GL_FRONT:
           case GL_BACK:
           case GL_FRONT_AND_BACK:
-            {
-                gl::Context *context = gl::getNonLostContext();
-
-                if (context)
-                {
-                    context->setCullMode(mode);
-                }
-            }
             break;
+
           default:
-            return gl::error(GL_INVALID_ENUM);
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
         }
-    }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
+
+        context->getState().setCullMode(mode);
     }
 }
 
@@ -1664,119 +1017,92 @@ void __stdcall glDeleteBuffers(GLsizei n, const GLuint* buffers)
 {
     EVENT("(GLsizei n = %d, const GLuint* buffers = 0x%0.8p)", n, buffers);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
         if (n < 0)
         {
-            return gl::error(GL_INVALID_VALUE);
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
         }
 
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
+        for (int i = 0; i < n; i++)
         {
-            for (int i = 0; i < n; i++)
-            {
-                context->deleteBuffer(buffers[i]);
-            }
+            context->deleteBuffer(buffers[i]);
         }
     }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
-    }
 }
 
 void __stdcall glDeleteFencesNV(GLsizei n, const GLuint* fences)
 {
     EVENT("(GLsizei n = %d, const GLuint* fences = 0x%0.8p)", n, fences);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
         if (n < 0)
         {
-            return gl::error(GL_INVALID_VALUE);
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
         }
 
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
+        for (int i = 0; i < n; i++)
         {
-            for (int i = 0; i < n; i++)
-            {
-                context->deleteFence(fences[i]);
-            }
+            context->deleteFenceNV(fences[i]);
         }
     }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
-    }
 }
 
 void __stdcall glDeleteFramebuffers(GLsizei n, const GLuint* framebuffers)
 {
     EVENT("(GLsizei n = %d, const GLuint* framebuffers = 0x%0.8p)", n, framebuffers);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
         if (n < 0)
         {
-            return gl::error(GL_INVALID_VALUE);
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
         }
 
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
+        for (int i = 0; i < n; i++)
         {
-            for (int i = 0; i < n; i++)
+            if (framebuffers[i] != 0)
             {
-                if (framebuffers[i] != 0)
-                {
-                    context->deleteFramebuffer(framebuffers[i]);
-                }
+                context->deleteFramebuffer(framebuffers[i]);
             }
         }
     }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
-    }
 }
 
 void __stdcall glDeleteProgram(GLuint program)
 {
     EVENT("(GLuint program = %d)", program);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
         if (program == 0)
         {
             return;
         }
 
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
+        if (!context->getProgram(program))
         {
-            if (!context->getProgram(program))
+            if(context->getShader(program))
             {
-                if(context->getShader(program))
-                {
-                    return gl::error(GL_INVALID_OPERATION);
-                }
-                else
-                {
-                    return gl::error(GL_INVALID_VALUE);
-                }
+                context->recordError(gl::Error(GL_INVALID_OPERATION));
+                return;
+            }
+            else
+            {
+                context->recordError(gl::Error(GL_INVALID_VALUE));
+                return;
             }
-
-            context->deleteProgram(program);
         }
-    }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
+
+        context->deleteProgram(program);
     }
 }
 
@@ -1784,89 +1110,69 @@ void __stdcall glDeleteQueriesEXT(GLsizei n, const GLuint *ids)
 {
     EVENT("(GLsizei n = %d, const GLuint *ids = 0x%0.8p)", n, ids);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
         if (n < 0)
         {
-            return gl::error(GL_INVALID_VALUE);
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
         }
 
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
+        for (int i = 0; i < n; i++)
         {
-            for (int i = 0; i < n; i++)
-            {
-                context->deleteQuery(ids[i]);
-            }
+            context->deleteQuery(ids[i]);
         }
     }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
-    }
 }
 
 void __stdcall glDeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers)
 {
     EVENT("(GLsizei n = %d, const GLuint* renderbuffers = 0x%0.8p)", n, renderbuffers);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
         if (n < 0)
         {
-            return gl::error(GL_INVALID_VALUE);
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
         }
 
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
+        for (int i = 0; i < n; i++)
         {
-            for (int i = 0; i < n; i++)
-            {
-                context->deleteRenderbuffer(renderbuffers[i]);
-            }
+            context->deleteRenderbuffer(renderbuffers[i]);
         }
     }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
-    }
 }
 
 void __stdcall glDeleteShader(GLuint shader)
 {
     EVENT("(GLuint shader = %d)", shader);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
         if (shader == 0)
         {
             return;
         }
 
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
+        if (!context->getShader(shader))
         {
-            if (!context->getShader(shader))
+            if(context->getProgram(shader))
             {
-                if(context->getProgram(shader))
-                {
-                    return gl::error(GL_INVALID_OPERATION);
-                }
-                else
-                {
-                    return gl::error(GL_INVALID_VALUE);
-                }
+                context->recordError(gl::Error(GL_INVALID_OPERATION));
+                return;
+            }
+            else
+            {
+                context->recordError(gl::Error(GL_INVALID_VALUE));
+                return;
             }
-
-            context->deleteShader(shader);
         }
-    }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
+
+        context->deleteShader(shader);
     }
 }
 
@@ -1874,37 +1180,31 @@ void __stdcall glDeleteTextures(GLsizei n, const GLuint* textures)
 {
     EVENT("(GLsizei n = %d, const GLuint* textures = 0x%0.8p)", n, textures);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
         if (n < 0)
         {
-            return gl::error(GL_INVALID_VALUE);
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
         }
 
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
+        for (int i = 0; i < n; i++)
         {
-            for (int i = 0; i < n; i++)
+            if (textures[i] != 0)
             {
-                if (textures[i] != 0)
-                {
-                    context->deleteTexture(textures[i]);
-                }
+                context->deleteTexture(textures[i]);
             }
         }
     }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
-    }
 }
 
 void __stdcall glDepthFunc(GLenum func)
 {
     EVENT("(GLenum func = 0x%X)", func);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
         switch (func)
         {
@@ -1916,40 +1216,24 @@ void __stdcall glDepthFunc(GLenum func)
           case GL_GREATER:
           case GL_GEQUAL:
           case GL_NOTEQUAL:
+            context->getState().setDepthFunc(func);
             break;
-          default:
-            return gl::error(GL_INVALID_ENUM);
-        }
 
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
-        {
-            context->setDepthFunc(func);
+          default:
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
         }
     }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
-    }
 }
 
 void __stdcall glDepthMask(GLboolean flag)
 {
-    EVENT("(GLboolean flag = %d)", flag);
-
-    try
-    {
-        gl::Context *context = gl::getNonLostContext();
+    EVENT("(GLboolean flag = %u)", flag);
 
-        if (context)
-        {
-            context->setDepthMask(flag != GL_FALSE);
-        }
-    }
-    catch(std::bad_alloc&)
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        return gl::error(GL_OUT_OF_MEMORY);
+        context->getState().setDepthMask(flag != GL_FALSE);
     }
 }
 
@@ -1957,18 +1241,10 @@ void __stdcall glDepthRangef(GLclampf zNear, GLclampf zFar)
 {
     EVENT("(GLclampf zNear = %f, GLclampf zFar = %f)", zNear, zFar);
 
-    try
-    {
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
-        {
-            context->setDepthRange(zNear, zFar);
-        }
-    }
-    catch(std::bad_alloc&)
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        return gl::error(GL_OUT_OF_MEMORY);
+        context->getState().setDepthRange(zNear, zFar);
     }
 }
 
@@ -1976,52 +1252,48 @@ void __stdcall glDetachShader(GLuint program, GLuint shader)
 {
     EVENT("(GLuint program = %d, GLuint shader = %d)", program, shader);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        gl::Context *context = gl::getNonLostContext();
+        gl::Program *programObject = context->getProgram(program);
+        gl::Shader *shaderObject = context->getShader(shader);
 
-        if (context)
+        if (!programObject)
         {
-
-            gl::Program *programObject = context->getProgram(program);
-            gl::Shader *shaderObject = context->getShader(shader);
-            
-            if (!programObject)
+            gl::Shader *shaderByProgramHandle;
+            shaderByProgramHandle = context->getShader(program);
+            if (!shaderByProgramHandle)
             {
-                gl::Shader *shaderByProgramHandle;
-                shaderByProgramHandle = context->getShader(program);
-                if (!shaderByProgramHandle)
-                {
-                    return gl::error(GL_INVALID_VALUE);
-                }
-                else
-                {
-                    return gl::error(GL_INVALID_OPERATION);
-                }
+                context->recordError(gl::Error(GL_INVALID_VALUE));
+                return;
             }
-
-            if (!shaderObject)
+            else
             {
-                gl::Program *programByShaderHandle = context->getProgram(shader);
-                if (!programByShaderHandle)
-                {
-                    return gl::error(GL_INVALID_VALUE);
-                }
-                else
-                {
-                    return gl::error(GL_INVALID_OPERATION);
-                }
+                context->recordError(gl::Error(GL_INVALID_OPERATION));
+                return;
             }
+        }
 
-            if (!programObject->detachShader(shaderObject))
+        if (!shaderObject)
+        {
+            gl::Program *programByShaderHandle = context->getProgram(shader);
+            if (!programByShaderHandle)
+            {
+                context->recordError(gl::Error(GL_INVALID_VALUE));
+                return;
+            }
+            else
             {
-                return gl::error(GL_INVALID_OPERATION);
+                context->recordError(gl::Error(GL_INVALID_OPERATION));
+                return;
             }
         }
-    }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
+
+        if (!programObject->detachShader(shaderObject))
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
     }
 }
 
@@ -2029,31 +1301,16 @@ void __stdcall glDisable(GLenum cap)
 {
     EVENT("(GLenum cap = 0x%X)", cap);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
+        if (!ValidCap(context, cap))
         {
-            switch (cap)
-            {
-              case GL_CULL_FACE:                context->setCullFace(false);              break;
-              case GL_POLYGON_OFFSET_FILL:      context->setPolygonOffsetFill(false);     break;
-              case GL_SAMPLE_ALPHA_TO_COVERAGE: context->setSampleAlphaToCoverage(false); break;
-              case GL_SAMPLE_COVERAGE:          context->setSampleCoverage(false);        break;
-              case GL_SCISSOR_TEST:             context->setScissorTest(false);           break;
-              case GL_STENCIL_TEST:             context->setStencilTest(false);           break;
-              case GL_DEPTH_TEST:               context->setDepthTest(false);             break;
-              case GL_BLEND:                    context->setBlend(false);                 break;
-              case GL_DITHER:                   context->setDither(false);                break;
-              default:
-                return gl::error(GL_INVALID_ENUM);
-            }
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
         }
-    }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
+
+        context->getState().setEnableFeature(cap, false);
     }
 }
 
@@ -2061,23 +1318,16 @@ void __stdcall glDisableVertexAttribArray(GLuint index)
 {
     EVENT("(GLuint index = %d)", index);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
         if (index >= gl::MAX_VERTEX_ATTRIBS)
         {
-            return gl::error(GL_INVALID_VALUE);
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
         }
 
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
-        {
-            context->setEnableVertexAttribArray(index, false);
-        }
-    }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
+        context->getState().setEnableVertexAttribArray(index, false);
     }
 }
 
@@ -2085,23 +1335,15 @@ void __stdcall glDrawArrays(GLenum mode, GLint first, GLsizei count)
 {
     EVENT("(GLenum mode = 0x%X, GLint first = %d, GLsizei count = %d)", mode, first, count);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        if (count < 0 || first < 0)
+        if (!ValidateDrawArrays(context, mode, first, count, 0))
         {
-            return gl::error(GL_INVALID_VALUE);
+            return;
         }
 
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
-        {
-            context->drawArrays(mode, first, count, 0);
-        }
-    }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
+        context->drawArrays(mode, first, count, 0);
     }
 }
 
@@ -2109,26 +1351,15 @@ void __stdcall glDrawArraysInstancedANGLE(GLenum mode, GLint first, GLsizei coun
 {
     EVENT("(GLenum mode = 0x%X, GLint first = %d, GLsizei count = %d, GLsizei primcount = %d)", mode, first, count, primcount);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        if (count < 0 || first < 0 || primcount < 0)
+        if (!ValidateDrawArraysInstancedANGLE(context, mode, first, count, primcount))
         {
-            return gl::error(GL_INVALID_VALUE);
+            return;
         }
 
-        if (primcount > 0)
-        {
-            gl::Context *context = gl::getNonLostContext();
-
-            if (context)
-            {
-                context->drawArrays(mode, first, count, primcount);
-            }
-        }
-    }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
+        context->drawArrays(mode, first, count, primcount);
     }
 }
 
@@ -2137,38 +1368,16 @@ void __stdcall glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLv
     EVENT("(GLenum mode = 0x%X, GLsizei count = %d, GLenum type = 0x%X, const GLvoid* indices = 0x%0.8p)",
           mode, count, type, indices);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        if (count < 0)
+        rx::RangeUI indexRange;
+        if (!ValidateDrawElements(context, mode, count, type, indices, 0, &indexRange))
         {
-            return gl::error(GL_INVALID_VALUE);
+            return;
         }
 
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
-        {
-            switch (type)
-            {
-              case GL_UNSIGNED_BYTE:
-              case GL_UNSIGNED_SHORT:
-                break;
-              case GL_UNSIGNED_INT:
-                if (!context->supports32bitIndices())
-                {
-                    return gl::error(GL_INVALID_ENUM);    
-                }
-                break;
-              default:
-                return gl::error(GL_INVALID_ENUM);
-            }
-        
-            context->drawElements(mode, count, type, indices, 0);
-        }
-    }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
+        context->drawElements(mode, count, type, indices, 0, indexRange);
     }
 }
 
@@ -2177,41 +1386,16 @@ void __stdcall glDrawElementsInstancedANGLE(GLenum mode, GLsizei count, GLenum t
     EVENT("(GLenum mode = 0x%X, GLsizei count = %d, GLenum type = 0x%X, const GLvoid* indices = 0x%0.8p, GLsizei primcount = %d)",
           mode, count, type, indices, primcount);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        if (count < 0 || primcount < 0)
+        rx::RangeUI indexRange;
+        if (!ValidateDrawElementsInstancedANGLE(context, mode, count, type, indices, primcount, &indexRange))
         {
-            return gl::error(GL_INVALID_VALUE);
+            return;
         }
 
-        if (primcount > 0)
-        {
-            gl::Context *context = gl::getNonLostContext();
-
-            if (context)
-            {
-                switch (type)
-                {
-                  case GL_UNSIGNED_BYTE:
-                  case GL_UNSIGNED_SHORT:
-                    break;
-                  case GL_UNSIGNED_INT:
-                    if (!context->supports32bitIndices())
-                    {
-                        return gl::error(GL_INVALID_ENUM);    
-                    }
-                    break;
-                  default:
-                    return gl::error(GL_INVALID_ENUM);
-                }
-            
-                context->drawElements(mode, count, type, indices, primcount);
-            }
-        }
-    }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
+        context->drawElements(mode, count, type, indices, primcount, indexRange);
     }
 }
 
@@ -2219,31 +1403,16 @@ void __stdcall glEnable(GLenum cap)
 {
     EVENT("(GLenum cap = 0x%X)", cap);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
+        if (!ValidCap(context, cap))
         {
-            switch (cap)
-            {
-              case GL_CULL_FACE:                context->setCullFace(true);              break;
-              case GL_POLYGON_OFFSET_FILL:      context->setPolygonOffsetFill(true);     break;
-              case GL_SAMPLE_ALPHA_TO_COVERAGE: context->setSampleAlphaToCoverage(true); break;
-              case GL_SAMPLE_COVERAGE:          context->setSampleCoverage(true);        break;
-              case GL_SCISSOR_TEST:             context->setScissorTest(true);           break;
-              case GL_STENCIL_TEST:             context->setStencilTest(true);           break;
-              case GL_DEPTH_TEST:               context->setDepthTest(true);             break;
-              case GL_BLEND:                    context->setBlend(true);                 break;
-              case GL_DITHER:                   context->setDither(true);                break;
-              default:
-                return gl::error(GL_INVALID_ENUM);
-            }
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
         }
-    }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
+
+        context->getState().setEnableFeature(cap, true);
     }
 }
 
@@ -2251,23 +1420,16 @@ void __stdcall glEnableVertexAttribArray(GLuint index)
 {
     EVENT("(GLuint index = %d)", index);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
         if (index >= gl::MAX_VERTEX_ATTRIBS)
         {
-            return gl::error(GL_INVALID_VALUE);
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
         }
 
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
-        {
-            context->setEnableVertexAttribArray(index, true);
-        }
-    }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
+        context->getState().setEnableVertexAttribArray(index, true);
     }
 }
 
@@ -2275,53 +1437,45 @@ void __stdcall glEndQueryEXT(GLenum target)
 {
     EVENT("GLenum target = 0x%X)", target);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        switch (target)
+        if (!ValidateEndQuery(context, target))
         {
-          case GL_ANY_SAMPLES_PASSED_EXT: 
-          case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT:
-              break;
-          default: 
-              return gl::error(GL_INVALID_ENUM);
+            return;
         }
 
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
+        gl::Error error = context->endQuery(target);
+        if (error.isError())
         {
-            context->endQuery(target);
+            context->recordError(error);
+            return;
         }
     }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
-    }
 }
 
 void __stdcall glFinishFenceNV(GLuint fence)
 {
     EVENT("(GLuint fence = %d)", fence);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        gl::Context *context = gl::getNonLostContext();
+        gl::FenceNV *fenceObject = context->getFenceNV(fence);
 
-        if (context)
+        if (fenceObject == NULL)
         {
-            gl::Fence* fenceObject = context->getFence(fence);
-
-            if (fenceObject == NULL)
-            {
-                return gl::error(GL_INVALID_OPERATION);
-            }
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
 
-            fenceObject->finishFence();
+        if (fenceObject->isFence() != GL_TRUE)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
         }
-    }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
+
+        fenceObject->finishFence();
     }
 }
 
@@ -2329,18 +1483,10 @@ void __stdcall glFinish(void)
 {
     EVENT("()");
 
-    try
-    {
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
-        {
-            context->sync(true);
-        }
-    }
-    catch(std::bad_alloc&)
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        return gl::error(GL_OUT_OF_MEMORY);
+        context->sync(true);
     }
 }
 
@@ -2348,18 +1494,10 @@ void __stdcall glFlush(void)
 {
     EVENT("()");
 
-    try
-    {
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
-        {
-            context->sync(false);
-        }
-    }
-    catch(std::bad_alloc&)
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        return gl::error(GL_OUT_OF_MEMORY);
+        context->sync(false);
     }
 }
 
@@ -2368,67 +1506,47 @@ void __stdcall glFramebufferRenderbuffer(GLenum target, GLenum attachment, GLenu
     EVENT("(GLenum target = 0x%X, GLenum attachment = 0x%X, GLenum renderbuffertarget = 0x%X, "
           "GLuint renderbuffer = %d)", target, attachment, renderbuffertarget, renderbuffer);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        if ((target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER_ANGLE && target != GL_READ_FRAMEBUFFER_ANGLE)
-            || (renderbuffertarget != GL_RENDERBUFFER && renderbuffer != 0))
+        if (!gl::ValidFramebufferTarget(target) || (renderbuffertarget != GL_RENDERBUFFER && renderbuffer != 0))
         {
-            return gl::error(GL_INVALID_ENUM);
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
         }
 
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
+        if (!gl::ValidateFramebufferRenderbufferParameters(context, target, attachment, renderbuffertarget, renderbuffer))
         {
-            gl::Framebuffer *framebuffer = NULL;
-            GLuint framebufferHandle = 0;
-            if (target == GL_READ_FRAMEBUFFER_ANGLE)
-            {
-                framebuffer = context->getReadFramebuffer();
-                framebufferHandle = context->getReadFramebufferHandle();
-            }
-            else
-            {
-                framebuffer = context->getDrawFramebuffer();
-                framebufferHandle = context->getDrawFramebufferHandle();
-            }
-
-            if (!framebuffer || (framebufferHandle == 0 && renderbuffer != 0))
-            {
-                return gl::error(GL_INVALID_OPERATION);
-            }
-
-            if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
-            {
-                const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT);
+            return;
+        }
 
-                if (colorAttachment >= context->getMaximumRenderTargets())
-                {
-                    return gl::error(GL_INVALID_VALUE);
-                }
+        gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
+        ASSERT(framebuffer);
 
-                framebuffer->setColorbuffer(colorAttachment, GL_RENDERBUFFER, renderbuffer);
-            }
-            else
+        if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
+        {
+            unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT);
+            framebuffer->setColorbuffer(colorAttachment, GL_RENDERBUFFER, renderbuffer, 0, 0);
+        }
+        else
+        {
+            switch (attachment)
             {
-                switch (attachment)
-                {
-                  case GL_DEPTH_ATTACHMENT:
-                    framebuffer->setDepthbuffer(GL_RENDERBUFFER, renderbuffer);
-                    break;
-                  case GL_STENCIL_ATTACHMENT:
-                    framebuffer->setStencilbuffer(GL_RENDERBUFFER, renderbuffer);
-                    break;
-                  default:
-                    return gl::error(GL_INVALID_ENUM);
-                }
+              case GL_DEPTH_ATTACHMENT:
+                framebuffer->setDepthbuffer(GL_RENDERBUFFER, renderbuffer, 0, 0);
+                break;
+              case GL_STENCIL_ATTACHMENT:
+                framebuffer->setStencilbuffer(GL_RENDERBUFFER, renderbuffer, 0, 0);
+                break;
+              case GL_DEPTH_STENCIL_ATTACHMENT:
+                framebuffer->setDepthStencilBuffer(GL_RENDERBUFFER, renderbuffer, 0, 0);
+                break;
+              default:
+                UNREACHABLE();
+                break;
             }
         }
     }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
-    }
 }
 
 void __stdcall glFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)
@@ -2436,247 +1554,149 @@ void __stdcall glFramebufferTexture2D(GLenum target, GLenum attachment, GLenum t
     EVENT("(GLenum target = 0x%X, GLenum attachment = 0x%X, GLenum textarget = 0x%X, "
           "GLuint texture = %d, GLint level = %d)", target, attachment, textarget, texture, level);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        if (target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER_ANGLE && target != GL_READ_FRAMEBUFFER_ANGLE)
+        if (!ValidateFramebufferTexture2D(context, target, attachment, textarget, texture, level))
         {
-            return gl::error(GL_INVALID_ENUM);
+            return;
         }
 
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
+        if (texture == 0)
         {
-            if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
-            {
-                const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT);
+            textarget = GL_NONE;
+        }
 
-                if (colorAttachment >= context->getMaximumRenderTargets())
-                {
-                    return gl::error(GL_INVALID_VALUE);
-                }
-            }
-            else
-            {
-                switch (attachment)
-                {
-                  case GL_DEPTH_ATTACHMENT:
-                  case GL_STENCIL_ATTACHMENT:
-                    break;
-                  default:
-                    return gl::error(GL_INVALID_ENUM);
-                }
-            }
+        gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
 
-            if (texture == 0)
+        if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
+        {
+            const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT);
+            framebuffer->setColorbuffer(colorAttachment, textarget, texture, level, 0);
+        }
+        else
+        {
+            switch (attachment)
             {
-                textarget = GL_NONE;
+              case GL_DEPTH_ATTACHMENT:         framebuffer->setDepthbuffer(textarget, texture, level, 0);        break;
+              case GL_STENCIL_ATTACHMENT:       framebuffer->setStencilbuffer(textarget, texture, level, 0);      break;
+              case GL_DEPTH_STENCIL_ATTACHMENT: framebuffer->setDepthStencilBuffer(textarget, texture, level, 0); break;
             }
-            else
-            {
-                gl::Texture *tex = context->getTexture(texture);
+        }
+    }
+}
 
-                if (tex == NULL)
-                {
-                    return gl::error(GL_INVALID_OPERATION);
-                }
+void __stdcall glFrontFace(GLenum mode)
+{
+    EVENT("(GLenum mode = 0x%X)", mode);
 
-                switch (textarget)
-                {
-                  case GL_TEXTURE_2D:
-                    {
-                        if (tex->getTarget() != GL_TEXTURE_2D)
-                        {
-                            return gl::error(GL_INVALID_OPERATION);
-                        }
-                        gl::Texture2D *tex2d = static_cast<gl::Texture2D *>(tex);
-                        if (tex2d->isCompressed(0))
-                        {
-                            return gl::error(GL_INVALID_OPERATION);
-                        }
-                        break;
-                    }
-
-                  case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
-                  case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
-                  case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
-                  case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
-                  case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
-                  case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
-                    {
-                        if (tex->getTarget() != GL_TEXTURE_CUBE_MAP)
-                        {
-                            return gl::error(GL_INVALID_OPERATION);
-                        }
-                        gl::TextureCubeMap *texcube = static_cast<gl::TextureCubeMap *>(tex);
-                        if (texcube->isCompressed(textarget, level))
-                        {
-                            return gl::error(GL_INVALID_OPERATION);
-                        }
-                        break;
-                    }
-
-                  default:
-                    return gl::error(GL_INVALID_ENUM);
-                }
-
-                if (level != 0)
-                {
-                    return gl::error(GL_INVALID_VALUE);
-                }
-            }
-
-            gl::Framebuffer *framebuffer = NULL;
-            GLuint framebufferHandle = 0;
-            if (target == GL_READ_FRAMEBUFFER_ANGLE)
-            {
-                framebuffer = context->getReadFramebuffer();
-                framebufferHandle = context->getReadFramebufferHandle();
-            }
-            else
-            {
-                framebuffer = context->getDrawFramebuffer();
-                framebufferHandle = context->getDrawFramebufferHandle();
-            }
-
-            if (framebufferHandle == 0 || !framebuffer)
-            {
-                return gl::error(GL_INVALID_OPERATION);
-            }
-
-            if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
-            {
-                const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT);
-
-                if (colorAttachment >= context->getMaximumRenderTargets())
-                {
-                    return gl::error(GL_INVALID_VALUE);
-                }
-
-                framebuffer->setColorbuffer(colorAttachment, textarget, texture);
-            }
-            else
-            {
-                switch (attachment)
-                {
-                  case GL_DEPTH_ATTACHMENT:   framebuffer->setDepthbuffer(textarget, texture);   break;
-                  case GL_STENCIL_ATTACHMENT: framebuffer->setStencilbuffer(textarget, texture); break;
-                }
-            }
-        }
-    }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
-    }
-}
-
-void __stdcall glFrontFace(GLenum mode)
-{
-    EVENT("(GLenum mode = 0x%X)", mode);
-
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
         switch (mode)
         {
           case GL_CW:
           case GL_CCW:
-            {
-                gl::Context *context = gl::getNonLostContext();
-
-                if (context)
-                {
-                    context->setFrontFace(mode);
-                }
-            }
+            context->getState().setFrontFace(mode);
             break;
           default:
-            return gl::error(GL_INVALID_ENUM);
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
         }
     }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
-    }
 }
 
 void __stdcall glGenBuffers(GLsizei n, GLuint* buffers)
 {
     EVENT("(GLsizei n = %d, GLuint* buffers = 0x%0.8p)", n, buffers);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
         if (n < 0)
         {
-            return gl::error(GL_INVALID_VALUE);
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
         }
 
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
+        for (int i = 0; i < n; i++)
         {
-            for (int i = 0; i < n; i++)
-            {
-                buffers[i] = context->createBuffer();
-            }
+            buffers[i] = context->createBuffer();
         }
     }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
-    }
 }
 
 void __stdcall glGenerateMipmap(GLenum target)
 {
     EVENT("(GLenum target = 0x%X)", target);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        gl::Context *context = gl::getNonLostContext();
+        if (!ValidTextureTarget(context, target))
+        {
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
+        }
 
-        if (context)
+        gl::Texture *texture = context->getTargetTexture(target);
+
+        if (texture == NULL)
         {
-            switch (target)
-            {
-              case GL_TEXTURE_2D:
-                {
-                    gl::Texture2D *tex2d = context->getTexture2D();
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
 
-                    if (tex2d->isCompressed(0))
-                    {
-                        return gl::error(GL_INVALID_OPERATION);
-                    }
-                    if (tex2d->isDepth(0))
-                    {
-                        return gl::error(GL_INVALID_OPERATION);
-                    }
+        GLenum internalFormat = texture->getBaseLevelInternalFormat();
+        const gl::TextureCaps &formatCaps = context->getTextureCaps().get(internalFormat);
+        const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat);
 
-                    tex2d->generateMipmaps();
-                    break;
-                }
+        // GenerateMipmap should not generate an INVALID_OPERATION for textures created with
+        // unsized formats or that are color renderable and filterable.  Since we do not track if
+        // the texture was created with sized or unsized format (only sized formats are stored),
+        // it is not possible to make sure the the LUMA formats can generate mipmaps (they should
+        // be able to) because they aren't color renderable.  Simply do a special case for LUMA
+        // textures since they're the only texture format that can be created with unsized formats
+        // that is not color renderable.  New unsized formats are unlikely to be added, since ES2
+        // was the last version to use add them.
+        bool isLUMA = internalFormat == GL_LUMINANCE8_EXT ||
+                      internalFormat == GL_LUMINANCE8_ALPHA8_EXT ||
+                      internalFormat == GL_ALPHA8_EXT;
 
-              case GL_TEXTURE_CUBE_MAP:
-                {
-                    gl::TextureCubeMap *texcube = context->getTextureCubeMap();
+        if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0 || !formatCaps.filterable ||
+            (!formatCaps.renderable && !isLUMA) || formatInfo.compressed)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
 
-                    if (texcube->isCompressed(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0))
-                    {
-                        return gl::error(GL_INVALID_OPERATION);
-                    }
+        // GL_EXT_sRGB does not support mipmap generation on sRGB textures
+        if (context->getClientVersion() == 2 && formatInfo.colorEncoding == GL_SRGB)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
 
-                    texcube->generateMipmaps();
-                    break;
-                }
+        // Non-power of 2 ES2 check
+        if (!context->getExtensions().textureNPOT && (!gl::isPow2(texture->getBaseLevelWidth()) || !gl::isPow2(texture->getBaseLevelHeight())))
+        {
+            ASSERT(context->getClientVersion() <= 2 && (target == GL_TEXTURE_2D || target == GL_TEXTURE_CUBE_MAP));
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
 
-              default:
-                return gl::error(GL_INVALID_ENUM);
+        // Cube completeness check
+        if (target == GL_TEXTURE_CUBE_MAP)
+        {
+            gl::TextureCubeMap *textureCube = static_cast<gl::TextureCubeMap *>(texture);
+            if (!textureCube->isCubeComplete())
+            {
+                context->recordError(gl::Error(GL_INVALID_OPERATION));
+                return;
             }
         }
-    }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
+
+        texture->generateMipmaps();
     }
 }
 
@@ -2684,135 +1704,100 @@ void __stdcall glGenFencesNV(GLsizei n, GLuint* fences)
 {
     EVENT("(GLsizei n = %d, GLuint* fences = 0x%0.8p)", n, fences);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
         if (n < 0)
         {
-            return gl::error(GL_INVALID_VALUE);
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
         }
 
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
+        for (int i = 0; i < n; i++)
         {
-            for (int i = 0; i < n; i++)
-            {
-                fences[i] = context->createFence();
-            }
+            fences[i] = context->createFenceNV();
         }
     }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
-    }
 }
 
 void __stdcall glGenFramebuffers(GLsizei n, GLuint* framebuffers)
 {
     EVENT("(GLsizei n = %d, GLuint* framebuffers = 0x%0.8p)", n, framebuffers);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
         if (n < 0)
         {
-            return gl::error(GL_INVALID_VALUE);
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
         }
 
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
+        for (int i = 0; i < n; i++)
         {
-            for (int i = 0; i < n; i++)
-            {
-                framebuffers[i] = context->createFramebuffer();
-            }
+            framebuffers[i] = context->createFramebuffer();
         }
     }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
-    }
 }
 
 void __stdcall glGenQueriesEXT(GLsizei n, GLuint* ids)
 {
     EVENT("(GLsizei n = %d, GLuint* ids = 0x%0.8p)", n, ids);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
         if (n < 0)
         {
-            return gl::error(GL_INVALID_VALUE);
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
         }
 
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
+        for (GLsizei i = 0; i < n; i++)
         {
-            for (int i = 0; i < n; i++)
-            {
-                ids[i] = context->createQuery();
-            }
+            ids[i] = context->createQuery();
         }
     }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
-    }
 }
 
 void __stdcall glGenRenderbuffers(GLsizei n, GLuint* renderbuffers)
 {
     EVENT("(GLsizei n = %d, GLuint* renderbuffers = 0x%0.8p)", n, renderbuffers);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
         if (n < 0)
         {
-            return gl::error(GL_INVALID_VALUE);
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
         }
 
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
+        for (int i = 0; i < n; i++)
         {
-            for (int i = 0; i < n; i++)
-            {
-                renderbuffers[i] = context->createRenderbuffer();
-            }
+            renderbuffers[i] = context->createRenderbuffer();
         }
     }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
-    }
 }
 
 void __stdcall glGenTextures(GLsizei n, GLuint* textures)
 {
-    EVENT("(GLsizei n = %d, GLuint* textures =  0x%0.8p)", n, textures);
+    EVENT("(GLsizei n = %d, GLuint* textures = 0x%0.8p)", n, textures);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
         if (n < 0)
         {
-            return gl::error(GL_INVALID_VALUE);
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
         }
 
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
+        for (int i = 0; i < n; i++)
         {
-            for (int i = 0; i < n; i++)
-            {
-                textures[i] = context->createTexture();
-            }
+            textures[i] = context->createTexture();
         }
     }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
-    }
 }
 
 void __stdcall glGetActiveAttrib(GLuint program, GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
@@ -2821,42 +1806,38 @@ void __stdcall glGetActiveAttrib(GLuint program, GLuint index, GLsizei bufsize,
           "GLint *size = 0x%0.8p, GLenum *type = %0.8p, GLchar *name = %0.8p)",
           program, index, bufsize, length, size, type, name);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
         if (bufsize < 0)
         {
-            return gl::error(GL_INVALID_VALUE);
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
         }
 
-        gl::Context *context = gl::getNonLostContext();
+        gl::Program *programObject = context->getProgram(program);
 
-        if (context)
+        if (!programObject)
         {
-            gl::Program *programObject = context->getProgram(program);
-
-            if (!programObject)
+            if (context->getShader(program))
             {
-                if (context->getShader(program))
-                {
-                    return gl::error(GL_INVALID_OPERATION);
-                }
-                else
-                {
-                    return gl::error(GL_INVALID_VALUE);
-                }
+                context->recordError(gl::Error(GL_INVALID_OPERATION));
+                return;
             }
-
-            if (index >= (GLuint)programObject->getActiveAttributeCount())
+            else
             {
-                return gl::error(GL_INVALID_VALUE);
+                context->recordError(gl::Error(GL_INVALID_VALUE));
+                return;
             }
+        }
 
-            programObject->getActiveAttribute(index, bufsize, length, size, type, name);
+        if (index >= (GLuint)programObject->getActiveAttributeCount())
+        {
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
         }
-    }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
+
+        programObject->getActiveAttribute(index, bufsize, length, size, type, name);
     }
 }
 
@@ -2866,42 +1847,39 @@ void __stdcall glGetActiveUniform(GLuint program, GLuint index, GLsizei bufsize,
           "GLsizei* length = 0x%0.8p, GLint* size = 0x%0.8p, GLenum* type = 0x%0.8p, GLchar* name = 0x%0.8p)",
           program, index, bufsize, length, size, type, name);
 
-    try
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
         if (bufsize < 0)
         {
-            return gl::error(GL_INVALID_VALUE);
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
         }
 
-        gl::Context *context = gl::getNonLostContext();
+        gl::Program *programObject = context->getProgram(program);
 
-        if (context)
+        if (!programObject)
         {
-            gl::Program *programObject = context->getProgram(program);
-
-            if (!programObject)
+            if (context->getShader(program))
             {
-                if (context->getShader(program))
-                {
-                    return gl::error(GL_INVALID_OPERATION);
-                }
-                else
-                {
-                    return gl::error(GL_INVALID_VALUE);
-                }
+                context->recordError(gl::Error(GL_INVALID_OPERATION));
+                return;
             }
-
-            if (index >= (GLuint)programObject->getActiveUniformCount())
+            else
             {
-                return gl::error(GL_INVALID_VALUE);
+                context->recordError(gl::Error(GL_INVALID_VALUE));
+                return;
             }
+        }
 
-            programObject->getActiveUniform(index, bufsize, length, size, type, name);
+        if (index >= (GLuint)programObject->getActiveUniformCount())
+        {
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
         }
-    }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
+
+        programObject->getActiveUniform(index, bufsize, length, size, type, name);
     }
 }
 
@@ -2910,77 +1888,66 @@ void __stdcall glGetAttachedShaders(GLuint program, GLsizei maxcount, GLsizei* c
     EVENT("(GLuint program = %d, GLsizei maxcount = %d, GLsizei* count = 0x%0.8p, GLuint* shaders = 0x%0.8p)",
           program, maxcount, count, shaders);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
         if (maxcount < 0)
         {
-            return gl::error(GL_INVALID_VALUE);
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
         }
 
-        gl::Context *context = gl::getNonLostContext();
+        gl::Program *programObject = context->getProgram(program);
 
-        if (context)
+        if (!programObject)
         {
-            gl::Program *programObject = context->getProgram(program);
-
-            if (!programObject)
+            if (context->getShader(program))
             {
-                if (context->getShader(program))
-                {
-                    return gl::error(GL_INVALID_OPERATION);
-                }
-                else
-                {
-                    return gl::error(GL_INVALID_VALUE);
-                }
+                context->recordError(gl::Error(GL_INVALID_OPERATION));
+                return;
+            }
+            else
+            {
+                context->recordError(gl::Error(GL_INVALID_VALUE));
+                return;
             }
-
-            return programObject->getAttachedShaders(maxcount, count, shaders);
         }
-    }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
+
+        return programObject->getAttachedShaders(maxcount, count, shaders);
     }
 }
 
-int __stdcall glGetAttribLocation(GLuint program, const GLchar* name)
+GLint __stdcall glGetAttribLocation(GLuint program, const GLchar* name)
 {
     EVENT("(GLuint program = %d, const GLchar* name = %s)", program, name);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        gl::Context *context = gl::getNonLostContext();
+        gl::Program *programObject = context->getProgram(program);
 
-        if (context)
+        if (!programObject)
         {
-
-            gl::Program *programObject = context->getProgram(program);
-
-            if (!programObject)
+            if (context->getShader(program))
             {
-                if (context->getShader(program))
-                {
-                    return gl::error(GL_INVALID_OPERATION, -1);
-                }
-                else
-                {
-                    return gl::error(GL_INVALID_VALUE, -1);
-                }
+                context->recordError(gl::Error(GL_INVALID_OPERATION));
+                return -1;
             }
-
-            gl::ProgramBinary *programBinary = programObject->getProgramBinary();
-            if (!programObject->isLinked() || !programBinary)
+            else
             {
-                return gl::error(GL_INVALID_OPERATION, -1);
+                context->recordError(gl::Error(GL_INVALID_VALUE));
+                return -1;
             }
+        }
 
-            return programBinary->getAttributeLocation(name);
+        gl::ProgramBinary *programBinary = programObject->getProgramBinary();
+        if (!programObject->isLinked() || !programBinary)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return -1;
         }
-    }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY, -1);
+
+        return programBinary->getAttributeLocation(name);
     }
 
     return -1;
@@ -2990,62 +1957,24 @@ void __stdcall glGetBooleanv(GLenum pname, GLboolean* params)
 {
     EVENT("(GLenum pname = 0x%X, GLboolean* params = 0x%0.8p)",  pname, params);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
+        GLenum nativeType;
+        unsigned int numParams = 0;
+        if (!ValidateStateQuery(context, pname, &nativeType, &numParams))
         {
-            if (!(context->getBooleanv(pname, params)))
-            {
-                GLenum nativeType;
-                unsigned int numParams = 0;
-                if (!context->getQueryParameterInfo(pname, &nativeType, &numParams))
-                    return gl::error(GL_INVALID_ENUM);
-
-                if (numParams == 0)
-                    return; // it is known that the pname is valid, but there are no parameters to return
-
-                if (nativeType == GL_FLOAT)
-                {
-                    GLfloat *floatParams = NULL;
-                    floatParams = new GLfloat[numParams];
-
-                    context->getFloatv(pname, floatParams);
-
-                    for (unsigned int i = 0; i < numParams; ++i)
-                    {
-                        if (floatParams[i] == 0.0f)
-                            params[i] = GL_FALSE;
-                        else
-                            params[i] = GL_TRUE;
-                    }
-
-                    delete [] floatParams;
-                }
-                else if (nativeType == GL_INT)
-                {
-                    GLint *intParams = NULL;
-                    intParams = new GLint[numParams];
-
-                    context->getIntegerv(pname, intParams);
-
-                    for (unsigned int i = 0; i < numParams; ++i)
-                    {
-                        if (intParams[i] == 0)
-                            params[i] = GL_FALSE;
-                        else
-                            params[i] = GL_TRUE;
-                    }
+            return;
+        }
 
-                    delete [] intParams;
-                }
-            }
+        if (nativeType == GL_BOOL)
+        {
+            context->getBooleanv(pname, params);
+        }
+        else
+        {
+            CastStateValues(context, nativeType, pname, numParams, params);
         }
-    }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
     }
 }
 
@@ -3053,47 +1982,53 @@ void __stdcall glGetBufferParameteriv(GLenum target, GLenum pname, GLint* params
 {
     EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", target, pname, params);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        gl::Context *context = gl::getNonLostContext();
+        if (!gl::ValidBufferTarget(context, target))
+        {
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
+        }
 
-        if (context)
+        if (!gl::ValidBufferParameter(context, pname))
         {
-            gl::Buffer *buffer;
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
+        }
 
-            switch (target)
-            {
-              case GL_ARRAY_BUFFER:
-                buffer = context->getArrayBuffer();
-                break;
-              case GL_ELEMENT_ARRAY_BUFFER:
-                buffer = context->getElementArrayBuffer();
-                break;
-              default: return gl::error(GL_INVALID_ENUM);
-            }
+        gl::Buffer *buffer = context->getState().getTargetBuffer(target);
 
-            if (!buffer)
-            {
-                // A null buffer means that "0" is bound to the requested buffer target
-                return gl::error(GL_INVALID_OPERATION);
-            }
+        if (!buffer)
+        {
+            // A null buffer means that "0" is bound to the requested buffer target
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
 
-            switch (pname)
-            {
-              case GL_BUFFER_USAGE:
-                *params = buffer->usage();
-                break;
-              case GL_BUFFER_SIZE:
-                *params = buffer->size();
-                break;
-              default: return gl::error(GL_INVALID_ENUM);
-            }
+        switch (pname)
+        {
+          case GL_BUFFER_USAGE:
+            *params = static_cast<GLint>(buffer->getUsage());
+            break;
+          case GL_BUFFER_SIZE:
+            *params = gl::clampCast<GLint>(buffer->getSize());
+            break;
+          case GL_BUFFER_ACCESS_FLAGS:
+            *params = buffer->getAccessFlags();
+            break;
+          case GL_BUFFER_MAPPED:
+            *params = static_cast<GLint>(buffer->isMapped());
+            break;
+          case GL_BUFFER_MAP_OFFSET:
+            *params = gl::clampCast<GLint>(buffer->getMapOffset());
+            break;
+          case GL_BUFFER_MAP_LENGTH:
+            *params = gl::clampCast<GLint>(buffer->getMapLength());
+            break;
+          default: UNREACHABLE(); break;
         }
     }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
-    }
 }
 
 GLenum __stdcall glGetError(void)
@@ -3114,26 +2049,35 @@ void __stdcall glGetFenceivNV(GLuint fence, GLenum pname, GLint *params)
 {
     EVENT("(GLuint fence = %d, GLenum pname = 0x%X, GLint *params = 0x%0.8p)", fence, pname, params);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-    
-        gl::Context *context = gl::getNonLostContext();
+        gl::FenceNV *fenceObject = context->getFenceNV(fence);
 
-        if (context)
+        if (fenceObject == NULL)
         {
-            gl::Fence *fenceObject = context->getFence(fence);
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
 
-            if (fenceObject == NULL)
-            {
-                return gl::error(GL_INVALID_OPERATION);
-            }
+        if (fenceObject->isFence() != GL_TRUE)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
 
-            fenceObject->getFenceiv(pname, params);
+        switch (pname)
+        {
+          case GL_FENCE_STATUS_NV:
+          case GL_FENCE_CONDITION_NV:
+            break;
+
+          default:
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
         }
-    }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
+
+        params[0] = fenceObject->getFencei(pname);
     }
 }
 
@@ -3141,59 +2085,24 @@ void __stdcall glGetFloatv(GLenum pname, GLfloat* params)
 {
     EVENT("(GLenum pname = 0x%X, GLfloat* params = 0x%0.8p)", pname, params);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
+        GLenum nativeType;
+        unsigned int numParams = 0;
+        if (!ValidateStateQuery(context, pname, &nativeType, &numParams))
         {
-            if (!(context->getFloatv(pname, params)))
-            {
-                GLenum nativeType;
-                unsigned int numParams = 0;
-                if (!context->getQueryParameterInfo(pname, &nativeType, &numParams))
-                    return gl::error(GL_INVALID_ENUM);
-
-                if (numParams == 0)
-                    return; // it is known that the pname is valid, but that there are no parameters to return.
-
-                if (nativeType == GL_BOOL)
-                {
-                    GLboolean *boolParams = NULL;
-                    boolParams = new GLboolean[numParams];
-
-                    context->getBooleanv(pname, boolParams);
-
-                    for (unsigned int i = 0; i < numParams; ++i)
-                    {
-                        if (boolParams[i] == GL_FALSE)
-                            params[i] = 0.0f;
-                        else
-                            params[i] = 1.0f;
-                    }
-
-                    delete [] boolParams;
-                }
-                else if (nativeType == GL_INT)
-                {
-                    GLint *intParams = NULL;
-                    intParams = new GLint[numParams];
-
-                    context->getIntegerv(pname, intParams);
-
-                    for (unsigned int i = 0; i < numParams; ++i)
-                    {
-                        params[i] = (GLfloat)intParams[i];
-                    }
+            return;
+        }
 
-                    delete [] intParams;
-                }
-            }
+        if (nativeType == GL_FLOAT)
+        {
+            context->getFloatv(pname, params);
+        }
+        else
+        {
+            CastStateValues(context, nativeType, pname, numParams, params);
         }
-    }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
     }
 }
 
@@ -3202,219 +2111,335 @@ void __stdcall glGetFramebufferAttachmentParameteriv(GLenum target, GLenum attac
     EVENT("(GLenum target = 0x%X, GLenum attachment = 0x%X, GLenum pname = 0x%X, GLint* params = 0x%0.8p)",
           target, attachment, pname, params);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        gl::Context *context = gl::getNonLostContext();
+        if (!gl::ValidFramebufferTarget(target))
+        {
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
+        }
 
-        if (context)
+        int clientVersion = context->getClientVersion();
+
+        switch (pname)
         {
-            if (target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER_ANGLE && target != GL_READ_FRAMEBUFFER_ANGLE)
-            {
-                return gl::error(GL_INVALID_ENUM);
-            }
+          case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
+          case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
+          case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
+          case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE:
+            break;
 
-            gl::Framebuffer *framebuffer = NULL;
-            if (target == GL_READ_FRAMEBUFFER_ANGLE)
+          case GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING:
+            if (clientVersion < 3 && !context->getExtensions().sRGB)
             {
-                if(context->getReadFramebufferHandle() == 0)
-                {
-                    return gl::error(GL_INVALID_OPERATION);
-                }
+                context->recordError(gl::Error(GL_INVALID_ENUM));
+                return;
+            }
+            break;
 
-                framebuffer = context->getReadFramebuffer();
+          case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE:
+          case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE:
+          case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE:
+          case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE:
+          case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE:
+          case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE:
+          case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE:
+          case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER:
+            if (clientVersion < 3)
+            {
+                context->recordError(gl::Error(GL_INVALID_ENUM));
+                return;
             }
-            else 
+            break;
+
+          default:
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
+        }
+
+        // Determine if the attachment is a valid enum
+        switch (attachment)
+        {
+          case GL_BACK:
+          case GL_FRONT:
+          case GL_DEPTH:
+          case GL_STENCIL:
+          case GL_DEPTH_STENCIL_ATTACHMENT:
+            if (clientVersion < 3)
             {
-                if (context->getDrawFramebufferHandle() == 0)
-                {
-                    return gl::error(GL_INVALID_OPERATION);
-                }
+                context->recordError(gl::Error(GL_INVALID_ENUM));
+                return;
+            }
+            break;
+
+          case GL_DEPTH_ATTACHMENT:
+          case GL_STENCIL_ATTACHMENT:
+            break;
 
-                framebuffer = context->getDrawFramebuffer();
+          default:
+            if (attachment < GL_COLOR_ATTACHMENT0_EXT ||
+                (attachment - GL_COLOR_ATTACHMENT0_EXT) >= context->getCaps().maxColorAttachments)
+            {
+                context->recordError(gl::Error(GL_INVALID_ENUM));
+                return;
             }
+            break;
+        }
 
-            GLenum attachmentType;
-            GLuint attachmentHandle;
+        GLuint framebufferHandle = context->getState().getTargetFramebuffer(target)->id();
+        gl::Framebuffer *framebuffer = context->getFramebuffer(framebufferHandle);
 
-            if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
+        if (framebufferHandle == 0)
+        {
+            if (clientVersion < 3)
             {
-                const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT);
+                context->recordError(gl::Error(GL_INVALID_OPERATION));
+                return;
+            }
 
-                if (colorAttachment >= context->getMaximumRenderTargets())
-                {
-                    return gl::error(GL_INVALID_ENUM);
-                }
+            switch (attachment)
+            {
+              case GL_BACK:
+              case GL_DEPTH:
+              case GL_STENCIL:
+                break;
 
-                attachmentType = framebuffer->getColorbufferType(colorAttachment);
-                attachmentHandle = framebuffer->getColorbufferHandle(colorAttachment);
+              default:
+                context->recordError(gl::Error(GL_INVALID_OPERATION));
+                return;
+            }
+        }
+        else
+        {
+            if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
+            {
+                // Valid attachment query
             }
             else
             {
                 switch (attachment)
                 {
                   case GL_DEPTH_ATTACHMENT:
-                    attachmentType = framebuffer->getDepthbufferType();
-                    attachmentHandle = framebuffer->getDepthbufferHandle();
-                    break;
                   case GL_STENCIL_ATTACHMENT:
-                    attachmentType = framebuffer->getStencilbufferType();
-                    attachmentHandle = framebuffer->getStencilbufferHandle();
                     break;
-                  default: return gl::error(GL_INVALID_ENUM);
+
+                  case GL_DEPTH_STENCIL_ATTACHMENT:
+                    if (framebuffer->hasValidDepthStencil())
+                    {
+                        context->recordError(gl::Error(GL_INVALID_OPERATION));
+                        return;
+                    }
+                    break;
+
+                  default:
+                    context->recordError(gl::Error(GL_INVALID_OPERATION));
+                    return;
                 }
             }
+        }
 
-            GLenum attachmentObjectType;   // Type category
-            if (attachmentType == GL_NONE || attachmentType == GL_RENDERBUFFER)
-            {
-                attachmentObjectType = attachmentType;
-            }
-            else if (gl::IsInternalTextureTarget(attachmentType))
-            {
-                attachmentObjectType = GL_TEXTURE;
-            }
-            else
-            {
-                UNREACHABLE();
-                return;
-            }
+        GLenum attachmentType = GL_NONE;
+        GLuint attachmentHandle = 0;
+        GLuint attachmentLevel = 0;
+        GLuint attachmentLayer = 0;
+
+        const gl::FramebufferAttachment *attachmentObject = framebuffer->getAttachment(attachment);
+
+        if (attachmentObject)
+        {
+            attachmentType = attachmentObject->type();
+            attachmentHandle = attachmentObject->id();
+            attachmentLevel = attachmentObject->mipLevel();
+            attachmentLayer = attachmentObject->layer();
+        }
+
+        GLenum attachmentObjectType;   // Type category
+        if (framebufferHandle == 0)
+        {
+            attachmentObjectType = GL_FRAMEBUFFER_DEFAULT;
+        }
+        else if (attachmentType == GL_NONE || attachmentType == GL_RENDERBUFFER)
+        {
+            attachmentObjectType = attachmentType;
+        }
+        else if (gl::ValidTexture2DDestinationTarget(context, attachmentType))
+        {
+            attachmentObjectType = GL_TEXTURE;
+        }
+        else
+        {
+            UNREACHABLE();
+            return;
+        }
+
+        if (attachmentObjectType == GL_NONE)
+        {
+            // ES 2.0.25 spec pg 127 states that if the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE
+            // is NONE, then querying any other pname will generate INVALID_ENUM.
+
+            // ES 3.0.2 spec pg 235 states that if the attachment type is none,
+            // GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME will return zero and be an
+            // INVALID_OPERATION for all other pnames
 
             switch (pname)
             {
               case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
                 *params = attachmentObjectType;
                 break;
+
               case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
-                if (attachmentObjectType == GL_RENDERBUFFER || attachmentObjectType == GL_TEXTURE)
+                if (clientVersion < 3)
+                {
+                    context->recordError(gl::Error(GL_INVALID_ENUM));
+                    return;
+                }
+                *params = 0;
+                break;
+
+              default:
+                if (clientVersion < 3)
                 {
-                    *params = attachmentHandle;
+                    context->recordError(gl::Error(GL_INVALID_ENUM));
+                    return;
                 }
                 else
                 {
-                    return gl::error(GL_INVALID_ENUM);
+                    context->recordError(gl::Error(GL_INVALID_OPERATION));
+                    return;
+                }
+            }
+        }
+        else
+        {
+            ASSERT(attachmentObjectType == GL_RENDERBUFFER || attachmentObjectType == GL_TEXTURE ||
+                   attachmentObjectType == GL_FRAMEBUFFER_DEFAULT);
+            ASSERT(attachmentObject != NULL);
+
+            switch (pname)
+            {
+              case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
+                *params = attachmentObjectType;
+                break;
+
+              case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
+                if (attachmentObjectType != GL_RENDERBUFFER && attachmentObjectType != GL_TEXTURE)
+                {
+                    context->recordError(gl::Error(GL_INVALID_ENUM));
+                    return;
                 }
+                *params = attachmentHandle;
                 break;
+
               case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
-                if (attachmentObjectType == GL_TEXTURE)
+                if (attachmentObjectType != GL_TEXTURE)
                 {
-                    *params = 0; // FramebufferTexture2D will not allow level to be set to anything else in GL ES 2.0
+                    context->recordError(gl::Error(GL_INVALID_ENUM));
+                    return;
                 }
-                else
+                *params = attachmentLevel;
+                break;
+
+              case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE:
+                if (attachmentObjectType != GL_TEXTURE)
                 {
-                    return gl::error(GL_INVALID_ENUM);
+                    context->recordError(gl::Error(GL_INVALID_ENUM));
+                    return;
                 }
+                *params = gl::IsCubemapTextureTarget(attachmentType) ? attachmentType : 0;
                 break;
-              case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE:
-                if (attachmentObjectType == GL_TEXTURE)
+
+              case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE:
+                *params = attachmentObject->getRedSize();
+                break;
+
+              case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE:
+                *params = attachmentObject->getGreenSize();
+                break;
+
+              case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE:
+                *params = attachmentObject->getBlueSize();
+                break;
+
+              case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE:
+                *params = attachmentObject->getAlphaSize();
+                break;
+
+              case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE:
+                *params = attachmentObject->getDepthSize();
+                break;
+
+              case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE:
+                *params = attachmentObject->getStencilSize();
+                break;
+
+              case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE:
+                if (attachment == GL_DEPTH_STENCIL_ATTACHMENT)
                 {
-                    if (gl::IsCubemapTextureTarget(attachmentType))
-                    {
-                        *params = attachmentType;
-                    }
-                    else
-                    {
-                        *params = 0;
-                    }
+                    context->recordError(gl::Error(GL_INVALID_OPERATION));
+                    return;
                 }
-                else
+                *params = attachmentObject->getComponentType();
+                break;
+
+              case GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING:
+                *params = attachmentObject->getColorEncoding();
+                break;
+
+              case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER:
+                if (attachmentObjectType != GL_TEXTURE)
                 {
-                    return gl::error(GL_INVALID_ENUM);
+                    context->recordError(gl::Error(GL_INVALID_ENUM));
+                    return;
                 }
+                *params = attachmentLayer;
                 break;
+
               default:
-                return gl::error(GL_INVALID_ENUM);
+                UNREACHABLE();
+                break;
             }
         }
     }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
-    }
 }
 
 GLenum __stdcall glGetGraphicsResetStatusEXT(void)
 {
     EVENT("()");
 
-    try
-    {
-        gl::Context *context = gl::getContext();
-
-        if (context)
-        {
-            return context->getResetStatus();
-        }
+    gl::Context *context = gl::getContext();
 
-        return GL_NO_ERROR;
-    }
-    catch(std::bad_alloc&)
+    if (context)
     {
-        return GL_OUT_OF_MEMORY;
+        return context->getResetStatus();
     }
+
+    return GL_NO_ERROR;
 }
 
 void __stdcall glGetIntegerv(GLenum pname, GLint* params)
 {
     EVENT("(GLenum pname = 0x%X, GLint* params = 0x%0.8p)", pname, params);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        gl::Context *context = gl::getNonLostContext();
+        GLenum nativeType;
+        unsigned int numParams = 0;
 
-        if (context)
+        if (!ValidateStateQuery(context, pname, &nativeType, &numParams))
         {
-            if (!(context->getIntegerv(pname, params)))
-            {
-                GLenum nativeType;
-                unsigned int numParams = 0;
-                if (!context->getQueryParameterInfo(pname, &nativeType, &numParams))
-                    return gl::error(GL_INVALID_ENUM);
-
-                if (numParams == 0)
-                    return; // it is known that pname is valid, but there are no parameters to return
-
-                if (nativeType == GL_BOOL)
-                {
-                    GLboolean *boolParams = NULL;
-                    boolParams = new GLboolean[numParams];
-
-                    context->getBooleanv(pname, boolParams);
-
-                    for (unsigned int i = 0; i < numParams; ++i)
-                    {
-                        if (boolParams[i] == GL_FALSE)
-                            params[i] = 0;
-                        else
-                            params[i] = 1;
-                    }
-
-                    delete [] boolParams;
-                }
-                else if (nativeType == GL_FLOAT)
-                {
-                    GLfloat *floatParams = NULL;
-                    floatParams = new GLfloat[numParams];
-
-                    context->getFloatv(pname, floatParams);
-
-                    for (unsigned int i = 0; i < numParams; ++i)
-                    {
-                        if (pname == GL_DEPTH_RANGE || pname == GL_COLOR_CLEAR_VALUE || pname == GL_DEPTH_CLEAR_VALUE || pname == GL_BLEND_COLOR)
-                        {
-                            params[i] = (GLint)(((GLfloat)(0xFFFFFFFF) * floatParams[i] - 1.0f) / 2.0f);
-                        }
-                        else
-                            params[i] = (GLint)(floatParams[i] > 0.0f ? floor(floatParams[i] + 0.5) : ceil(floatParams[i] - 0.5));
-                    }
+            return;
+        }
 
-                    delete [] floatParams;
-                }
-            }
+        if (nativeType == GL_INT)
+        {
+            context->getIntegerv(pname, params);
+        }
+        else
+        {
+            CastStateValues(context, nativeType, pname, numParams, params);
         }
-    }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
     }
 }
 
@@ -3422,91 +2447,109 @@ void __stdcall glGetProgramiv(GLuint program, GLenum pname, GLint* params)
 {
     EVENT("(GLuint program = %d, GLenum pname = %d, GLint* params = 0x%0.8p)", program, pname, params);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        gl::Context *context = gl::getNonLostContext();
+        gl::Program *programObject = context->getProgram(program);
 
-        if (context)
+        if (!programObject)
         {
-            gl::Program *programObject = context->getProgram(program);
-
-            if (!programObject)
-            {
-                return gl::error(GL_INVALID_VALUE);
-            }
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
+        }
 
+        if (context->getClientVersion() < 3)
+        {
             switch (pname)
             {
-              case GL_DELETE_STATUS:
-                *params = programObject->isFlaggedForDeletion();
-                return;
-              case GL_LINK_STATUS:
-                *params = programObject->isLinked();
-                return;
-              case GL_VALIDATE_STATUS:
-                *params = programObject->isValidated();
-                return;
-              case GL_INFO_LOG_LENGTH:
-                *params = programObject->getInfoLogLength();
-                return;
-              case GL_ATTACHED_SHADERS:
-                *params = programObject->getAttachedShadersCount();
-                return;
-              case GL_ACTIVE_ATTRIBUTES:
-                *params = programObject->getActiveAttributeCount();
-                return;
-              case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
-                *params = programObject->getActiveAttributeMaxLength();
+              case GL_ACTIVE_UNIFORM_BLOCKS:
+              case GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH:
+              case GL_TRANSFORM_FEEDBACK_BUFFER_MODE:
+              case GL_TRANSFORM_FEEDBACK_VARYINGS:
+              case GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH:
+                context->recordError(gl::Error(GL_INVALID_ENUM));
                 return;
-              case GL_ACTIVE_UNIFORMS:
-                *params = programObject->getActiveUniformCount();
-                return;
-              case GL_ACTIVE_UNIFORM_MAX_LENGTH:
-                *params = programObject->getActiveUniformMaxLength();
-                return;
-              case GL_PROGRAM_BINARY_LENGTH_OES:
-                *params = programObject->getProgramBinaryLength();
-                return;
-              default:
-                return gl::error(GL_INVALID_ENUM);
             }
         }
-    }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
-    }
-}
+
+        switch (pname)
+        {
+          case GL_DELETE_STATUS:
+            *params = programObject->isFlaggedForDeletion();
+            return;
+          case GL_LINK_STATUS:
+            *params = programObject->isLinked();
+            return;
+          case GL_VALIDATE_STATUS:
+            *params = programObject->isValidated();
+            return;
+          case GL_INFO_LOG_LENGTH:
+            *params = programObject->getInfoLogLength();
+            return;
+          case GL_ATTACHED_SHADERS:
+            *params = programObject->getAttachedShadersCount();
+            return;
+          case GL_ACTIVE_ATTRIBUTES:
+            *params = programObject->getActiveAttributeCount();
+            return;
+          case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
+            *params = programObject->getActiveAttributeMaxLength();
+            return;
+          case GL_ACTIVE_UNIFORMS:
+            *params = programObject->getActiveUniformCount();
+            return;
+          case GL_ACTIVE_UNIFORM_MAX_LENGTH:
+            *params = programObject->getActiveUniformMaxLength();
+            return;
+          case GL_PROGRAM_BINARY_LENGTH_OES:
+            *params = programObject->getProgramBinaryLength();
+            return;
+          case GL_ACTIVE_UNIFORM_BLOCKS:
+            *params = programObject->getActiveUniformBlockCount();
+            return;
+          case GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH:
+            *params = programObject->getActiveUniformBlockMaxLength();
+            break;
+          case GL_TRANSFORM_FEEDBACK_BUFFER_MODE:
+            *params = programObject->getTransformFeedbackBufferMode();
+            break;
+          case GL_TRANSFORM_FEEDBACK_VARYINGS:
+            *params = programObject->getTransformFeedbackVaryingCount();
+            break;
+          case GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH:
+            *params = programObject->getTransformFeedbackVaryingMaxLength();
+            break;
+
+          default:
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
+        }
+    }
+}
 
 void __stdcall glGetProgramInfoLog(GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog)
 {
     EVENT("(GLuint program = %d, GLsizei bufsize = %d, GLsizei* length = 0x%0.8p, GLchar* infolog = 0x%0.8p)",
           program, bufsize, length, infolog);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
         if (bufsize < 0)
         {
-            return gl::error(GL_INVALID_VALUE);
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
         }
 
-        gl::Context *context = gl::getNonLostContext();
+        gl::Program *programObject = context->getProgram(program);
 
-        if (context)
+        if (!programObject)
         {
-            gl::Program *programObject = context->getProgram(program);
-
-            if (!programObject)
-            {
-                return gl::error(GL_INVALID_VALUE);
-            }
-
-            programObject->getInfoLog(bufsize, length, infolog);
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
         }
-    }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
+
+        programObject->getInfoLog(bufsize, length, infolog);
     }
 }
 
@@ -3514,178 +2557,170 @@ void __stdcall glGetQueryivEXT(GLenum target, GLenum pname, GLint *params)
 {
     EVENT("GLenum target = 0x%X, GLenum pname = 0x%X, GLint *params = 0x%0.8p)", target, pname, params);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
+        if (!ValidQueryType(context, target))
+        {
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
+        }
+
         switch (pname)
         {
           case GL_CURRENT_QUERY_EXT:
+            params[0] = context->getState().getActiveQueryId(target);
             break;
-          default:
-            return gl::error(GL_INVALID_ENUM);
-        }
 
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
-        {
-            params[0] = context->getActiveQuery(target);
+          default:
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
         }
     }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
-    }
 }
 
 void __stdcall glGetQueryObjectuivEXT(GLuint id, GLenum pname, GLuint *params)
 {
     EVENT("(GLuint id = %d, GLenum pname = 0x%X, GLuint *params = 0x%0.8p)", id, pname, params);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        switch (pname)
+        gl::Query *queryObject = context->getQuery(id, false, GL_NONE);
+
+        if (!queryObject)
         {
-          case GL_QUERY_RESULT_EXT:
-          case GL_QUERY_RESULT_AVAILABLE_EXT:
-            break;
-          default:
-            return gl::error(GL_INVALID_ENUM);
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
         }
-        gl::Context *context = gl::getNonLostContext();
 
-        if (context)
+        if (context->getState().getActiveQueryId(queryObject->getType()) == id)
         {
-            gl::Query *queryObject = context->getQuery(id, false, GL_NONE);
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
 
-            if (!queryObject)
+        switch(pname)
+        {
+          case GL_QUERY_RESULT_EXT:
             {
-                return gl::error(GL_INVALID_OPERATION);
+                gl::Error error = queryObject->getResult(params);
+                if (error.isError())
+                {
+                    context->recordError(error);
+                    return;
+                }
             }
+            break;
 
-            if (context->getActiveQuery(queryObject->getType()) == id)
+          case GL_QUERY_RESULT_AVAILABLE_EXT:
             {
-                return gl::error(GL_INVALID_OPERATION);
+                gl::Error error = queryObject->isResultAvailable(params);
+                if (error.isError())
+                {
+                    context->recordError(error);
+                    return;
+                }
             }
+            break;
 
-            switch(pname)
-            {
-              case GL_QUERY_RESULT_EXT:
-                params[0] = queryObject->getResult();
-                break;
-              case GL_QUERY_RESULT_AVAILABLE_EXT:
-                params[0] = queryObject->isResultAvailable();
-                break;
-              default:
-                ASSERT(false);
-            }
+          default:
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
         }
     }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
-    }
 }
 
 void __stdcall glGetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params)
 {
     EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", target, pname, params);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        gl::Context *context = gl::getNonLostContext();
+        if (target != GL_RENDERBUFFER)
+        {
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
+        }
 
-        if (context)
+        if (context->getState().getRenderbufferId() == 0)
         {
-            if (target != GL_RENDERBUFFER)
-            {
-                return gl::error(GL_INVALID_ENUM);
-            }
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
 
-            if (context->getRenderbufferHandle() == 0)
-            {
-                return gl::error(GL_INVALID_OPERATION);
-            }
+        gl::Renderbuffer *renderbuffer = context->getRenderbuffer(context->getState().getRenderbufferId());
 
-            gl::Renderbuffer *renderbuffer = context->getRenderbuffer(context->getRenderbufferHandle());
+        switch (pname)
+        {
+          case GL_RENDERBUFFER_WIDTH:           *params = renderbuffer->getWidth();          break;
+          case GL_RENDERBUFFER_HEIGHT:          *params = renderbuffer->getHeight();         break;
+          case GL_RENDERBUFFER_INTERNAL_FORMAT: *params = renderbuffer->getInternalFormat(); break;
+          case GL_RENDERBUFFER_RED_SIZE:        *params = renderbuffer->getRedSize();        break;
+          case GL_RENDERBUFFER_GREEN_SIZE:      *params = renderbuffer->getGreenSize();      break;
+          case GL_RENDERBUFFER_BLUE_SIZE:       *params = renderbuffer->getBlueSize();       break;
+          case GL_RENDERBUFFER_ALPHA_SIZE:      *params = renderbuffer->getAlphaSize();      break;
+          case GL_RENDERBUFFER_DEPTH_SIZE:      *params = renderbuffer->getDepthSize();      break;
+          case GL_RENDERBUFFER_STENCIL_SIZE:    *params = renderbuffer->getStencilSize();    break;
 
-            switch (pname)
+          case GL_RENDERBUFFER_SAMPLES_ANGLE:
+            if (!context->getExtensions().framebufferMultisample)
             {
-              case GL_RENDERBUFFER_WIDTH:           *params = renderbuffer->getWidth();          break;
-              case GL_RENDERBUFFER_HEIGHT:          *params = renderbuffer->getHeight();         break;
-              case GL_RENDERBUFFER_INTERNAL_FORMAT: *params = renderbuffer->getInternalFormat(); break;
-              case GL_RENDERBUFFER_RED_SIZE:        *params = renderbuffer->getRedSize();        break;
-              case GL_RENDERBUFFER_GREEN_SIZE:      *params = renderbuffer->getGreenSize();      break;
-              case GL_RENDERBUFFER_BLUE_SIZE:       *params = renderbuffer->getBlueSize();       break;
-              case GL_RENDERBUFFER_ALPHA_SIZE:      *params = renderbuffer->getAlphaSize();      break;
-              case GL_RENDERBUFFER_DEPTH_SIZE:      *params = renderbuffer->getDepthSize();      break;
-              case GL_RENDERBUFFER_STENCIL_SIZE:    *params = renderbuffer->getStencilSize();    break;
-              case GL_RENDERBUFFER_SAMPLES_ANGLE:
-                if (context->getMaxSupportedSamples() != 0)
-                {
-                    *params = renderbuffer->getSamples();
-                }
-                else
-                {
-                    return gl::error(GL_INVALID_ENUM);
-                }
-                break;
-              default:
-                return gl::error(GL_INVALID_ENUM);
+                context->recordError(gl::Error(GL_INVALID_ENUM));
+                return;
             }
+            *params = renderbuffer->getSamples();
+            break;
+
+          default:
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
         }
     }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
-    }
 }
 
 void __stdcall glGetShaderiv(GLuint shader, GLenum pname, GLint* params)
 {
     EVENT("(GLuint shader = %d, GLenum pname = %d, GLint* params = 0x%0.8p)", shader, pname, params);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        gl::Context *context = gl::getNonLostContext();
+        gl::Shader *shaderObject = context->getShader(shader);
 
-        if (context)
+        if (!shaderObject)
         {
-            gl::Shader *shaderObject = context->getShader(shader);
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
+        }
 
-            if (!shaderObject)
-            {
-                return gl::error(GL_INVALID_VALUE);
-            }
+        switch (pname)
+        {
+          case GL_SHADER_TYPE:
+            *params = shaderObject->getType();
+            return;
+          case GL_DELETE_STATUS:
+            *params = shaderObject->isFlaggedForDeletion();
+            return;
+          case GL_COMPILE_STATUS:
+            *params = shaderObject->isCompiled() ? GL_TRUE : GL_FALSE;
+            return;
+          case GL_INFO_LOG_LENGTH:
+            *params = shaderObject->getInfoLogLength();
+            return;
+          case GL_SHADER_SOURCE_LENGTH:
+            *params = shaderObject->getSourceLength();
+            return;
+          case GL_TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE:
+            *params = shaderObject->getTranslatedSourceLength();
+            return;
 
-            switch (pname)
-            {
-              case GL_SHADER_TYPE:
-                *params = shaderObject->getType();
-                return;
-              case GL_DELETE_STATUS:
-                *params = shaderObject->isFlaggedForDeletion();
-                return;
-              case GL_COMPILE_STATUS:
-                *params = shaderObject->isCompiled() ? GL_TRUE : GL_FALSE;
-                return;
-              case GL_INFO_LOG_LENGTH:
-                *params = shaderObject->getInfoLogLength();
-                return;
-              case GL_SHADER_SOURCE_LENGTH:
-                *params = shaderObject->getSourceLength();
-                return;
-              case GL_TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE:
-                *params = shaderObject->getTranslatedSourceLength();
-                return;
-              default:
-                return gl::error(GL_INVALID_ENUM);
-            }
+          default:
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
         }
     }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
-    }
 }
 
 void __stdcall glGetShaderInfoLog(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* infolog)
@@ -3693,30 +2728,24 @@ void __stdcall glGetShaderInfoLog(GLuint shader, GLsizei bufsize, GLsizei* lengt
     EVENT("(GLuint shader = %d, GLsizei bufsize = %d, GLsizei* length = 0x%0.8p, GLchar* infolog = 0x%0.8p)",
           shader, bufsize, length, infolog);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
         if (bufsize < 0)
         {
-            return gl::error(GL_INVALID_VALUE);
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
         }
 
-        gl::Context *context = gl::getNonLostContext();
+        gl::Shader *shaderObject = context->getShader(shader);
 
-        if (context)
+        if (!shaderObject)
         {
-            gl::Shader *shaderObject = context->getShader(shader);
-
-            if (!shaderObject)
-            {
-                return gl::error(GL_INVALID_VALUE);
-            }
-
-            shaderObject->getInfoLog(bufsize, length, infolog);
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
         }
-    }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
+
+        shaderObject->getInfoLog(bufsize, length, infolog);
     }
 }
 
@@ -3725,15 +2754,18 @@ void __stdcall glGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontyp
     EVENT("(GLenum shadertype = 0x%X, GLenum precisiontype = 0x%X, GLint* range = 0x%0.8p, GLint* precision = 0x%0.8p)",
           shadertype, precisiontype, range, precision);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
         switch (shadertype)
         {
           case GL_VERTEX_SHADER:
           case GL_FRAGMENT_SHADER:
             break;
+
           default:
-            return gl::error(GL_INVALID_ENUM);
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
         }
 
         switch (precisiontype)
@@ -3746,6 +2778,7 @@ void __stdcall glGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontyp
             range[1] = 127;
             *precision = 23;
             break;
+
           case GL_LOW_INT:
           case GL_MEDIUM_INT:
           case GL_HIGH_INT:
@@ -3755,14 +2788,12 @@ void __stdcall glGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontyp
             range[1] = 24;
             *precision = 0;
             break;
+
           default:
-            return gl::error(GL_INVALID_ENUM);
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
         }
     }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
-    }
 }
 
 void __stdcall glGetShaderSource(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source)
@@ -3770,30 +2801,24 @@ void __stdcall glGetShaderSource(GLuint shader, GLsizei bufsize, GLsizei* length
     EVENT("(GLuint shader = %d, GLsizei bufsize = %d, GLsizei* length = 0x%0.8p, GLchar* source = 0x%0.8p)",
           shader, bufsize, length, source);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
         if (bufsize < 0)
         {
-            return gl::error(GL_INVALID_VALUE);
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
         }
 
-        gl::Context *context = gl::getNonLostContext();
+        gl::Shader *shaderObject = context->getShader(shader);
 
-        if (context)
+        if (!shaderObject)
         {
-            gl::Shader *shaderObject = context->getShader(shader);
-
-            if (!shaderObject)
-            {
-                return gl::error(GL_INVALID_OPERATION);
-            }
-
-            shaderObject->getSource(bufsize, length, source);
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
         }
-    }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
+
+        shaderObject->getSource(bufsize, length, source);
     }
 }
 
@@ -3802,30 +2827,24 @@ void __stdcall glGetTranslatedShaderSourceANGLE(GLuint shader, GLsizei bufsize,
     EVENT("(GLuint shader = %d, GLsizei bufsize = %d, GLsizei* length = 0x%0.8p, GLchar* source = 0x%0.8p)",
           shader, bufsize, length, source);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
         if (bufsize < 0)
         {
-            return gl::error(GL_INVALID_VALUE);
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
         }
 
-        gl::Context *context = gl::getNonLostContext();
+        gl::Shader *shaderObject = context->getShader(shader);
 
-        if (context)
+        if (!shaderObject)
         {
-            gl::Shader *shaderObject = context->getShader(shader);
-
-            if (!shaderObject)
-            {
-                return gl::error(GL_INVALID_OPERATION);
-            }
-
-            shaderObject->getTranslatedSource(bufsize, length, source);
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
         }
-    }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
+
+        shaderObject->getTranslatedSource(bufsize, length, source);
     }
 }
 
@@ -3833,285 +2852,374 @@ const GLubyte* __stdcall glGetString(GLenum name)
 {
     EVENT("(GLenum name = 0x%X)", name);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+
+    switch (name)
     {
-        gl::Context *context = gl::getNonLostContext();
+      case GL_VENDOR:
+        return (GLubyte*)"Google Inc.";
+
+      case GL_RENDERER:
+        return (GLubyte*)((context != NULL) ? context->getRendererString().c_str() : "ANGLE");
 
-        switch (name)
+      case GL_VERSION:
+        if (context->getClientVersion() == 2)
         {
-          case GL_VENDOR:
-            return (GLubyte*)"Google Inc.";
-          case GL_RENDERER:
-            return (GLubyte*)((context != NULL) ? context->getRendererString() : "ANGLE");
-          case GL_VERSION:
             return (GLubyte*)"OpenGL ES 2.0 (ANGLE " ANGLE_VERSION_STRING ")";
-          case GL_SHADING_LANGUAGE_VERSION:
-            return (GLubyte*)"OpenGL ES GLSL ES 1.00 (ANGLE " ANGLE_VERSION_STRING ")";
-          case GL_EXTENSIONS:
-            return (GLubyte*)((context != NULL) ? context->getExtensionString() : "");
-          default:
-            return gl::error(GL_INVALID_ENUM, (GLubyte*)NULL);
         }
-    }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY, (GLubyte*)NULL);
-    }
-}
+        else
+        {
+            return (GLubyte*)"OpenGL ES 3.0 (ANGLE " ANGLE_VERSION_STRING ")";
+        }
 
-void __stdcall glGetTexParameterfv(GLenum target, GLenum pname, GLfloat* params)
-{
-    EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLfloat* params = 0x%0.8p)", target, pname, params);
+      case GL_SHADING_LANGUAGE_VERSION:
+        if (context->getClientVersion() == 2)
+        {
+            return (GLubyte*)"OpenGL ES GLSL ES 1.00 (ANGLE " ANGLE_VERSION_STRING ")";
+        }
+        else
+        {
+            return (GLubyte*)"OpenGL ES GLSL ES 3.00 (ANGLE " ANGLE_VERSION_STRING ")";
+        }
 
-    try
-    {
-        gl::Context *context = gl::getNonLostContext();
+      case GL_EXTENSIONS:
+        return (GLubyte*)((context != NULL) ? context->getExtensionString().c_str() : "");
 
+      default:
         if (context)
         {
-            gl::Texture *texture;
-
-            switch (target)
-            {
-              case GL_TEXTURE_2D:
-                texture = context->getTexture2D();
-                break;
-              case GL_TEXTURE_CUBE_MAP:
-                texture = context->getTextureCubeMap();
-                break;
-              default:
-                return gl::error(GL_INVALID_ENUM);
-            }
-
-            switch (pname)
-            {
-              case GL_TEXTURE_MAG_FILTER:
-                *params = (GLfloat)texture->getMagFilter();
-                break;
-              case GL_TEXTURE_MIN_FILTER:
-                *params = (GLfloat)texture->getMinFilter();
-                break;
-              case GL_TEXTURE_WRAP_S:
-                *params = (GLfloat)texture->getWrapS();
-                break;
-              case GL_TEXTURE_WRAP_T:
-                *params = (GLfloat)texture->getWrapT();
-                break;
-              case GL_TEXTURE_IMMUTABLE_FORMAT_EXT:
-                *params = (GLfloat)(texture->isImmutable() ? GL_TRUE : GL_FALSE);
-                break;
-              case GL_TEXTURE_USAGE_ANGLE:
-                *params = (GLfloat)texture->getUsage();
-                break;
-              case GL_TEXTURE_MAX_ANISOTROPY_EXT:
-                if (!context->supportsTextureFilterAnisotropy())
-                {
-                    return gl::error(GL_INVALID_ENUM);
-                }
-                *params = (GLfloat)texture->getMaxAnisotropy();
-                break;
-              default:
-                return gl::error(GL_INVALID_ENUM);
-            }
+            context->recordError(gl::Error(GL_INVALID_ENUM));
         }
-    }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
+        return NULL;
     }
 }
 
-void __stdcall glGetTexParameteriv(GLenum target, GLenum pname, GLint* params)
+void __stdcall glGetTexParameterfv(GLenum target, GLenum pname, GLfloat* params)
 {
-    EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", target, pname, params);
+    EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLfloat* params = 0x%0.8p)", target, pname, params);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        gl::Context *context = gl::getNonLostContext();
+        gl::Texture *texture = context->getTargetTexture(target);
 
-        if (context)
+        if (!texture)
         {
-            gl::Texture *texture;
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
+        }
 
-            switch (target)
+        switch (pname)
+        {
+          case GL_TEXTURE_MAG_FILTER:
+            *params = (GLfloat)texture->getSamplerState().magFilter;
+            break;
+          case GL_TEXTURE_MIN_FILTER:
+            *params = (GLfloat)texture->getSamplerState().minFilter;
+            break;
+          case GL_TEXTURE_WRAP_S:
+            *params = (GLfloat)texture->getSamplerState().wrapS;
+            break;
+          case GL_TEXTURE_WRAP_T:
+            *params = (GLfloat)texture->getSamplerState().wrapT;
+            break;
+          case GL_TEXTURE_WRAP_R:
+            if (context->getClientVersion() < 3)
             {
-              case GL_TEXTURE_2D:
-                texture = context->getTexture2D();
-                break;
-              case GL_TEXTURE_CUBE_MAP:
-                texture = context->getTextureCubeMap();
-                break;
-              default:
-                return gl::error(GL_INVALID_ENUM);
+                context->recordError(gl::Error(GL_INVALID_ENUM));
+                return;
             }
-
-            switch (pname)
+            *params = (GLfloat)texture->getSamplerState().wrapR;
+            break;
+          case GL_TEXTURE_IMMUTABLE_FORMAT:
+            // Exposed to ES2.0 through EXT_texture_storage, no client version validation.
+            *params = (GLfloat)(texture->isImmutable() ? GL_TRUE : GL_FALSE);
+            break;
+          case GL_TEXTURE_IMMUTABLE_LEVELS:
+            if (context->getClientVersion() < 3)
             {
-              case GL_TEXTURE_MAG_FILTER:
-                *params = texture->getMagFilter();
-                break;
-              case GL_TEXTURE_MIN_FILTER:
-                *params = texture->getMinFilter();
-                break;
-              case GL_TEXTURE_WRAP_S:
-                *params = texture->getWrapS();
-                break;
-              case GL_TEXTURE_WRAP_T:
-                *params = texture->getWrapT();
-                break;
-              case GL_TEXTURE_IMMUTABLE_FORMAT_EXT:
-                *params = texture->isImmutable() ? GL_TRUE : GL_FALSE;
-                break;
-              case GL_TEXTURE_USAGE_ANGLE:
-                *params = texture->getUsage();
-                break;
-              case GL_TEXTURE_MAX_ANISOTROPY_EXT:
-                if (!context->supportsTextureFilterAnisotropy())
-                {
-                    return gl::error(GL_INVALID_ENUM);
-                }
-                *params = (GLint)texture->getMaxAnisotropy();
-                break;
-              default:
-                return gl::error(GL_INVALID_ENUM);
+                context->recordError(gl::Error(GL_INVALID_ENUM));
+                return;
             }
-        }
-    }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
-    }
-}
-
-void __stdcall glGetnUniformfvEXT(GLuint program, GLint location, GLsizei bufSize, GLfloat* params)
-{
-    EVENT("(GLuint program = %d, GLint location = %d, GLsizei bufSize = %d, GLfloat* params = 0x%0.8p)",
-          program, location, bufSize, params);
-
-    try
-    {
-        if (bufSize < 0)
-        {
-            return gl::error(GL_INVALID_VALUE);
-        }
-
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
-        {
-            if (program == 0)
+            *params = (GLfloat)texture->immutableLevelCount();
+            break;
+          case GL_TEXTURE_USAGE_ANGLE:
+            *params = (GLfloat)texture->getUsage();
+            break;
+          case GL_TEXTURE_MAX_ANISOTROPY_EXT:
+            if (!context->getExtensions().textureFilterAnisotropic)
             {
-                return gl::error(GL_INVALID_VALUE);
+                context->recordError(gl::Error(GL_INVALID_ENUM));
+                return;
             }
-
-            gl::Program *programObject = context->getProgram(program);
-
-            if (!programObject || !programObject->isLinked())
+            *params = (GLfloat)texture->getSamplerState().maxAnisotropy;
+            break;
+          case GL_TEXTURE_SWIZZLE_R:
+            if (context->getClientVersion() < 3)
             {
-                return gl::error(GL_INVALID_OPERATION);
+                context->recordError(gl::Error(GL_INVALID_ENUM));
+                return;
             }
-
-            gl::ProgramBinary *programBinary = programObject->getProgramBinary();
-            if (!programBinary)
+            *params = (GLfloat)texture->getSamplerState().swizzleRed;
+            break;
+          case GL_TEXTURE_SWIZZLE_G:
+            if (context->getClientVersion() < 3)
+            {
+                context->recordError(gl::Error(GL_INVALID_ENUM));
+                return;
+            }
+            *params = (GLfloat)texture->getSamplerState().swizzleGreen;
+            break;
+          case GL_TEXTURE_SWIZZLE_B:
+            if (context->getClientVersion() < 3)
             {
-                return gl::error(GL_INVALID_OPERATION);
+                context->recordError(gl::Error(GL_INVALID_ENUM));
+                return;
             }
-
-            if (!programBinary->getUniformfv(location, &bufSize, params))
+            *params = (GLfloat)texture->getSamplerState().swizzleBlue;
+            break;
+          case GL_TEXTURE_SWIZZLE_A:
+            if (context->getClientVersion() < 3)
+            {
+                context->recordError(gl::Error(GL_INVALID_ENUM));
+                return;
+            }
+            *params = (GLfloat)texture->getSamplerState().swizzleAlpha;
+            break;
+          case GL_TEXTURE_BASE_LEVEL:
+            if (context->getClientVersion() < 3)
+            {
+                context->recordError(gl::Error(GL_INVALID_ENUM));
+                return;
+            }
+            *params = (GLfloat)texture->getSamplerState().baseLevel;
+            break;
+          case GL_TEXTURE_MAX_LEVEL:
+            if (context->getClientVersion() < 3)
+            {
+                context->recordError(gl::Error(GL_INVALID_ENUM));
+                return;
+            }
+            *params = (GLfloat)texture->getSamplerState().maxLevel;
+            break;
+          case GL_TEXTURE_MIN_LOD:
+            if (context->getClientVersion() < 3)
+            {
+                context->recordError(gl::Error(GL_INVALID_ENUM));
+                return;
+            }
+            *params = texture->getSamplerState().minLod;
+            break;
+          case GL_TEXTURE_MAX_LOD:
+            if (context->getClientVersion() < 3)
             {
-                return gl::error(GL_INVALID_OPERATION);
+                context->recordError(gl::Error(GL_INVALID_ENUM));
+                return;
             }
+            *params = texture->getSamplerState().maxLod;
+            break;
+
+          default:
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
         }
     }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
-    }
 }
 
-void __stdcall glGetUniformfv(GLuint program, GLint location, GLfloat* params)
+void __stdcall glGetTexParameteriv(GLenum target, GLenum pname, GLint* params)
 {
-    EVENT("(GLuint program = %d, GLint location = %d, GLfloat* params = 0x%0.8p)", program, location, params);
+    EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", target, pname, params);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        gl::Context *context = gl::getNonLostContext();
+        gl::Texture *texture = context->getTargetTexture(target);
 
-        if (context)
+        if (!texture)
+        {
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
+        }
+
+        switch (pname)
         {
-            if (program == 0)
+          case GL_TEXTURE_MAG_FILTER:
+            *params = texture->getSamplerState().magFilter;
+            break;
+          case GL_TEXTURE_MIN_FILTER:
+            *params = texture->getSamplerState().minFilter;
+            break;
+          case GL_TEXTURE_WRAP_S:
+            *params = texture->getSamplerState().wrapS;
+            break;
+          case GL_TEXTURE_WRAP_T:
+            *params = texture->getSamplerState().wrapT;
+            break;
+          case GL_TEXTURE_WRAP_R:
+            if (context->getClientVersion() < 3)
             {
-                return gl::error(GL_INVALID_VALUE);
+                context->recordError(gl::Error(GL_INVALID_ENUM));
+                return;
             }
-
-            gl::Program *programObject = context->getProgram(program);
-
-            if (!programObject || !programObject->isLinked())
+            *params = texture->getSamplerState().wrapR;
+            break;
+          case GL_TEXTURE_IMMUTABLE_FORMAT:
+            // Exposed to ES2.0 through EXT_texture_storage, no client version validation.
+            *params = texture->isImmutable() ? GL_TRUE : GL_FALSE;
+            break;
+          case GL_TEXTURE_IMMUTABLE_LEVELS:
+            if (context->getClientVersion() < 3)
             {
-                return gl::error(GL_INVALID_OPERATION);
+                context->recordError(gl::Error(GL_INVALID_ENUM));
+                return;
             }
-
-            gl::ProgramBinary *programBinary = programObject->getProgramBinary();
-            if (!programBinary)
+            *params = texture->immutableLevelCount();
+            break;
+          case GL_TEXTURE_USAGE_ANGLE:
+            *params = texture->getUsage();
+            break;
+          case GL_TEXTURE_MAX_ANISOTROPY_EXT:
+            if (!context->getExtensions().textureFilterAnisotropic)
             {
-                return gl::error(GL_INVALID_OPERATION);
+                context->recordError(gl::Error(GL_INVALID_ENUM));
+                return;
             }
-
-            if (!programBinary->getUniformfv(location, NULL, params))
+            *params = (GLint)texture->getSamplerState().maxAnisotropy;
+            break;
+          case GL_TEXTURE_SWIZZLE_R:
+            if (context->getClientVersion() < 3)
+            {
+                context->recordError(gl::Error(GL_INVALID_ENUM));
+                return;
+            }
+            *params = texture->getSamplerState().swizzleRed;
+            break;
+          case GL_TEXTURE_SWIZZLE_G:
+            if (context->getClientVersion() < 3)
+            {
+                context->recordError(gl::Error(GL_INVALID_ENUM));
+                return;
+            }
+            *params = texture->getSamplerState().swizzleGreen;
+            break;
+          case GL_TEXTURE_SWIZZLE_B:
+            if (context->getClientVersion() < 3)
+            {
+                context->recordError(gl::Error(GL_INVALID_ENUM));
+                return;
+            }
+            *params = texture->getSamplerState().swizzleBlue;
+            break;
+          case GL_TEXTURE_SWIZZLE_A:
+            if (context->getClientVersion() < 3)
+            {
+                context->recordError(gl::Error(GL_INVALID_ENUM));
+                return;
+            }
+            *params = texture->getSamplerState().swizzleAlpha;
+            break;
+          case GL_TEXTURE_BASE_LEVEL:
+            if (context->getClientVersion() < 3)
             {
-                return gl::error(GL_INVALID_OPERATION);
+                context->recordError(gl::Error(GL_INVALID_ENUM));
+                return;
+            }
+            *params = texture->getSamplerState().baseLevel;
+            break;
+          case GL_TEXTURE_MAX_LEVEL:
+            if (context->getClientVersion() < 3)
+            {
+                context->recordError(gl::Error(GL_INVALID_ENUM));
+                return;
+            }
+            *params = texture->getSamplerState().maxLevel;
+            break;
+          case GL_TEXTURE_MIN_LOD:
+            if (context->getClientVersion() < 3)
+            {
+                context->recordError(gl::Error(GL_INVALID_ENUM));
+                return;
+            }
+            *params = (GLint)texture->getSamplerState().minLod;
+            break;
+          case GL_TEXTURE_MAX_LOD:
+            if (context->getClientVersion() < 3)
+            {
+                context->recordError(gl::Error(GL_INVALID_ENUM));
+                return;
             }
+            *params = (GLint)texture->getSamplerState().maxLod;
+            break;
+
+          default:
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
         }
     }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
-    }
 }
 
-void __stdcall glGetnUniformivEXT(GLuint program, GLint location, GLsizei bufSize, GLint* params)
+void __stdcall glGetnUniformfvEXT(GLuint program, GLint location, GLsizei bufSize, GLfloat* params)
 {
-    EVENT("(GLuint program = %d, GLint location = %d, GLsizei bufSize = %d, GLint* params = 0x%0.8p)", 
+    EVENT("(GLuint program = %d, GLint location = %d, GLsizei bufSize = %d, GLfloat* params = 0x%0.8p)",
           program, location, bufSize, params);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        if (bufSize < 0)
+        if (!ValidateGetnUniformfvEXT(context, program, location, bufSize, params))
         {
-            return gl::error(GL_INVALID_VALUE);
+            return;
         }
 
-        gl::Context *context = gl::getNonLostContext();
+        gl::Program *programObject = context->getProgram(program);
+        ASSERT(programObject);
+        gl::ProgramBinary *programBinary = programObject->getProgramBinary();
+        ASSERT(programBinary);
 
-        if (context)
-        {
-            if (program == 0)
-            {
-                return gl::error(GL_INVALID_VALUE);
-            }
+        programBinary->getUniformfv(location, params);
+    }
+}
 
-            gl::Program *programObject = context->getProgram(program);
+void __stdcall glGetUniformfv(GLuint program, GLint location, GLfloat* params)
+{
+    EVENT("(GLuint program = %d, GLint location = %d, GLfloat* params = 0x%0.8p)", program, location, params);
 
-            if (!programObject || !programObject->isLinked())
-            {
-                return gl::error(GL_INVALID_OPERATION);
-            }
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (!ValidateGetUniformfv(context, program, location, params))
+        {
+            return;
+        }
 
-            gl::ProgramBinary *programBinary = programObject->getProgramBinary();
-            if (!programBinary)
-            {
-                return gl::error(GL_INVALID_OPERATION);
-            }
+        gl::Program *programObject = context->getProgram(program);
+        ASSERT(programObject);
+        gl::ProgramBinary *programBinary = programObject->getProgramBinary();
+        ASSERT(programBinary);
 
-            if (!programBinary->getUniformiv(location, &bufSize, params))
-            {
-                return gl::error(GL_INVALID_OPERATION);
-            }
-        }
+        programBinary->getUniformfv(location, params);
     }
-    catch(std::bad_alloc&)
+}
+
+void __stdcall glGetnUniformivEXT(GLuint program, GLint location, GLsizei bufSize, GLint* params)
+{
+    EVENT("(GLuint program = %d, GLint location = %d, GLsizei bufSize = %d, GLint* params = 0x%0.8p)",
+          program, location, bufSize, params);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        return gl::error(GL_OUT_OF_MEMORY);
+        if (!ValidateGetnUniformivEXT(context, program, location, bufSize, params))
+        {
+            return;
+        }
+
+        gl::Program *programObject = context->getProgram(program);
+        ASSERT(programObject);
+        gl::ProgramBinary *programBinary = programObject->getProgramBinary();
+        ASSERT(programBinary);
+
+        programBinary->getUniformiv(location, params);
     }
 }
 
@@ -4119,83 +3227,59 @@ void __stdcall glGetUniformiv(GLuint program, GLint location, GLint* params)
 {
     EVENT("(GLuint program = %d, GLint location = %d, GLint* params = 0x%0.8p)", program, location, params);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
+        if (!ValidateGetUniformiv(context, program, location, params))
         {
-            if (program == 0)
-            {
-                return gl::error(GL_INVALID_VALUE);
-            }
-
-            gl::Program *programObject = context->getProgram(program);
-
-            if (!programObject || !programObject->isLinked())
-            {
-                return gl::error(GL_INVALID_OPERATION);
-            }
+            return;
+        }
 
-            gl::ProgramBinary *programBinary = programObject->getProgramBinary();
-            if (!programBinary)
-            {
-                return gl::error(GL_INVALID_OPERATION);
-            }
+        gl::Program *programObject = context->getProgram(program);
+        ASSERT(programObject);
+        gl::ProgramBinary *programBinary = programObject->getProgramBinary();
+        ASSERT(programBinary);
 
-            if (!programBinary->getUniformiv(location, NULL, params))
-            {
-                return gl::error(GL_INVALID_OPERATION);
-            }
-        }
-    }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
+        programBinary->getUniformiv(location, params);
     }
 }
 
-int __stdcall glGetUniformLocation(GLuint program, const GLchar* name)
+GLint __stdcall glGetUniformLocation(GLuint program, const GLchar* name)
 {
     EVENT("(GLuint program = %d, const GLchar* name = 0x%0.8p)", program, name);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        gl::Context *context = gl::getNonLostContext();
-
         if (strstr(name, "gl_") == name)
         {
             return -1;
         }
 
-        if (context)
-        {
-            gl::Program *programObject = context->getProgram(program);
+        gl::Program *programObject = context->getProgram(program);
 
-            if (!programObject)
+        if (!programObject)
+        {
+            if (context->getShader(program))
             {
-                if (context->getShader(program))
-                {
-                    return gl::error(GL_INVALID_OPERATION, -1);
-                }
-                else
-                {
-                    return gl::error(GL_INVALID_VALUE, -1);
-                }
+                context->recordError(gl::Error(GL_INVALID_OPERATION));
+                return -1;
             }
-
-            gl::ProgramBinary *programBinary = programObject->getProgramBinary();
-            if (!programObject->isLinked() || !programBinary)
+            else
             {
-                return gl::error(GL_INVALID_OPERATION, -1);
+                context->recordError(gl::Error(GL_INVALID_VALUE));
+                return -1;
             }
+        }
 
-            return programBinary->getUniformLocation(name);
+        gl::ProgramBinary *programBinary = programObject->getProgramBinary();
+        if (!programObject->isLinked() || !programBinary)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return -1;
         }
-    }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY, -1);
+
+        return programBinary->getUniformLocation(name);
     }
 
     return -1;
@@ -4205,55 +3289,33 @@ void __stdcall glGetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params)
 {
     EVENT("(GLuint index = %d, GLenum pname = 0x%X, GLfloat* params = 0x%0.8p)", index, pname, params);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
+        if (index >= gl::MAX_VERTEX_ATTRIBS)
         {
-            if (index >= gl::MAX_VERTEX_ATTRIBS)
-            {
-                return gl::error(GL_INVALID_VALUE);
-            }
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
+        }
 
-            const gl::VertexAttribute &attribState = context->getVertexAttribState(index);
+        const gl::VertexAttribute &attribState = context->getState().getVertexAttribState(index);
+        if (!gl::ValidateGetVertexAttribParameters(context, pname))
+        {
+            return;
+        }
 
-            switch (pname)
+        if (pname == GL_CURRENT_VERTEX_ATTRIB)
+        {
+            const gl::VertexAttribCurrentValueData &currentValueData = context->getState().getVertexAttribCurrentValue(index);
+            for (int i = 0; i < 4; ++i)
             {
-              case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
-                *params = (GLfloat)(attribState.mArrayEnabled ? GL_TRUE : GL_FALSE);
-                break;
-              case GL_VERTEX_ATTRIB_ARRAY_SIZE:
-                *params = (GLfloat)attribState.mSize;
-                break;
-              case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
-                *params = (GLfloat)attribState.mStride;
-                break;
-              case GL_VERTEX_ATTRIB_ARRAY_TYPE:
-                *params = (GLfloat)attribState.mType;
-                break;
-              case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
-                *params = (GLfloat)(attribState.mNormalized ? GL_TRUE : GL_FALSE);
-                break;
-              case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
-                *params = (GLfloat)attribState.mBoundBuffer.id();
-                break;
-              case GL_CURRENT_VERTEX_ATTRIB:
-                for (int i = 0; i < 4; ++i)
-                {
-                    params[i] = attribState.mCurrentValue[i];
-                }
-                break;
-              case GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE:
-                *params = (GLfloat)attribState.mDivisor;
-                break;
-              default: return gl::error(GL_INVALID_ENUM);
+                params[i] = currentValueData.FloatValues[i];
             }
         }
-    }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
+        else
+        {
+            *params = gl::QuerySingleVertexAttributeParameter<GLfloat>(attribState, pname);
+        }
     }
 }
 
@@ -4261,56 +3323,35 @@ void __stdcall glGetVertexAttribiv(GLuint index, GLenum pname, GLint* params)
 {
     EVENT("(GLuint index = %d, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", index, pname, params);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
+        if (index >= gl::MAX_VERTEX_ATTRIBS)
         {
-            if (index >= gl::MAX_VERTEX_ATTRIBS)
-            {
-                return gl::error(GL_INVALID_VALUE);
-            }
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
+        }
 
-            const gl::VertexAttribute &attribState = context->getVertexAttribState(index);
+        const gl::VertexAttribute &attribState = context->getState().getVertexAttribState(index);
 
-            switch (pname)
+        if (!gl::ValidateGetVertexAttribParameters(context, pname))
+        {
+            return;
+        }
+
+        if (pname == GL_CURRENT_VERTEX_ATTRIB)
+        {
+            const gl::VertexAttribCurrentValueData &currentValueData = context->getState().getVertexAttribCurrentValue(index);
+            for (int i = 0; i < 4; ++i)
             {
-              case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
-                *params = (attribState.mArrayEnabled ? GL_TRUE : GL_FALSE);
-                break;
-              case GL_VERTEX_ATTRIB_ARRAY_SIZE:
-                *params = attribState.mSize;
-                break;
-              case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
-                *params = attribState.mStride;
-                break;
-              case GL_VERTEX_ATTRIB_ARRAY_TYPE:
-                *params = attribState.mType;
-                break;
-              case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
-                *params = (attribState.mNormalized ? GL_TRUE : GL_FALSE);
-                break;
-              case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
-                *params = attribState.mBoundBuffer.id();
-                break;
-              case GL_CURRENT_VERTEX_ATTRIB:
-                for (int i = 0; i < 4; ++i)
-                {
-                    float currentValue = attribState.mCurrentValue[i];
-                    params[i] = (GLint)(currentValue > 0.0f ? floor(currentValue + 0.5f) : ceil(currentValue - 0.5f));
-                }
-                break;
-              case GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE:
-                *params = (GLint)attribState.mDivisor;
-                break;
-              default: return gl::error(GL_INVALID_ENUM);
+                float currentValue = currentValueData.FloatValues[i];
+                params[i] = gl::iround<GLint>(currentValue);
             }
         }
-    }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
+        else
+        {
+            *params = gl::QuerySingleVertexAttributeParameter<GLint>(attribState, pname);
+        }
     }
 }
 
@@ -4318,28 +3359,22 @@ void __stdcall glGetVertexAttribPointerv(GLuint index, GLenum pname, GLvoid** po
 {
     EVENT("(GLuint index = %d, GLenum pname = 0x%X, GLvoid** pointer = 0x%0.8p)", index, pname, pointer);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        gl::Context *context = gl::getNonLostContext();
+        if (index >= gl::MAX_VERTEX_ATTRIBS)
+        {
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
+        }
 
-        if (context)
+        if (pname != GL_VERTEX_ATTRIB_ARRAY_POINTER)
         {
-            if (index >= gl::MAX_VERTEX_ATTRIBS)
-            {
-                return gl::error(GL_INVALID_VALUE);
-            }
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
+        }
 
-            if (pname != GL_VERTEX_ATTRIB_ARRAY_POINTER)
-            {
-                return gl::error(GL_INVALID_ENUM);
-            }
-
-            *pointer = const_cast<GLvoid*>(context->getVertexAttribPointer(index));
-        }
-    }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
+        *pointer = const_cast<GLvoid*>(context->getState().getVertexAttribPointer(index));
     }
 }
 
@@ -4347,7 +3382,8 @@ void __stdcall glHint(GLenum target, GLenum mode)
 {
     EVENT("(GLenum target = 0x%X, GLenum mode = 0x%X)", target, mode);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
         switch (mode)
         {
@@ -4355,51 +3391,43 @@ void __stdcall glHint(GLenum target, GLenum mode)
           case GL_NICEST:
           case GL_DONT_CARE:
             break;
+
           default:
-            return gl::error(GL_INVALID_ENUM); 
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
         }
 
-        gl::Context *context = gl::getNonLostContext();
         switch (target)
         {
           case GL_GENERATE_MIPMAP_HINT:
-            if (context) context->setGenerateMipmapHint(mode);
+            context->getState().setGenerateMipmapHint(mode);
             break;
+
           case GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES:
-            if (context) context->setFragmentShaderDerivativeHint(mode);
+            context->getState().setFragmentShaderDerivativeHint(mode);
             break;
+
           default:
-            return gl::error(GL_INVALID_ENUM);
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
         }
     }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
-    }
 }
 
 GLboolean __stdcall glIsBuffer(GLuint buffer)
 {
     EVENT("(GLuint buffer = %d)", buffer);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context && buffer)
     {
-        gl::Context *context = gl::getNonLostContext();
+        gl::Buffer *bufferObject = context->getBuffer(buffer);
 
-        if (context && buffer)
+        if (bufferObject)
         {
-            gl::Buffer *bufferObject = context->getBuffer(buffer);
-
-            if (bufferObject)
-            {
-                return GL_TRUE;
-            }
+            return GL_TRUE;
         }
     }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY, GL_FALSE);
-    }
 
     return GL_FALSE;
 }
@@ -4408,31 +3436,16 @@ GLboolean __stdcall glIsEnabled(GLenum cap)
 {
     EVENT("(GLenum cap = 0x%X)", cap);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
+        if (!ValidCap(context, cap))
         {
-            switch (cap)
-            {
-              case GL_CULL_FACE:                return context->isCullFaceEnabled();
-              case GL_POLYGON_OFFSET_FILL:      return context->isPolygonOffsetFillEnabled();
-              case GL_SAMPLE_ALPHA_TO_COVERAGE: return context->isSampleAlphaToCoverageEnabled();
-              case GL_SAMPLE_COVERAGE:          return context->isSampleCoverageEnabled();
-              case GL_SCISSOR_TEST:             return context->isScissorTestEnabled();
-              case GL_STENCIL_TEST:             return context->isStencilTestEnabled();
-              case GL_DEPTH_TEST:               return context->isDepthTestEnabled();
-              case GL_BLEND:                    return context->isBlendEnabled();
-              case GL_DITHER:                   return context->isDitherEnabled();
-              default:
-                return gl::error(GL_INVALID_ENUM, false);
-            }
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return GL_FALSE;
         }
-    }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY, false);
+
+        return context->getState().getEnableFeature(cap);
     }
 
     return false;
@@ -4442,25 +3455,17 @@ GLboolean __stdcall glIsFenceNV(GLuint fence)
 {
     EVENT("(GLuint fence = %d)", fence);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        gl::Context *context = gl::getNonLostContext();
+        gl::FenceNV *fenceObject = context->getFenceNV(fence);
 
-        if (context)
+        if (fenceObject == NULL)
         {
-            gl::Fence *fenceObject = context->getFence(fence);
-
-            if (fenceObject == NULL)
-            {
-                return GL_FALSE;
-            }
-
-            return fenceObject->isFence();
+            return GL_FALSE;
         }
-    }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY, GL_FALSE);
+
+        return fenceObject->isFence();
     }
 
     return GL_FALSE;
@@ -4470,24 +3475,16 @@ GLboolean __stdcall glIsFramebuffer(GLuint framebuffer)
 {
     EVENT("(GLuint framebuffer = %d)", framebuffer);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context && framebuffer)
     {
-        gl::Context *context = gl::getNonLostContext();
+        gl::Framebuffer *framebufferObject = context->getFramebuffer(framebuffer);
 
-        if (context && framebuffer)
+        if (framebufferObject)
         {
-            gl::Framebuffer *framebufferObject = context->getFramebuffer(framebuffer);
-
-            if (framebufferObject)
-            {
-                return GL_TRUE;
-            }
+            return GL_TRUE;
         }
     }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY, GL_FALSE);
-    }
 
     return GL_FALSE;
 }
@@ -4496,24 +3493,16 @@ GLboolean __stdcall glIsProgram(GLuint program)
 {
     EVENT("(GLuint program = %d)", program);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context && program)
     {
-        gl::Context *context = gl::getNonLostContext();
+        gl::Program *programObject = context->getProgram(program);
 
-        if (context && program)
+        if (programObject)
         {
-            gl::Program *programObject = context->getProgram(program);
-
-            if (programObject)
-            {
-                return GL_TRUE;
-            }
+            return GL_TRUE;
         }
     }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY, GL_FALSE);
-    }
 
     return GL_FALSE;
 }
@@ -4522,28 +3511,10 @@ GLboolean __stdcall glIsQueryEXT(GLuint id)
 {
     EVENT("(GLuint id = %d)", id);
 
-    try
-    {
-        if (id == 0)
-        {
-            return GL_FALSE;
-        }
-
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
-        {
-            gl::Query *queryObject = context->getQuery(id, false, GL_NONE);
-
-            if (queryObject)
-            {
-                return GL_TRUE;
-            }
-        }
-    }
-    catch(std::bad_alloc&)
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        return gl::error(GL_OUT_OF_MEMORY, GL_FALSE);
+        return (context->getQuery(id, false, GL_NONE) != NULL) ? GL_TRUE : GL_FALSE;
     }
 
     return GL_FALSE;
@@ -4553,24 +3524,16 @@ GLboolean __stdcall glIsRenderbuffer(GLuint renderbuffer)
 {
     EVENT("(GLuint renderbuffer = %d)", renderbuffer);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context && renderbuffer)
     {
-        gl::Context *context = gl::getNonLostContext();
+        gl::Renderbuffer *renderbufferObject = context->getRenderbuffer(renderbuffer);
 
-        if (context && renderbuffer)
+        if (renderbufferObject)
         {
-            gl::Renderbuffer *renderbufferObject = context->getRenderbuffer(renderbuffer);
-
-            if (renderbufferObject)
-            {
-                return GL_TRUE;
-            }
+            return GL_TRUE;
         }
     }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY, GL_FALSE);
-    }
 
     return GL_FALSE;
 }
@@ -4579,24 +3542,16 @@ GLboolean __stdcall glIsShader(GLuint shader)
 {
     EVENT("(GLuint shader = %d)", shader);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context && shader)
     {
-        gl::Context *context = gl::getNonLostContext();
+        gl::Shader *shaderObject = context->getShader(shader);
 
-        if (context && shader)
+        if (shaderObject)
         {
-            gl::Shader *shaderObject = context->getShader(shader);
-
-            if (shaderObject)
-            {
-                return GL_TRUE;
-            }
+            return GL_TRUE;
         }
     }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY, GL_FALSE);
-    }
 
     return GL_FALSE;
 }
@@ -4605,24 +3560,16 @@ GLboolean __stdcall glIsTexture(GLuint texture)
 {
     EVENT("(GLuint texture = %d)", texture);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context && texture)
     {
-        gl::Context *context = gl::getNonLostContext();
+        gl::Texture *textureObject = context->getTexture(texture);
 
-        if (context && texture)
+        if (textureObject)
         {
-            gl::Texture *textureObject = context->getTexture(texture);
-
-            if (textureObject)
-            {
-                return GL_TRUE;
-            }
+            return GL_TRUE;
         }
     }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY, GL_FALSE);
-    }
 
     return GL_FALSE;
 }
@@ -4631,23 +3578,16 @@ void __stdcall glLineWidth(GLfloat width)
 {
     EVENT("(GLfloat width = %f)", width);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
         if (width <= 0.0f)
         {
-            return gl::error(GL_INVALID_VALUE);
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
         }
 
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
-        {
-            context->setLineWidth(width);
-        }
-    }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
+        context->getState().setLineWidth(width);
     }
 }
 
@@ -4655,32 +3595,26 @@ void __stdcall glLinkProgram(GLuint program)
 {
     EVENT("(GLuint program = %d)", program);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        gl::Context *context = gl::getNonLostContext();
+        gl::Program *programObject = context->getProgram(program);
 
-        if (context)
+        if (!programObject)
         {
-            gl::Program *programObject = context->getProgram(program);
-
-            if (!programObject)
+            if (context->getShader(program))
             {
-                if (context->getShader(program))
-                {
-                    return gl::error(GL_INVALID_OPERATION);
-                }
-                else
-                {
-                    return gl::error(GL_INVALID_VALUE);
-                }
+                context->recordError(gl::Error(GL_INVALID_OPERATION));
+                return;
+            }
+            else
+            {
+                context->recordError(gl::Error(GL_INVALID_VALUE));
+                return;
             }
-
-            context->linkProgram(program);
         }
-    }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
+
+        context->linkProgram(program);
     }
 }
 
@@ -4688,63 +3622,66 @@ void __stdcall glPixelStorei(GLenum pname, GLint param)
 {
     EVENT("(GLenum pname = 0x%X, GLint param = %d)", pname, param);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
+        switch (pname)
         {
-            switch (pname)
+          case GL_UNPACK_ALIGNMENT:
+            if (param != 1 && param != 2 && param != 4 && param != 8)
             {
-              case GL_UNPACK_ALIGNMENT:
-                if (param != 1 && param != 2 && param != 4 && param != 8)
-                {
-                    return gl::error(GL_INVALID_VALUE);
-                }
+                context->recordError(gl::Error(GL_INVALID_VALUE));
+                return;
+            }
 
-                context->setUnpackAlignment(param);
-                break;
+            context->getState().setUnpackAlignment(param);
+            break;
 
-              case GL_PACK_ALIGNMENT:
-                if (param != 1 && param != 2 && param != 4 && param != 8)
-                {
-                    return gl::error(GL_INVALID_VALUE);
-                }
+          case GL_PACK_ALIGNMENT:
+            if (param != 1 && param != 2 && param != 4 && param != 8)
+            {
+                context->recordError(gl::Error(GL_INVALID_VALUE));
+                return;
+            }
 
-                context->setPackAlignment(param);
-                break;
+            context->getState().setPackAlignment(param);
+            break;
 
-              case GL_PACK_REVERSE_ROW_ORDER_ANGLE:
-                context->setPackReverseRowOrder(param != 0);
-                break;
+          case GL_PACK_REVERSE_ROW_ORDER_ANGLE:
+            context->getState().setPackReverseRowOrder(param != 0);
+            break;
 
-              default:
-                return gl::error(GL_INVALID_ENUM);
+          case GL_UNPACK_IMAGE_HEIGHT:
+          case GL_UNPACK_SKIP_IMAGES:
+          case GL_UNPACK_ROW_LENGTH:
+          case GL_UNPACK_SKIP_ROWS:
+          case GL_UNPACK_SKIP_PIXELS:
+          case GL_PACK_ROW_LENGTH:
+          case GL_PACK_SKIP_ROWS:
+          case GL_PACK_SKIP_PIXELS:
+            if (context->getClientVersion() < 3)
+            {
+                context->recordError(gl::Error(GL_INVALID_ENUM));
+                return;
             }
+            UNIMPLEMENTED();
+            break;
+
+          default:
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
         }
     }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
-    }
 }
 
 void __stdcall glPolygonOffset(GLfloat factor, GLfloat units)
 {
     EVENT("(GLfloat factor = %f, GLfloat units = %f)", factor, units);
 
-    try
-    {
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
-        {
-            context->setPolygonOffsetParams(factor, units);
-        }
-    }
-    catch(std::bad_alloc&)
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        return gl::error(GL_OUT_OF_MEMORY);
+        context->getState().setPolygonOffsetParams(factor, units);
     }
 }
 
@@ -4756,37 +3693,28 @@ void __stdcall glReadnPixelsEXT(GLint x, GLint y, GLsizei width, GLsizei height,
           "GLenum format = 0x%X, GLenum type = 0x%X, GLsizei bufSize = 0x%d, GLvoid *data = 0x%0.8p)",
           x, y, width, height, format, type, bufSize, data);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
         if (width < 0 || height < 0 || bufSize < 0)
         {
-            return gl::error(GL_INVALID_VALUE);
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
         }
 
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
+        if (!gl::ValidateReadPixelsParameters(context, x, y, width, height,
+                                              format, type, &bufSize, data))
         {
-            GLenum currentFormat, currentType;
-    
-            // Failure in getCurrentReadFormatType indicates that no color attachment is currently bound,
-            // and attempting to read back if that's the case is an error. The error will be registered
-            // by getCurrentReadFormat.
-            if (!context->getCurrentReadFormatType(&currentFormat, &currentType))
-                return;
-
-            if (!(currentFormat == format && currentType == type) && !validReadFormatType(format, type))
-            {
-                return gl::error(GL_INVALID_OPERATION);
-            }
+            return;
+        }
 
-            context->readPixels(x, y, width, height, format, type, &bufSize, data);
+        gl::Error error = context->readPixels(x, y, width, height, format, type, &bufSize, data);
+        if (error.isError())
+        {
+            context->recordError(error);
+            return;
         }
     }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
-    }
 }
 
 void __stdcall glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height,
@@ -4796,50 +3724,39 @@ void __stdcall glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height,
           "GLenum format = 0x%X, GLenum type = 0x%X, GLvoid* pixels = 0x%0.8p)",
           x, y, width, height, format, type,  pixels);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
         if (width < 0 || height < 0)
         {
-            return gl::error(GL_INVALID_VALUE);
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
         }
 
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
+        if (!gl::ValidateReadPixelsParameters(context, x, y, width, height,
+                                              format, type, NULL, pixels))
         {
-            GLenum currentFormat, currentType;
-    
-            // Failure in getCurrentReadFormatType indicates that no color attachment is currently bound,
-            // and attempting to read back if that's the case is an error. The error will be registered
-            // by getCurrentReadFormat.
-            if (!context->getCurrentReadFormatType(&currentFormat, &currentType))
-                return;
-
-            if (!(currentFormat == format && currentType == type) && !validReadFormatType(format, type))
-            {
-                return gl::error(GL_INVALID_OPERATION);
-            }
+            return;
+        }
 
-            context->readPixels(x, y, width, height, format, type, NULL, pixels);
+        gl::Error error = context->readPixels(x, y, width, height, format, type, NULL, pixels);
+        if (error.isError())
+        {
+            context->recordError(error);
+            return;
         }
     }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
-    }
 }
 
 void __stdcall glReleaseShaderCompiler(void)
 {
     EVENT("()");
 
-    try
-    {
-        gl::Shader::releaseCompiler();
-    }
-    catch(std::bad_alloc&)
+    gl::Context *context = gl::getNonLostContext();
+
+    if (context)
     {
-        return gl::error(GL_OUT_OF_MEMORY);
+        context->releaseShaderCompiler();
     }
 }
 
@@ -4848,63 +3765,16 @@ void __stdcall glRenderbufferStorageMultisampleANGLE(GLenum target, GLsizei samp
     EVENT("(GLenum target = 0x%X, GLsizei samples = %d, GLenum internalformat = 0x%X, GLsizei width = %d, GLsizei height = %d)",
           target, samples, internalformat, width, height);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        switch (target)
-        {
-          case GL_RENDERBUFFER:
-            break;
-          default:
-            return gl::error(GL_INVALID_ENUM);
-        }
-
-        if (!gl::IsColorRenderable(internalformat) && !gl::IsDepthRenderable(internalformat) && !gl::IsStencilRenderable(internalformat))
-        {
-            return gl::error(GL_INVALID_ENUM);
-        }
-
-        if (width < 0 || height < 0 || samples < 0)
+        if (!ValidateRenderbufferStorageParameters(context, target, samples, internalformat,
+                                                   width, height, true))
         {
-            return gl::error(GL_INVALID_VALUE);
+            return;
         }
 
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
-        {
-            if (width > context->getMaximumRenderbufferDimension() || 
-                height > context->getMaximumRenderbufferDimension() ||
-                samples > context->getMaxSupportedSamples())
-            {
-                return gl::error(GL_INVALID_VALUE);
-            }
-
-            GLuint handle = context->getRenderbufferHandle();
-            if (handle == 0)
-            {
-                return gl::error(GL_INVALID_OPERATION);
-            }
-
-            switch (internalformat)
-            {
-              case GL_DEPTH_COMPONENT16:
-              case GL_RGBA4:
-              case GL_RGB5_A1:
-              case GL_RGB565:
-              case GL_RGB8_OES:
-              case GL_RGBA8_OES:
-              case GL_STENCIL_INDEX8:
-              case GL_DEPTH24_STENCIL8_OES:
-                context->setRenderbufferStorage(width, height, internalformat, samples);
-                break;
-              default:
-                return gl::error(GL_INVALID_ENUM);
-            }
-        }
-    }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
+        context->setRenderbufferStorage(width, height, internalformat, samples);
     }
 }
 
@@ -4915,20 +3785,13 @@ void __stdcall glRenderbufferStorage(GLenum target, GLenum internalformat, GLsiz
 
 void __stdcall glSampleCoverage(GLclampf value, GLboolean invert)
 {
-    EVENT("(GLclampf value = %f, GLboolean invert = %d)", value, invert);
+    EVENT("(GLclampf value = %f, GLboolean invert = %u)", value, invert);
 
-    try
-    {
-        gl::Context* context = gl::getNonLostContext();
+    gl::Context* context = gl::getNonLostContext();
 
-        if (context)
-        {
-            context->setSampleCoverageParams(gl::clamp01(value), invert == GL_TRUE);
-        }
-    }
-    catch(std::bad_alloc&)
+    if (context)
     {
-        return gl::error(GL_OUT_OF_MEMORY);
+        context->getState().setSampleCoverageParams(gl::clamp01(value), invert == GL_TRUE);
     }
 }
 
@@ -4936,30 +3799,24 @@ void __stdcall glSetFenceNV(GLuint fence, GLenum condition)
 {
     EVENT("(GLuint fence = %d, GLenum condition = 0x%X)", fence, condition);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
         if (condition != GL_ALL_COMPLETED_NV)
         {
-            return gl::error(GL_INVALID_ENUM);
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
         }
 
-        gl::Context *context = gl::getNonLostContext();
+        gl::FenceNV *fenceObject = context->getFenceNV(fence);
 
-        if (context)
+        if (fenceObject == NULL)
         {
-            gl::Fence *fenceObject = context->getFence(fence);
-
-            if (fenceObject == NULL)
-            {
-                return gl::error(GL_INVALID_OPERATION);
-            }
-
-            fenceObject->setFence(condition);    
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
         }
-    }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
+
+        fenceObject->setFence(condition);
     }
 }
 
@@ -4967,23 +3824,16 @@ void __stdcall glScissor(GLint x, GLint y, GLsizei width, GLsizei height)
 {
     EVENT("(GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d)", x, y, width, height);
 
-    try
+    gl::Context* context = gl::getNonLostContext();
+    if (context)
     {
         if (width < 0 || height < 0)
         {
-            return gl::error(GL_INVALID_VALUE);
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
         }
 
-        gl::Context* context = gl::getNonLostContext();
-
-        if (context)
-        {
-            context->setScissorParams(x, y, width, height);
-        }
-    }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
+        context->getState().setScissorParams(x, y, width, height);
     }
 }
 
@@ -4993,53 +3843,52 @@ void __stdcall glShaderBinary(GLsizei n, const GLuint* shaders, GLenum binaryfor
           "const GLvoid* binary = 0x%0.8p, GLsizei length = %d)",
           n, shaders, binaryformat, binary, length);
 
-    try
+    gl::Context* context = gl::getNonLostContext();
+    if (context)
     {
+        const std::vector<GLenum> &shaderBinaryFormats = context->getCaps().shaderBinaryFormats;
+        if (std::find(shaderBinaryFormats.begin(), shaderBinaryFormats.end(), binaryformat) == shaderBinaryFormats.end())
+        {
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
+        }
+
         // No binary shader formats are supported.
-        return gl::error(GL_INVALID_ENUM);
-    }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
+        UNIMPLEMENTED();
     }
 }
 
-void __stdcall glShaderSource(GLuint shader, GLsizei count, const GLchar** string, const GLint* length)
+void __stdcall glShaderSource(GLuint shader, GLsizei count, const GLchar* const* string, const GLint* length)
 {
     EVENT("(GLuint shader = %d, GLsizei count = %d, const GLchar** string = 0x%0.8p, const GLint* length = 0x%0.8p)",
           shader, count, string, length);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
         if (count < 0)
         {
-            return gl::error(GL_INVALID_VALUE);
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
         }
 
-        gl::Context *context = gl::getNonLostContext();
+        gl::Shader *shaderObject = context->getShader(shader);
 
-        if (context)
+        if (!shaderObject)
         {
-            gl::Shader *shaderObject = context->getShader(shader);
-
-            if (!shaderObject)
+            if (context->getProgram(shader))
             {
-                if (context->getProgram(shader))
-                {
-                    return gl::error(GL_INVALID_OPERATION);
-                }
-                else
-                {
-                    return gl::error(GL_INVALID_VALUE);
-                }
+                context->recordError(gl::Error(GL_INVALID_OPERATION));
+                return;
+            }
+            else
+            {
+                context->recordError(gl::Error(GL_INVALID_VALUE));
+                return;
             }
-
-            shaderObject->setSource(count, string, length);
         }
-    }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
+
+        shaderObject->setSource(count, string, length);
     }
 }
 
@@ -5052,7 +3901,8 @@ void __stdcall glStencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint
 {
     EVENT("(GLenum face = 0x%X, GLenum func = 0x%X, GLint ref = %d, GLuint mask = %d)", face, func, ref, mask);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
         switch (face)
         {
@@ -5060,8 +3910,10 @@ void __stdcall glStencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint
           case GL_BACK:
           case GL_FRONT_AND_BACK:
             break;
+
           default:
-            return gl::error(GL_INVALID_ENUM);
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
         }
 
         switch (func)
@@ -5075,29 +3927,22 @@ void __stdcall glStencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint
           case GL_GREATER:
           case GL_NOTEQUAL:
             break;
+
           default:
-            return gl::error(GL_INVALID_ENUM);
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
         }
 
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
+        if (face == GL_FRONT || face == GL_FRONT_AND_BACK)
         {
-            if (face == GL_FRONT || face == GL_FRONT_AND_BACK)
-            {
-                context->setStencilParams(func, ref, mask);
-            }
+            context->getState().setStencilParams(func, ref, mask);
+        }
 
-            if (face == GL_BACK || face == GL_FRONT_AND_BACK)
-            {
-                context->setStencilBackParams(func, ref, mask);
-            }
+        if (face == GL_BACK || face == GL_FRONT_AND_BACK)
+        {
+            context->getState().setStencilBackParams(func, ref, mask);
         }
     }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
-    }
 }
 
 void __stdcall glStencilMask(GLuint mask)
@@ -5109,7 +3954,8 @@ void __stdcall glStencilMaskSeparate(GLenum face, GLuint mask)
 {
     EVENT("(GLenum face = 0x%X, GLuint mask = %d)", face, mask);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
         switch (face)
         {
@@ -5117,29 +3963,22 @@ void __stdcall glStencilMaskSeparate(GLenum face, GLuint mask)
           case GL_BACK:
           case GL_FRONT_AND_BACK:
             break;
+
           default:
-            return gl::error(GL_INVALID_ENUM);
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
         }
 
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
+        if (face == GL_FRONT || face == GL_FRONT_AND_BACK)
         {
-            if (face == GL_FRONT || face == GL_FRONT_AND_BACK)
-            {
-                context->setStencilWritemask(mask);
-            }
+            context->getState().setStencilWritemask(mask);
+        }
 
-            if (face == GL_BACK || face == GL_FRONT_AND_BACK)
-            {
-                context->setStencilBackWritemask(mask);
-            }
+        if (face == GL_BACK || face == GL_FRONT_AND_BACK)
+        {
+            context->getState().setStencilBackWritemask(mask);
         }
     }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
-    }
 }
 
 void __stdcall glStencilOp(GLenum fail, GLenum zfail, GLenum zpass)
@@ -5152,7 +3991,8 @@ void __stdcall glStencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenu
     EVENT("(GLenum face = 0x%X, GLenum fail = 0x%X, GLenum zfail = 0x%X, GLenum zpas = 0x%Xs)",
           face, fail, zfail, zpass);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
         switch (face)
         {
@@ -5160,8 +4000,10 @@ void __stdcall glStencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenu
           case GL_BACK:
           case GL_FRONT_AND_BACK:
             break;
+
           default:
-            return gl::error(GL_INVALID_ENUM);
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
         }
 
         switch (fail)
@@ -5175,8 +4017,10 @@ void __stdcall glStencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenu
           case GL_INCR_WRAP:
           case GL_DECR_WRAP:
             break;
+
           default:
-            return gl::error(GL_INVALID_ENUM);
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
         }
 
         switch (zfail)
@@ -5190,8 +4034,10 @@ void __stdcall glStencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenu
           case GL_INCR_WRAP:
           case GL_DECR_WRAP:
             break;
+
           default:
-            return gl::error(GL_INVALID_ENUM);
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
         }
 
         switch (zpass)
@@ -5205,56 +4051,48 @@ void __stdcall glStencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenu
           case GL_INCR_WRAP:
           case GL_DECR_WRAP:
             break;
+
           default:
-            return gl::error(GL_INVALID_ENUM);
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
         }
 
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
+        if (face == GL_FRONT || face == GL_FRONT_AND_BACK)
         {
-            if (face == GL_FRONT || face == GL_FRONT_AND_BACK)
-            {
-                context->setStencilOperations(fail, zfail, zpass);
-            }
+            context->getState().setStencilOperations(fail, zfail, zpass);
+        }
 
-            if (face == GL_BACK || face == GL_FRONT_AND_BACK)
-            {
-                context->setStencilBackOperations(fail, zfail, zpass);
-            }
+        if (face == GL_BACK || face == GL_FRONT_AND_BACK)
+        {
+            context->getState().setStencilBackOperations(fail, zfail, zpass);
         }
     }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
-    }
 }
 
 GLboolean __stdcall glTestFenceNV(GLuint fence)
 {
     EVENT("(GLuint fence = %d)", fence);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        gl::Context *context = gl::getNonLostContext();
+        gl::FenceNV *fenceObject = context->getFenceNV(fence);
 
-        if (context)
+        if (fenceObject == NULL)
         {
-            gl::Fence *fenceObject = context->getFence(fence);
-
-            if (fenceObject == NULL)
-            {
-                return gl::error(GL_INVALID_OPERATION, GL_TRUE);
-            }
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return GL_TRUE;
+        }
 
-            return fenceObject->testFence();
+        if (fenceObject->isFence() != GL_TRUE)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return GL_TRUE;
         }
+
+        return fenceObject->testFence();
     }
-    catch(std::bad_alloc&)
-    {
-        gl::error(GL_OUT_OF_MEMORY);
-    }
-    
+
     return GL_TRUE;
 }
 
@@ -5262,365 +4100,116 @@ void __stdcall glTexImage2D(GLenum target, GLint level, GLint internalformat, GL
                             GLint border, GLenum format, GLenum type, const GLvoid* pixels)
 {
     EVENT("(GLenum target = 0x%X, GLint level = %d, GLint internalformat = %d, GLsizei width = %d, GLsizei height = %d, "
-          "GLint border = %d, GLenum format = 0x%X, GLenum type = 0x%X, const GLvoid* pixels =  0x%0.8p)",
+          "GLint border = %d, GLenum format = 0x%X, GLenum type = 0x%X, const GLvoid* pixels = 0x%0.8p)",
           target, level, internalformat, width, height, border, format, type, pixels);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        if (!validImageSize(level, width, height))
+        if (context->getClientVersion() < 3 &&
+            !ValidateES2TexImageParameters(context, target, level, internalformat, false, false,
+                                           0, 0, width, height, border, format, type, pixels))
         {
-            return gl::error(GL_INVALID_VALUE);
-        }
-
-        if (internalformat != GLint(format))
-        {
-            return gl::error(GL_INVALID_OPERATION);
+            return;
         }
 
-        // validate <type> by itself (used as secondary key below)
-        switch (type)
+        if (context->getClientVersion() >= 3 &&
+            !ValidateES3TexImageParameters(context, target, level, internalformat, false, false,
+                                           0, 0, 0, width, height, 1, border, format, type, pixels))
         {
-          case GL_UNSIGNED_BYTE:
-          case GL_UNSIGNED_SHORT_5_6_5:
-          case GL_UNSIGNED_SHORT_4_4_4_4:
-          case GL_UNSIGNED_SHORT_5_5_5_1:
-          case GL_UNSIGNED_SHORT:
-          case GL_UNSIGNED_INT:
-          case GL_UNSIGNED_INT_24_8_OES:
-          case GL_HALF_FLOAT_OES:
-          case GL_FLOAT:
-            break;
-          default:
-            return gl::error(GL_INVALID_ENUM);
+            return;
         }
 
-        // validate <format> + <type> combinations
-        // - invalid <format> -> sets INVALID_ENUM
-        // - invalid <format>+<type> combination -> sets INVALID_OPERATION
-        switch (format)
+        switch (target)
         {
-          case GL_ALPHA:
-          case GL_LUMINANCE:
-          case GL_LUMINANCE_ALPHA:
-            switch (type)
+          case GL_TEXTURE_2D:
             {
-              case GL_UNSIGNED_BYTE:
-              case GL_FLOAT:
-              case GL_HALF_FLOAT_OES:
-                break;
-              default:
-                return gl::error(GL_INVALID_OPERATION);
+                gl::Texture2D *texture = context->getTexture2D();
+                texture->setImage(level, width, height, internalformat, format, type, context->getState().getUnpackState(), pixels);
             }
             break;
-          case GL_RGB:
-            switch (type)
+          case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
             {
-              case GL_UNSIGNED_BYTE:
-              case GL_UNSIGNED_SHORT_5_6_5:
-              case GL_FLOAT:
-              case GL_HALF_FLOAT_OES:
-                break;
-              default:
-                return gl::error(GL_INVALID_OPERATION);
+                gl::TextureCubeMap *texture = context->getTextureCubeMap();
+                texture->setImagePosX(level, width, height, internalformat, format, type, context->getState().getUnpackState(), pixels);
             }
             break;
-          case GL_RGBA:
-            switch (type)
+          case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
             {
-              case GL_UNSIGNED_BYTE:
-              case GL_UNSIGNED_SHORT_4_4_4_4:
-              case GL_UNSIGNED_SHORT_5_5_5_1:
-              case GL_FLOAT:
-              case GL_HALF_FLOAT_OES:
-                break;
-              default:
-                return gl::error(GL_INVALID_OPERATION);
+                gl::TextureCubeMap *texture = context->getTextureCubeMap();
+                texture->setImageNegX(level, width, height, internalformat, format, type, context->getState().getUnpackState(), pixels);
             }
             break;
-          case GL_BGRA_EXT:
-            switch (type)
+          case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
             {
-              case GL_UNSIGNED_BYTE:
-                break;
-              default:
-                return gl::error(GL_INVALID_OPERATION);
+                gl::TextureCubeMap *texture = context->getTextureCubeMap();
+                texture->setImagePosY(level, width, height, internalformat, format, type, context->getState().getUnpackState(), pixels);
             }
             break;
-          case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:  // error cases for compressed textures are handled below
-          case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
-          case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
-          case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
-            break; 
-          case GL_DEPTH_COMPONENT:
-            switch (type)
+          case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
             {
-              case GL_UNSIGNED_SHORT:
-              case GL_UNSIGNED_INT:
-                break;
-              default:
-                return gl::error(GL_INVALID_OPERATION);
+                gl::TextureCubeMap *texture = context->getTextureCubeMap();
+                texture->setImageNegY(level, width, height, internalformat, format, type, context->getState().getUnpackState(), pixels);
             }
             break;
-          case GL_DEPTH_STENCIL_OES:
-            switch (type)
+          case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
             {
-              case GL_UNSIGNED_INT_24_8_OES:
-                break;
-              default:
-                return gl::error(GL_INVALID_OPERATION);
+                gl::TextureCubeMap *texture = context->getTextureCubeMap();
+                texture->setImagePosZ(level, width, height, internalformat, format, type, context->getState().getUnpackState(), pixels);
             }
             break;
-          default:
-            return gl::error(GL_INVALID_ENUM);
-        }
-
-        if (border != 0)
-        {
-            return gl::error(GL_INVALID_VALUE);
-        }
-
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
-        {
-            if (level > context->getMaximumTextureLevel())
-            {
-                return gl::error(GL_INVALID_VALUE);
-            }
-
-            switch (target)
-            {
-              case GL_TEXTURE_2D:
-                if (width > (context->getMaximumTextureDimension() >> level) ||
-                    height > (context->getMaximumTextureDimension() >> level))
-                {
-                    return gl::error(GL_INVALID_VALUE);
-                }
-                break;
-              case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
-              case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
-              case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
-              case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
-              case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
-              case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
-                if (width != height)
-                {
-                    return gl::error(GL_INVALID_VALUE);
-                }
-
-                if (width > (context->getMaximumCubeTextureDimension() >> level) ||
-                    height > (context->getMaximumCubeTextureDimension() >> level))
-                {
-                    return gl::error(GL_INVALID_VALUE);
-                }
-                break;
-              default:
-                return gl::error(GL_INVALID_ENUM);
-            }
-
-            switch (format) {
-              case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
-              case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
-                if (context->supportsDXT1Textures())
-                {
-                    return gl::error(GL_INVALID_OPERATION);
-                }
-                else
-                {
-                    return gl::error(GL_INVALID_ENUM);
-                }
-                break;
-              case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
-                if (context->supportsDXT3Textures())
-                {
-                    return gl::error(GL_INVALID_OPERATION);
-                }
-                else
-                {
-                    return gl::error(GL_INVALID_ENUM);
-                }
-                break;
-              case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
-                if (context->supportsDXT5Textures())
-                {
-                    return gl::error(GL_INVALID_OPERATION);
-                }
-                else
-                {
-                    return gl::error(GL_INVALID_ENUM);
-                }
-                break;
-              case GL_DEPTH_COMPONENT:
-              case GL_DEPTH_STENCIL_OES:
-                if (!context->supportsDepthTextures())
-                {
-                    return gl::error(GL_INVALID_VALUE);
-                }
-                if (target != GL_TEXTURE_2D)
-                {
-                    return gl::error(GL_INVALID_OPERATION);
-                }
-                // OES_depth_texture supports loading depth data and multiple levels,
-                // but ANGLE_depth_texture does not
-                if (pixels != NULL || level != 0)
-                {
-                    return gl::error(GL_INVALID_OPERATION);
-                }
-                break;
-              default:
-                break;
-            }
-
-            if (type == GL_FLOAT)
-            {
-                if (!context->supportsFloat32Textures())
-                {
-                    return gl::error(GL_INVALID_ENUM);
-                }
-            }
-            else if (type == GL_HALF_FLOAT_OES)
-            {
-                if (!context->supportsFloat16Textures())
-                {
-                    return gl::error(GL_INVALID_ENUM);
-                }
-            }
-
-            if (target == GL_TEXTURE_2D)
-            {
-                gl::Texture2D *texture = context->getTexture2D();
-
-                if (!texture)
-                {
-                    return gl::error(GL_INVALID_OPERATION);
-                }
-
-                if (texture->isImmutable())
-                {
-                    return gl::error(GL_INVALID_OPERATION);
-                }
-
-                texture->setImage(level, width, height, format, type, context->getUnpackAlignment(), pixels);
-            }
-            else
+          case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
             {
                 gl::TextureCubeMap *texture = context->getTextureCubeMap();
-
-                if (!texture)
-                {
-                    return gl::error(GL_INVALID_OPERATION);
-                }
-
-                if (texture->isImmutable())
-                {
-                    return gl::error(GL_INVALID_OPERATION);
-                }
-
-                switch (target)
-                {
-                  case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
-                    texture->setImagePosX(level, width, height, format, type, context->getUnpackAlignment(), pixels);
-                    break;
-                  case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
-                    texture->setImageNegX(level, width, height, format, type, context->getUnpackAlignment(), pixels);
-                    break;
-                  case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
-                    texture->setImagePosY(level, width, height, format, type, context->getUnpackAlignment(), pixels);
-                    break;
-                  case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
-                    texture->setImageNegY(level, width, height, format, type, context->getUnpackAlignment(), pixels);
-                    break;
-                  case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
-                    texture->setImagePosZ(level, width, height, format, type, context->getUnpackAlignment(), pixels);
-                    break;
-                  case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
-                    texture->setImageNegZ(level, width, height, format, type, context->getUnpackAlignment(), pixels);
-                    break;
-                  default: UNREACHABLE();
-                }
+                texture->setImageNegZ(level, width, height, internalformat, format, type, context->getState().getUnpackState(), pixels);
             }
+            break;
+          default: UNREACHABLE();
         }
     }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
-    }
 }
 
 void __stdcall glTexParameterf(GLenum target, GLenum pname, GLfloat param)
 {
     EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint param = %f)", target, pname, param);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
+        if (!ValidateTexParamParameters(context, pname, static_cast<GLint>(param)))
         {
-            gl::Texture *texture;
+            return;
+        }
 
-            switch (target)
-            {
-              case GL_TEXTURE_2D:
-                texture = context->getTexture2D();
-                break;
-              case GL_TEXTURE_CUBE_MAP:
-                texture = context->getTextureCubeMap();
-                break;
-              default:
-                return gl::error(GL_INVALID_ENUM);
-            }
+        gl::Texture *texture = context->getTargetTexture(target);
 
-            switch (pname)
-            {
-              case GL_TEXTURE_WRAP_S:
-                if (!texture->setWrapS((GLenum)param))
-                {
-                    return gl::error(GL_INVALID_ENUM);
-                }
-                break;
-              case GL_TEXTURE_WRAP_T:
-                if (!texture->setWrapT((GLenum)param))
-                {
-                    return gl::error(GL_INVALID_ENUM);
-                }
-                break;
-              case GL_TEXTURE_MIN_FILTER:
-                if (!texture->setMinFilter((GLenum)param))
-                {
-                    return gl::error(GL_INVALID_ENUM);
-                }
-                break;
-              case GL_TEXTURE_MAG_FILTER:
-                if (!texture->setMagFilter((GLenum)param))
-                {
-                    return gl::error(GL_INVALID_ENUM);
-                }
-                break;
-              case GL_TEXTURE_USAGE_ANGLE:
-                if (!texture->setUsage((GLenum)param))
-                {
-                    return gl::error(GL_INVALID_ENUM);
-                }
-                break;
-              case GL_TEXTURE_MAX_ANISOTROPY_EXT:
-                if (!context->supportsTextureFilterAnisotropy())
-                {
-                    return gl::error(GL_INVALID_ENUM);
-                }
-                if (!texture->setMaxAnisotropy((float)param, context->getTextureMaxAnisotropy()))
-                {
-                    return gl::error(GL_INVALID_VALUE);
-                }
-                break;
-              default:
-                return gl::error(GL_INVALID_ENUM);
-            }
+        if (!texture)
+        {
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
+        }
+
+        switch (pname)
+        {
+          case GL_TEXTURE_WRAP_S:               texture->getSamplerState().wrapS = gl::uiround<GLenum>(param);        break;
+          case GL_TEXTURE_WRAP_T:               texture->getSamplerState().wrapT = gl::uiround<GLenum>(param);        break;
+          case GL_TEXTURE_WRAP_R:               texture->getSamplerState().wrapR = gl::uiround<GLenum>(param);        break;
+          case GL_TEXTURE_MIN_FILTER:           texture->getSamplerState().minFilter = gl::uiround<GLenum>(param);    break;
+          case GL_TEXTURE_MAG_FILTER:           texture->getSamplerState().magFilter = gl::uiround<GLenum>(param);    break;
+          case GL_TEXTURE_USAGE_ANGLE:          texture->setUsage(gl::uiround<GLenum>(param));                        break;
+          case GL_TEXTURE_MAX_ANISOTROPY_EXT:   texture->getSamplerState().maxAnisotropy = std::min(param, context->getExtensions().maxTextureAnisotropy); break;
+          case GL_TEXTURE_COMPARE_MODE:         texture->getSamplerState().compareMode = gl::uiround<GLenum>(param);  break;
+          case GL_TEXTURE_COMPARE_FUNC:         texture->getSamplerState().compareFunc = gl::uiround<GLenum>(param);  break;
+          case GL_TEXTURE_SWIZZLE_R:            texture->getSamplerState().swizzleRed = gl::uiround<GLenum>(param);   break;
+          case GL_TEXTURE_SWIZZLE_G:            texture->getSamplerState().swizzleGreen = gl::uiround<GLenum>(param); break;
+          case GL_TEXTURE_SWIZZLE_B:            texture->getSamplerState().swizzleBlue = gl::uiround<GLenum>(param);  break;
+          case GL_TEXTURE_SWIZZLE_A:            texture->getSamplerState().swizzleAlpha = gl::uiround<GLenum>(param); break;
+          case GL_TEXTURE_BASE_LEVEL:           texture->getSamplerState().baseLevel = gl::iround<GLint>(param);      break;
+          case GL_TEXTURE_MAX_LEVEL:            texture->getSamplerState().maxLevel = gl::iround<GLint>(param);       break;
+          case GL_TEXTURE_MIN_LOD:              texture->getSamplerState().minLod = param;                            break;
+          case GL_TEXTURE_MAX_LOD:              texture->getSamplerState().maxLod = param;                            break;
+          default: UNREACHABLE(); break;
         }
-    }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
     }
 }
 
@@ -5633,76 +4222,43 @@ void __stdcall glTexParameteri(GLenum target, GLenum pname, GLint param)
 {
     EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint param = %d)", target, pname, param);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
+        if (!ValidateTexParamParameters(context, pname, param))
         {
-            gl::Texture *texture;
+            return;
+        }
 
-            switch (target)
-            {
-              case GL_TEXTURE_2D:
-                texture = context->getTexture2D();
-                break;
-              case GL_TEXTURE_CUBE_MAP:
-                texture = context->getTextureCubeMap();
-                break;
-              default:
-                return gl::error(GL_INVALID_ENUM);
-            }
+        gl::Texture *texture = context->getTargetTexture(target);
 
-            switch (pname)
-            {
-              case GL_TEXTURE_WRAP_S:
-                if (!texture->setWrapS((GLenum)param))
-                {
-                    return gl::error(GL_INVALID_ENUM);
-                }
-                break;
-              case GL_TEXTURE_WRAP_T:
-                if (!texture->setWrapT((GLenum)param))
-                {
-                    return gl::error(GL_INVALID_ENUM);
-                }
-                break;
-              case GL_TEXTURE_MIN_FILTER:
-                if (!texture->setMinFilter((GLenum)param))
-                {
-                    return gl::error(GL_INVALID_ENUM);
-                }
-                break;
-              case GL_TEXTURE_MAG_FILTER:
-                if (!texture->setMagFilter((GLenum)param))
-                {
-                    return gl::error(GL_INVALID_ENUM);
-                }
-                break;
-              case GL_TEXTURE_USAGE_ANGLE:
-                if (!texture->setUsage((GLenum)param))
-                {
-                    return gl::error(GL_INVALID_ENUM);
-                }
-                break;
-              case GL_TEXTURE_MAX_ANISOTROPY_EXT:
-                if (!context->supportsTextureFilterAnisotropy())
-                {
-                    return gl::error(GL_INVALID_ENUM);
-                }
-                if (!texture->setMaxAnisotropy((float)param, context->getTextureMaxAnisotropy()))
-                {
-                    return gl::error(GL_INVALID_VALUE);
-                }
-                break;
-              default:
-                return gl::error(GL_INVALID_ENUM);
-            }
+        if (!texture)
+        {
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
+        }
+
+        switch (pname)
+        {
+          case GL_TEXTURE_WRAP_S:               texture->getSamplerState().wrapS = (GLenum)param;        break;
+          case GL_TEXTURE_WRAP_T:               texture->getSamplerState().wrapT = (GLenum)param;        break;
+          case GL_TEXTURE_WRAP_R:               texture->getSamplerState().wrapR = (GLenum)param;        break;
+          case GL_TEXTURE_MIN_FILTER:           texture->getSamplerState().minFilter = (GLenum)param;    break;
+          case GL_TEXTURE_MAG_FILTER:           texture->getSamplerState().magFilter = (GLenum)param;    break;
+          case GL_TEXTURE_USAGE_ANGLE:          texture->setUsage((GLenum)param);                        break;
+          case GL_TEXTURE_MAX_ANISOTROPY_EXT:   texture->getSamplerState().maxAnisotropy = std::min((float)param, context->getExtensions().maxTextureAnisotropy); break;
+          case GL_TEXTURE_COMPARE_MODE:         texture->getSamplerState().compareMode = (GLenum)param;  break;
+          case GL_TEXTURE_COMPARE_FUNC:         texture->getSamplerState().compareFunc = (GLenum)param;  break;
+          case GL_TEXTURE_SWIZZLE_R:            texture->getSamplerState().swizzleRed = (GLenum)param;   break;
+          case GL_TEXTURE_SWIZZLE_G:            texture->getSamplerState().swizzleGreen = (GLenum)param; break;
+          case GL_TEXTURE_SWIZZLE_B:            texture->getSamplerState().swizzleBlue = (GLenum)param;  break;
+          case GL_TEXTURE_SWIZZLE_A:            texture->getSamplerState().swizzleAlpha = (GLenum)param; break;
+          case GL_TEXTURE_BASE_LEVEL:           texture->getSamplerState().baseLevel = param;            break;
+          case GL_TEXTURE_MAX_LEVEL:            texture->getSamplerState().maxLevel = param;             break;
+          case GL_TEXTURE_MIN_LOD:              texture->getSamplerState().minLod = (GLfloat)param;      break;
+          case GL_TEXTURE_MAX_LOD:              texture->getSamplerState().maxLod = (GLfloat)param;      break;
+          default: UNREACHABLE(); break;
         }
-    }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
     }
 }
 
@@ -5716,258 +4272,3258 @@ void __stdcall glTexStorage2DEXT(GLenum target, GLsizei levels, GLenum internalf
     EVENT("(GLenum target = 0x%X, GLsizei levels = %d, GLenum internalformat = 0x%X, GLsizei width = %d, GLsizei height = %d)",
            target, levels, internalformat, width, height);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        if (target != GL_TEXTURE_2D && target != GL_TEXTURE_CUBE_MAP)
+        if (!context->getExtensions().textureStorage)
         {
-            return gl::error(GL_INVALID_ENUM);
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
+
+        if (context->getClientVersion() < 3 &&
+            !ValidateES2TexStorageParameters(context, target, levels, internalformat, width, height))
+        {
+            return;
+        }
+
+        if (context->getClientVersion() >= 3 &&
+            !ValidateES3TexStorageParameters(context, target, levels, internalformat, width, height, 1))
+        {
+            return;
+        }
+
+        switch (target)
+        {
+          case GL_TEXTURE_2D:
+            {
+                gl::Texture2D *texture2d = context->getTexture2D();
+                texture2d->storage(levels, internalformat, width, height);
+            }
+            break;
+
+          case GL_TEXTURE_CUBE_MAP:
+            {
+                gl::TextureCubeMap *textureCube = context->getTextureCubeMap();
+                textureCube->storage(levels, internalformat, width);
+            }
+            break;
+
+          default:
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
+        }
+    }
+}
+
+void __stdcall glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+                               GLenum format, GLenum type, const GLvoid* pixels)
+{
+    EVENT("(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, "
+          "GLsizei width = %d, GLsizei height = %d, GLenum format = 0x%X, GLenum type = 0x%X, "
+          "const GLvoid* pixels = 0x%0.8p)",
+           target, level, xoffset, yoffset, width, height, format, type, pixels);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (context->getClientVersion() < 3 &&
+            !ValidateES2TexImageParameters(context, target, level, GL_NONE, false, true,
+                                           xoffset, yoffset, width, height, 0, format, type, pixels))
+        {
+            return;
+        }
+
+        if (context->getClientVersion() >= 3 &&
+            !ValidateES3TexImageParameters(context, target, level, GL_NONE, false, true,
+                                           xoffset, yoffset, 0, width, height, 1, 0, format, type, pixels))
+        {
+            return;
+        }
+
+        // Zero sized uploads are valid but no-ops
+        if (width == 0 || height == 0)
+        {
+            return;
+        }
+
+        switch (target)
+        {
+          case GL_TEXTURE_2D:
+            {
+                gl::Texture2D *texture = context->getTexture2D();
+                texture->subImage(level, xoffset, yoffset, width, height, format, type, context->getState().getUnpackState(), pixels);
+            }
+            break;
+
+          case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
+          case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
+          case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
+          case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
+          case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
+          case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
+            {
+                gl::TextureCubeMap *texture = context->getTextureCubeMap();
+                texture->subImage(target, level, xoffset, yoffset, width, height, format, type, context->getState().getUnpackState(), pixels);
+            }
+            break;
+
+          default:
+            UNREACHABLE();
+        }
+    }
+}
+
+void __stdcall glUniform1f(GLint location, GLfloat x)
+{
+    glUniform1fv(location, 1, &x);
+}
+
+void __stdcall glUniform1fv(GLint location, GLsizei count, const GLfloat* v)
+{
+    EVENT("(GLint location = %d, GLsizei count = %d, const GLfloat* v = 0x%0.8p)", location, count, v);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (!ValidateUniform(context, GL_FLOAT, location, count))
+        {
+            return;
+        }
+
+        gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary();
+        programBinary->setUniform1fv(location, count, v);
+    }
+}
+
+void __stdcall glUniform1i(GLint location, GLint x)
+{
+    glUniform1iv(location, 1, &x);
+}
+
+void __stdcall glUniform1iv(GLint location, GLsizei count, const GLint* v)
+{
+    EVENT("(GLint location = %d, GLsizei count = %d, const GLint* v = 0x%0.8p)", location, count, v);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (!ValidateUniform(context, GL_INT, location, count))
+        {
+            return;
+        }
+
+        gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary();
+        programBinary->setUniform1iv(location, count, v);
+    }
+}
+
+void __stdcall glUniform2f(GLint location, GLfloat x, GLfloat y)
+{
+    GLfloat xy[2] = {x, y};
+
+    glUniform2fv(location, 1, xy);
+}
+
+void __stdcall glUniform2fv(GLint location, GLsizei count, const GLfloat* v)
+{
+    EVENT("(GLint location = %d, GLsizei count = %d, const GLfloat* v = 0x%0.8p)", location, count, v);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (!ValidateUniform(context, GL_FLOAT_VEC2, location, count))
+        {
+            return;
+        }
+
+        gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary();
+        programBinary->setUniform2fv(location, count, v);
+    }
+}
+
+void __stdcall glUniform2i(GLint location, GLint x, GLint y)
+{
+    GLint xy[2] = {x, y};
+
+    glUniform2iv(location, 1, xy);
+}
+
+void __stdcall glUniform2iv(GLint location, GLsizei count, const GLint* v)
+{
+    EVENT("(GLint location = %d, GLsizei count = %d, const GLint* v = 0x%0.8p)", location, count, v);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (!ValidateUniform(context, GL_INT_VEC2, location, count))
+        {
+            return;
+        }
+
+        gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary();
+        programBinary->setUniform2iv(location, count, v);
+    }
+}
+
+void __stdcall glUniform3f(GLint location, GLfloat x, GLfloat y, GLfloat z)
+{
+    GLfloat xyz[3] = {x, y, z};
+
+    glUniform3fv(location, 1, xyz);
+}
+
+void __stdcall glUniform3fv(GLint location, GLsizei count, const GLfloat* v)
+{
+    EVENT("(GLint location = %d, GLsizei count = %d, const GLfloat* v = 0x%0.8p)", location, count, v);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (!ValidateUniform(context, GL_FLOAT_VEC3, location, count))
+        {
+            return;
+        }
+
+        gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary();
+        programBinary->setUniform3fv(location, count, v);
+    }
+}
+
+void __stdcall glUniform3i(GLint location, GLint x, GLint y, GLint z)
+{
+    GLint xyz[3] = {x, y, z};
+
+    glUniform3iv(location, 1, xyz);
+}
+
+void __stdcall glUniform3iv(GLint location, GLsizei count, const GLint* v)
+{
+    EVENT("(GLint location = %d, GLsizei count = %d, const GLint* v = 0x%0.8p)", location, count, v);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (!ValidateUniform(context, GL_INT_VEC3, location, count))
+        {
+            return;
+        }
+
+        gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary();
+        programBinary->setUniform3iv(location, count, v);
+    }
+}
+
+void __stdcall glUniform4f(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+{
+    GLfloat xyzw[4] = {x, y, z, w};
+
+    glUniform4fv(location, 1, xyzw);
+}
+
+void __stdcall glUniform4fv(GLint location, GLsizei count, const GLfloat* v)
+{
+    EVENT("(GLint location = %d, GLsizei count = %d, const GLfloat* v = 0x%0.8p)", location, count, v);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (!ValidateUniform(context, GL_FLOAT_VEC4, location, count))
+        {
+            return;
+        }
+
+        gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary();
+        programBinary->setUniform4fv(location, count, v);
+    }
+}
+
+void __stdcall glUniform4i(GLint location, GLint x, GLint y, GLint z, GLint w)
+{
+    GLint xyzw[4] = {x, y, z, w};
+
+    glUniform4iv(location, 1, xyzw);
+}
+
+void __stdcall glUniform4iv(GLint location, GLsizei count, const GLint* v)
+{
+    EVENT("(GLint location = %d, GLsizei count = %d, const GLint* v = 0x%0.8p)", location, count, v);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (!ValidateUniform(context, GL_INT_VEC4, location, count))
+        {
+            return;
+        }
+
+        gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary();
+        programBinary->setUniform4iv(location, count, v);
+    }
+}
+
+void __stdcall glUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+{
+    EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %u, const GLfloat* value = 0x%0.8p)",
+          location, count, transpose, value);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (!ValidateUniformMatrix(context, GL_FLOAT_MAT2, location, count, transpose))
+        {
+            return;
+        }
+
+        gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary();
+        programBinary->setUniformMatrix2fv(location, count, transpose, value);
+    }
+}
+
+void __stdcall glUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+{
+    EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %u, const GLfloat* value = 0x%0.8p)",
+          location, count, transpose, value);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (!ValidateUniformMatrix(context, GL_FLOAT_MAT3, location, count, transpose))
+        {
+            return;
+        }
+
+        gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary();
+        programBinary->setUniformMatrix3fv(location, count, transpose, value);
+    }
+}
+
+void __stdcall glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+{
+    EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %u, const GLfloat* value = 0x%0.8p)",
+          location, count, transpose, value);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (!ValidateUniformMatrix(context, GL_FLOAT_MAT4, location, count, transpose))
+        {
+            return;
+        }
+
+        gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary();
+        programBinary->setUniformMatrix4fv(location, count, transpose, value);
+    }
+}
+
+void __stdcall glUseProgram(GLuint program)
+{
+    EVENT("(GLuint program = %d)", program);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        gl::Program *programObject = context->getProgram(program);
+
+        if (!programObject && program != 0)
+        {
+            if (context->getShader(program))
+            {
+                context->recordError(gl::Error(GL_INVALID_OPERATION));
+                return;
+            }
+            else
+            {
+                context->recordError(gl::Error(GL_INVALID_VALUE));
+                return;
+            }
+        }
+
+        if (program != 0 && !programObject->isLinked())
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
+
+        context->useProgram(program);
+    }
+}
+
+void __stdcall glValidateProgram(GLuint program)
+{
+    EVENT("(GLuint program = %d)", program);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        gl::Program *programObject = context->getProgram(program);
+
+        if (!programObject)
+        {
+            if (context->getShader(program))
+            {
+                context->recordError(gl::Error(GL_INVALID_OPERATION));
+                return;
+            }
+            else
+            {
+                context->recordError(gl::Error(GL_INVALID_VALUE));
+                return;
+            }
+        }
+
+        programObject->validate(context->getCaps());
+    }
+}
+
+void __stdcall glVertexAttrib1f(GLuint index, GLfloat x)
+{
+    EVENT("(GLuint index = %d, GLfloat x = %f)", index, x);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (index >= gl::MAX_VERTEX_ATTRIBS)
+        {
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
+        }
+
+        GLfloat vals[4] = { x, 0, 0, 1 };
+        context->getState().setVertexAttribf(index, vals);
+    }
+}
+
+void __stdcall glVertexAttrib1fv(GLuint index, const GLfloat* values)
+{
+    EVENT("(GLuint index = %d, const GLfloat* values = 0x%0.8p)", index, values);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (index >= gl::MAX_VERTEX_ATTRIBS)
+        {
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
+        }
+
+        GLfloat vals[4] = { values[0], 0, 0, 1 };
+        context->getState().setVertexAttribf(index, vals);
+    }
+}
+
+void __stdcall glVertexAttrib2f(GLuint index, GLfloat x, GLfloat y)
+{
+    EVENT("(GLuint index = %d, GLfloat x = %f, GLfloat y = %f)", index, x, y);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (index >= gl::MAX_VERTEX_ATTRIBS)
+        {
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
+        }
+
+        GLfloat vals[4] = { x, y, 0, 1 };
+        context->getState().setVertexAttribf(index, vals);
+    }
+}
+
+void __stdcall glVertexAttrib2fv(GLuint index, const GLfloat* values)
+{
+    EVENT("(GLuint index = %d, const GLfloat* values = 0x%0.8p)", index, values);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (index >= gl::MAX_VERTEX_ATTRIBS)
+        {
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
+        }
+
+        GLfloat vals[4] = { values[0], values[1], 0, 1 };
+        context->getState().setVertexAttribf(index, vals);
+    }
+}
+
+void __stdcall glVertexAttrib3f(GLuint index, GLfloat x, GLfloat y, GLfloat z)
+{
+    EVENT("(GLuint index = %d, GLfloat x = %f, GLfloat y = %f, GLfloat z = %f)", index, x, y, z);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (index >= gl::MAX_VERTEX_ATTRIBS)
+        {
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
+        }
+
+        GLfloat vals[4] = { x, y, z, 1 };
+        context->getState().setVertexAttribf(index, vals);
+    }
+}
+
+void __stdcall glVertexAttrib3fv(GLuint index, const GLfloat* values)
+{
+    EVENT("(GLuint index = %d, const GLfloat* values = 0x%0.8p)", index, values);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (index >= gl::MAX_VERTEX_ATTRIBS)
+        {
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
+        }
+
+        GLfloat vals[4] = { values[0], values[1], values[2], 1 };
+        context->getState().setVertexAttribf(index, vals);
+    }
+}
+
+void __stdcall glVertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+{
+    EVENT("(GLuint index = %d, GLfloat x = %f, GLfloat y = %f, GLfloat z = %f, GLfloat w = %f)", index, x, y, z, w);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (index >= gl::MAX_VERTEX_ATTRIBS)
+        {
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
+        }
+
+        GLfloat vals[4] = { x, y, z, w };
+        context->getState().setVertexAttribf(index, vals);
+    }
+}
+
+void __stdcall glVertexAttrib4fv(GLuint index, const GLfloat* values)
+{
+    EVENT("(GLuint index = %d, const GLfloat* values = 0x%0.8p)", index, values);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (index >= gl::MAX_VERTEX_ATTRIBS)
+        {
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
+        }
+
+        context->getState().setVertexAttribf(index, values);
+    }
+}
+
+void __stdcall glVertexAttribDivisorANGLE(GLuint index, GLuint divisor)
+{
+    EVENT("(GLuint index = %d, GLuint divisor = %d)", index, divisor);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (index >= gl::MAX_VERTEX_ATTRIBS)
+        {
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
+        }
+
+        context->setVertexAttribDivisor(index, divisor);
+    }
+}
+
+void __stdcall glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr)
+{
+    EVENT("(GLuint index = %d, GLint size = %d, GLenum type = 0x%X, "
+          "GLboolean normalized = %u, GLsizei stride = %d, const GLvoid* ptr = 0x%0.8p)",
+          index, size, type, normalized, stride, ptr);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (index >= gl::MAX_VERTEX_ATTRIBS)
+        {
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
+        }
+
+        if (size < 1 || size > 4)
+        {
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
+        }
+
+        switch (type)
+        {
+          case GL_BYTE:
+          case GL_UNSIGNED_BYTE:
+          case GL_SHORT:
+          case GL_UNSIGNED_SHORT:
+          case GL_FIXED:
+          case GL_FLOAT:
+            break;
+
+          case GL_HALF_FLOAT:
+          case GL_INT:
+          case GL_UNSIGNED_INT:
+          case GL_INT_2_10_10_10_REV:
+          case GL_UNSIGNED_INT_2_10_10_10_REV:
+            if (context->getClientVersion() < 3)
+            {
+                context->recordError(gl::Error(GL_INVALID_ENUM));
+                return;
+            }
+            break;
+
+          default:
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
+        }
+
+        if (stride < 0)
+        {
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
+        }
+
+        if ((type == GL_INT_2_10_10_10_REV || type == GL_UNSIGNED_INT_2_10_10_10_REV) && size != 4)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
+
+        // [OpenGL ES 3.0.2] Section 2.8 page 24:
+        // An INVALID_OPERATION error is generated when a non-zero vertex array object
+        // is bound, zero is bound to the ARRAY_BUFFER buffer object binding point,
+        // and the pointer argument is not NULL.
+        if (context->getState().getVertexArray()->id() != 0 && context->getState().getArrayBufferId() == 0 && ptr != NULL)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
+
+        context->getState().setVertexAttribState(index, context->getState().getTargetBuffer(GL_ARRAY_BUFFER), size, type,
+                                                 normalized == GL_TRUE, false, stride, ptr);
+    }
+}
+
+void __stdcall glViewport(GLint x, GLint y, GLsizei width, GLsizei height)
+{
+    EVENT("(GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d)", x, y, width, height);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (width < 0 || height < 0)
+        {
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
+        }
+
+        context->getState().setViewportParams(x, y, width, height);
+    }
+}
+
+// OpenGL ES 3.0 functions
+
+void __stdcall glReadBuffer(GLenum mode)
+{
+    EVENT("(GLenum mode = 0x%X)", mode);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (context->getClientVersion() < 3)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
+
+        // glReadBuffer
+        UNIMPLEMENTED();
+    }
+}
+
+void __stdcall glDrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid* indices)
+{
+    EVENT("(GLenum mode = 0x%X, GLuint start = %u, GLuint end = %u, GLsizei count = %d, GLenum type = 0x%X, "
+          "const GLvoid* indices = 0x%0.8p)", mode, start, end, count, type, indices);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (context->getClientVersion() < 3)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
+
+        // glDrawRangeElements
+        UNIMPLEMENTED();
+    }
+}
+
+void __stdcall glTexImage3D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid* pixels)
+{
+    EVENT("(GLenum target = 0x%X, GLint level = %d, GLint internalformat = %d, GLsizei width = %d, "
+          "GLsizei height = %d, GLsizei depth = %d, GLint border = %d, GLenum format = 0x%X, "
+          "GLenum type = 0x%X, const GLvoid* pixels = 0x%0.8p)",
+          target, level, internalformat, width, height, depth, border, format, type, pixels);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (context->getClientVersion() < 3)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
+
+        // validateES3TexImageFormat sets the error code if there is an error
+        if (!ValidateES3TexImageParameters(context, target, level, internalformat, false, false,
+                                           0, 0, 0, width, height, depth, border, format, type, pixels))
+        {
+            return;
+        }
+
+        switch(target)
+        {
+          case GL_TEXTURE_3D:
+            {
+                gl::Texture3D *texture = context->getTexture3D();
+                texture->setImage(level, width, height, depth, internalformat, format, type, context->getState().getUnpackState(), pixels);
+            }
+            break;
+
+          case GL_TEXTURE_2D_ARRAY:
+            {
+                gl::Texture2DArray *texture = context->getTexture2DArray();
+                texture->setImage(level, width, height, depth, internalformat, format, type, context->getState().getUnpackState(), pixels);
+            }
+            break;
+
+          default:
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
+        }
+    }
+}
+
+void __stdcall glTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid* pixels)
+{
+    EVENT("(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, "
+          "GLint zoffset = %d, GLsizei width = %d, GLsizei height = %d, GLsizei depth = %d, "
+          "GLenum format = 0x%X, GLenum type = 0x%X, const GLvoid* pixels = 0x%0.8p)",
+          target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (context->getClientVersion() < 3)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
+
+        // validateES3TexImageFormat sets the error code if there is an error
+        if (!ValidateES3TexImageParameters(context, target, level, GL_NONE, false, true,
+                                           xoffset, yoffset, zoffset, width, height, depth, 0,
+                                           format, type, pixels))
+        {
+            return;
+        }
+
+        // Zero sized uploads are valid but no-ops
+        if (width == 0 || height == 0 || depth == 0)
+        {
+            return;
+        }
+
+        switch(target)
+        {
+          case GL_TEXTURE_3D:
+            {
+                gl::Texture3D *texture = context->getTexture3D();
+                texture->subImage(level, xoffset, yoffset, zoffset, width, height, depth, format, type, context->getState().getUnpackState(), pixels);
+            }
+            break;
+
+          case GL_TEXTURE_2D_ARRAY:
+            {
+                gl::Texture2DArray *texture = context->getTexture2DArray();
+                texture->subImage(level, xoffset, yoffset, zoffset, width, height, depth, format, type, context->getState().getUnpackState(), pixels);
+            }
+            break;
+
+          default:
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
+        }
+    }
+}
+
+void __stdcall glCopyTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height)
+{
+    EVENT("(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, "
+          "GLint zoffset = %d, GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d)",
+          target, level, xoffset, yoffset, zoffset, x, y, width, height);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (context->getClientVersion() < 3)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
+
+        if (!ValidateES3CopyTexImageParameters(context, target, level, GL_NONE, true, xoffset, yoffset, zoffset,
+                                               x, y, width, height, 0))
+        {
+            return;
+        }
+
+        gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
+        gl::Texture *texture = NULL;
+        switch (target)
+        {
+          case GL_TEXTURE_3D:
+            texture = context->getTexture3D();
+            break;
+
+          case GL_TEXTURE_2D_ARRAY:
+            texture = context->getTexture2DArray();
+            break;
+
+          default:
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
+        }
+
+        texture->copySubImage(target, level, xoffset, yoffset, zoffset, x, y, width, height, framebuffer);
+    }
+}
+
+void __stdcall glCompressedTexImage3D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid* data)
+{
+    EVENT("(GLenum target = 0x%X, GLint level = %d, GLenum internalformat = 0x%X, GLsizei width = %d, "
+          "GLsizei height = %d, GLsizei depth = %d, GLint border = %d, GLsizei imageSize = %d, "
+          "const GLvoid* data = 0x%0.8p)",
+          target, level, internalformat, width, height, depth, border, imageSize, data);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (context->getClientVersion() < 3)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
+
+        const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
+        if (imageSize < 0 || static_cast<GLuint>(imageSize) != formatInfo.computeBlockSize(GL_UNSIGNED_BYTE, width, height))
+        {
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
+        }
+
+        // validateES3TexImageFormat sets the error code if there is an error
+        if (!ValidateES3TexImageParameters(context, target, level, internalformat, true, false,
+                                           0, 0, 0, width, height, depth, border, GL_NONE, GL_NONE, data))
+        {
+            return;
+        }
+
+        switch(target)
+        {
+          case GL_TEXTURE_3D:
+            {
+                gl::Texture3D *texture = context->getTexture3D();
+                texture->setCompressedImage(level, internalformat, width, height, depth, imageSize, data);
+            }
+            break;
+
+          case GL_TEXTURE_2D_ARRAY:
+            {
+                gl::Texture2DArray *texture = context->getTexture2DArray();
+                texture->setCompressedImage(level, internalformat, width, height, depth, imageSize, data);
+            }
+            break;
+
+          default:
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
+        }
+    }
+}
+
+void __stdcall glCompressedTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid* data)
+{
+    EVENT("(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, "
+        "GLint zoffset = %d, GLsizei width = %d, GLsizei height = %d, GLsizei depth = %d, "
+        "GLenum format = 0x%X, GLsizei imageSize = %d, const GLvoid* data = 0x%0.8p)",
+        target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (context->getClientVersion() < 3)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
+
+        const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
+        if (imageSize < 0 || static_cast<GLuint>(imageSize) != formatInfo.computeBlockSize(GL_UNSIGNED_BYTE, width, height))
+        {
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
+        }
+
+        if (!data)
+        {
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
+        }
+
+        // validateES3TexImageFormat sets the error code if there is an error
+        if (!ValidateES3TexImageParameters(context, target, level, GL_NONE, true, true,
+                                           0, 0, 0, width, height, depth, 0, GL_NONE, GL_NONE, data))
+        {
+            return;
+        }
+
+        // Zero sized uploads are valid but no-ops
+        if (width == 0 || height == 0)
+        {
+            return;
+        }
+
+        switch(target)
+        {
+          case GL_TEXTURE_3D:
+            {
+                gl::Texture3D *texture = context->getTexture3D();
+                texture->subImageCompressed(level, xoffset, yoffset, zoffset, width, height, depth,
+                                            format, imageSize, data);
+            }
+            break;
+
+          case GL_TEXTURE_2D_ARRAY:
+            {
+                gl::Texture2DArray *texture = context->getTexture2DArray();
+                texture->subImageCompressed(level, xoffset, yoffset, zoffset, width, height, depth,
+                                            format, imageSize, data);
+            }
+            break;
+
+          default:
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
+        }
+    }
+}
+
+void __stdcall glGenQueries(GLsizei n, GLuint* ids)
+{
+    EVENT("(GLsizei n = %d, GLuint* ids = 0x%0.8p)", n, ids);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (context->getClientVersion() < 3)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
+
+        if (n < 0)
+        {
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
+        }
+
+        for (GLsizei i = 0; i < n; i++)
+        {
+            ids[i] = context->createQuery();
+        }
+    }
+}
+
+void __stdcall glDeleteQueries(GLsizei n, const GLuint* ids)
+{
+    EVENT("(GLsizei n = %d, GLuint* ids = 0x%0.8p)", n, ids);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (context->getClientVersion() < 3)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
+
+        if (n < 0)
+        {
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
+        }
+
+        for (GLsizei i = 0; i < n; i++)
+        {
+            context->deleteQuery(ids[i]);
+        }
+    }
+}
+
+GLboolean __stdcall glIsQuery(GLuint id)
+{
+    EVENT("(GLuint id = %u)", id);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (context->getClientVersion() < 3)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return GL_FALSE;
+        }
+
+        return (context->getQuery(id, false, GL_NONE) != NULL) ? GL_TRUE : GL_FALSE;
+    }
+
+    return GL_FALSE;
+}
+
+void __stdcall glBeginQuery(GLenum target, GLuint id)
+{
+    EVENT("(GLenum target = 0x%X, GLuint id = %u)", target, id);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (context->getClientVersion() < 3)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
+
+        if (!ValidateBeginQuery(context, target, id))
+        {
+            return;
+        }
+
+        gl::Error error = context->beginQuery(target, id);
+        if (error.isError())
+        {
+            context->recordError(error);
+            return;
+        }
+    }
+}
+
+void __stdcall glEndQuery(GLenum target)
+{
+    EVENT("(GLenum target = 0x%X)", target);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (context->getClientVersion() < 3)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
+
+        if (!ValidateEndQuery(context, target))
+        {
+            return;
+        }
+
+        gl::Error error = context->endQuery(target);
+        if (error.isError())
+        {
+            context->recordError(error);
+            return;
+        }
+    }
+}
+
+void __stdcall glGetQueryiv(GLenum target, GLenum pname, GLint* params)
+{
+    EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", target, pname, params);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (context->getClientVersion() < 3)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
+
+        if (!ValidQueryType(context, target))
+        {
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
+        }
+
+        switch (pname)
+        {
+          case GL_CURRENT_QUERY:
+            params[0] = static_cast<GLint>(context->getState().getActiveQueryId(target));
+            break;
+
+          default:
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
+        }
+    }
+}
+
+void __stdcall glGetQueryObjectuiv(GLuint id, GLenum pname, GLuint* params)
+{
+    EVENT("(GLuint id = %u, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", id, pname, params);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (context->getClientVersion() < 3)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
+
+        gl::Query *queryObject = context->getQuery(id, false, GL_NONE);
+
+        if (!queryObject)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
+
+        if (context->getState().getActiveQueryId(queryObject->getType()) == id)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
+
+        switch(pname)
+        {
+          case GL_QUERY_RESULT_EXT:
+            {
+                gl::Error error = queryObject->getResult(params);
+                if (error.isError())
+                {
+                    context->recordError(error);
+                    return;
+                }
+            }
+            break;
+
+          case GL_QUERY_RESULT_AVAILABLE_EXT:
+            {
+                gl::Error error = queryObject->isResultAvailable(params);
+                if (error.isError())
+                {
+                    context->recordError(error);
+                    return;
+                }
+            }
+            break;
+
+          default:
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
+        }
+    }
+}
+
+GLboolean __stdcall glUnmapBuffer(GLenum target)
+{
+    EVENT("(GLenum target = 0x%X)", target);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (context->getClientVersion() < 3)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return GL_FALSE;
+        }
+
+        return glUnmapBufferOES(target);
+    }
+
+    return GL_FALSE;
+}
+
+void __stdcall glGetBufferPointerv(GLenum target, GLenum pname, GLvoid** params)
+{
+    EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLvoid** params = 0x%0.8p)", target, pname, params);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (context->getClientVersion() < 3)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
+
+        glGetBufferPointervOES(target, pname, params);
+    }
+}
+
+void __stdcall glDrawBuffers(GLsizei n, const GLenum* bufs)
+{
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (context->getClientVersion() < 3)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
+
+        glDrawBuffersEXT(n, bufs);
+    }
+}
+
+void __stdcall glUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+{
+    EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %u, const GLfloat* value = 0x%0.8p)",
+          location, count, transpose, value);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (!ValidateUniformMatrix(context, GL_FLOAT_MAT2x3, location, count, transpose))
+        {
+            return;
+        }
+
+        gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary();
+        programBinary->setUniformMatrix2x3fv(location, count, transpose, value);
+    }
+}
+
+void __stdcall glUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+{
+    EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %u, const GLfloat* value = 0x%0.8p)",
+          location, count, transpose, value);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (!ValidateUniformMatrix(context, GL_FLOAT_MAT3x2, location, count, transpose))
+        {
+            return;
+        }
+
+        gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary();
+        programBinary->setUniformMatrix3x2fv(location, count, transpose, value);
+    }
+}
+
+void __stdcall glUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+{
+    EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %u, const GLfloat* value = 0x%0.8p)",
+          location, count, transpose, value);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (!ValidateUniformMatrix(context, GL_FLOAT_MAT2x4, location, count, transpose))
+        {
+            return;
+        }
+
+        gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary();
+        programBinary->setUniformMatrix2x4fv(location, count, transpose, value);
+    }
+}
+
+void __stdcall glUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+{
+    EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %u, const GLfloat* value = 0x%0.8p)",
+          location, count, transpose, value);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (!ValidateUniformMatrix(context, GL_FLOAT_MAT4x2, location, count, transpose))
+        {
+            return;
+        }
+
+        gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary();
+        programBinary->setUniformMatrix4x2fv(location, count, transpose, value);
+    }
+}
+
+void __stdcall glUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+{
+    EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %u, const GLfloat* value = 0x%0.8p)",
+          location, count, transpose, value);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (!ValidateUniformMatrix(context, GL_FLOAT_MAT3x4, location, count, transpose))
+        {
+            return;
+        }
+
+        gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary();
+        programBinary->setUniformMatrix3x4fv(location, count, transpose, value);
+    }
+}
+
+void __stdcall glUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+{
+    EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %u, const GLfloat* value = 0x%0.8p)",
+          location, count, transpose, value);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (!ValidateUniformMatrix(context, GL_FLOAT_MAT4x3, location, count, transpose))
+        {
+            return;
+        }
+
+        gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary();
+        programBinary->setUniformMatrix4x3fv(location, count, transpose, value);
+    }
+}
+
+void __stdcall glBlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter)
+{
+    EVENT("(GLint srcX0 = %d, GLint srcY0 = %d, GLint srcX1 = %d, GLint srcY1 = %d, GLint dstX0 = %d, "
+          "GLint dstY0 = %d, GLint dstX1 = %d, GLint dstY1 = %d, GLbitfield mask = 0x%X, GLenum filter = 0x%X)",
+          srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (context->getClientVersion() < 3)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
+
+        if (!ValidateBlitFramebufferParameters(context, srcX0, srcY0, srcX1, srcY1,
+                                               dstX0, dstY0, dstX1, dstY1, mask, filter,
+                                               false))
+        {
+            return;
+        }
+
+        context->blitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1,
+                                 mask, filter);
+    }
+}
+
+void __stdcall glRenderbufferStorageMultisample(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height)
+{
+    EVENT("(GLenum target = 0x%X, GLsizei samples = %d, GLenum internalformat = 0x%X, GLsizei width = %d, GLsizei height = %d)",
+        target, samples, internalformat, width, height);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (context->getClientVersion() < 3)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
+
+        if (!ValidateRenderbufferStorageParameters(context, target, samples, internalformat,
+                                                   width, height, false))
+        {
+            return;
+        }
+
+        context->setRenderbufferStorage(width, height, internalformat, samples);
+    }
+}
+
+void __stdcall glFramebufferTextureLayer(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer)
+{
+    EVENT("(GLenum target = 0x%X, GLenum attachment = 0x%X, GLuint texture = %u, GLint level = %d, GLint layer = %d)",
+        target, attachment, texture, level, layer);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (!ValidateFramebufferTextureLayer(context, target, attachment, texture,
+                                             level, layer))
+        {
+            return;
+        }
+
+        gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
+        ASSERT(framebuffer);
+
+        gl::Texture *textureObject = context->getTexture(texture);
+        GLenum textarget = textureObject ? textureObject->getTarget() : GL_NONE;
+
+        if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
+        {
+            const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT);
+            framebuffer->setColorbuffer(colorAttachment, textarget, texture, level, layer);
+        }
+        else
+        {
+            switch (attachment)
+            {
+              case GL_DEPTH_ATTACHMENT:         framebuffer->setDepthbuffer(textarget, texture, level, layer);        break;
+              case GL_STENCIL_ATTACHMENT:       framebuffer->setStencilbuffer(textarget, texture, level, layer);      break;
+              case GL_DEPTH_STENCIL_ATTACHMENT: framebuffer->setDepthStencilBuffer(textarget, texture, level, layer); break;
+            }
+        }
+    }
+}
+
+GLvoid* __stdcall glMapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access)
+{
+    EVENT("(GLenum target = 0x%X, GLintptr offset = %d, GLsizeiptr length = %d, GLbitfield access = 0x%X)",
+          target, offset, length, access);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (context->getClientVersion() < 3)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return NULL;
+        }
+
+        return glMapBufferRangeEXT(target, offset, length, access);
+    }
+
+    return NULL;
+}
+
+void __stdcall glFlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length)
+{
+    EVENT("(GLenum target = 0x%X, GLintptr offset = %d, GLsizeiptr length = %d)", target, offset, length);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (context->getClientVersion() < 3)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
+
+        glFlushMappedBufferRangeEXT(target, offset, length);
+    }
+}
+
+void __stdcall glBindVertexArray(GLuint array)
+{
+    EVENT("(GLuint array = %u)", array);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (context->getClientVersion() < 3)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
+
+        gl::VertexArray *vao = context->getVertexArray(array);
+
+        if (!vao)
+        {
+            // The default VAO should always exist
+            ASSERT(array != 0);
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
+
+        context->bindVertexArray(array);
+    }
+}
+
+void __stdcall glDeleteVertexArrays(GLsizei n, const GLuint* arrays)
+{
+    EVENT("(GLsizei n = %d, const GLuint* arrays = 0x%0.8p)", n, arrays);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (context->getClientVersion() < 3)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
+
+        if (n < 0)
+        {
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
+        }
+
+        for (int arrayIndex = 0; arrayIndex < n; arrayIndex++)
+        {
+            if (arrays[arrayIndex] != 0)
+            {
+                context->deleteVertexArray(arrays[arrayIndex]);
+            }
+        }
+    }
+}
+
+void __stdcall glGenVertexArrays(GLsizei n, GLuint* arrays)
+{
+    EVENT("(GLsizei n = %d, GLuint* arrays = 0x%0.8p)", n, arrays);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (context->getClientVersion() < 3)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
+
+        if (n < 0)
+        {
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
+        }
+
+        for (int arrayIndex = 0; arrayIndex < n; arrayIndex++)
+        {
+            arrays[arrayIndex] = context->createVertexArray();
+        }
+    }
+}
+
+GLboolean __stdcall glIsVertexArray(GLuint array)
+{
+    EVENT("(GLuint array = %u)", array);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (context->getClientVersion() < 3)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return GL_FALSE;
+        }
+
+        if (array == 0)
+        {
+            return GL_FALSE;
+        }
+
+        gl::VertexArray *vao = context->getVertexArray(array);
+
+        return (vao != NULL ? GL_TRUE : GL_FALSE);
+    }
+
+    return GL_FALSE;
+}
+
+void __stdcall glGetIntegeri_v(GLenum target, GLuint index, GLint* data)
+{
+    EVENT("(GLenum target = 0x%X, GLuint index = %u, GLint* data = 0x%0.8p)",
+          target, index, data);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (context->getClientVersion() < 3)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
+
+        const gl::Caps &caps = context->getCaps();
+        switch (target)
+        {
+          case GL_TRANSFORM_FEEDBACK_BUFFER_START:
+          case GL_TRANSFORM_FEEDBACK_BUFFER_SIZE:
+          case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING:
+            if (index >= caps.maxTransformFeedbackSeparateAttributes)
+            {
+                context->recordError(gl::Error(GL_INVALID_VALUE));
+                return;
+            }
+            break;
+
+          case GL_UNIFORM_BUFFER_START:
+          case GL_UNIFORM_BUFFER_SIZE:
+          case GL_UNIFORM_BUFFER_BINDING:
+            if (index >= caps.maxCombinedUniformBlocks)
+            {
+                context->recordError(gl::Error(GL_INVALID_VALUE));
+                return;
+            }
+            break;
+
+          default:
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
+        }
+
+        if (!(context->getIndexedIntegerv(target, index, data)))
+        {
+            GLenum nativeType;
+            unsigned int numParams = 0;
+            if (!context->getIndexedQueryParameterInfo(target, &nativeType, &numParams))
+            {
+                context->recordError(gl::Error(GL_INVALID_ENUM));
+                return;
+            }
+
+            if (numParams == 0)
+            {
+                return; // it is known that pname is valid, but there are no parameters to return
+            }
+
+            if (nativeType == GL_INT_64_ANGLEX)
+            {
+                GLint64 minIntValue = static_cast<GLint64>(std::numeric_limits<int>::min());
+                GLint64 maxIntValue = static_cast<GLint64>(std::numeric_limits<int>::max());
+                GLint64 *int64Params = new GLint64[numParams];
+
+                context->getIndexedInteger64v(target, index, int64Params);
+
+                for (unsigned int i = 0; i < numParams; ++i)
+                {
+                    GLint64 clampedValue = std::max(std::min(int64Params[i], maxIntValue), minIntValue);
+                    data[i] = static_cast<GLint>(clampedValue);
+                }
+
+                delete [] int64Params;
+            }
+            else
+            {
+                UNREACHABLE();
+            }
+        }
+    }
+}
+
+void __stdcall glBeginTransformFeedback(GLenum primitiveMode)
+{
+    EVENT("(GLenum primitiveMode = 0x%X)", primitiveMode);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (context->getClientVersion() < 3)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
+
+        switch (primitiveMode)
+        {
+          case GL_TRIANGLES:
+          case GL_LINES:
+          case GL_POINTS:
+            break;
+
+          default:
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
+        }
+
+        gl::TransformFeedback *transformFeedback = context->getState().getCurrentTransformFeedback();
+        ASSERT(transformFeedback != NULL);
+
+        if (transformFeedback->isStarted())
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
+
+        if (transformFeedback->isPaused())
+        {
+            transformFeedback->resume();
+        }
+        else
+        {
+            transformFeedback->start(primitiveMode);
+        }
+    }
+}
+
+void __stdcall glEndTransformFeedback(void)
+{
+    EVENT("(void)");
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (context->getClientVersion() < 3)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
+
+        gl::TransformFeedback *transformFeedback = context->getState().getCurrentTransformFeedback();
+        ASSERT(transformFeedback != NULL);
+
+        if (!transformFeedback->isStarted())
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
+
+        transformFeedback->stop();
+    }
+}
+
+void __stdcall glBindBufferRange(GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size)
+{
+    EVENT("(GLenum target = 0x%X, GLuint index = %u, GLuint buffer = %u, GLintptr offset = %d, GLsizeiptr size = %d)",
+          target, index, buffer, offset, size);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (context->getClientVersion() < 3)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
+
+        const gl::Caps &caps = context->getCaps();
+        switch (target)
+        {
+          case GL_TRANSFORM_FEEDBACK_BUFFER:
+            if (index >= caps.maxTransformFeedbackSeparateAttributes)
+            {
+                context->recordError(gl::Error(GL_INVALID_VALUE));
+                return;
+            }
+            break;
+
+          case GL_UNIFORM_BUFFER:
+            if (index >= caps.maxUniformBufferBindings)
+            {
+                context->recordError(gl::Error(GL_INVALID_VALUE));
+                return;
+            }
+            break;
+
+          default:
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
+        }
+
+        if (buffer != 0 && size <= 0)
+        {
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
+        }
+
+        switch (target)
+        {
+          case GL_TRANSFORM_FEEDBACK_BUFFER:
+
+            // size and offset must be a multiple of 4
+            if (buffer != 0 && ((offset % 4) != 0 || (size % 4) != 0))
+            {
+                context->recordError(gl::Error(GL_INVALID_VALUE));
+                return;
+            }
+
+            context->bindIndexedTransformFeedbackBuffer(buffer, index, offset, size);
+            context->bindGenericTransformFeedbackBuffer(buffer);
+            break;
+
+          case GL_UNIFORM_BUFFER:
+
+            // it is an error to bind an offset not a multiple of the alignment
+            if (buffer != 0 && (offset % caps.uniformBufferOffsetAlignment) != 0)
+            {
+                context->recordError(gl::Error(GL_INVALID_VALUE));
+                return;
+            }
+
+            context->bindIndexedUniformBuffer(buffer, index, offset, size);
+            context->bindGenericUniformBuffer(buffer);
+            break;
+
+          default:
+            UNREACHABLE();
+        }
+    }
+}
+
+void __stdcall glBindBufferBase(GLenum target, GLuint index, GLuint buffer)
+{
+    EVENT("(GLenum target = 0x%X, GLuint index = %u, GLuint buffer = %u)",
+          target, index, buffer);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (context->getClientVersion() < 3)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
+
+        const gl::Caps &caps = context->getCaps();
+        switch (target)
+        {
+          case GL_TRANSFORM_FEEDBACK_BUFFER:
+            if (index >= caps.maxTransformFeedbackSeparateAttributes)
+            {
+                context->recordError(gl::Error(GL_INVALID_VALUE));
+                return;
+            }
+            break;
+
+          case GL_UNIFORM_BUFFER:
+            if (index >= caps.maxUniformBufferBindings)
+            {
+                context->recordError(gl::Error(GL_INVALID_VALUE));
+                return;
+            }
+            break;
+
+          default:
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
+        }
+
+        switch (target)
+        {
+          case GL_TRANSFORM_FEEDBACK_BUFFER:
+            context->bindIndexedTransformFeedbackBuffer(buffer, index, 0, 0);
+            context->bindGenericTransformFeedbackBuffer(buffer);
+            break;
+
+          case GL_UNIFORM_BUFFER:
+            context->bindIndexedUniformBuffer(buffer, index, 0, 0);
+            context->bindGenericUniformBuffer(buffer);
+            break;
+
+          default:
+            UNREACHABLE();
+        }
+    }
+}
+
+void __stdcall glTransformFeedbackVaryings(GLuint program, GLsizei count, const GLchar* const* varyings, GLenum bufferMode)
+{
+    EVENT("(GLuint program = %u, GLsizei count = %d, const GLchar* const* varyings = 0x%0.8p, GLenum bufferMode = 0x%X)",
+          program, count, varyings, bufferMode);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (context->getClientVersion() < 3)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
+
+        if (count < 0)
+        {
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
+        }
+
+        const gl::Caps &caps = context->getCaps();
+        switch (bufferMode)
+        {
+          case GL_INTERLEAVED_ATTRIBS:
+            break;
+          case GL_SEPARATE_ATTRIBS:
+            if (static_cast<GLuint>(count) > caps.maxTransformFeedbackSeparateAttributes)
+            {
+                context->recordError(gl::Error(GL_INVALID_VALUE));
+                return;
+            }
+            break;
+          default:
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
+        }
+
+        if (!gl::ValidProgram(context, program))
+        {
+            return;
+        }
+
+        gl::Program *programObject = context->getProgram(program);
+        ASSERT(programObject);
+
+        programObject->setTransformFeedbackVaryings(count, varyings, bufferMode);
+    }
+}
+
+void __stdcall glGetTransformFeedbackVarying(GLuint program, GLuint index, GLsizei bufSize, GLsizei* length, GLsizei* size, GLenum* type, GLchar* name)
+{
+    EVENT("(GLuint program = %u, GLuint index = %u, GLsizei bufSize = %d, GLsizei* length = 0x%0.8p, "
+          "GLsizei* size = 0x%0.8p, GLenum* type = 0x%0.8p, GLchar* name = 0x%0.8p)",
+          program, index, bufSize, length, size, type, name);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (context->getClientVersion() < 3)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
+
+        if (bufSize < 0)
+        {
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
+        }
+
+        if (!gl::ValidProgram(context, program))
+        {
+            return;
+        }
+
+        gl::Program *programObject = context->getProgram(program);
+        ASSERT(programObject);
+
+        if (index >= static_cast<GLuint>(programObject->getTransformFeedbackVaryingCount()))
+        {
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
+        }
+
+        programObject->getTransformFeedbackVarying(index, bufSize, length, size, type, name);
+    }
+}
+
+void __stdcall glVertexAttribIPointer(GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid* pointer)
+{
+    EVENT("(GLuint index = %u, GLint size = %d, GLenum type = 0x%X, GLsizei stride = %d, const GLvoid* pointer = 0x%0.8p)",
+          index, size, type, stride, pointer);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (context->getClientVersion() < 3)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
+
+        if (index >= gl::MAX_VERTEX_ATTRIBS)
+        {
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
+        }
+
+        if (size < 1 || size > 4)
+        {
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            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_INT_2_10_10_10_REV:
+          case GL_UNSIGNED_INT_2_10_10_10_REV:
+            break;
+
+          default:
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
+        }
+
+        if (stride < 0)
+        {
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
+        }
+
+        if ((type == GL_INT_2_10_10_10_REV || type == GL_UNSIGNED_INT_2_10_10_10_REV) && size != 4)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
+
+        // [OpenGL ES 3.0.2] Section 2.8 page 24:
+        // An INVALID_OPERATION error is generated when a non-zero vertex array object
+        // is bound, zero is bound to the ARRAY_BUFFER buffer object binding point,
+        // and the pointer argument is not NULL.
+        if (context->getState().getVertexArray()->id() != 0 && context->getState().getArrayBufferId() == 0 && pointer != NULL)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
+
+        context->getState().setVertexAttribState(index, context->getState().getTargetBuffer(GL_ARRAY_BUFFER), size, type, false, true,
+                                                 stride, pointer);
+    }
+}
+
+void __stdcall glGetVertexAttribIiv(GLuint index, GLenum pname, GLint* params)
+{
+    EVENT("(GLuint index = %u, GLenum pname = 0x%X, GLint* params = 0x%0.8p)",
+          index, pname, params);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (context->getClientVersion() < 3)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
+
+        if (index >= gl::MAX_VERTEX_ATTRIBS)
+        {
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
+        }
+
+        const gl::VertexAttribute &attribState = context->getState().getVertexAttribState(index);
+
+        if (!gl::ValidateGetVertexAttribParameters(context, pname))
+        {
+            return;
+        }
+
+        if (pname == GL_CURRENT_VERTEX_ATTRIB)
+        {
+            const gl::VertexAttribCurrentValueData &currentValueData = context->getState().getVertexAttribCurrentValue(index);
+            for (int i = 0; i < 4; ++i)
+            {
+                params[i] = currentValueData.IntValues[i];
+            }
+        }
+        else
+        {
+            *params = gl::QuerySingleVertexAttributeParameter<GLint>(attribState, pname);
+        }
+    }
+}
+
+void __stdcall glGetVertexAttribIuiv(GLuint index, GLenum pname, GLuint* params)
+{
+    EVENT("(GLuint index = %u, GLenum pname = 0x%X, GLuint* params = 0x%0.8p)",
+          index, pname, params);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (context->getClientVersion() < 3)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
+
+        if (index >= gl::MAX_VERTEX_ATTRIBS)
+        {
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
+        }
+
+        const gl::VertexAttribute &attribState = context->getState().getVertexAttribState(index);
+
+        if (!gl::ValidateGetVertexAttribParameters(context, pname))
+        {
+            return;
+        }
+
+        if (pname == GL_CURRENT_VERTEX_ATTRIB)
+        {
+            const gl::VertexAttribCurrentValueData &currentValueData = context->getState().getVertexAttribCurrentValue(index);
+            for (int i = 0; i < 4; ++i)
+            {
+                params[i] = currentValueData.UnsignedIntValues[i];
+            }
+        }
+        else
+        {
+            *params = gl::QuerySingleVertexAttributeParameter<GLuint>(attribState, pname);
+        }
+    }
+}
+
+void __stdcall glVertexAttribI4i(GLuint index, GLint x, GLint y, GLint z, GLint w)
+{
+    EVENT("(GLuint index = %u, GLint x = %d, GLint y = %d, GLint z = %d, GLint w = %d)",
+          index, x, y, z, w);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (context->getClientVersion() < 3)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
+
+        if (index >= gl::MAX_VERTEX_ATTRIBS)
+        {
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
+        }
+
+        GLint vals[4] = { x, y, z, w };
+        context->getState().setVertexAttribi(index, vals);
+    }
+}
+
+void __stdcall glVertexAttribI4ui(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w)
+{
+    EVENT("(GLuint index = %u, GLuint x = %u, GLuint y = %u, GLuint z = %u, GLuint w = %u)",
+          index, x, y, z, w);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (context->getClientVersion() < 3)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
+
+        if (index >= gl::MAX_VERTEX_ATTRIBS)
+        {
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
+        }
+
+        GLuint vals[4] = { x, y, z, w };
+        context->getState().setVertexAttribu(index, vals);
+    }
+}
+
+void __stdcall glVertexAttribI4iv(GLuint index, const GLint* v)
+{
+    EVENT("(GLuint index = %u, const GLint* v = 0x%0.8p)", index, v);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (context->getClientVersion() < 3)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
+
+        if (index >= gl::MAX_VERTEX_ATTRIBS)
+        {
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
+        }
+
+        context->getState().setVertexAttribi(index, v);
+    }
+}
+
+void __stdcall glVertexAttribI4uiv(GLuint index, const GLuint* v)
+{
+    EVENT("(GLuint index = %u, const GLuint* v = 0x%0.8p)", index, v);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (context->getClientVersion() < 3)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
+
+        if (index >= gl::MAX_VERTEX_ATTRIBS)
+        {
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
+        }
+
+        context->getState().setVertexAttribu(index, v);
+    }
+}
+
+void __stdcall glGetUniformuiv(GLuint program, GLint location, GLuint* params)
+{
+    EVENT("(GLuint program = %u, GLint location = %d, GLuint* params = 0x%0.8p)",
+          program, location, params);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (!ValidateGetUniformuiv(context, program, location, params))
+        {
+            return;
+        }
+
+        gl::Program *programObject = context->getProgram(program);
+        ASSERT(programObject);
+        gl::ProgramBinary *programBinary = programObject->getProgramBinary();
+        ASSERT(programBinary);
+
+        programBinary->getUniformuiv(location, params);
+    }
+}
+
+GLint __stdcall glGetFragDataLocation(GLuint program, const GLchar *name)
+{
+    EVENT("(GLuint program = %u, const GLchar *name = 0x%0.8p)",
+          program, name);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (context->getClientVersion() < 3)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return -1;
+        }
+
+        if (program == 0)
+        {
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return -1;
+        }
+
+        gl::Program *programObject = context->getProgram(program);
+
+        if (!programObject || !programObject->isLinked())
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return -1;
+        }
+
+        gl::ProgramBinary *programBinary = programObject->getProgramBinary();
+        if (!programBinary)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return -1;
+        }
+
+        return programBinary->getFragDataLocation(name);
+    }
+
+    return 0;
+}
+
+void __stdcall glUniform1ui(GLint location, GLuint v0)
+{
+    glUniform1uiv(location, 1, &v0);
+}
+
+void __stdcall glUniform2ui(GLint location, GLuint v0, GLuint v1)
+{
+    const GLuint xy[] = { v0, v1 };
+    glUniform2uiv(location, 1, xy);
+}
+
+void __stdcall glUniform3ui(GLint location, GLuint v0, GLuint v1, GLuint v2)
+{
+    const GLuint xyz[] = { v0, v1, v2 };
+    glUniform3uiv(location, 1, xyz);
+}
+
+void __stdcall glUniform4ui(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3)
+{
+    const GLuint xyzw[] = { v0, v1, v2, v3 };
+    glUniform4uiv(location, 1, xyzw);
+}
+
+void __stdcall glUniform1uiv(GLint location, GLsizei count, const GLuint* value)
+{
+    EVENT("(GLint location = %d, GLsizei count = %d, const GLuint* value = 0x%0.8p)",
+          location, count, value);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (!ValidateUniform(context, GL_UNSIGNED_INT, location, count))
+        {
+            return;
+        }
+
+        gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary();
+        programBinary->setUniform1uiv(location, count, value);
+    }
+}
+
+void __stdcall glUniform2uiv(GLint location, GLsizei count, const GLuint* value)
+{
+    EVENT("(GLint location = %d, GLsizei count = %d, const GLuint* value = 0x%0.8p)",
+          location, count, value);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (!ValidateUniform(context, GL_UNSIGNED_INT_VEC2, location, count))
+        {
+            return;
+        }
+
+        gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary();
+        programBinary->setUniform2uiv(location, count, value);
+    }
+}
+
+void __stdcall glUniform3uiv(GLint location, GLsizei count, const GLuint* value)
+{
+    EVENT("(GLint location = %d, GLsizei count = %d, const GLuint* value)",
+          location, count, value);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (!ValidateUniform(context, GL_UNSIGNED_INT_VEC3, location, count))
+        {
+            return;
+        }
+
+        gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary();
+        programBinary->setUniform3uiv(location, count, value);
+    }
+}
+
+void __stdcall glUniform4uiv(GLint location, GLsizei count, const GLuint* value)
+{
+    EVENT("(GLint location = %d, GLsizei count = %d, const GLuint* value = 0x%0.8p)",
+          location, count, value);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (!ValidateUniform(context, GL_UNSIGNED_INT_VEC4, location, count))
+        {
+            return;
+        }
+
+        gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary();
+        programBinary->setUniform4uiv(location, count, value);
+    }
+}
+
+void __stdcall glClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint* value)
+{
+    EVENT("(GLenum buffer = 0x%X, GLint drawbuffer = %d, const GLint* value = 0x%0.8p)",
+          buffer, drawbuffer, value);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (!ValidateClearBuffer(context))
+        {
+            return;
+        }
+
+        switch (buffer)
+        {
+          case GL_COLOR:
+            if (drawbuffer < 0 || static_cast<GLuint>(drawbuffer) >= context->getCaps().maxDrawBuffers)
+            {
+                context->recordError(gl::Error(GL_INVALID_VALUE));
+                return;
+            }
+            break;
+
+          case GL_STENCIL:
+            if (drawbuffer != 0)
+            {
+                context->recordError(gl::Error(GL_INVALID_VALUE));
+                return;
+            }
+            break;
+
+          default:
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
+        }
+
+        gl::Error error = context->clearBufferiv(buffer, drawbuffer, value);
+        if (error.isError())
+        {
+            context->recordError(error);
+            return;
+        }
+    }
+}
+
+void __stdcall glClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint* value)
+{
+    EVENT("(GLenum buffer = 0x%X, GLint drawbuffer = %d, const GLuint* value = 0x%0.8p)",
+          buffer, drawbuffer, value);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (!ValidateClearBuffer(context))
+        {
+            return;
+        }
+
+        switch (buffer)
+        {
+          case GL_COLOR:
+            if (drawbuffer < 0 || static_cast<GLuint>(drawbuffer) >= context->getCaps().maxDrawBuffers)
+            {
+                context->recordError(gl::Error(GL_INVALID_VALUE));
+                return;
+            }
+            break;
+
+          default:
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
+        }
+
+        gl::Error error = context->clearBufferuiv(buffer, drawbuffer, value);
+        if (error.isError())
+        {
+            context->recordError(error);
+            return;
+        }
+    }
+}
+
+void __stdcall glClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat* value)
+{
+    EVENT("(GLenum buffer = 0x%X, GLint drawbuffer = %d, const GLfloat* value = 0x%0.8p)",
+          buffer, drawbuffer, value);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (!ValidateClearBuffer(context))
+        {
+            return;
+        }
+
+        switch (buffer)
+        {
+          case GL_COLOR:
+            if (drawbuffer < 0 || static_cast<GLuint>(drawbuffer) >= context->getCaps().maxDrawBuffers)
+            {
+                context->recordError(gl::Error(GL_INVALID_VALUE));
+                return;
+            }
+            break;
+
+          case GL_DEPTH:
+            if (drawbuffer != 0)
+            {
+                context->recordError(gl::Error(GL_INVALID_VALUE));
+                return;
+            }
+            break;
+
+          default:
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
+        }
+
+        gl::Error error = context->clearBufferfv(buffer, drawbuffer, value);
+        if (error.isError())
+        {
+            context->recordError(error);
+            return;
+        }
+    }
+}
+
+void __stdcall glClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil)
+{
+    EVENT("(GLenum buffer = 0x%X, GLint drawbuffer = %d, GLfloat depth, GLint stencil = %d)",
+          buffer, drawbuffer, depth, stencil);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (!ValidateClearBuffer(context))
+        {
+            return;
+        }
+
+        switch (buffer)
+        {
+          case GL_DEPTH_STENCIL:
+            if (drawbuffer != 0)
+            {
+                context->recordError(gl::Error(GL_INVALID_VALUE));
+                return;
+            }
+            break;
+
+          default:
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
+        }
+
+        gl::Error error = context->clearBufferfi(buffer, drawbuffer, depth, stencil);
+        if (error.isError())
+        {
+            context->recordError(error);
+            return;
+        }
+    }
+}
+
+const GLubyte* __stdcall glGetStringi(GLenum name, GLuint index)
+{
+    EVENT("(GLenum name = 0x%X, GLuint index = %u)", name, index);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (context->getClientVersion() < 3)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return NULL;
+        }
+
+        if (name != GL_EXTENSIONS)
+        {
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return NULL;
+        }
+
+        if (index >= context->getExtensionStringCount())
+        {
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return NULL;
+        }
+
+        return reinterpret_cast<const GLubyte*>(context->getExtensionString(index).c_str());
+    }
+
+    return NULL;
+}
+
+void __stdcall glCopyBufferSubData(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size)
+{
+    EVENT("(GLenum readTarget = 0x%X, GLenum writeTarget = 0x%X, GLintptr readOffset = %d, GLintptr writeOffset = %d, GLsizeiptr size = %d)",
+          readTarget, writeTarget, readOffset, writeOffset, size);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (context->getClientVersion() < 3)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
+
+        if (!gl::ValidBufferTarget(context, readTarget) || !gl::ValidBufferTarget(context, readTarget))
+        {
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
+        }
+
+        gl::Buffer *readBuffer = context->getState().getTargetBuffer(readTarget);
+        gl::Buffer *writeBuffer = context->getState().getTargetBuffer(writeTarget);
+
+        if (!readBuffer || !writeBuffer)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
+
+        // Verify that readBuffer and writeBuffer are not currently mapped
+        if (readBuffer->isMapped() || writeBuffer->isMapped())
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
+
+        if (readOffset < 0 || writeOffset < 0 || size < 0 ||
+            static_cast<unsigned int>(readOffset + size) > readBuffer->getSize() ||
+            static_cast<unsigned int>(writeOffset + size) > writeBuffer->getSize())
+        {
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
+        }
+
+        if (readBuffer == writeBuffer && abs(readOffset - writeOffset) < size)
+        {
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
+        }
+
+        // if size is zero, the copy is a successful no-op
+        if (size > 0)
+        {
+            gl::Error error = writeBuffer->copyBufferSubData(readBuffer, readOffset, writeOffset, size);
+            if (error.isError())
+            {
+                context->recordError(error);
+                return;
+            }
+        }
+    }
+}
+
+void __stdcall glGetUniformIndices(GLuint program, GLsizei uniformCount, const GLchar* const* uniformNames, GLuint* uniformIndices)
+{
+    EVENT("(GLuint program = %u, GLsizei uniformCount = %d, const GLchar* const* uniformNames = 0x%0.8p, GLuint* uniformIndices = 0x%0.8p)",
+          program, uniformCount, uniformNames, uniformIndices);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (context->getClientVersion() < 3)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
+
+        if (uniformCount < 0)
+        {
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
+        }
+
+        gl::Program *programObject = context->getProgram(program);
+
+        if (!programObject)
+        {
+            if (context->getShader(program))
+            {
+                context->recordError(gl::Error(GL_INVALID_OPERATION));
+                return;
+            }
+            else
+            {
+                context->recordError(gl::Error(GL_INVALID_VALUE));
+                return;
+            }
+        }
+
+        gl::ProgramBinary *programBinary = programObject->getProgramBinary();
+        if (!programObject->isLinked() || !programBinary)
+        {
+            for (int uniformId = 0; uniformId < uniformCount; uniformId++)
+            {
+                uniformIndices[uniformId] = GL_INVALID_INDEX;
+            }
+        }
+        else
+        {
+            for (int uniformId = 0; uniformId < uniformCount; uniformId++)
+            {
+                uniformIndices[uniformId] = programBinary->getUniformIndex(uniformNames[uniformId]);
+            }
+        }
+    }
+}
+
+void __stdcall glGetActiveUniformsiv(GLuint program, GLsizei uniformCount, const GLuint* uniformIndices, GLenum pname, GLint* params)
+{
+    EVENT("(GLuint program = %u, GLsizei uniformCount = %d, const GLuint* uniformIndices = 0x%0.8p, GLenum pname = 0x%X, GLint* params = 0x%0.8p)",
+          program, uniformCount, uniformIndices, pname, params);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (context->getClientVersion() < 3)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
+
+        if (uniformCount < 0)
+        {
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
+        }
+
+        gl::Program *programObject = context->getProgram(program);
+
+        if (!programObject)
+        {
+            if (context->getShader(program))
+            {
+                context->recordError(gl::Error(GL_INVALID_OPERATION));
+                return;
+            }
+            else
+            {
+                context->recordError(gl::Error(GL_INVALID_VALUE));
+                return;
+            }
+        }
+
+        switch (pname)
+        {
+          case GL_UNIFORM_TYPE:
+          case GL_UNIFORM_SIZE:
+          case GL_UNIFORM_NAME_LENGTH:
+          case GL_UNIFORM_BLOCK_INDEX:
+          case GL_UNIFORM_OFFSET:
+          case GL_UNIFORM_ARRAY_STRIDE:
+          case GL_UNIFORM_MATRIX_STRIDE:
+          case GL_UNIFORM_IS_ROW_MAJOR:
+            break;
+
+          default:
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
+        }
+
+        gl::ProgramBinary *programBinary = programObject->getProgramBinary();
+
+        if (!programBinary && uniformCount > 0)
+        {
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
+        }
+
+        for (int uniformId = 0; uniformId < uniformCount; uniformId++)
+        {
+            const GLuint index = uniformIndices[uniformId];
+
+            if (index >= (GLuint)programBinary->getActiveUniformCount())
+            {
+                context->recordError(gl::Error(GL_INVALID_VALUE));
+                return;
+            }
+        }
+
+        for (int uniformId = 0; uniformId < uniformCount; uniformId++)
+        {
+            const GLuint index = uniformIndices[uniformId];
+            params[uniformId] = programBinary->getActiveUniformi(index, pname);
+        }
+    }
+}
+
+GLuint __stdcall glGetUniformBlockIndex(GLuint program, const GLchar* uniformBlockName)
+{
+    EVENT("(GLuint program = %u, const GLchar* uniformBlockName = 0x%0.8p)", program, uniformBlockName);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (context->getClientVersion() < 3)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return GL_INVALID_INDEX;
+        }
+
+        gl::Program *programObject = context->getProgram(program);
+
+        if (!programObject)
+        {
+            if (context->getShader(program))
+            {
+                context->recordError(gl::Error(GL_INVALID_OPERATION));
+                return GL_INVALID_INDEX;
+            }
+            else
+            {
+                context->recordError(gl::Error(GL_INVALID_VALUE));
+                return GL_INVALID_INDEX;
+            }
         }
 
-        if (width < 1 || height < 1 || levels < 1)
+        gl::ProgramBinary *programBinary = programObject->getProgramBinary();
+        if (!programBinary)
         {
-            return gl::error(GL_INVALID_VALUE);
+            return GL_INVALID_INDEX;
         }
 
-        if (target == GL_TEXTURE_CUBE_MAP && width != height)
+        return programBinary->getUniformBlockIndex(uniformBlockName);
+    }
+
+    return 0;
+}
+
+void __stdcall glGetActiveUniformBlockiv(GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint* params)
+{
+    EVENT("(GLuint program = %u, GLuint uniformBlockIndex = %u, GLenum pname = 0x%X, GLint* params = 0x%0.8p)",
+          program, uniformBlockIndex, pname, params);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (context->getClientVersion() < 3)
         {
-            return gl::error(GL_INVALID_VALUE);
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
         }
+        gl::Program *programObject = context->getProgram(program);
 
-        if (levels != 1 && levels != gl::log2(std::max(width, height)) + 1)
+        if (!programObject)
         {
-            return gl::error(GL_INVALID_OPERATION);
+            if (context->getShader(program))
+            {
+                context->recordError(gl::Error(GL_INVALID_OPERATION));
+                return;
+            }
+            else
+            {
+                context->recordError(gl::Error(GL_INVALID_VALUE));
+                return;
+            }
         }
 
-        GLenum format = gl::ExtractFormat(internalformat);
-        GLenum type = gl::ExtractType(internalformat);
+        gl::ProgramBinary *programBinary = programObject->getProgramBinary();
 
-        if (format == GL_NONE || type == GL_NONE)
+        if (!programBinary || uniformBlockIndex >= programBinary->getActiveUniformBlockCount())
         {
-            return gl::error(GL_INVALID_ENUM);
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
         }
 
-        gl::Context *context = gl::getNonLostContext();
+        switch (pname)
+        {
+          case GL_UNIFORM_BLOCK_BINDING:
+            *params = static_cast<GLint>(programObject->getUniformBlockBinding(uniformBlockIndex));
+            break;
 
-        if (context)
+          case GL_UNIFORM_BLOCK_DATA_SIZE:
+          case GL_UNIFORM_BLOCK_NAME_LENGTH:
+          case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
+          case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:
+          case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
+          case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
+            programBinary->getActiveUniformBlockiv(uniformBlockIndex, pname, params);
+            break;
+
+          default:
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
+        }
+    }
+}
+
+void __stdcall glGetActiveUniformBlockName(GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei* length, GLchar* uniformBlockName)
+{
+    EVENT("(GLuint program = %u, GLuint uniformBlockIndex = %u, GLsizei bufSize = %d, GLsizei* length = 0x%0.8p, GLchar* uniformBlockName = 0x%0.8p)",
+          program, uniformBlockIndex, bufSize, length, uniformBlockName);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (context->getClientVersion() < 3)
         {
-            switch (target)
-            {
-              case GL_TEXTURE_2D:
-                if (width > context->getMaximumTextureDimension() ||
-                    height > context->getMaximumTextureDimension())
-                {
-                    return gl::error(GL_INVALID_VALUE);
-                }
-                break;
-              case GL_TEXTURE_CUBE_MAP:
-                if (width > context->getMaximumCubeTextureDimension() ||
-                    height > context->getMaximumCubeTextureDimension())
-                {
-                    return gl::error(GL_INVALID_VALUE);
-                }
-                break;
-              default:
-                return gl::error(GL_INVALID_ENUM);
-            }
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
+
+        gl::Program *programObject = context->getProgram(program);
 
-            if (levels != 1 && !context->supportsNonPower2Texture())
+        if (!programObject)
+        {
+            if (context->getShader(program))
             {
-                if (!gl::isPow2(width) || !gl::isPow2(height))
-                {
-                    return gl::error(GL_INVALID_OPERATION);
-                }
+                context->recordError(gl::Error(GL_INVALID_OPERATION));
+                return;
             }
-
-            switch (internalformat)
+            else
             {
-              case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
-              case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
-                if (!context->supportsDXT1Textures())
-                {
-                    return gl::error(GL_INVALID_ENUM);
-                }
-                break;
-              case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
-                if (!context->supportsDXT3Textures())
-                {
-                    return gl::error(GL_INVALID_ENUM);
-                }
-                break;
-              case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
-                if (!context->supportsDXT5Textures())
-                {
-                    return gl::error(GL_INVALID_ENUM);
-                }
-                break;
-              case GL_RGBA32F_EXT:
-              case GL_RGB32F_EXT:
-              case GL_ALPHA32F_EXT:
-              case GL_LUMINANCE32F_EXT:
-              case GL_LUMINANCE_ALPHA32F_EXT:
-                if (!context->supportsFloat32Textures())
-                {
-                    return gl::error(GL_INVALID_ENUM);
-                }
-                break;
-              case GL_RGBA16F_EXT:
-              case GL_RGB16F_EXT:
-              case GL_ALPHA16F_EXT:
-              case GL_LUMINANCE16F_EXT:
-              case GL_LUMINANCE_ALPHA16F_EXT:
-                if (!context->supportsFloat16Textures())
-                {
-                    return gl::error(GL_INVALID_ENUM);
-                }
-                break;
-              case GL_DEPTH_COMPONENT16:
-              case GL_DEPTH_COMPONENT32_OES:
-              case GL_DEPTH24_STENCIL8_OES:
-                if (!context->supportsDepthTextures())
-                {
-                    return gl::error(GL_INVALID_ENUM);
-                }
-                if (target != GL_TEXTURE_2D)
-                {
-                    return gl::error(GL_INVALID_OPERATION);
-                }
-                // ANGLE_depth_texture only supports 1-level textures
-                if (levels != 1)
-                {
-                    return gl::error(GL_INVALID_OPERATION);
-                }
-                break;
-              default:
-                break;
+                context->recordError(gl::Error(GL_INVALID_VALUE));
+                return;
             }
+        }
 
-            if (target == GL_TEXTURE_2D)
-            {
-                gl::Texture2D *texture = context->getTexture2D();
+        gl::ProgramBinary *programBinary = programObject->getProgramBinary();
 
-                if (!texture || texture->id() == 0)
-                {
-                    return gl::error(GL_INVALID_OPERATION);
-                }
+        if (!programBinary || uniformBlockIndex >= programBinary->getActiveUniformBlockCount())
+        {
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
+        }
 
-                if (texture->isImmutable())
-                {
-                    return gl::error(GL_INVALID_OPERATION);
-                }
+        programBinary->getActiveUniformBlockName(uniformBlockIndex, bufSize, length, uniformBlockName);
+    }
+}
+
+void __stdcall glUniformBlockBinding(GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding)
+{
+    EVENT("(GLuint program = %u, GLuint uniformBlockIndex = %u, GLuint uniformBlockBinding = %u)",
+          program, uniformBlockIndex, uniformBlockBinding);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (context->getClientVersion() < 3)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
+
+        if (uniformBlockBinding >= context->getCaps().maxUniformBufferBindings)
+        {
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
+        }
+
+        gl::Program *programObject = context->getProgram(program);
 
-                texture->storage(levels, internalformat, width, height);
+        if (!programObject)
+        {
+            if (context->getShader(program))
+            {
+                context->recordError(gl::Error(GL_INVALID_OPERATION));
+                return;
             }
-            else if (target == GL_TEXTURE_CUBE_MAP)
+            else
             {
-                gl::TextureCubeMap *texture = context->getTextureCubeMap();
+                context->recordError(gl::Error(GL_INVALID_VALUE));
+                return;
+            }
+        }
 
-                if (!texture || texture->id() == 0)
-                {
-                    return gl::error(GL_INVALID_OPERATION);
-                }
+        gl::ProgramBinary *programBinary = programObject->getProgramBinary();
 
-                if (texture->isImmutable())
-                {
-                    return gl::error(GL_INVALID_OPERATION);
-                }
+        // if never linked, there won't be any uniform blocks
+        if (!programBinary || uniformBlockIndex >= programBinary->getActiveUniformBlockCount())
+        {
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
+        }
 
-                texture->storage(levels, internalformat, width);
-            }
-            else UNREACHABLE();
+        programObject->bindUniformBlock(uniformBlockIndex, uniformBlockBinding);
+    }
+}
+
+void __stdcall glDrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instanceCount)
+{
+    EVENT("(GLenum mode = 0x%X, GLint first = %d, GLsizei count = %d, GLsizei instanceCount = %d)",
+          mode, first, count, instanceCount);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (context->getClientVersion() < 3)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
         }
+
+        // glDrawArraysInstanced
+        UNIMPLEMENTED();
     }
-    catch(std::bad_alloc&)
+}
+
+void __stdcall glDrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices, GLsizei instanceCount)
+{
+    EVENT("(GLenum mode = 0x%X, GLsizei count = %d, GLenum type = 0x%X, const GLvoid* indices = 0x%0.8p, GLsizei instanceCount = %d)",
+          mode, count, type, indices, instanceCount);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        return gl::error(GL_OUT_OF_MEMORY);
+        if (context->getClientVersion() < 3)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
+
+        // glDrawElementsInstanced
+        UNIMPLEMENTED();
     }
 }
 
-void __stdcall glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
-                               GLenum format, GLenum type, const GLvoid* pixels)
+GLsync __stdcall glFenceSync(GLenum condition, GLbitfield flags)
+{
+    EVENT("(GLenum condition = 0x%X, GLbitfield flags = 0x%X)", condition, flags);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (context->getClientVersion() < 3)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return 0;
+        }
+
+        if (condition != GL_SYNC_GPU_COMMANDS_COMPLETE)
+        {
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return 0;
+        }
+
+        if (flags != 0)
+        {
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return 0;
+        }
+
+        return context->createFenceSync(condition);
+    }
+
+    return NULL;
+}
+
+GLboolean __stdcall glIsSync(GLsync sync)
+{
+    EVENT("(GLsync sync = 0x%0.8p)", sync);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (context->getClientVersion() < 3)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return GL_FALSE;
+        }
+
+        return (context->getFenceSync(sync) != NULL);
+    }
+
+    return GL_FALSE;
+}
+
+void __stdcall glDeleteSync(GLsync sync)
+{
+    EVENT("(GLsync sync = 0x%0.8p)", sync);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (context->getClientVersion() < 3)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
+
+        if (sync != static_cast<GLsync>(0) && !context->getFenceSync(sync))
+        {
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
+        }
+
+        context->deleteFenceSync(sync);
+    }
+}
+
+GLenum __stdcall glClientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout)
+{
+    EVENT("(GLsync sync = 0x%0.8p, GLbitfield flags = 0x%X, GLuint64 timeout = %llu)",
+          sync, flags, timeout);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (context->getClientVersion() < 3)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return GL_WAIT_FAILED;
+        }
+
+        if ((flags & ~(GL_SYNC_FLUSH_COMMANDS_BIT)) != 0)
+        {
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return GL_WAIT_FAILED;
+        }
+
+        gl::FenceSync *fenceSync = context->getFenceSync(sync);
+
+        if (!fenceSync)
+        {
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return GL_WAIT_FAILED;
+        }
+
+        return fenceSync->clientWait(flags, timeout);
+    }
+
+    return GL_FALSE;
+}
+
+void __stdcall glWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout)
+{
+    EVENT("(GLsync sync = 0x%0.8p, GLbitfield flags = 0x%X, GLuint64 timeout = %llu)",
+          sync, flags, timeout);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (context->getClientVersion() < 3)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
+
+        if (flags != 0)
+        {
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
+        }
+
+        if (timeout != GL_TIMEOUT_IGNORED)
+        {
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
+        }
+
+        gl::FenceSync *fenceSync = context->getFenceSync(sync);
+
+        if (!fenceSync)
+        {
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
+        }
+
+        fenceSync->serverWait();
+    }
+}
+
+void __stdcall glGetInteger64v(GLenum pname, GLint64* params)
+{
+    EVENT("(GLenum pname = 0x%X, GLint64* params = 0x%0.8p)",
+          pname, params);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (context->getClientVersion() < 3)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
+
+        GLenum nativeType;
+        unsigned int numParams = 0;
+        if (!ValidateStateQuery(context, pname, &nativeType, &numParams))
+        {
+            return;
+        }
+
+        if (nativeType == GL_INT_64_ANGLEX)
+        {
+            context->getInteger64v(pname, params);
+        }
+        else
+        {
+            CastStateValues(context, nativeType, pname, numParams, params);
+        }
+    }
+}
+
+void __stdcall glGetSynciv(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei* length, GLint* values)
 {
-    EVENT("(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, "
-          "GLsizei width = %d, GLsizei height = %d, GLenum format = 0x%X, GLenum type = 0x%X, "
-          "const GLvoid* pixels = 0x%0.8p)",
-           target, level, xoffset, yoffset, width, height, format, type, pixels);
+    EVENT("(GLsync sync = 0x%0.8p, GLenum pname = 0x%X, GLsizei bufSize = %d, GLsizei* length = 0x%0.8p, GLint* values = 0x%0.8p)",
+          sync, pname, bufSize, length, values);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        if (!gl::IsInternalTextureTarget(target))
+        if (context->getClientVersion() < 3)
         {
-            return gl::error(GL_INVALID_ENUM);
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
         }
 
-        if (level < 0 || xoffset < 0 || yoffset < 0 || width < 0 || height < 0)
+        if (bufSize < 0)
         {
-            return gl::error(GL_INVALID_VALUE);
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
         }
 
-        if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
+        gl::FenceSync *fenceSync = context->getFenceSync(sync);
+
+        if (!fenceSync)
         {
-            return gl::error(GL_INVALID_VALUE);
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
         }
 
-        if (!checkTextureFormatType(format, type))
+        switch (pname)
         {
-            return; // error is set by helper function
+          case GL_OBJECT_TYPE:     values[0] = static_cast<GLint>(GL_SYNC_FENCE);              break;
+          case GL_SYNC_STATUS:     values[0] = static_cast<GLint>(fenceSync->getStatus());     break;
+          case GL_SYNC_CONDITION:  values[0] = static_cast<GLint>(fenceSync->getCondition());  break;
+          case GL_SYNC_FLAGS:      values[0] = 0;                                              break;
+
+          default:
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
         }
+    }
+}
 
-        gl::Context *context = gl::getNonLostContext();
+void __stdcall glGetInteger64i_v(GLenum target, GLuint index, GLint64* data)
+{
+    EVENT("(GLenum target = 0x%X, GLuint index = %u, GLint64* data = 0x%0.8p)",
+          target, index, data);
 
-        if (context)
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (context->getClientVersion() < 3)
         {
-            if (level > context->getMaximumTextureLevel())
-            {
-                return gl::error(GL_INVALID_VALUE);
-            }
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
 
-            if (format == GL_FLOAT)
-            {
-                if (!context->supportsFloat32Textures())
-                {
-                    return gl::error(GL_INVALID_ENUM);
-                }
-            }
-            else if (format == GL_HALF_FLOAT_OES)
-            {
-                if (!context->supportsFloat16Textures())
-                {
-                    return gl::error(GL_INVALID_ENUM);
-                }
-            }
-            else if (gl::IsDepthTexture(format))
+        const gl::Caps &caps = context->getCaps();
+        switch (target)
+        {
+          case GL_TRANSFORM_FEEDBACK_BUFFER_START:
+          case GL_TRANSFORM_FEEDBACK_BUFFER_SIZE:
+          case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING:
+            if (index >= caps.maxTransformFeedbackSeparateAttributes)
             {
-                if (!context->supportsDepthTextures())
-                {
-                    return gl::error(GL_INVALID_ENUM);
-                }
-                if (target != GL_TEXTURE_2D)
-                {
-                    return gl::error(GL_INVALID_OPERATION);
-                }
-                // OES_depth_texture supports loading depth data, but ANGLE_depth_texture does not
-                return gl::error(GL_INVALID_OPERATION);
+                context->recordError(gl::Error(GL_INVALID_VALUE));
+                return;
             }
+            break;
 
-            if (width == 0 || height == 0 || pixels == NULL)
+          case GL_UNIFORM_BUFFER_START:
+          case GL_UNIFORM_BUFFER_SIZE:
+          case GL_UNIFORM_BUFFER_BINDING:
+            if (index >= caps.maxUniformBufferBindings)
             {
+                context->recordError(gl::Error(GL_INVALID_VALUE));
                 return;
             }
+            break;
+
+          default:
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
+        }
 
-            if (target == GL_TEXTURE_2D)
+        if (!(context->getIndexedInteger64v(target, index, data)))
+        {
+            GLenum nativeType;
+            unsigned int numParams = 0;
+            if (!context->getIndexedQueryParameterInfo(target, &nativeType, &numParams))
             {
-                gl::Texture2D *texture = context->getTexture2D();
-                if (validateSubImageParams2D(false, width, height, xoffset, yoffset, level, format, type, texture))
-                {
-                    texture->subImage(level, xoffset, yoffset, width, height, format, type, context->getUnpackAlignment(), pixels);
-                }
+                context->recordError(gl::Error(GL_INVALID_ENUM));
+                return;
             }
-            else if (gl::IsCubemapTextureTarget(target))
+
+            if (numParams == 0)
+                return; // it is known that pname is valid, but there are no parameters to return
+
+            if (nativeType == GL_INT)
             {
-                gl::TextureCubeMap *texture = context->getTextureCubeMap();
-                if (validateSubImageParamsCube(false, width, height, xoffset, yoffset, target, level, format, type, texture))
+                GLint *intParams = new GLint[numParams];
+
+                context->getIndexedIntegerv(target, index, intParams);
+
+                for (unsigned int i = 0; i < numParams; ++i)
                 {
-                    texture->subImage(target, level, xoffset, yoffset, width, height, format, type, context->getUnpackAlignment(), pixels);
+                    data[i] = static_cast<GLint64>(intParams[i]);
                 }
+
+                delete [] intParams;
             }
             else
             {
@@ -5975,1046 +7531,1133 @@ void __stdcall glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint
             }
         }
     }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
-    }
 }
 
-void __stdcall glUniform1f(GLint location, GLfloat x)
+void __stdcall glGetBufferParameteri64v(GLenum target, GLenum pname, GLint64* params)
 {
-    glUniform1fv(location, 1, &x);
+    EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint64* params = 0x%0.8p)",
+          target, pname, params);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (context->getClientVersion() < 3)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
+
+        if (!gl::ValidBufferTarget(context, target))
+        {
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
+        }
+
+        if (!gl::ValidBufferParameter(context, pname))
+        {
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
+        }
+
+        gl::Buffer *buffer = context->getState().getTargetBuffer(target);
+
+        if (!buffer)
+        {
+            // A null buffer means that "0" is bound to the requested buffer target
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
+
+        switch (pname)
+        {
+          case GL_BUFFER_USAGE:
+            *params = static_cast<GLint64>(buffer->getUsage());
+            break;
+          case GL_BUFFER_SIZE:
+            *params = buffer->getSize();
+            break;
+          case GL_BUFFER_ACCESS_FLAGS:
+            *params = static_cast<GLint64>(buffer->getAccessFlags());
+            break;
+          case GL_BUFFER_MAPPED:
+            *params = static_cast<GLint64>(buffer->isMapped());
+            break;
+          case GL_BUFFER_MAP_OFFSET:
+            *params = buffer->getMapOffset();
+            break;
+          case GL_BUFFER_MAP_LENGTH:
+            *params = buffer->getMapLength();
+            break;
+          default: UNREACHABLE(); break;
+        }
+    }
 }
 
-void __stdcall glUniform1fv(GLint location, GLsizei count, const GLfloat* v)
+void __stdcall glGenSamplers(GLsizei count, GLuint* samplers)
 {
-    EVENT("(GLint location = %d, GLsizei count = %d, const GLfloat* v = 0x%0.8p)", location, count, v);
+    EVENT("(GLsizei count = %d, GLuint* samplers = 0x%0.8p)", count, samplers);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        if (count < 0)
+        if (context->getClientVersion() < 3)
         {
-            return gl::error(GL_INVALID_VALUE);
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
         }
 
-        if (location == -1)
+        if (count < 0)
         {
+            context->recordError(gl::Error(GL_INVALID_VALUE));
             return;
         }
 
-        gl::Context *context = gl::getNonLostContext();
+        for (int i = 0; i < count; i++)
+        {
+            samplers[i] = context->createSampler();
+        }
+    }
+}
+
+void __stdcall glDeleteSamplers(GLsizei count, const GLuint* samplers)
+{
+    EVENT("(GLsizei count = %d, const GLuint* samplers = 0x%0.8p)", count, samplers);
 
-        if (context)
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (context->getClientVersion() < 3)
         {
-            gl::ProgramBinary *programBinary = context->getCurrentProgramBinary();
-            if (!programBinary)
-            {
-                return gl::error(GL_INVALID_OPERATION);
-            }
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
 
-            if (!programBinary->setUniform1fv(location, count, v))
-            {
-                return gl::error(GL_INVALID_OPERATION);
-            }
+        if (count < 0)
+        {
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
+        }
+
+        for (int i = 0; i < count; i++)
+        {
+            context->deleteSampler(samplers[i]);
         }
     }
-    catch(std::bad_alloc&)
+}
+
+GLboolean __stdcall glIsSampler(GLuint sampler)
+{
+    EVENT("(GLuint sampler = %u)", sampler);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        return gl::error(GL_OUT_OF_MEMORY);
+        if (context->getClientVersion() < 3)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return GL_FALSE;
+        }
+
+        return context->isSampler(sampler);
     }
+
+    return GL_FALSE;
 }
 
-void __stdcall glUniform1i(GLint location, GLint x)
+void __stdcall glBindSampler(GLuint unit, GLuint sampler)
 {
-    glUniform1iv(location, 1, &x);
+    EVENT("(GLuint unit = %u, GLuint sampler = %u)", unit, sampler);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (context->getClientVersion() < 3)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
+
+        if (sampler != 0 && !context->isSampler(sampler))
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
+
+        if (unit >= context->getCaps().maxCombinedTextureImageUnits)
+        {
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
+        }
+
+        context->bindSampler(unit, sampler);
+    }
 }
 
-void __stdcall glUniform1iv(GLint location, GLsizei count, const GLint* v)
+void __stdcall glSamplerParameteri(GLuint sampler, GLenum pname, GLint param)
 {
-    EVENT("(GLint location = %d, GLsizei count = %d, const GLint* v = 0x%0.8p)", location, count, v);
+    EVENT("(GLuint sampler = %u, GLenum pname = 0x%X, GLint param = %d)", sampler, pname, param);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        if (count < 0)
+        if (context->getClientVersion() < 3)
         {
-            return gl::error(GL_INVALID_VALUE);
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
         }
 
-        if (location == -1)
+        if (!gl::ValidateSamplerObjectParameter(context, pname))
         {
             return;
         }
 
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
+        if (!gl::ValidateTexParamParameters(context, pname, param))
         {
-            gl::ProgramBinary *programBinary = context->getCurrentProgramBinary();
-            if (!programBinary)
-            {
-                return gl::error(GL_INVALID_OPERATION);
-            }
+            return;
+        }
 
-            if (!programBinary->setUniform1iv(location, count, v))
-            {
-                return gl::error(GL_INVALID_OPERATION);
-            }
+        if (!context->isSampler(sampler))
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
         }
-    }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
+
+        context->samplerParameteri(sampler, pname, param);
     }
 }
 
-void __stdcall glUniform2f(GLint location, GLfloat x, GLfloat y)
+void __stdcall glSamplerParameteriv(GLuint sampler, GLenum pname, const GLint* param)
 {
-    GLfloat xy[2] = {x, y};
-
-    glUniform2fv(location, 1, (GLfloat*)&xy);
+    glSamplerParameteri(sampler, pname, *param);
 }
 
-void __stdcall glUniform2fv(GLint location, GLsizei count, const GLfloat* v)
+void __stdcall glSamplerParameterf(GLuint sampler, GLenum pname, GLfloat param)
 {
-    EVENT("(GLint location = %d, GLsizei count = %d, const GLfloat* v = 0x%0.8p)", location, count, v);
+    EVENT("(GLuint sampler = %u, GLenum pname = 0x%X, GLfloat param = %g)", sampler, pname, param);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        if (count < 0)
+        if (context->getClientVersion() < 3)
         {
-            return gl::error(GL_INVALID_VALUE);
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
         }
-        
-        if (location == -1)
+
+        if (!gl::ValidateSamplerObjectParameter(context, pname))
         {
             return;
         }
 
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
+        if (!gl::ValidateTexParamParameters(context, pname, static_cast<GLint>(param)))
         {
-            gl::ProgramBinary *programBinary = context->getCurrentProgramBinary();
-            if (!programBinary)
-            {
-                return gl::error(GL_INVALID_OPERATION);
-            }
+            return;
+        }
 
-            if (!programBinary->setUniform2fv(location, count, v))
-            {
-                return gl::error(GL_INVALID_OPERATION);
-            }
+        if (!context->isSampler(sampler))
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
         }
-    }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
+
+        context->samplerParameterf(sampler, pname, param);
     }
 }
 
-void __stdcall glUniform2i(GLint location, GLint x, GLint y)
+void __stdcall glSamplerParameterfv(GLuint sampler, GLenum pname, const GLfloat* param)
 {
-    GLint xy[4] = {x, y};
-
-    glUniform2iv(location, 1, (GLint*)&xy);
+    glSamplerParameterf(sampler, pname, *param);
 }
 
-void __stdcall glUniform2iv(GLint location, GLsizei count, const GLint* v)
+void __stdcall glGetSamplerParameteriv(GLuint sampler, GLenum pname, GLint* params)
 {
-    EVENT("(GLint location = %d, GLsizei count = %d, const GLint* v = 0x%0.8p)", location, count, v);
+    EVENT("(GLuint sampler = %u, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", sampler, pname, params);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        if (count < 0)
+        if (context->getClientVersion() < 3)
         {
-            return gl::error(GL_INVALID_VALUE);
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
         }
 
-        if (location == -1)
+        if (!gl::ValidateSamplerObjectParameter(context, pname))
         {
             return;
         }
 
-        gl::Context *context = gl::getNonLostContext();
+        if (!context->isSampler(sampler))
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
 
-        if (context)
+        *params = context->getSamplerParameteri(sampler, pname);
+    }
+}
+
+void __stdcall glGetSamplerParameterfv(GLuint sampler, GLenum pname, GLfloat* params)
+{
+    EVENT("(GLuint sample = %ur, GLenum pname = 0x%X, GLfloat* params = 0x%0.8p)", sampler, pname, params);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (context->getClientVersion() < 3)
         {
-            gl::ProgramBinary *programBinary = context->getCurrentProgramBinary();
-            if (!programBinary)
-            {
-                return gl::error(GL_INVALID_OPERATION);
-            }
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
 
-            if (!programBinary->setUniform2iv(location, count, v))
-            {
-                return gl::error(GL_INVALID_OPERATION);
-            }
+        if (!gl::ValidateSamplerObjectParameter(context, pname))
+        {
+            return;
+        }
+
+        if (!context->isSampler(sampler))
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
         }
+
+        *params = context->getSamplerParameterf(sampler, pname);
     }
-    catch(std::bad_alloc&)
+}
+
+void __stdcall glVertexAttribDivisor(GLuint index, GLuint divisor)
+{
+    EVENT("(GLuint index = %u, GLuint divisor = %u)", index, divisor);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        return gl::error(GL_OUT_OF_MEMORY);
+        if (context->getClientVersion() < 3)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
+
+        if (index >= gl::MAX_VERTEX_ATTRIBS)
+        {
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
+        }
+
+        context->setVertexAttribDivisor(index, divisor);
     }
 }
 
-void __stdcall glUniform3f(GLint location, GLfloat x, GLfloat y, GLfloat z)
+void __stdcall glBindTransformFeedback(GLenum target, GLuint id)
 {
-    GLfloat xyz[3] = {x, y, z};
+    EVENT("(GLenum target = 0x%X, GLuint id = %u)", target, id);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (context->getClientVersion() < 3)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
 
-    glUniform3fv(location, 1, (GLfloat*)&xyz);
+        switch (target)
+        {
+          case GL_TRANSFORM_FEEDBACK:
+            {
+                // Cannot bind a transform feedback object if the current one is started and not paused (3.0.2 pg 85 section 2.14.1)
+                gl::TransformFeedback *curTransformFeedback = context->getState().getCurrentTransformFeedback();
+                if (curTransformFeedback && curTransformFeedback->isStarted() && !curTransformFeedback->isPaused())
+                {
+                    context->recordError(gl::Error(GL_INVALID_OPERATION));
+                    return;
+                }
+
+                // Cannot bind a transform feedback object that does not exist (3.0.2 pg 85 section 2.14.1)
+                if (context->getTransformFeedback(id) == NULL)
+                {
+                    context->recordError(gl::Error(GL_INVALID_OPERATION));
+                    return;
+                }
+
+                context->bindTransformFeedback(id);
+            }
+            break;
+
+          default:
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
+        }
+    }
 }
 
-void __stdcall glUniform3fv(GLint location, GLsizei count, const GLfloat* v)
+void __stdcall glDeleteTransformFeedbacks(GLsizei n, const GLuint* ids)
 {
-    EVENT("(GLint location = %d, GLsizei count = %d, const GLfloat* v = 0x%0.8p)", location, count, v);
+    EVENT("(GLsizei n = %d, const GLuint* ids = 0x%0.8p)", n, ids);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        if (count < 0)
+        if (context->getClientVersion() < 3)
         {
-            return gl::error(GL_INVALID_VALUE);
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
         }
 
-        if (location == -1)
+        for (int i = 0; i < n; i++)
         {
-            return;
+            context->deleteTransformFeedback(ids[i]);
         }
+    }
+}
 
-        gl::Context *context = gl::getNonLostContext();
+void __stdcall glGenTransformFeedbacks(GLsizei n, GLuint* ids)
+{
+    EVENT("(GLsizei n = %d, GLuint* ids = 0x%0.8p)", n, ids);
 
-        if (context)
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (context->getClientVersion() < 3)
         {
-            gl::ProgramBinary *programBinary = context->getCurrentProgramBinary();
-            if (!programBinary)
-            {
-                return gl::error(GL_INVALID_OPERATION);
-            }
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
 
-            if (!programBinary->setUniform3fv(location, count, v))
-            {
-                return gl::error(GL_INVALID_OPERATION);
-            }
+        for (int i = 0; i < n; i++)
+        {
+            ids[i] = context->createTransformFeedback();
         }
     }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
-    }
 }
 
-void __stdcall glUniform3i(GLint location, GLint x, GLint y, GLint z)
+GLboolean __stdcall glIsTransformFeedback(GLuint id)
 {
-    GLint xyz[3] = {x, y, z};
+    EVENT("(GLuint id = %u)", id);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (context->getClientVersion() < 3)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return GL_FALSE;
+        }
+
+        return ((context->getTransformFeedback(id) != NULL) ? GL_TRUE : GL_FALSE);
+    }
 
-    glUniform3iv(location, 1, (GLint*)&xyz);
+    return GL_FALSE;
 }
 
-void __stdcall glUniform3iv(GLint location, GLsizei count, const GLint* v)
+void __stdcall glPauseTransformFeedback(void)
 {
-    EVENT("(GLint location = %d, GLsizei count = %d, const GLint* v = 0x%0.8p)", location, count, v);
+    EVENT("(void)");
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        if (count < 0)
-        {
-            return gl::error(GL_INVALID_VALUE);
-        }
-
-        if (location == -1)
+        if (context->getClientVersion() < 3)
         {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
             return;
         }
 
-        gl::Context *context = gl::getNonLostContext();
+        gl::TransformFeedback *transformFeedback = context->getState().getCurrentTransformFeedback();
+        ASSERT(transformFeedback != NULL);
 
-        if (context)
+        // Current transform feedback must be started and not paused in order to pause (3.0.2 pg 86)
+        if (!transformFeedback->isStarted() || transformFeedback->isPaused())
         {
-            gl::ProgramBinary *programBinary = context->getCurrentProgramBinary();
-            if (!programBinary)
-            {
-                return gl::error(GL_INVALID_OPERATION);
-            }
-
-            if (!programBinary->setUniform3iv(location, count, v))
-            {
-                return gl::error(GL_INVALID_OPERATION);
-            }
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
         }
-    }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
-    }
-}
-
-void __stdcall glUniform4f(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
-{
-    GLfloat xyzw[4] = {x, y, z, w};
 
-    glUniform4fv(location, 1, (GLfloat*)&xyzw);
+        transformFeedback->pause();
+    }
 }
 
-void __stdcall glUniform4fv(GLint location, GLsizei count, const GLfloat* v)
+void __stdcall glResumeTransformFeedback(void)
 {
-    EVENT("(GLint location = %d, GLsizei count = %d, const GLfloat* v = 0x%0.8p)", location, count, v);
+    EVENT("(void)");
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        if (count < 0)
-        {
-            return gl::error(GL_INVALID_VALUE);
-        }
-
-        if (location == -1)
+        if (context->getClientVersion() < 3)
         {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
             return;
         }
 
-        gl::Context *context = gl::getNonLostContext();
+        gl::TransformFeedback *transformFeedback = context->getState().getCurrentTransformFeedback();
+        ASSERT(transformFeedback != NULL);
 
-        if (context)
+        // Current transform feedback must be started and paused in order to resume (3.0.2 pg 86)
+        if (!transformFeedback->isStarted() || !transformFeedback->isPaused())
         {
-            gl::ProgramBinary *programBinary = context->getCurrentProgramBinary();
-            if (!programBinary)
-            {
-                return gl::error(GL_INVALID_OPERATION);
-            }
-
-            if (!programBinary->setUniform4fv(location, count, v))
-            {
-                return gl::error(GL_INVALID_OPERATION);
-            }
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
         }
-    }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
+
+        transformFeedback->resume();
     }
 }
 
-void __stdcall glUniform4i(GLint location, GLint x, GLint y, GLint z, GLint w)
+void __stdcall glGetProgramBinary(GLuint program, GLsizei bufSize, GLsizei* length, GLenum* binaryFormat, GLvoid* binary)
 {
-    GLint xyzw[4] = {x, y, z, w};
+    EVENT("(GLuint program = %u, GLsizei bufSize = %d, GLsizei* length = 0x%0.8p, GLenum* binaryFormat = 0x%0.8p, GLvoid* binary = 0x%0.8p)",
+          program, bufSize, length, binaryFormat, binary);
+
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
+    {
+        if (context->getClientVersion() < 3)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
 
-    glUniform4iv(location, 1, (GLint*)&xyzw);
+        // glGetProgramBinary
+        UNIMPLEMENTED();
+    }
 }
 
-void __stdcall glUniform4iv(GLint location, GLsizei count, const GLint* v)
+void __stdcall glProgramBinary(GLuint program, GLenum binaryFormat, const GLvoid* binary, GLsizei length)
 {
-    EVENT("(GLint location = %d, GLsizei count = %d, const GLint* v = 0x%0.8p)", location, count, v);
+    EVENT("(GLuint program = %u, GLenum binaryFormat = 0x%X, const GLvoid* binary = 0x%0.8p, GLsizei length = %d)",
+          program, binaryFormat, binary, length);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        if (count < 0)
-        {
-            return gl::error(GL_INVALID_VALUE);
-        }
-
-        if (location == -1)
+        if (context->getClientVersion() < 3)
         {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
             return;
         }
 
-        gl::Context *context = gl::getNonLostContext();
+        // glProgramBinary
+        UNIMPLEMENTED();
+    }
+}
 
-        if (context)
-        {
-            gl::ProgramBinary *programBinary = context->getCurrentProgramBinary();
-            if (!programBinary)
-            {
-                return gl::error(GL_INVALID_OPERATION);
-            }
+void __stdcall glProgramParameteri(GLuint program, GLenum pname, GLint value)
+{
+    EVENT("(GLuint program = %u, GLenum pname = 0x%X, GLint value = %d)",
+          program, pname, value);
 
-            if (!programBinary->setUniform4iv(location, count, v))
-            {
-                return gl::error(GL_INVALID_OPERATION);
-            }
-        }
-    }
-    catch(std::bad_alloc&)
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        return gl::error(GL_OUT_OF_MEMORY);
+        if (context->getClientVersion() < 3)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
+
+        // glProgramParameteri
+        UNIMPLEMENTED();
     }
 }
 
-void __stdcall glUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+void __stdcall glInvalidateFramebuffer(GLenum target, GLsizei numAttachments, const GLenum* attachments)
 {
-    EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %d, const GLfloat* value = 0x%0.8p)",
-          location, count, transpose, value);
+    EVENT("(GLenum target = 0x%X, GLsizei numAttachments = %d, const GLenum* attachments = 0x%0.8p)",
+          target, numAttachments, attachments);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        if (count < 0 || transpose != GL_FALSE)
+        if (context->getClientVersion() < 3)
         {
-            return gl::error(GL_INVALID_VALUE);
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
         }
 
-        if (location == -1)
+        if (!ValidateInvalidateFramebufferParameters(context, target, numAttachments, attachments))
         {
             return;
         }
 
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
+        gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
+        if (framebuffer && framebuffer->completeness() == GL_FRAMEBUFFER_COMPLETE)
         {
-            gl::ProgramBinary *programBinary = context->getCurrentProgramBinary();
-            if (!programBinary)
-            {
-                return gl::error(GL_INVALID_OPERATION);
-            }
-
-            if (!programBinary->setUniformMatrix2fv(location, count, value))
-            {
-                return gl::error(GL_INVALID_OPERATION);
-            }
+            framebuffer->invalidate(context->getCaps(), numAttachments, attachments);
         }
     }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
-    }
 }
 
-void __stdcall glUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+void __stdcall glInvalidateSubFramebuffer(GLenum target, GLsizei numAttachments, const GLenum* attachments, GLint x, GLint y, GLsizei width, GLsizei height)
 {
-    EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %d, const GLfloat* value = 0x%0.8p)",
-          location, count, transpose, value);
+    EVENT("(GLenum target = 0x%X, GLsizei numAttachments = %d, const GLenum* attachments = 0x%0.8p, GLint x = %d, "
+          "GLint y = %d, GLsizei width = %d, GLsizei height = %d)",
+          target, numAttachments, attachments, x, y, width, height);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        if (count < 0 || transpose != GL_FALSE)
+        if (context->getClientVersion() < 3)
         {
-            return gl::error(GL_INVALID_VALUE);
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
         }
 
-        if (location == -1)
+        if (!ValidateInvalidateFramebufferParameters(context, target, numAttachments, attachments))
         {
             return;
         }
 
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
+        gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
+        if (framebuffer && framebuffer->completeness() == GL_FRAMEBUFFER_COMPLETE)
         {
-            gl::ProgramBinary *programBinary = context->getCurrentProgramBinary();
-            if (!programBinary)
-            {
-                return gl::error(GL_INVALID_OPERATION);
-            }
-
-            if (!programBinary->setUniformMatrix3fv(location, count, value))
-            {
-                return gl::error(GL_INVALID_OPERATION);
-            }
+            framebuffer->invalidateSub(context->getCaps(), numAttachments, attachments, x, y, width, height);
         }
     }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
-    }
 }
 
-void __stdcall glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+void __stdcall glTexStorage2D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
 {
-    EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %d, const GLfloat* value = 0x%0.8p)",
-          location, count, transpose, value);
+    EVENT("(GLenum target = 0x%X, GLsizei levels = %d, GLenum internalformat = 0x%X, GLsizei width = %d, GLsizei height = %d)",
+          target, levels, internalformat, width, height);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        if (count < 0 || transpose != GL_FALSE)
+        if (context->getClientVersion() < 3)
         {
-            return gl::error(GL_INVALID_VALUE);
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
         }
 
-        if (location == -1)
+        if (!ValidateES3TexStorageParameters(context, target, levels, internalformat, width, height, 1))
         {
             return;
         }
 
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
+        switch (target)
         {
-            gl::ProgramBinary *programBinary = context->getCurrentProgramBinary();
-            if (!programBinary)
+          case GL_TEXTURE_2D:
             {
-                return gl::error(GL_INVALID_OPERATION);
+                gl::Texture2D *texture2d = context->getTexture2D();
+                texture2d->storage(levels, internalformat, width, height);
             }
+            break;
 
-            if (!programBinary->setUniformMatrix4fv(location, count, value))
+          case GL_TEXTURE_CUBE_MAP:
             {
-                return gl::error(GL_INVALID_OPERATION);
+                gl::TextureCubeMap *textureCube = context->getTextureCubeMap();
+                textureCube->storage(levels, internalformat, width);
             }
+            break;
+
+          default:
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
         }
     }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
-    }
 }
 
-void __stdcall glUseProgram(GLuint program)
+void __stdcall glTexStorage3D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
 {
-    EVENT("(GLuint program = %d)", program);
+    EVENT("(GLenum target = 0x%X, GLsizei levels = %d, GLenum internalformat = 0x%X, GLsizei width = %d, "
+          "GLsizei height = %d, GLsizei depth = %d)",
+          target, levels, internalformat, width, height, depth);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        gl::Context *context = gl::getNonLostContext();
+        if (context->getClientVersion() < 3)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
 
-        if (context)
+        if (!ValidateES3TexStorageParameters(context, target, levels, internalformat, width, height, depth))
         {
-            gl::Program *programObject = context->getProgram(program);
+            return;
+        }
 
-            if (!programObject && program != 0)
+        switch (target)
+        {
+          case GL_TEXTURE_3D:
             {
-                if (context->getShader(program))
-                {
-                    return gl::error(GL_INVALID_OPERATION);
-                }
-                else
-                {
-                    return gl::error(GL_INVALID_VALUE);
-                }
+                gl::Texture3D *texture3d = context->getTexture3D();
+                texture3d->storage(levels, internalformat, width, height, depth);
             }
+            break;
 
-            if (program != 0 && !programObject->isLinked())
+          case GL_TEXTURE_2D_ARRAY:
             {
-                return gl::error(GL_INVALID_OPERATION);
+                gl::Texture2DArray *texture2darray = context->getTexture2DArray();
+                texture2darray->storage(levels, internalformat, width, height, depth);
             }
+            break;
 
-            context->useProgram(program);
+          default:
+            UNREACHABLE();
         }
     }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
-    }
 }
 
-void __stdcall glValidateProgram(GLuint program)
+void __stdcall glGetInternalformativ(GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint* params)
 {
-    EVENT("(GLuint program = %d)", program);
+    EVENT("(GLenum target = 0x%X, GLenum internalformat = 0x%X, GLenum pname = 0x%X, GLsizei bufSize = %d, "
+          "GLint* params = 0x%0.8p)",
+          target, internalformat, pname, bufSize, params);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
+        if (context->getClientVersion() < 3)
         {
-            gl::Program *programObject = context->getProgram(program);
-
-            if (!programObject)
-            {
-                if (context->getShader(program))
-                {
-                    return gl::error(GL_INVALID_OPERATION);
-                }
-                else
-                {
-                    return gl::error(GL_INVALID_VALUE);
-                }
-            }
-
-            programObject->validate();
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
         }
-    }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
-    }
-}
-
-void __stdcall glVertexAttrib1f(GLuint index, GLfloat x)
-{
-    EVENT("(GLuint index = %d, GLfloat x = %f)", index, x);
 
-    try
-    {
-        if (index >= gl::MAX_VERTEX_ATTRIBS)
+        const gl::TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
+        if (!formatCaps.renderable)
         {
-            return gl::error(GL_INVALID_VALUE);
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
         }
 
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
+        if (target != GL_RENDERBUFFER)
         {
-            GLfloat vals[4] = { x, 0, 0, 1 };
-            context->setVertexAttrib(index, vals);
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
         }
-    }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
-    }
-}
-
-void __stdcall glVertexAttrib1fv(GLuint index, const GLfloat* values)
-{
-    EVENT("(GLuint index = %d, const GLfloat* values = 0x%0.8p)", index, values);
 
-    try
-    {
-        if (index >= gl::MAX_VERTEX_ATTRIBS)
+        if (bufSize < 0)
         {
-            return gl::error(GL_INVALID_VALUE);
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
         }
 
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
+        switch (pname)
         {
-            GLfloat vals[4] = { values[0], 0, 0, 1 };
-            context->setVertexAttrib(index, vals);
+          case GL_NUM_SAMPLE_COUNTS:
+            if (bufSize != 0)
+            {
+                *params = formatCaps.sampleCounts.size();
+            }
+            break;
+
+          case GL_SAMPLES:
+            std::copy_n(formatCaps.sampleCounts.rbegin(), std::min<size_t>(bufSize, formatCaps.sampleCounts.size()), params);
+            break;
+
+          default:
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
         }
     }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
-    }
 }
 
-void __stdcall glVertexAttrib2f(GLuint index, GLfloat x, GLfloat y)
+// Extension functions
+
+void __stdcall glBlitFramebufferANGLE(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
+                                      GLbitfield mask, GLenum filter)
 {
-    EVENT("(GLuint index = %d, GLfloat x = %f, GLfloat y = %f)", index, x, y);
+    EVENT("(GLint srcX0 = %d, GLint srcY0 = %d, GLint srcX1 = %d, GLint srcY1 = %d, "
+          "GLint dstX0 = %d, GLint dstY0 = %d, GLint dstX1 = %d, GLint dstY1 = %d, "
+          "GLbitfield mask = 0x%X, GLenum filter = 0x%X)",
+          srcX0, srcY0, srcX1, srcX1, dstX0, dstY0, dstX1, dstY1, mask, filter);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        if (index >= gl::MAX_VERTEX_ATTRIBS)
+        if (!ValidateBlitFramebufferParameters(context, srcX0, srcY0, srcX1, srcY1,
+                                               dstX0, dstY0, dstX1, dstY1, mask, filter,
+                                               true))
         {
-            return gl::error(GL_INVALID_VALUE);
+            return;
         }
 
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
-        {
-            GLfloat vals[4] = { x, y, 0, 1 };
-            context->setVertexAttrib(index, vals);
-        }
-    }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
+        context->blitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1,
+                                 mask, filter);
     }
 }
 
-void __stdcall glVertexAttrib2fv(GLuint index, const GLfloat* values)
+void __stdcall glTexImage3DOES(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth,
+                               GLint border, GLenum format, GLenum type, const GLvoid* pixels)
 {
-    EVENT("(GLuint index = %d, const GLfloat* values = 0x%0.8p)", index, values);
+    EVENT("(GLenum target = 0x%X, GLint level = %d, GLenum internalformat = 0x%X, "
+          "GLsizei width = %d, GLsizei height = %d, GLsizei depth = %d, GLint border = %d, "
+          "GLenum format = 0x%X, GLenum type = 0x%x, const GLvoid* pixels = 0x%0.8p)",
+          target, level, internalformat, width, height, depth, border, format, type, pixels);
+
+    UNIMPLEMENTED();   // FIXME
+}
+
+void __stdcall glGetProgramBinaryOES(GLuint program, GLsizei bufSize, GLsizei *length,
+                                     GLenum *binaryFormat, void *binary)
+{
+    EVENT("(GLenum program = 0x%X, bufSize = %d, length = 0x%0.8p, binaryFormat = 0x%0.8p, binary = 0x%0.8p)",
+          program, bufSize, length, binaryFormat, binary);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        if (index >= gl::MAX_VERTEX_ATTRIBS)
+        gl::Program *programObject = context->getProgram(program);
+
+        if (!programObject || !programObject->isLinked())
         {
-            return gl::error(GL_INVALID_VALUE);
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
         }
 
-        gl::Context *context = gl::getNonLostContext();
+        gl::ProgramBinary *programBinary = programObject->getProgramBinary();
 
-        if (context)
+        if (!programBinary)
         {
-            GLfloat vals[4] = { values[0], values[1], 0, 1 };
-            context->setVertexAttrib(index, vals);
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
+
+        if (!programBinary->save(binaryFormat, binary, bufSize, length))
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
         }
-    }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
     }
 }
 
-void __stdcall glVertexAttrib3f(GLuint index, GLfloat x, GLfloat y, GLfloat z)
+void __stdcall glProgramBinaryOES(GLuint program, GLenum binaryFormat,
+                                  const void *binary, GLint length)
 {
-    EVENT("(GLuint index = %d, GLfloat x = %f, GLfloat y = %f, GLfloat z = %f)", index, x, y, z);
+    EVENT("(GLenum program = 0x%X, binaryFormat = 0x%x, binary = 0x%0.8p, length = %d)",
+          program, binaryFormat, binary, length);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        if (index >= gl::MAX_VERTEX_ATTRIBS)
+        const std::vector<GLenum> &programBinaryFormats = context->getCaps().programBinaryFormats;
+        if (std::find(programBinaryFormats.begin(), programBinaryFormats.end(), binaryFormat) == programBinaryFormats.end())
         {
-            return gl::error(GL_INVALID_VALUE);
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
         }
 
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
+        gl::Program *programObject = context->getProgram(program);
+        if (!programObject)
         {
-            GLfloat vals[4] = { x, y, z, 1 };
-            context->setVertexAttrib(index, vals);
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
         }
-    }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
+
+        context->setProgramBinary(program, binaryFormat, binary, length);
     }
 }
 
-void __stdcall glVertexAttrib3fv(GLuint index, const GLfloat* values)
+void __stdcall glDrawBuffersEXT(GLsizei n, const GLenum *bufs)
 {
-    EVENT("(GLuint index = %d, const GLfloat* values = 0x%0.8p)", index, values);
+    EVENT("(GLenum n = %d, bufs = 0x%0.8p)", n, bufs);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        if (index >= gl::MAX_VERTEX_ATTRIBS)
+        if (n < 0 || static_cast<GLuint>(n) > context->getCaps().maxDrawBuffers)
         {
-            return gl::error(GL_INVALID_VALUE);
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
         }
 
-        gl::Context *context = gl::getNonLostContext();
+        if (context->getState().getDrawFramebuffer()->id() == 0)
+        {
+            if (n != 1)
+            {
+                context->recordError(gl::Error(GL_INVALID_OPERATION));
+                return;
+            }
 
-        if (context)
+            if (bufs[0] != GL_NONE && bufs[0] != GL_BACK)
+            {
+                context->recordError(gl::Error(GL_INVALID_OPERATION));
+                return;
+            }
+        }
+        else
         {
-            GLfloat vals[4] = { values[0], values[1], values[2], 1 };
-            context->setVertexAttrib(index, vals);
+            for (int colorAttachment = 0; colorAttachment < n; colorAttachment++)
+            {
+                const GLenum attachment = GL_COLOR_ATTACHMENT0_EXT + colorAttachment;
+                if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != attachment)
+                {
+                    context->recordError(gl::Error(GL_INVALID_OPERATION));
+                    return;
+                }
+            }
         }
-    }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
-    }
-}
 
-void __stdcall glVertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
-{
-    EVENT("(GLuint index = %d, GLfloat x = %f, GLfloat y = %f, GLfloat z = %f, GLfloat w = %f)", index, x, y, z, w);
+        gl::Framebuffer *framebuffer = context->getState().getDrawFramebuffer();
 
-    try
-    {
-        if (index >= gl::MAX_VERTEX_ATTRIBS)
+        for (unsigned int colorAttachment = 0; colorAttachment < static_cast<unsigned int>(n); colorAttachment++)
         {
-            return gl::error(GL_INVALID_VALUE);
+            framebuffer->setDrawBufferState(colorAttachment, bufs[colorAttachment]);
         }
 
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
+        for (unsigned int colorAttachment = n; colorAttachment < context->getCaps().maxDrawBuffers; colorAttachment++)
         {
-            GLfloat vals[4] = { x, y, z, w };
-            context->setVertexAttrib(index, vals);
+            framebuffer->setDrawBufferState(colorAttachment, GL_NONE);
         }
     }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
-    }
 }
 
-void __stdcall glVertexAttrib4fv(GLuint index, const GLfloat* values)
+void __stdcall glGetBufferPointervOES(GLenum target, GLenum pname, void** params)
 {
-    EVENT("(GLuint index = %d, const GLfloat* values = 0x%0.8p)", index, values);
+    EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLvoid** params = 0x%0.8p)", target, pname, params);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        if (index >= gl::MAX_VERTEX_ATTRIBS)
+        if (!gl::ValidBufferTarget(context, target))
         {
-            return gl::error(GL_INVALID_VALUE);
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
         }
 
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
+        if (pname != GL_BUFFER_MAP_POINTER)
         {
-            context->setVertexAttrib(index, values);
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
         }
-    }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
-    }
-}
 
-void __stdcall glVertexAttribDivisorANGLE(GLuint index, GLuint divisor)
-{
-    EVENT("(GLuint index = %d, GLuint divisor = %d)", index, divisor);
+        gl::Buffer *buffer = context->getState().getTargetBuffer(target);
 
-    try
-    {
-        if (index >= gl::MAX_VERTEX_ATTRIBS)
+        if (!buffer || !buffer->isMapped())
         {
-            return gl::error(GL_INVALID_VALUE);
+            *params = NULL;
         }
-
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
+        else
         {
-            context->setVertexAttribDivisor(index, divisor);
+            *params = buffer->getMapPointer();
         }
     }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
-    }
 }
 
-void __stdcall glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr)
+void * __stdcall glMapBufferOES(GLenum target, GLenum access)
 {
-    EVENT("(GLuint index = %d, GLint size = %d, GLenum type = 0x%X, "
-          "GLboolean normalized = %d, GLsizei stride = %d, const GLvoid* ptr = 0x%0.8p)",
-          index, size, type, normalized, stride, ptr);
+    EVENT("(GLenum target = 0x%X, GLbitfield access = 0x%X)", target, access);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        if (index >= gl::MAX_VERTEX_ATTRIBS)
+        if (!gl::ValidBufferTarget(context, target))
         {
-            return gl::error(GL_INVALID_VALUE);
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return NULL;
         }
 
-        if (size < 1 || size > 4)
+        gl::Buffer *buffer = context->getState().getTargetBuffer(target);
+
+        if (buffer == NULL)
         {
-            return gl::error(GL_INVALID_VALUE);
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return NULL;
         }
 
-        switch (type)
+        if (access != GL_WRITE_ONLY_OES)
         {
-          case GL_BYTE:
-          case GL_UNSIGNED_BYTE:
-          case GL_SHORT:
-          case GL_UNSIGNED_SHORT:
-          case GL_FIXED:
-          case GL_FLOAT:
-            break;
-          default:
-            return gl::error(GL_INVALID_ENUM);
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return NULL;
         }
 
-        if (stride < 0)
+        if (buffer->isMapped())
         {
-            return gl::error(GL_INVALID_VALUE);
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return NULL;
         }
 
-        gl::Context *context = gl::getNonLostContext();
-
-        if (context)
+        gl::Error error = buffer->mapRange(0, buffer->getSize(), GL_MAP_WRITE_BIT);
+        if (error.isError())
         {
-            context->setVertexAttribState(index, context->getArrayBuffer(), size, type, (normalized == GL_TRUE), stride, ptr);
+            context->recordError(error);
+            return NULL;
         }
+
+        return buffer->getMapPointer();
     }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
-    }
+
+    return NULL;
 }
 
-void __stdcall glViewport(GLint x, GLint y, GLsizei width, GLsizei height)
+GLboolean __stdcall glUnmapBufferOES(GLenum target)
 {
-    EVENT("(GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d)", x, y, width, height);
+    EVENT("(GLenum target = 0x%X)", target);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        if (width < 0 || height < 0)
+        if (!gl::ValidBufferTarget(context, target))
         {
-            return gl::error(GL_INVALID_VALUE);
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return GL_FALSE;
         }
 
-        gl::Context *context = gl::getNonLostContext();
+        gl::Buffer *buffer = context->getState().getTargetBuffer(target);
 
-        if (context)
+        if (buffer == NULL || !buffer->isMapped())
         {
-            context->setViewportParams(x, y, width, height);
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return GL_FALSE;
         }
+
+        // TODO: detect if we had corruption. if so, throw an error and return false.
+
+        gl::Error error = buffer->unmap();
+        if (error.isError())
+        {
+            context->recordError(error);
+            return GL_FALSE;
+        }
+
+        return GL_TRUE;
     }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
-    }
+
+    return GL_FALSE;
 }
 
-void __stdcall glBlitFramebufferANGLE(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
-                                      GLbitfield mask, GLenum filter)
+void* __stdcall glMapBufferRangeEXT (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access)
 {
-    EVENT("(GLint srcX0 = %d, GLint srcY0 = %d, GLint srcX1 = %d, GLint srcY1 = %d, "
-          "GLint dstX0 = %d, GLint dstY0 = %d, GLint dstX1 = %d, GLint dstY1 = %d, "
-          "GLbitfield mask = 0x%X, GLenum filter = 0x%X)",
-          srcX0, srcY0, srcX1, srcX1, dstX0, dstY0, dstX1, dstY1, mask, filter);
+    EVENT("(GLenum target = 0x%X, GLintptr offset = %d, GLsizeiptr length = %d, GLbitfield access = 0x%X)",
+          target, offset, length, access);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        switch (filter)
+        if (!gl::ValidBufferTarget(context, target))
         {
-          case GL_NEAREST:
-            break;
-          default:
-            return gl::error(GL_INVALID_ENUM);
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return NULL;
         }
 
-        if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0)
+        if (offset < 0 || length < 0)
         {
-            return gl::error(GL_INVALID_VALUE);
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return NULL;
         }
 
-        if (srcX1 - srcX0 != dstX1 - dstX0 || srcY1 - srcY0 != dstY1 - dstY0)
+        gl::Buffer *buffer = context->getState().getTargetBuffer(target);
+
+        if (buffer == NULL)
         {
-            ERR("Scaling and flipping in BlitFramebufferANGLE not supported by this implementation");
-            return gl::error(GL_INVALID_OPERATION);
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return NULL;
         }
 
-        gl::Context *context = gl::getNonLostContext();
+        // Check for buffer overflow
+        size_t offsetSize = static_cast<size_t>(offset);
+        size_t lengthSize = static_cast<size_t>(length);
 
-        if (context)
+        if (!rx::IsUnsignedAdditionSafe(offsetSize, lengthSize) ||
+            offsetSize + lengthSize > static_cast<size_t>(buffer->getSize()))
         {
-            if (context->getReadFramebufferHandle() == context->getDrawFramebufferHandle())
-            {
-                ERR("Blits with the same source and destination framebuffer are not supported by this implementation.");
-                return gl::error(GL_INVALID_OPERATION);
-            }
-
-            context->blitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask);
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return NULL;
         }
-    }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
-    }
-}
-
-void __stdcall glTexImage3DOES(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth,
-                               GLint border, GLenum format, GLenum type, const GLvoid* pixels)
-{
-    EVENT("(GLenum target = 0x%X, GLint level = %d, GLenum internalformat = 0x%X, "
-          "GLsizei width = %d, GLsizei height = %d, GLsizei depth = %d, GLint border = %d, "
-          "GLenum format = 0x%X, GLenum type = 0x%x, const GLvoid* pixels = 0x%0.8p)",
-          target, level, internalformat, width, height, depth, border, format, type, pixels);
-
-    try
-    {
-        UNIMPLEMENTED();   // FIXME
-    }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
-    }
-}
-
-void __stdcall glGetProgramBinaryOES(GLuint program, GLsizei bufSize, GLsizei *length, 
-                                     GLenum *binaryFormat, void *binary)
-{
-    EVENT("(GLenum program = 0x%X, bufSize = %d, length = 0x%0.8p, binaryFormat = 0x%0.8p, binary = 0x%0.8p)",
-          program, bufSize, length, binaryFormat, binary);
 
-    try
-    {
-        gl::Context *context = gl::getNonLostContext();
+        // Check for invalid bits in the mask
+        GLbitfield allAccessBits = GL_MAP_READ_BIT |
+                                   GL_MAP_WRITE_BIT |
+                                   GL_MAP_INVALIDATE_RANGE_BIT |
+                                   GL_MAP_INVALIDATE_BUFFER_BIT |
+                                   GL_MAP_FLUSH_EXPLICIT_BIT |
+                                   GL_MAP_UNSYNCHRONIZED_BIT;
 
-        if (context)
+        if (access & ~(allAccessBits))
         {
-            gl::Program *programObject = context->getProgram(program);
-
-            if (!programObject || !programObject->isLinked())
-            {
-                return gl::error(GL_INVALID_OPERATION);
-            }
-
-            gl::ProgramBinary *programBinary = programObject->getProgramBinary();
-
-            if (!programBinary)
-            {
-                return gl::error(GL_INVALID_OPERATION);
-            }
-
-            if (!programBinary->save(binary, bufSize, length))
-            {
-                return gl::error(GL_INVALID_OPERATION);
-            }
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return NULL;
+        }
 
-            *binaryFormat = GL_PROGRAM_BINARY_ANGLE;
+        if (length == 0 || buffer->isMapped())
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return NULL;
         }
-    }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
-    }
-}
 
-void __stdcall glProgramBinaryOES(GLuint program, GLenum binaryFormat,
-                                  const void *binary, GLint length)
-{
-    EVENT("(GLenum program = 0x%X, binaryFormat = 0x%x, binary = 0x%0.8p, length = %d)",
-          program, binaryFormat, binary, length);
+        // Check for invalid bit combinations
+        if ((access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)) == 0)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return NULL;
+        }
 
-    try
-    {
-        gl::Context *context = gl::getNonLostContext();
+        GLbitfield writeOnlyBits = GL_MAP_INVALIDATE_RANGE_BIT |
+                                   GL_MAP_INVALIDATE_BUFFER_BIT |
+                                   GL_MAP_UNSYNCHRONIZED_BIT;
 
-        if (context)
+        if ((access & GL_MAP_READ_BIT) != 0 && (access & writeOnlyBits) != 0)
         {
-            if (binaryFormat != GL_PROGRAM_BINARY_ANGLE)
-            {
-                return gl::error(GL_INVALID_ENUM);
-            }
-
-            gl::Program *programObject = context->getProgram(program);
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return NULL;
+        }
 
-            if (!programObject)
-            {
-                return gl::error(GL_INVALID_OPERATION);
-            }
+        if ((access & GL_MAP_WRITE_BIT) == 0 && (access & GL_MAP_FLUSH_EXPLICIT_BIT) != 0)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return NULL;
+        }
 
-            context->setProgramBinary(program, binary, length);
+        gl::Error error = buffer->mapRange(offset, length, access);
+        if (error.isError())
+        {
+            context->recordError(error);
+            return NULL;
         }
+
+        return buffer->getMapPointer();
     }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
-    }
+
+    return NULL;
 }
 
-void __stdcall glDrawBuffersEXT(GLsizei n, const GLenum *bufs)
+void __stdcall glFlushMappedBufferRangeEXT (GLenum target, GLintptr offset, GLsizeiptr length)
 {
-    EVENT("(GLenum n = %d, bufs = 0x%0.8p)", n, bufs);
+    EVENT("(GLenum target = 0x%X, GLintptr offset = %d, GLsizeiptr length = %d)", target, offset, length);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        gl::Context *context = gl::getNonLostContext();
+        if (offset < 0 || length < 0)
+        {
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
+        }
 
-        if (context)
+        if (!gl::ValidBufferTarget(context, target))
         {
-            if (n < 0 || (unsigned int)n > context->getMaximumRenderTargets())
-            {
-                return gl::error(GL_INVALID_VALUE);
-            }
+            context->recordError(gl::Error(GL_INVALID_ENUM));
+            return;
+        }
 
-            if (context->getDrawFramebufferHandle() == 0)
-            {
-                if (n != 1)
-                {
-                    return gl::error(GL_INVALID_OPERATION);
-                }
+        gl::Buffer *buffer = context->getState().getTargetBuffer(target);
 
-                if (bufs[0] != GL_NONE && bufs[0] != GL_BACK)
-                {
-                    return gl::error(GL_INVALID_OPERATION);
-                }
-            }
-            else
-            {
-                for (int colorAttachment = 0; colorAttachment < n; colorAttachment++)
-                {
-                    const GLenum attachment = GL_COLOR_ATTACHMENT0_EXT + colorAttachment;
-                    if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != attachment)
-                    {
-                        return gl::error(GL_INVALID_OPERATION);
-                    }
-                }
-            }
+        if (buffer == NULL)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
 
-            gl::Framebuffer *framebuffer = context->getDrawFramebuffer();
+        if (!buffer->isMapped() || (buffer->getAccessFlags() & GL_MAP_FLUSH_EXPLICIT_BIT) == 0)
+        {
+            context->recordError(gl::Error(GL_INVALID_OPERATION));
+            return;
+        }
 
-            for (int colorAttachment = 0; colorAttachment < n; colorAttachment++)
-            {
-                framebuffer->setDrawBufferState(colorAttachment, bufs[colorAttachment]);
-            }
+        // Check for buffer overflow
+        size_t offsetSize = static_cast<size_t>(offset);
+        size_t lengthSize = static_cast<size_t>(length);
 
-            for (int colorAttachment = n; colorAttachment < (int)context->getMaximumRenderTargets(); colorAttachment++)
-            {
-                framebuffer->setDrawBufferState(colorAttachment, GL_NONE);
-            }
+        if (!rx::IsUnsignedAdditionSafe(offsetSize, lengthSize) ||
+            offsetSize + lengthSize > static_cast<size_t>(buffer->getMapLength()))
+        {
+            context->recordError(gl::Error(GL_INVALID_VALUE));
+            return;
         }
-    }
-    catch (std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY);
+
+        // We do not currently support a non-trivial implementation of FlushMappedBufferRange
     }
 }
 
@@ -7056,7 +8699,12 @@ __eglMustCastToProperFunctionPointerType __stdcall glGetProcAddress(const char *
         {"glDrawArraysInstancedANGLE", (__eglMustCastToProperFunctionPointerType)glDrawArraysInstancedANGLE},
         {"glDrawElementsInstancedANGLE", (__eglMustCastToProperFunctionPointerType)glDrawElementsInstancedANGLE},
         {"glGetProgramBinaryOES", (__eglMustCastToProperFunctionPointerType)glGetProgramBinaryOES},
-        {"glProgramBinaryOES", (__eglMustCastToProperFunctionPointerType)glProgramBinaryOES},    };
+        {"glProgramBinaryOES", (__eglMustCastToProperFunctionPointerType)glProgramBinaryOES},
+        {"glGetBufferPointervOES", (__eglMustCastToProperFunctionPointerType)glGetBufferPointervOES},
+        {"glMapBufferOES", (__eglMustCastToProperFunctionPointerType)glMapBufferOES},
+        {"glUnmapBufferOES", (__eglMustCastToProperFunctionPointerType)glUnmapBufferOES},
+        {"glMapBufferRangeEXT", (__eglMustCastToProperFunctionPointerType)glMapBufferRangeEXT},
+        {"glFlushMappedBufferRangeEXT", (__eglMustCastToProperFunctionPointerType)glFlushMappedBufferRangeEXT},    };
 
     for (unsigned int ext = 0; ext < ArraySize(glExtensions); ext++)
     {
@@ -7076,28 +8724,18 @@ bool __stdcall glBindTexImage(egl::Surface *surface)
     EVENT("(egl::Surface* surface = 0x%0.8p)",
           surface);
 
-    try
+    gl::Context *context = gl::getNonLostContext();
+    if (context)
     {
-        gl::Context *context = gl::getNonLostContext();
+        gl::Texture2D *textureObject = context->getTexture2D();
+        ASSERT(textureObject != NULL);
 
-        if (context)
+        if (textureObject->isImmutable())
         {
-            gl::Texture2D *textureObject = context->getTexture2D();
-
-            if (textureObject->isImmutable())
-            {
-                return false;
-            }
-
-            if (textureObject)
-            {
-                textureObject->bindTexImage(surface);
-            }
+            return false;
         }
-    }
-    catch(std::bad_alloc&)
-    {
-        return gl::error(GL_OUT_OF_MEMORY, false);
+
+        textureObject->bindTexImage(surface);
     }
 
     return true;