OSDN Git Service

Accept GL_TEXTURE_MAX_ANISOTROPY_EXT for samplers.
[android-x86/external-swiftshader.git] / src / OpenGL / libGLESv2 / Context.cpp
index 2421359..7bd9fea 100644 (file)
 #include "VertexDataManager.h"
 #include "IndexDataManager.h"
 #include "libEGL/Display.h"
-#include "libEGL/EGLSurface.h"
+#include "common/Surface.hpp"
 #include "Common/Half.hpp"
 
 #include <EGL/eglext.h>
 
+#include <algorithm>
+#include <string>
+
 namespace es2
 {
-Context::Context(egl::Display *display, const Context *shareContext, EGLint clientVersion)
-       : egl::Context(display), clientVersion(clientVersion)
+Context::Context(egl::Display *display, const Context *shareContext, EGLint clientVersion, const egl::Config *config)
+       : egl::Context(display), clientVersion(clientVersion), config(config)
 {
        sw::Context *context = new sw::Context();
        device = new es2::Device(context);
@@ -97,6 +100,7 @@ Context::Context(egl::Display *display, const Context *shareContext, EGLint clie
        mState.rasterizerDiscardEnabled = false;
        mState.generateMipmapHint = GL_DONT_CARE;
        mState.fragmentShaderDerivativeHint = GL_DONT_CARE;
+       mState.textureFilteringHint = GL_DONT_CARE;
 
        mState.lineWidth = 1.0f;
 
@@ -138,14 +142,19 @@ Context::Context(egl::Display *display, const Context *shareContext, EGLint clie
        mTexture3DZero = new Texture3D(0);
        mTexture2DArrayZero = new Texture2DArray(0);
        mTextureCubeMapZero = new TextureCubeMap(0);
+       mTexture2DRectZero = new Texture2DRect(0);
        mTextureExternalZero = new TextureExternal(0);
 
        mState.activeSampler = 0;
+
+       for(int type = 0; type < TEXTURE_TYPE_COUNT; type++)
+       {
+               bindTexture((TextureType)type, 0);
+       }
+
        bindVertexArray(0);
        bindArrayBuffer(0);
        bindElementArrayBuffer(0);
-       bindTextureCubeMap(0);
-       bindTexture2D(0);
        bindReadFramebuffer(0);
        bindDrawFramebuffer(0);
        bindRenderbuffer(0);
@@ -154,19 +163,6 @@ Context::Context(egl::Display *display, const Context *shareContext, EGLint clie
 
        mState.currentProgram = 0;
 
-       mState.packAlignment = 4;
-       mState.unpackInfo.alignment = 4;
-       mState.packRowLength = 0;
-       mState.packImageHeight = 0;
-       mState.packSkipPixels = 0;
-       mState.packSkipRows = 0;
-       mState.packSkipImages = 0;
-       mState.unpackInfo.rowLength = 0;
-       mState.unpackInfo.imageHeight = 0;
-       mState.unpackInfo.skipPixels = 0;
-       mState.unpackInfo.skipRows = 0;
-       mState.unpackInfo.skipImages = 0;
-
        mVertexDataManager = nullptr;
        mIndexDataManager = nullptr;
 
@@ -210,7 +206,7 @@ Context::~Context()
 
        while(!mVertexArrayNameSpace.empty())
        {
-               deleteVertexArray(mVertexArrayNameSpace.firstName());
+               deleteVertexArray(mVertexArrayNameSpace.lastName());
        }
 
        while(!mTransformFeedbackNameSpace.empty())
@@ -242,6 +238,11 @@ Context::~Context()
        mState.pixelPackBuffer = nullptr;
        mState.pixelUnpackBuffer = nullptr;
        mState.genericUniformBuffer = nullptr;
+
+       for(int i = 0; i < MAX_UNIFORM_BUFFER_BINDINGS; i++) {
+               mState.uniformBuffers[i].set(nullptr, 0, 0);
+       }
+
        mState.renderbuffer = nullptr;
 
        for(int i = 0; i < MAX_COMBINED_TEXTURE_IMAGE_UNITS; ++i)
@@ -253,6 +254,7 @@ Context::~Context()
        mTexture3DZero = nullptr;
        mTexture2DArrayZero = nullptr;
        mTextureCubeMapZero = nullptr;
+       mTexture2DRectZero = nullptr;
        mTextureExternalZero = nullptr;
 
        delete mVertexDataManager;
@@ -262,7 +264,7 @@ Context::~Context()
        delete device;
 }
 
-void Context::makeCurrent(egl::Surface *surface)
+void Context::makeCurrent(gl::Surface *surface)
 {
        if(!mHasBeenCurrent)
        {
@@ -271,35 +273,42 @@ void Context::makeCurrent(egl::Surface *surface)
 
                mState.viewportX = 0;
                mState.viewportY = 0;
-               mState.viewportWidth = surface->getWidth();
-               mState.viewportHeight = surface->getHeight();
+               mState.viewportWidth = surface ? surface->getWidth() : 0;
+               mState.viewportHeight = surface ? surface->getHeight() : 0;
 
                mState.scissorX = 0;
                mState.scissorY = 0;
-               mState.scissorWidth = surface->getWidth();
-               mState.scissorHeight = surface->getHeight();
+               mState.scissorWidth = surface ? surface->getWidth() : 0;
+               mState.scissorHeight = surface ? surface->getHeight() : 0;
 
                mHasBeenCurrent = true;
        }
 
-       // Wrap the existing resources into GL objects and assign them to the '0' names
-       egl::Image *defaultRenderTarget = surface->getRenderTarget();
-       egl::Image *depthStencil = surface->getDepthStencil();
+       if(surface)
+       {
+               // Wrap the existing resources into GL objects and assign them to the '0' names
+               egl::Image *defaultRenderTarget = surface->getRenderTarget();
+               egl::Image *depthStencil = surface->getDepthStencil();
 
-       Colorbuffer *colorbufferZero = new Colorbuffer(defaultRenderTarget);
-       DepthStencilbuffer *depthStencilbufferZero = new DepthStencilbuffer(depthStencil);
-       Framebuffer *framebufferZero = new DefaultFramebuffer(colorbufferZero, depthStencilbufferZero);
+               Colorbuffer *colorbufferZero = new Colorbuffer(defaultRenderTarget);
+               DepthStencilbuffer *depthStencilbufferZero = new DepthStencilbuffer(depthStencil);
+               Framebuffer *framebufferZero = new DefaultFramebuffer(colorbufferZero, depthStencilbufferZero);
 
-       setFramebufferZero(framebufferZero);
+               setFramebufferZero(framebufferZero);
 
-       if(defaultRenderTarget)
-       {
-               defaultRenderTarget->release();
-       }
+               if(defaultRenderTarget)
+               {
+                       defaultRenderTarget->release();
+               }
 
-       if(depthStencil)
+               if(depthStencil)
+               {
+                       depthStencil->release();
+               }
+       }
+       else
        {
-               depthStencil->release();
+               setFramebufferZero(nullptr);
        }
 
        markAllStateDirty();
@@ -310,6 +319,11 @@ EGLint Context::getClientVersion() const
        return clientVersion;
 }
 
+EGLint Context::getConfigID() const
+{
+       return config->mConfigID;
+}
+
 // This function will set all of the state-related dirty flags, so that all state is set during next pre-draw.
 void Context::markAllStateDirty()
 {
@@ -625,7 +639,6 @@ bool Context::isDitherEnabled() const
 
 void Context::setPrimitiveRestartFixedIndexEnabled(bool enabled)
 {
-       UNIMPLEMENTED();
        mState.primitiveRestartFixedIndexEnabled = enabled;
 }
 
@@ -663,12 +676,17 @@ void Context::setFragmentShaderDerivativeHint(GLenum hint)
        // Ignore for now. It is valid for implementations to ignore hint.
 }
 
+void Context::setTextureFilteringHint(GLenum hint)
+{
+       mState.textureFilteringHint = hint;
+}
+
 void Context::setViewportParams(GLint x, GLint y, GLsizei width, GLsizei height)
 {
        mState.viewportX = x;
        mState.viewportY = y;
-       mState.viewportWidth = width;
-       mState.viewportHeight = height;
+       mState.viewportWidth = std::min<GLsizei>(width, IMPLEMENTATION_MAX_RENDERBUFFER_SIZE);     // GL_MAX_VIEWPORT_DIMS[0]
+       mState.viewportHeight = std::min<GLsizei>(height, IMPLEMENTATION_MAX_RENDERBUFFER_SIZE);   // GL_MAX_VIEWPORT_DIMS[1]
 }
 
 void Context::setScissorParams(GLint x, GLint y, GLsizei width, GLsizei height)
@@ -731,31 +749,33 @@ GLuint Context::getRenderbufferName() const
 
 void Context::setFramebufferReadBuffer(GLuint buf)
 {
-       getReadFramebuffer()->setReadBuffer(buf);
+       Framebuffer *framebuffer = getReadFramebuffer();
+
+       if(framebuffer)
+       {
+               framebuffer->setReadBuffer(buf);
+       }
+       else
+       {
+               return error(GL_INVALID_OPERATION);
+       }
 }
 
 void Context::setFramebufferDrawBuffers(GLsizei n, const GLenum *bufs)
 {
        Framebuffer *drawFramebuffer = getDrawFramebuffer();
 
-       for(int i = 0; i < MAX_COLOR_ATTACHMENTS; i++)
+       if(drawFramebuffer)
        {
-               drawFramebuffer->setDrawBuffer(i, (i < n) ? bufs[i] : GL_NONE);
+               for(int i = 0; i < MAX_COLOR_ATTACHMENTS; i++)
+               {
+                       drawFramebuffer->setDrawBuffer(i, (i < n) ? bufs[i] : GL_NONE);
+               }
        }
-}
-
-GLuint Context::getReadFramebufferColorIndex() const
-{
-       GLenum buf = getReadFramebuffer()->getReadBuffer();
-       switch(buf)
+       else
        {
-       case GL_BACK:
-               return 0;
-       case GL_NONE:
-               return GL_INVALID_INDEX;
-       default:
-               return buf - GL_COLOR_ATTACHMENT0;
-}
+               return error(GL_INVALID_OPERATION);
+       }
 }
 
 GLuint Context::getArrayBufferName() const
@@ -811,10 +831,10 @@ const VertexAttribute &Context::getVertexAttribState(unsigned int attribNum) con
        return getCurrentVertexArray()->getVertexAttribute(attribNum);
 }
 
-void Context::setVertexAttribState(unsigned int attribNum, Buffer *boundBuffer, GLint size, GLenum type, bool normalized,
-                                   GLsizei stride, const void *pointer)
+void Context::setVertexAttribState(unsigned int attribNum, Buffer *boundBuffer, GLint size, GLenum type,
+                                   bool normalized, bool pureInteger, GLsizei stride, const void *pointer)
 {
-       getCurrentVertexArray()->setAttributeState(attribNum, boundBuffer, size, type, normalized, stride, pointer);
+       getCurrentVertexArray()->setAttributeState(attribNum, boundBuffer, size, type, normalized, pureInteger, stride, pointer);
 }
 
 const void *Context::getVertexAttribPointer(unsigned int attribNum) const
@@ -834,67 +854,57 @@ const VertexAttributeArray &Context::getCurrentVertexAttributes()
 
 void Context::setPackAlignment(GLint alignment)
 {
-       mState.packAlignment = alignment;
+       mState.packParameters.alignment = alignment;
 }
 
 void Context::setUnpackAlignment(GLint alignment)
 {
-       mState.unpackInfo.alignment = alignment;
+       mState.unpackParameters.alignment = alignment;
 }
 
-const egl::Image::UnpackInfo& Context::getUnpackInfo() const
+const gl::PixelStorageModes &Context::getUnpackParameters() const
 {
-       return mState.unpackInfo;
+       return mState.unpackParameters;
 }
 
 void Context::setPackRowLength(GLint rowLength)
 {
-       mState.packRowLength = rowLength;
-}
-
-void Context::setPackImageHeight(GLint imageHeight)
-{
-       mState.packImageHeight = imageHeight;
+       mState.packParameters.rowLength = rowLength;
 }
 
 void Context::setPackSkipPixels(GLint skipPixels)
 {
-       mState.packSkipPixels = skipPixels;
+       mState.packParameters.skipPixels = skipPixels;
 }
 
 void Context::setPackSkipRows(GLint skipRows)
 {
-       mState.packSkipRows = skipRows;
-}
-
-void Context::setPackSkipImages(GLint skipImages)
-{
-       mState.packSkipImages = skipImages;
+       mState.packParameters.skipRows = skipRows;
 }
 
 void Context::setUnpackRowLength(GLint rowLength)
 {
-       mState.unpackInfo.rowLength = rowLength;
+       mState.unpackParameters.rowLength = rowLength;
 }
 
 void Context::setUnpackImageHeight(GLint imageHeight)
 {
-       mState.unpackInfo.imageHeight = imageHeight;
+       mState.unpackParameters.imageHeight = imageHeight;
 }
 
 void Context::setUnpackSkipPixels(GLint skipPixels)
 {
-       mState.unpackInfo.skipPixels = skipPixels;
+       mState.unpackParameters.skipPixels = skipPixels;
 }
 
 void Context::setUnpackSkipRows(GLint skipRows)
 {
-       mState.unpackInfo.skipRows = skipRows;
+       mState.unpackParameters.skipRows = skipRows;
 }
 
 void Context::setUnpackSkipImages(GLint skipImages)
 {
-       mState.unpackInfo.skipImages = skipImages;
+       mState.unpackParameters.skipImages = skipImages;
 }
 
 GLuint Context::createBuffer()
@@ -1163,46 +1173,25 @@ void Context::bindTransformFeedbackBuffer(GLuint buffer)
        }
 }
 
-void Context::bindTexture2D(GLuint texture)
-{
-       mResourceManager->checkTextureAllocation(texture, TEXTURE_2D);
-
-       mState.samplerTexture[TEXTURE_2D][mState.activeSampler] = getTexture(texture);
-}
-
-void Context::bindTextureCubeMap(GLuint texture)
-{
-       mResourceManager->checkTextureAllocation(texture, TEXTURE_CUBE);
-
-       mState.samplerTexture[TEXTURE_CUBE][mState.activeSampler] = getTexture(texture);
-}
-
-void Context::bindTextureExternal(GLuint texture)
-{
-       mResourceManager->checkTextureAllocation(texture, TEXTURE_EXTERNAL);
-
-       mState.samplerTexture[TEXTURE_EXTERNAL][mState.activeSampler] = getTexture(texture);
-}
-
-void Context::bindTexture3D(GLuint texture)
-{
-       mResourceManager->checkTextureAllocation(texture, TEXTURE_3D);
-
-       mState.samplerTexture[TEXTURE_3D][mState.activeSampler] = getTexture(texture);
-}
-
-void Context::bindTexture2DArray(GLuint texture)
+void Context::bindTexture(TextureType type, GLuint texture)
 {
-       mResourceManager->checkTextureAllocation(texture, TEXTURE_2D_ARRAY);
+       mResourceManager->checkTextureAllocation(texture, type);
 
-       mState.samplerTexture[TEXTURE_2D_ARRAY][mState.activeSampler] = getTexture(texture);
+       mState.samplerTexture[type][mState.activeSampler] = getTexture(texture);
 }
 
 void Context::bindReadFramebuffer(GLuint framebuffer)
 {
        if(!getFramebuffer(framebuffer))
        {
-               mFramebufferNameSpace.insert(framebuffer, new Framebuffer());
+               if(framebuffer == 0)
+               {
+                       mFramebufferNameSpace.insert(framebuffer, new DefaultFramebuffer());
+               }
+               else
+               {
+                       mFramebufferNameSpace.insert(framebuffer, new Framebuffer());
+               }
        }
 
        mState.readFramebuffer = framebuffer;
@@ -1212,7 +1201,14 @@ void Context::bindDrawFramebuffer(GLuint framebuffer)
 {
        if(!getFramebuffer(framebuffer))
        {
-               mFramebufferNameSpace.insert(framebuffer, new Framebuffer());
+               if(framebuffer == 0)
+               {
+                       mFramebufferNameSpace.insert(framebuffer, new DefaultFramebuffer());
+               }
+               else
+               {
+                       mFramebufferNameSpace.insert(framebuffer, new Framebuffer());
+               }
        }
 
        mState.drawFramebuffer = framebuffer;
@@ -1332,7 +1328,25 @@ void Context::beginQuery(GLenum target, GLuint query)
        {
                if(mState.activeQuery[i])
                {
-                       return error(GL_INVALID_OPERATION);
+                       switch(mState.activeQuery[i]->getType())
+                       {
+                       case GL_ANY_SAMPLES_PASSED_EXT:
+                       case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT:
+                               if((target == GL_ANY_SAMPLES_PASSED_EXT) ||
+                                  (target == GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT))
+                               {
+                                       return error(GL_INVALID_OPERATION);
+                               }
+                               break;
+                       case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
+                               if(target == GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN)
+                               {
+                                       return error(GL_INVALID_OPERATION);
+                               }
+                               break;
+                       default:
+                               break;
+                       }
                }
        }
 
@@ -1486,6 +1500,11 @@ TransformFeedback *Context::getTransformFeedback(GLuint transformFeedback) const
        return mTransformFeedbackNameSpace.find(transformFeedback);
 }
 
+bool Context::isTransformFeedback(GLuint array) const
+{
+       return mTransformFeedbackNameSpace.isReserved(array);
+}
+
 Sampler *Context::getSampler(GLuint sampler) const
 {
        return mResourceManager->getSampler(sampler);
@@ -1531,11 +1550,46 @@ Buffer *Context::getGenericUniformBuffer() const
        return mState.genericUniformBuffer;
 }
 
-const GLvoid* Context::getPixels(const GLvoid* data) const
+GLsizei Context::getRequiredBufferSize(GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type) const
+{
+       GLsizei inputWidth = (mState.unpackParameters.rowLength == 0) ? width : mState.unpackParameters.rowLength;
+       GLsizei inputPitch = gl::ComputePitch(inputWidth, format, type, mState.unpackParameters.alignment);
+       GLsizei inputHeight = (mState.unpackParameters.imageHeight == 0) ? height : mState.unpackParameters.imageHeight;
+       return inputPitch * inputHeight * depth;
+}
+
+GLenum Context::getPixels(const GLvoid **pixels, GLenum type, GLsizei imageSize) const
 {
-       es2::Buffer* unpackBuffer = getPixelUnpackBuffer();
-       const unsigned char* unpackBufferData = unpackBuffer ? static_cast<const unsigned char*>(unpackBuffer->data()) : nullptr;
-       return unpackBufferData ? unpackBufferData + (ptrdiff_t)(data) : data;
+       if(mState.pixelUnpackBuffer)
+       {
+               ASSERT(mState.pixelUnpackBuffer->name != 0);
+
+               if(mState.pixelUnpackBuffer->isMapped())
+               {
+                       return GL_INVALID_OPERATION;
+               }
+
+               size_t offset = static_cast<size_t>((ptrdiff_t)(*pixels));
+
+               if(offset % GetTypeSize(type) != 0)
+               {
+                       return GL_INVALID_OPERATION;
+               }
+
+               if(offset > mState.pixelUnpackBuffer->size())
+               {
+                       return GL_INVALID_OPERATION;
+               }
+
+               if(mState.pixelUnpackBuffer->size() - offset < static_cast<size_t>(imageSize))
+               {
+                       return GL_INVALID_OPERATION;
+               }
+
+               *pixels = static_cast<const unsigned char*>(mState.pixelUnpackBuffer->data()) + offset;
+       }
+
+       return GL_NO_ERROR;
 }
 
 bool Context::getBuffer(GLenum target, es2::Buffer **buffer) const
@@ -1612,6 +1666,19 @@ Texture2D *Context::getTexture2D() const
        return static_cast<Texture2D*>(getSamplerTexture(mState.activeSampler, TEXTURE_2D));
 }
 
+Texture2D *Context::getTexture2D(GLenum target) const
+{
+       switch(target)
+       {
+       case GL_TEXTURE_2D:            return getTexture2D();
+       case GL_TEXTURE_RECTANGLE_ARB: return getTexture2DRect();
+       case GL_TEXTURE_EXTERNAL_OES:  return getTextureExternal();
+       default:                       UNREACHABLE(target);
+       }
+
+       return nullptr;
+}
+
 Texture3D *Context::getTexture3D() const
 {
        return static_cast<Texture3D*>(getSamplerTexture(mState.activeSampler, TEXTURE_3D));
@@ -1627,6 +1694,11 @@ TextureCubeMap *Context::getTextureCubeMap() const
        return static_cast<TextureCubeMap*>(getSamplerTexture(mState.activeSampler, TEXTURE_CUBE));
 }
 
+Texture2DRect *Context::getTexture2DRect() const
+{
+       return static_cast<Texture2DRect*>(getSamplerTexture(mState.activeSampler, TEXTURE_2D_RECT));
+}
+
 TextureExternal *Context::getTextureExternal() const
 {
        return static_cast<TextureExternal*>(getSamplerTexture(mState.activeSampler, TEXTURE_EXTERNAL));
@@ -1644,6 +1716,7 @@ Texture *Context::getSamplerTexture(unsigned int sampler, TextureType type) cons
                case TEXTURE_3D: return mTexture3DZero;
                case TEXTURE_2D_ARRAY: return mTexture2DArrayZero;
                case TEXTURE_CUBE: return mTextureCubeMapZero;
+               case TEXTURE_2D_RECT: return mTexture2DRectZero;
                case TEXTURE_EXTERNAL: return mTextureExternalZero;
                default: UNREACHABLE(type);
                }
@@ -1661,16 +1734,17 @@ void Context::samplerParameteri(GLuint sampler, GLenum pname, GLint param)
 
        switch(pname)
        {
-       case GL_TEXTURE_MIN_FILTER:    samplerObject->setMinFilter(static_cast<GLenum>(param));       break;
-       case GL_TEXTURE_MAG_FILTER:    samplerObject->setMagFilter(static_cast<GLenum>(param));       break;
-       case GL_TEXTURE_WRAP_S:        samplerObject->setWrapS(static_cast<GLenum>(param));           break;
-       case GL_TEXTURE_WRAP_T:        samplerObject->setWrapT(static_cast<GLenum>(param));           break;
-       case GL_TEXTURE_WRAP_R:        samplerObject->setWrapR(static_cast<GLenum>(param));           break;
-       case GL_TEXTURE_MIN_LOD:       samplerObject->setMinLod(static_cast<GLfloat>(param));         break;
-       case GL_TEXTURE_MAX_LOD:       samplerObject->setMaxLod(static_cast<GLfloat>(param));         break;
-       case GL_TEXTURE_COMPARE_MODE:  samplerObject->setComparisonMode(static_cast<GLenum>(param));  break;
-       case GL_TEXTURE_COMPARE_FUNC:  samplerObject->setComparisonFunc(static_cast<GLenum>(param));  break;
-       default:                       UNREACHABLE(pname); break;
+       case GL_TEXTURE_MIN_FILTER:         samplerObject->setMinFilter(static_cast<GLenum>(param));      break;
+       case GL_TEXTURE_MAG_FILTER:         samplerObject->setMagFilter(static_cast<GLenum>(param));      break;
+       case GL_TEXTURE_WRAP_S:             samplerObject->setWrapS(static_cast<GLenum>(param));          break;
+       case GL_TEXTURE_WRAP_T:             samplerObject->setWrapT(static_cast<GLenum>(param));          break;
+       case GL_TEXTURE_WRAP_R:             samplerObject->setWrapR(static_cast<GLenum>(param));          break;
+       case GL_TEXTURE_MIN_LOD:            samplerObject->setMinLod(static_cast<GLfloat>(param));        break;
+       case GL_TEXTURE_MAX_LOD:            samplerObject->setMaxLod(static_cast<GLfloat>(param));        break;
+       case GL_TEXTURE_COMPARE_MODE:       samplerObject->setCompareMode(static_cast<GLenum>(param));    break;
+       case GL_TEXTURE_COMPARE_FUNC:       samplerObject->setCompareFunc(static_cast<GLenum>(param));    break;
+       case GL_TEXTURE_MAX_ANISOTROPY_EXT: samplerObject->setMaxAnisotropy(static_cast<GLfloat>(param)); break;
+       default:                            UNREACHABLE(pname); break;
        }
 }
 
@@ -1683,16 +1757,17 @@ void Context::samplerParameterf(GLuint sampler, GLenum pname, GLfloat param)
 
        switch(pname)
        {
-       case GL_TEXTURE_MIN_FILTER:    samplerObject->setMinFilter(static_cast<GLenum>(roundf(param)));       break;
-       case GL_TEXTURE_MAG_FILTER:    samplerObject->setMagFilter(static_cast<GLenum>(roundf(param)));       break;
-       case GL_TEXTURE_WRAP_S:        samplerObject->setWrapS(static_cast<GLenum>(roundf(param)));           break;
-       case GL_TEXTURE_WRAP_T:        samplerObject->setWrapT(static_cast<GLenum>(roundf(param)));           break;
-       case GL_TEXTURE_WRAP_R:        samplerObject->setWrapR(static_cast<GLenum>(roundf(param)));           break;
-       case GL_TEXTURE_MIN_LOD:       samplerObject->setMinLod(param);                                       break;
-       case GL_TEXTURE_MAX_LOD:       samplerObject->setMaxLod(param);                                       break;
-       case GL_TEXTURE_COMPARE_MODE:  samplerObject->setComparisonMode(static_cast<GLenum>(roundf(param)));  break;
-       case GL_TEXTURE_COMPARE_FUNC:  samplerObject->setComparisonFunc(static_cast<GLenum>(roundf(param)));  break;
-       default:                       UNREACHABLE(pname); break;
+       case GL_TEXTURE_MIN_FILTER:         samplerObject->setMinFilter(static_cast<GLenum>(roundf(param)));   break;
+       case GL_TEXTURE_MAG_FILTER:         samplerObject->setMagFilter(static_cast<GLenum>(roundf(param)));   break;
+       case GL_TEXTURE_WRAP_S:             samplerObject->setWrapS(static_cast<GLenum>(roundf(param)));       break;
+       case GL_TEXTURE_WRAP_T:             samplerObject->setWrapT(static_cast<GLenum>(roundf(param)));       break;
+       case GL_TEXTURE_WRAP_R:             samplerObject->setWrapR(static_cast<GLenum>(roundf(param)));       break;
+       case GL_TEXTURE_MIN_LOD:            samplerObject->setMinLod(param);                                   break;
+       case GL_TEXTURE_MAX_LOD:            samplerObject->setMaxLod(param);                                   break;
+       case GL_TEXTURE_COMPARE_MODE:       samplerObject->setCompareMode(static_cast<GLenum>(roundf(param))); break;
+       case GL_TEXTURE_COMPARE_FUNC:       samplerObject->setCompareFunc(static_cast<GLenum>(roundf(param))); break;
+       case GL_TEXTURE_MAX_ANISOTROPY_EXT: samplerObject->setMaxAnisotropy(param);                            break;
+       default:                            UNREACHABLE(pname); break;
        }
 }
 
@@ -1705,16 +1780,17 @@ GLint Context::getSamplerParameteri(GLuint sampler, GLenum pname)
 
        switch(pname)
        {
-       case GL_TEXTURE_MIN_FILTER:    return static_cast<GLint>(samplerObject->getMinFilter());
-       case GL_TEXTURE_MAG_FILTER:    return static_cast<GLint>(samplerObject->getMagFilter());
-       case GL_TEXTURE_WRAP_S:        return static_cast<GLint>(samplerObject->getWrapS());
-       case GL_TEXTURE_WRAP_T:        return static_cast<GLint>(samplerObject->getWrapT());
-       case GL_TEXTURE_WRAP_R:        return static_cast<GLint>(samplerObject->getWrapR());
-       case GL_TEXTURE_MIN_LOD:       return static_cast<GLint>(roundf(samplerObject->getMinLod()));
-       case GL_TEXTURE_MAX_LOD:       return static_cast<GLint>(roundf(samplerObject->getMaxLod()));
-       case GL_TEXTURE_COMPARE_MODE:  return static_cast<GLint>(samplerObject->getComparisonMode());
-       case GL_TEXTURE_COMPARE_FUNC:  return static_cast<GLint>(samplerObject->getComparisonFunc());
-       default:                       UNREACHABLE(pname); return 0;
+       case GL_TEXTURE_MIN_FILTER:         return static_cast<GLint>(samplerObject->getMinFilter());
+       case GL_TEXTURE_MAG_FILTER:         return static_cast<GLint>(samplerObject->getMagFilter());
+       case GL_TEXTURE_WRAP_S:             return static_cast<GLint>(samplerObject->getWrapS());
+       case GL_TEXTURE_WRAP_T:             return static_cast<GLint>(samplerObject->getWrapT());
+       case GL_TEXTURE_WRAP_R:             return static_cast<GLint>(samplerObject->getWrapR());
+       case GL_TEXTURE_MIN_LOD:            return static_cast<GLint>(roundf(samplerObject->getMinLod()));
+       case GL_TEXTURE_MAX_LOD:            return static_cast<GLint>(roundf(samplerObject->getMaxLod()));
+       case GL_TEXTURE_COMPARE_MODE:       return static_cast<GLint>(samplerObject->getCompareMode());
+       case GL_TEXTURE_COMPARE_FUNC:       return static_cast<GLint>(samplerObject->getCompareFunc());
+       case GL_TEXTURE_MAX_ANISOTROPY_EXT: return static_cast<GLint>(samplerObject->getMaxAnisotropy());
+       default:                            UNREACHABLE(pname); return 0;
        }
 }
 
@@ -1727,16 +1803,17 @@ GLfloat Context::getSamplerParameterf(GLuint sampler, GLenum pname)
 
        switch(pname)
        {
-       case GL_TEXTURE_MIN_FILTER:    return static_cast<GLfloat>(samplerObject->getMinFilter());
-       case GL_TEXTURE_MAG_FILTER:    return static_cast<GLfloat>(samplerObject->getMagFilter());
-       case GL_TEXTURE_WRAP_S:        return static_cast<GLfloat>(samplerObject->getWrapS());
-       case GL_TEXTURE_WRAP_T:        return static_cast<GLfloat>(samplerObject->getWrapT());
-       case GL_TEXTURE_WRAP_R:        return static_cast<GLfloat>(samplerObject->getWrapR());
-       case GL_TEXTURE_MIN_LOD:       return samplerObject->getMinLod();
-       case GL_TEXTURE_MAX_LOD:       return samplerObject->getMaxLod();
-       case GL_TEXTURE_COMPARE_MODE:  return static_cast<GLfloat>(samplerObject->getComparisonMode());
-       case GL_TEXTURE_COMPARE_FUNC:  return static_cast<GLfloat>(samplerObject->getComparisonFunc());
-       default:                       UNREACHABLE(pname); return 0;
+       case GL_TEXTURE_MIN_FILTER:         return static_cast<GLfloat>(samplerObject->getMinFilter());
+       case GL_TEXTURE_MAG_FILTER:         return static_cast<GLfloat>(samplerObject->getMagFilter());
+       case GL_TEXTURE_WRAP_S:             return static_cast<GLfloat>(samplerObject->getWrapS());
+       case GL_TEXTURE_WRAP_T:             return static_cast<GLfloat>(samplerObject->getWrapT());
+       case GL_TEXTURE_WRAP_R:             return static_cast<GLfloat>(samplerObject->getWrapR());
+       case GL_TEXTURE_MIN_LOD:            return samplerObject->getMinLod();
+       case GL_TEXTURE_MAX_LOD:            return samplerObject->getMaxLod();
+       case GL_TEXTURE_COMPARE_MODE:       return static_cast<GLfloat>(samplerObject->getCompareMode());
+       case GL_TEXTURE_COMPARE_FUNC:       return static_cast<GLfloat>(samplerObject->getCompareFunc());
+       case GL_TEXTURE_MAX_ANISOTROPY_EXT: return samplerObject->getMaxAnisotropy();
+       default:                            UNREACHABLE(pname); return 0;
        }
 }
 
@@ -1850,62 +1927,64 @@ template<typename T> bool Context::getIntegerv(GLenum pname, T *params) const
        // Context::getFloatv.
        switch(pname)
        {
-       case GL_MAX_VERTEX_ATTRIBS:               *params = MAX_VERTEX_ATTRIBS;               break;
-       case GL_MAX_VERTEX_UNIFORM_VECTORS:       *params = MAX_VERTEX_UNIFORM_VECTORS;       break;
-       case GL_MAX_VARYING_VECTORS:              *params = MAX_VARYING_VECTORS;              break;
-       case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: *params = MAX_COMBINED_TEXTURE_IMAGE_UNITS; break;
-       case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS:   *params = MAX_VERTEX_TEXTURE_IMAGE_UNITS;   break;
-       case GL_MAX_TEXTURE_IMAGE_UNITS:          *params = MAX_TEXTURE_IMAGE_UNITS;          break;
-       case GL_MAX_FRAGMENT_UNIFORM_VECTORS:     *params = MAX_FRAGMENT_UNIFORM_VECTORS;     break;
-       case GL_MAX_RENDERBUFFER_SIZE:            *params = IMPLEMENTATION_MAX_RENDERBUFFER_SIZE; break;
-       case GL_NUM_SHADER_BINARY_FORMATS:        *params = 0;                                    break;
-       case GL_SHADER_BINARY_FORMATS:      /* no shader binary formats are supported */          break;
-       case GL_ARRAY_BUFFER_BINDING:             *params = getArrayBufferName();                 break;
-       case GL_ELEMENT_ARRAY_BUFFER_BINDING:     *params = getElementArrayBufferName();          break;
+       case GL_MAX_VERTEX_ATTRIBS:               *params = MAX_VERTEX_ATTRIBS;               return true;
+       case GL_MAX_VERTEX_UNIFORM_VECTORS:       *params = MAX_VERTEX_UNIFORM_VECTORS;       return true;
+       case GL_MAX_VARYING_VECTORS:              *params = MAX_VARYING_VECTORS;              return true;
+       case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: *params = MAX_COMBINED_TEXTURE_IMAGE_UNITS; return true;
+       case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS:   *params = MAX_VERTEX_TEXTURE_IMAGE_UNITS;   return true;
+       case GL_MAX_TEXTURE_IMAGE_UNITS:          *params = MAX_TEXTURE_IMAGE_UNITS;          return true;
+       case GL_MAX_FRAGMENT_UNIFORM_VECTORS:     *params = MAX_FRAGMENT_UNIFORM_VECTORS;     return true;
+       case GL_MAX_RENDERBUFFER_SIZE:            *params = IMPLEMENTATION_MAX_RENDERBUFFER_SIZE; return true;
+       case GL_NUM_SHADER_BINARY_FORMATS:        *params = 0;                                    return true;
+       case GL_SHADER_BINARY_FORMATS:      /* no shader binary formats are supported */          return true;
+       case GL_ARRAY_BUFFER_BINDING:             *params = getArrayBufferName();                 return true;
+       case GL_ELEMENT_ARRAY_BUFFER_BINDING:     *params = getElementArrayBufferName();          return true;
 //     case GL_FRAMEBUFFER_BINDING:            // now equivalent to GL_DRAW_FRAMEBUFFER_BINDING_ANGLE
-       case GL_DRAW_FRAMEBUFFER_BINDING_ANGLE:   *params = mState.drawFramebuffer;               break;
-       case GL_READ_FRAMEBUFFER_BINDING_ANGLE:   *params = mState.readFramebuffer;               break;
-       case GL_RENDERBUFFER_BINDING:             *params = mState.renderbuffer.name();           break;
-       case GL_CURRENT_PROGRAM:                  *params = mState.currentProgram;                break;
-       case GL_PACK_ALIGNMENT:                   *params = mState.packAlignment;                 break;
-       case GL_UNPACK_ALIGNMENT:                 *params = mState.unpackInfo.alignment;          break;
-       case GL_GENERATE_MIPMAP_HINT:             *params = mState.generateMipmapHint;            break;
-       case GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES: *params = mState.fragmentShaderDerivativeHint; break;
-       case GL_ACTIVE_TEXTURE:                   *params = (mState.activeSampler + GL_TEXTURE0); break;
-       case GL_STENCIL_FUNC:                     *params = mState.stencilFunc;                   break;
-       case GL_STENCIL_REF:                      *params = mState.stencilRef;                    break;
-       case GL_STENCIL_VALUE_MASK:               *params = sw::clampToSignedInt(mState.stencilMask); break;
-       case GL_STENCIL_BACK_FUNC:                *params = mState.stencilBackFunc;               break;
-       case GL_STENCIL_BACK_REF:                 *params = mState.stencilBackRef;                break;
-       case GL_STENCIL_BACK_VALUE_MASK:          *params = sw::clampToSignedInt(mState.stencilBackMask); break;
-       case GL_STENCIL_FAIL:                     *params = mState.stencilFail;                   break;
-       case GL_STENCIL_PASS_DEPTH_FAIL:          *params = mState.stencilPassDepthFail;          break;
-       case GL_STENCIL_PASS_DEPTH_PASS:          *params = mState.stencilPassDepthPass;          break;
-       case GL_STENCIL_BACK_FAIL:                *params = mState.stencilBackFail;               break;
-       case GL_STENCIL_BACK_PASS_DEPTH_FAIL:     *params = mState.stencilBackPassDepthFail;      break;
-       case GL_STENCIL_BACK_PASS_DEPTH_PASS:     *params = mState.stencilBackPassDepthPass;      break;
-       case GL_DEPTH_FUNC:                       *params = mState.depthFunc;                     break;
-       case GL_BLEND_SRC_RGB:                    *params = mState.sourceBlendRGB;                break;
-       case GL_BLEND_SRC_ALPHA:                  *params = mState.sourceBlendAlpha;              break;
-       case GL_BLEND_DST_RGB:                    *params = mState.destBlendRGB;                  break;
-       case GL_BLEND_DST_ALPHA:                  *params = mState.destBlendAlpha;                break;
-       case GL_BLEND_EQUATION_RGB:               *params = mState.blendEquationRGB;              break;
-       case GL_BLEND_EQUATION_ALPHA:             *params = mState.blendEquationAlpha;            break;
-       case GL_STENCIL_WRITEMASK:                *params = sw::clampToSignedInt(mState.stencilWritemask); break;
-       case GL_STENCIL_BACK_WRITEMASK:           *params = sw::clampToSignedInt(mState.stencilBackWritemask); break;
-       case GL_STENCIL_CLEAR_VALUE:              *params = mState.stencilClearValue;             break;
-       case GL_SUBPIXEL_BITS:                    *params = 4;                                    break;
-       case GL_MAX_TEXTURE_SIZE:                 *params = IMPLEMENTATION_MAX_TEXTURE_SIZE;          break;
-       case GL_MAX_CUBE_MAP_TEXTURE_SIZE:        *params = IMPLEMENTATION_MAX_CUBE_MAP_TEXTURE_SIZE; break;
-       case GL_NUM_COMPRESSED_TEXTURE_FORMATS:   *params = NUM_COMPRESSED_TEXTURE_FORMATS;           break;
-       case GL_MAX_SAMPLES_ANGLE:                *params = IMPLEMENTATION_MAX_SAMPLES;               break;
+       case GL_DRAW_FRAMEBUFFER_BINDING:         *params = mState.drawFramebuffer;               return true;
+       case GL_READ_FRAMEBUFFER_BINDING:         *params = mState.readFramebuffer;               return true;
+       case GL_RENDERBUFFER_BINDING:             *params = mState.renderbuffer.name();           return true;
+       case GL_CURRENT_PROGRAM:                  *params = mState.currentProgram;                return true;
+       case GL_PACK_ALIGNMENT:                   *params = mState.packParameters.alignment;                 return true;
+       case GL_UNPACK_ALIGNMENT:                 *params = mState.unpackParameters.alignment;          return true;
+       case GL_GENERATE_MIPMAP_HINT:             *params = mState.generateMipmapHint;            return true;
+       case GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES: *params = mState.fragmentShaderDerivativeHint; return true;
+       case GL_TEXTURE_FILTERING_HINT_CHROMIUM:  *params = mState.textureFilteringHint;          return true;
+       case GL_ACTIVE_TEXTURE:                   *params = (mState.activeSampler + GL_TEXTURE0); return true;
+       case GL_STENCIL_FUNC:                     *params = mState.stencilFunc;                   return true;
+       case GL_STENCIL_REF:                      *params = mState.stencilRef;                    return true;
+       case GL_STENCIL_VALUE_MASK:               *params = sw::clampToSignedInt(mState.stencilMask); return true;
+       case GL_STENCIL_BACK_FUNC:                *params = mState.stencilBackFunc;               return true;
+       case GL_STENCIL_BACK_REF:                 *params = mState.stencilBackRef;                return true;
+       case GL_STENCIL_BACK_VALUE_MASK:          *params = sw::clampToSignedInt(mState.stencilBackMask); return true;
+       case GL_STENCIL_FAIL:                     *params = mState.stencilFail;                   return true;
+       case GL_STENCIL_PASS_DEPTH_FAIL:          *params = mState.stencilPassDepthFail;          return true;
+       case GL_STENCIL_PASS_DEPTH_PASS:          *params = mState.stencilPassDepthPass;          return true;
+       case GL_STENCIL_BACK_FAIL:                *params = mState.stencilBackFail;               return true;
+       case GL_STENCIL_BACK_PASS_DEPTH_FAIL:     *params = mState.stencilBackPassDepthFail;      return true;
+       case GL_STENCIL_BACK_PASS_DEPTH_PASS:     *params = mState.stencilBackPassDepthPass;      return true;
+       case GL_DEPTH_FUNC:                       *params = mState.depthFunc;                     return true;
+       case GL_BLEND_SRC_RGB:                    *params = mState.sourceBlendRGB;                return true;
+       case GL_BLEND_SRC_ALPHA:                  *params = mState.sourceBlendAlpha;              return true;
+       case GL_BLEND_DST_RGB:                    *params = mState.destBlendRGB;                  return true;
+       case GL_BLEND_DST_ALPHA:                  *params = mState.destBlendAlpha;                return true;
+       case GL_BLEND_EQUATION_RGB:               *params = mState.blendEquationRGB;              return true;
+       case GL_BLEND_EQUATION_ALPHA:             *params = mState.blendEquationAlpha;            return true;
+       case GL_STENCIL_WRITEMASK:                *params = sw::clampToSignedInt(mState.stencilWritemask); return true;
+       case GL_STENCIL_BACK_WRITEMASK:           *params = sw::clampToSignedInt(mState.stencilBackWritemask); return true;
+       case GL_STENCIL_CLEAR_VALUE:              *params = mState.stencilClearValue;             return true;
+       case GL_SUBPIXEL_BITS:                    *params = 4;                                    return true;
+       case GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB:
+       case GL_MAX_TEXTURE_SIZE:                 *params = IMPLEMENTATION_MAX_TEXTURE_SIZE;          return true;
+       case GL_MAX_CUBE_MAP_TEXTURE_SIZE:        *params = IMPLEMENTATION_MAX_CUBE_MAP_TEXTURE_SIZE; return true;
+       case GL_NUM_COMPRESSED_TEXTURE_FORMATS:   *params = NUM_COMPRESSED_TEXTURE_FORMATS;           return true;
+       case GL_MAX_SAMPLES:                      *params = IMPLEMENTATION_MAX_SAMPLES;               return true;
        case GL_SAMPLE_BUFFERS:
        case GL_SAMPLES:
                {
                        Framebuffer *framebuffer = getDrawFramebuffer();
                        int width, height, samples;
 
-                       if(framebuffer->completeness(width, height, samples) == GL_FRAMEBUFFER_COMPLETE)
+                       if(framebuffer && (framebuffer->completeness(width, height, samples) == GL_FRAMEBUFFER_COMPLETE))
                        {
                                switch(pname)
                                {
@@ -1929,26 +2008,40 @@ template<typename T> bool Context::getIntegerv(GLenum pname, T *params) const
                                *params = 0;
                        }
                }
-               break;
+               return true;
        case GL_IMPLEMENTATION_COLOR_READ_TYPE:
                {
                        Framebuffer *framebuffer = getReadFramebuffer();
-                       *params = framebuffer->getImplementationColorReadType();
+                       if(framebuffer)
+                       {
+                               *params = framebuffer->getImplementationColorReadType();
+                       }
+                       else
+                       {
+                               return error(GL_INVALID_OPERATION, true);
+                       }
                }
-               break;
+               return true;
        case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
                {
                        Framebuffer *framebuffer = getReadFramebuffer();
-                       *params = framebuffer->getImplementationColorReadFormat();
+                       if(framebuffer)
+                       {
+                               *params = framebuffer->getImplementationColorReadFormat();
+                       }
+                       else
+                       {
+                               return error(GL_INVALID_OPERATION, true);
+                       }
                }
-               break;
+               return true;
        case GL_MAX_VIEWPORT_DIMS:
                {
                        int maxDimension = IMPLEMENTATION_MAX_RENDERBUFFER_SIZE;
                        params[0] = maxDimension;
                        params[1] = maxDimension;
                }
-               break;
+               return true;
        case GL_COMPRESSED_TEXTURE_FORMATS:
                {
                        for(int i = 0; i < NUM_COMPRESSED_TEXTURE_FORMATS; i++)
@@ -1956,37 +2049,37 @@ template<typename T> bool Context::getIntegerv(GLenum pname, T *params) const
                                params[i] = compressedTextureFormats[i];
                        }
                }
-               break;
+               return true;
        case GL_VIEWPORT:
                params[0] = mState.viewportX;
                params[1] = mState.viewportY;
                params[2] = mState.viewportWidth;
                params[3] = mState.viewportHeight;
-               break;
+               return true;
        case GL_SCISSOR_BOX:
                params[0] = mState.scissorX;
                params[1] = mState.scissorY;
                params[2] = mState.scissorWidth;
                params[3] = mState.scissorHeight;
-               break;
-       case GL_CULL_FACE_MODE:                   *params = mState.cullMode;                 break;
-       case GL_FRONT_FACE:                       *params = mState.frontFace;                break;
+               return true;
+       case GL_CULL_FACE_MODE:                   *params = mState.cullMode;                 return true;
+       case GL_FRONT_FACE:                       *params = mState.frontFace;                return true;
        case GL_RED_BITS:
        case GL_GREEN_BITS:
        case GL_BLUE_BITS:
        case GL_ALPHA_BITS:
                {
                        Framebuffer *framebuffer = getDrawFramebuffer();
-                       Renderbuffer *colorbuffer = framebuffer->getColorbuffer(0);
+                       Renderbuffer *colorbuffer = framebuffer ? framebuffer->getColorbuffer(0) : nullptr;
 
                        if(colorbuffer)
                        {
                                switch(pname)
                                {
-                               case GL_RED_BITS:   *params = colorbuffer->getRedSize();   break;
-                               case GL_GREEN_BITS: *params = colorbuffer->getGreenSize(); break;
-                               case GL_BLUE_BITS:  *params = colorbuffer->getBlueSize();  break;
-                               case GL_ALPHA_BITS: *params = colorbuffer->getAlphaSize(); break;
+                               case GL_RED_BITS:   *params = colorbuffer->getRedSize();   return true;
+                               case GL_GREEN_BITS: *params = colorbuffer->getGreenSize(); return true;
+                               case GL_BLUE_BITS:  *params = colorbuffer->getBlueSize();  return true;
+                               case GL_ALPHA_BITS: *params = colorbuffer->getAlphaSize(); return true;
                                }
                        }
                        else
@@ -1994,11 +2087,11 @@ template<typename T> bool Context::getIntegerv(GLenum pname, T *params) const
                                *params = 0;
                        }
                }
-               break;
+               return true;
        case GL_DEPTH_BITS:
                {
                        Framebuffer *framebuffer = getDrawFramebuffer();
-                       Renderbuffer *depthbuffer = framebuffer->getDepthbuffer();
+                       Renderbuffer *depthbuffer = framebuffer ? framebuffer->getDepthbuffer() : nullptr;
 
                        if(depthbuffer)
                        {
@@ -2009,11 +2102,11 @@ template<typename T> bool Context::getIntegerv(GLenum pname, T *params) const
                                *params = 0;
                        }
                }
-               break;
+               return true;
        case GL_STENCIL_BITS:
                {
                        Framebuffer *framebuffer = getDrawFramebuffer();
-                       Renderbuffer *stencilbuffer = framebuffer->getStencilbuffer();
+                       Renderbuffer *stencilbuffer = framebuffer ? framebuffer->getStencilbuffer() : nullptr;
 
                        if(stencilbuffer)
                        {
@@ -2024,7 +2117,7 @@ template<typename T> bool Context::getIntegerv(GLenum pname, T *params) const
                                *params = 0;
                        }
                }
-               break;
+               return true;
        case GL_TEXTURE_BINDING_2D:
                if(mState.activeSampler > MAX_COMBINED_TEXTURE_IMAGE_UNITS - 1)
                {
@@ -2033,7 +2126,7 @@ template<typename T> bool Context::getIntegerv(GLenum pname, T *params) const
                }
 
                *params = mState.samplerTexture[TEXTURE_2D][mState.activeSampler].name();
-               break;
+               return true;
        case GL_TEXTURE_BINDING_CUBE_MAP:
                if(mState.activeSampler > MAX_COMBINED_TEXTURE_IMAGE_UNITS - 1)
                {
@@ -2042,58 +2135,34 @@ template<typename T> bool Context::getIntegerv(GLenum pname, T *params) const
                }
 
                *params = mState.samplerTexture[TEXTURE_CUBE][mState.activeSampler].name();
-               break;
-       case GL_TEXTURE_BINDING_EXTERNAL_OES:
+               return true;
+       case GL_TEXTURE_BINDING_RECTANGLE_ARB:
                if(mState.activeSampler > MAX_COMBINED_TEXTURE_IMAGE_UNITS - 1)
                {
                        error(GL_INVALID_OPERATION);
                        return false;
                }
 
-               *params = mState.samplerTexture[TEXTURE_EXTERNAL][mState.activeSampler].name();
-               break;
-       case GL_TEXTURE_BINDING_3D_OES:
+               *params = mState.samplerTexture[TEXTURE_2D_RECT][mState.activeSampler].name();
+               return true;
+       case GL_TEXTURE_BINDING_EXTERNAL_OES:
                if(mState.activeSampler > MAX_COMBINED_TEXTURE_IMAGE_UNITS - 1)
                {
                        error(GL_INVALID_OPERATION);
                        return false;
                }
 
-               *params = mState.samplerTexture[TEXTURE_3D][mState.activeSampler].name();
-               break;
-       case GL_TEXTURE_BINDING_2D_ARRAY: // GLES 3.0
-               if(clientVersion < 3)
-               {
-                       return false;
-               }
-               else if(mState.activeSampler > MAX_COMBINED_TEXTURE_IMAGE_UNITS - 1)
+               *params = mState.samplerTexture[TEXTURE_EXTERNAL][mState.activeSampler].name();
+               return true;
+       case GL_TEXTURE_BINDING_3D_OES:
+               if(mState.activeSampler > MAX_COMBINED_TEXTURE_IMAGE_UNITS - 1)
                {
                        error(GL_INVALID_OPERATION);
                        return false;
                }
 
-               *params = mState.samplerTexture[TEXTURE_2D_ARRAY][mState.activeSampler].name();
-               break;
-       case GL_COPY_READ_BUFFER_BINDING: // name, initially 0
-               if(clientVersion >= 3)
-               {
-                       *params = mState.copyReadBuffer.name();
-               }
-               else
-               {
-                       return false;
-               }
-               break;
-       case GL_COPY_WRITE_BUFFER_BINDING: // name, initially 0
-               if(clientVersion >= 3)
-               {
-                       *params = mState.copyWriteBuffer.name();
-               }
-               else
-               {
-                       return false;
-               }
-               break;
+               *params = mState.samplerTexture[TEXTURE_3D][mState.activeSampler].name();
+               return true;
        case GL_DRAW_BUFFER0:
        case GL_DRAW_BUFFER1:
        case GL_DRAW_BUFFER2:
@@ -2110,239 +2179,233 @@ template<typename T> bool Context::getIntegerv(GLenum pname, T *params) const
        case GL_DRAW_BUFFER13:
        case GL_DRAW_BUFFER14:
        case GL_DRAW_BUFFER15:
-               *params = getDrawFramebuffer()->getDrawBuffer(pname - GL_DRAW_BUFFER0);
-               break;
-       case GL_MAJOR_VERSION:
-               if(clientVersion >= 3)
+               if((pname - GL_DRAW_BUFFER0) < MAX_DRAW_BUFFERS)
                {
-                       *params = clientVersion;
+                       Framebuffer* framebuffer = getDrawFramebuffer();
+                       *params = framebuffer ? framebuffer->getDrawBuffer(pname - GL_DRAW_BUFFER0) : GL_NONE;
                }
                else
                {
                        return false;
                }
-               break;
-       case GL_MAX_3D_TEXTURE_SIZE: // GLint, at least 2048
-               *params = IMPLEMENTATION_MAX_TEXTURE_SIZE;
-               break;
-       case GL_MAX_ARRAY_TEXTURE_LAYERS: // GLint, at least 2048
-               *params = IMPLEMENTATION_MAX_TEXTURE_SIZE;
-               break;
-       case GL_MAX_COLOR_ATTACHMENTS:
-               *params = MAX_COLOR_ATTACHMENTS;
-               break;
-       case GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS: // integer, at least 50048
-               *params = MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS;
-               break;
-       case GL_MAX_COMBINED_UNIFORM_BLOCKS: // integer, at least 70
-               UNIMPLEMENTED();
-               *params = 70;
-               break;
-       case GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS: // integer, at least 50176
-               *params = MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS;
-               break;
+               return true;
        case GL_MAX_DRAW_BUFFERS:
                *params = MAX_DRAW_BUFFERS;
+               return true;
+       case GL_MAX_COLOR_ATTACHMENTS: // Note: MAX_COLOR_ATTACHMENTS_EXT added by GL_EXT_draw_buffers
+               *params = MAX_COLOR_ATTACHMENTS;
+               return true;
+       default:
                break;
-       case GL_MAX_ELEMENT_INDEX:
-               *params = MAX_ELEMENT_INDEX;
-               break;
-       case GL_MAX_ELEMENTS_INDICES:
-               *params = MAX_ELEMENTS_INDICES;
-               break;
-       case GL_MAX_ELEMENTS_VERTICES:
-               *params = MAX_ELEMENTS_VERTICES;
-               break;
-       case GL_MAX_FRAGMENT_INPUT_COMPONENTS: // integer, at least 128
-               UNIMPLEMENTED();
-               *params = 128;
-               break;
-       case GL_MAX_FRAGMENT_UNIFORM_BLOCKS: // integer, at least 12
-               *params = MAX_FRAGMENT_UNIFORM_BLOCKS;
-               break;
-       case GL_MAX_FRAGMENT_UNIFORM_COMPONENTS: // integer, at least 896
-               *params = MAX_FRAGMENT_UNIFORM_COMPONENTS;
-               break;
-       case GL_MAX_PROGRAM_TEXEL_OFFSET: // integer, minimum is 7
-               UNIMPLEMENTED();
-               *params = 7;
-               break;
-       case GL_MAX_SERVER_WAIT_TIMEOUT: // integer
-               UNIMPLEMENTED();
-               *params = 0;
-               break;
-       case GL_MAX_TEXTURE_LOD_BIAS: // integer,  at least 2.0
-               UNIMPLEMENTED();
-               *params = 2;
-               break;
-       case GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS: // integer, at least 64
-               *params = sw::MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS;
-               break;
-       case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS: // integer, at least 4
-               *params = MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS;
-               break;
-       case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS: // integer, at least 4
-               *params = sw::MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS;
-               break;
-       case GL_MAX_UNIFORM_BLOCK_SIZE: // integer, at least 16384
-               *params = MAX_UNIFORM_BLOCK_SIZE;
-               break;
-       case GL_MAX_UNIFORM_BUFFER_BINDINGS: // integer, at least 24
-               *params = MAX_UNIFORM_BUFFER_BINDINGS;
-               break;
-       case GL_MAX_VARYING_COMPONENTS: // integer, at least 60
-               UNIMPLEMENTED();
-               *params = 60;
-               break;
-       case GL_MAX_VERTEX_OUTPUT_COMPONENTS: // integer,  at least 64
-               UNIMPLEMENTED();
-               *params = 64;
-               break;
-       case GL_MAX_VERTEX_UNIFORM_BLOCKS: // integer,  at least 12
-               *params = MAX_VERTEX_UNIFORM_BLOCKS;
-               break;
-       case GL_MAX_VERTEX_UNIFORM_COMPONENTS: // integer,  at least 1024
-               *params = MAX_VERTEX_UNIFORM_COMPONENTS;
-               break;
-       case GL_MIN_PROGRAM_TEXEL_OFFSET: // integer, maximum is -8
-               UNIMPLEMENTED();
-               *params = -8;
-               break;
-       case GL_MINOR_VERSION: // integer
-               UNIMPLEMENTED();
-               *params = 0;
-               break;
-       case GL_NUM_EXTENSIONS: // integer
-               GLuint numExtensions;
-               getExtensions(0, &numExtensions);
-               *params = numExtensions;
-               break;
-       case GL_NUM_PROGRAM_BINARY_FORMATS: // integer, at least 0
-               UNIMPLEMENTED();
-               *params = 0;
-               break;
-       case GL_PACK_ROW_LENGTH: // integer, initially 0
-               *params = mState.packRowLength;
-               break;
-       case GL_PACK_SKIP_PIXELS: // integer, initially 0
-               *params = mState.packSkipPixels;
-               break;
-       case GL_PACK_SKIP_ROWS: // integer, initially 0
-               *params = mState.packSkipRows;
-               break;
-       case GL_PIXEL_PACK_BUFFER_BINDING: // integer, initially 0
-               if(clientVersion >= 3)
-               {
-                       *params = mState.pixelPackBuffer.name();
-               }
-               else
-               {
-                       return false;
-               }
-               break;
-       case GL_PIXEL_UNPACK_BUFFER_BINDING: // integer, initially 0
-               if(clientVersion >= 3)
+       }
+
+       if(clientVersion >= 3)
+       {
+               switch(pname)
                {
-                       *params = mState.pixelUnpackBuffer.name();
-               }
-               else
-               {
-                       return false;
-               }
-               break;
-       case GL_PROGRAM_BINARY_FORMATS: // integer[GL_NUM_PROGRAM_BINARY_FORMATS​]
-               UNIMPLEMENTED();
-               *params = 0;
-               break;
-       case GL_READ_BUFFER: // symbolic constant,  initial value is GL_BACK​
-               *params = getReadFramebuffer()->getReadBuffer();
-               break;
-       case GL_SAMPLER_BINDING: // GLint, default 0
-               *params = mState.sampler[mState.activeSampler].name();
-               break;
-       case GL_UNIFORM_BUFFER_BINDING: // name, initially 0
-               if(clientVersion >= 3)
-               {
-                       *params = mState.genericUniformBuffer.name();
-               }
-               else
-               {
-                       return false;
-               }
-               break;
-       case GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT: // integer, defaults to 1
-               *params = UNIFORM_BUFFER_OFFSET_ALIGNMENT;
-               break;
-       case GL_UNIFORM_BUFFER_SIZE: // indexed[n] 64-bit integer, initially 0
-               if(clientVersion >= 3)
-               {
-                       *params = static_cast<T>(mState.genericUniformBuffer->size());
-               }
-               else
-               {
-                       return false;
-               }
-               break;
-       case GL_UNIFORM_BUFFER_START: // indexed[n] 64-bit integer, initially 0
-               if(clientVersion >= 3)
-               {
-                       *params = static_cast<T>(mState.genericUniformBuffer->offset());
-               }
-               else
-               {
-                       return false;
-               }
-               *params = 0;
-               break;
-       case GL_UNPACK_IMAGE_HEIGHT: // integer, initially 0
-               *params = mState.unpackInfo.imageHeight;
-               break;
-       case GL_UNPACK_ROW_LENGTH: // integer, initially 0
-               *params = mState.unpackInfo.rowLength;
-               break;
-       case GL_UNPACK_SKIP_IMAGES: // integer, initially 0
-               *params = mState.unpackInfo.skipImages;
-               break;
-       case GL_UNPACK_SKIP_PIXELS: // integer, initially 0
-               *params = mState.unpackInfo.skipPixels;
-               break;
-       case GL_UNPACK_SKIP_ROWS: // integer, initially 0
-               *params = mState.unpackInfo.skipRows;
-               break;
-       case GL_VERTEX_ARRAY_BINDING: // GLint, initially 0
-               *params = getCurrentVertexArray()->name;
-               break;
-       case GL_TRANSFORM_FEEDBACK_BINDING:
-               {
-                       TransformFeedback* transformFeedback = getTransformFeedback(mState.transformFeedback);
-                       if(transformFeedback)
+               case GL_TEXTURE_BINDING_2D_ARRAY:
+                       if(mState.activeSampler > MAX_COMBINED_TEXTURE_IMAGE_UNITS - 1)
                        {
-                               *params = transformFeedback->name;
+                               error(GL_INVALID_OPERATION);
+                               return false;
                        }
-                       else
+
+                       *params = mState.samplerTexture[TEXTURE_2D_ARRAY][mState.activeSampler].name();
+                       return true;
+               case GL_COPY_READ_BUFFER_BINDING:
+                       *params = mState.copyReadBuffer.name();
+                       return true;
+               case GL_COPY_WRITE_BUFFER_BINDING:
+                       *params = mState.copyWriteBuffer.name();
+                       return true;
+               case GL_MAJOR_VERSION:
+                       *params = clientVersion;
+                       return true;
+               case GL_MAX_3D_TEXTURE_SIZE:
+                       *params = IMPLEMENTATION_MAX_3D_TEXTURE_SIZE;
+                       return true;
+               case GL_MAX_ARRAY_TEXTURE_LAYERS:
+                       *params = IMPLEMENTATION_MAX_TEXTURE_SIZE;
+                       return true;
+               case GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS:
+                       *params = MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS;
+                       return true;
+               case GL_MAX_COMBINED_UNIFORM_BLOCKS:
+                       *params = MAX_VERTEX_UNIFORM_BLOCKS + MAX_FRAGMENT_UNIFORM_BLOCKS;
+                       return true;
+               case GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS:
+                       *params = MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS;
+                       return true;
+               case GL_MAX_ELEMENT_INDEX:
+                       *params = MAX_ELEMENT_INDEX;
+                       return true;
+               case GL_MAX_ELEMENTS_INDICES:
+                       *params = MAX_ELEMENTS_INDICES;
+                       return true;
+               case GL_MAX_ELEMENTS_VERTICES:
+                       *params = MAX_ELEMENTS_VERTICES;
+                       return true;
+               case GL_MAX_FRAGMENT_INPUT_COMPONENTS:
+                       *params = MAX_FRAGMENT_INPUT_VECTORS * 4;
+                       return true;
+               case GL_MAX_FRAGMENT_UNIFORM_BLOCKS:
+                       *params = MAX_FRAGMENT_UNIFORM_BLOCKS;
+                       return true;
+               case GL_MAX_FRAGMENT_UNIFORM_COMPONENTS:
+                       *params = MAX_FRAGMENT_UNIFORM_COMPONENTS;
+                       return true;
+               case GL_MAX_PROGRAM_TEXEL_OFFSET:
+                       // Note: SwiftShader has no actual texel offset limit, so this limit can be modified if required.
+                       // In any case, any behavior outside the specified range is valid since the spec mentions:
+                       // (see OpenGL ES 3.0.5, 3.8.10.1 Scale Factor and Level of Detail, p.153)
+                       // "If any of the offset values are outside the range of the  implementation-defined values
+                       //  MIN_PROGRAM_TEXEL_OFFSET and MAX_PROGRAM_TEXEL_OFFSET, results of the texture lookup are
+                       //  undefined."
+                       *params = MAX_PROGRAM_TEXEL_OFFSET;
+                       return true;
+               case GL_MAX_SERVER_WAIT_TIMEOUT:
+                       *params = 0;
+                       return true;
+               case GL_MAX_TEXTURE_LOD_BIAS:
+                       *params = MAX_TEXTURE_LOD_BIAS;
+                       return true;
+               case GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS:
+                       *params = sw::MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS;
+                       return true;
+               case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS:
+                       *params = MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS;
+                       return true;
+               case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS:
+                       *params = sw::MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS;
+                       return true;
+               case GL_MAX_UNIFORM_BLOCK_SIZE:
+                       *params = MAX_UNIFORM_BLOCK_SIZE;
+                       return true;
+               case GL_MAX_UNIFORM_BUFFER_BINDINGS:
+                       *params = MAX_UNIFORM_BUFFER_BINDINGS;
+                       return true;
+               case GL_MAX_VARYING_COMPONENTS:
+                       *params = MAX_VARYING_VECTORS * 4;
+                       return true;
+               case GL_MAX_VERTEX_OUTPUT_COMPONENTS:
+                       *params = MAX_VERTEX_OUTPUT_VECTORS * 4;
+                       return true;
+               case GL_MAX_VERTEX_UNIFORM_BLOCKS:
+                       *params = MAX_VERTEX_UNIFORM_BLOCKS;
+                       return true;
+               case GL_MAX_VERTEX_UNIFORM_COMPONENTS:
+                       *params = MAX_VERTEX_UNIFORM_COMPONENTS;
+                       return true;
+               case GL_MIN_PROGRAM_TEXEL_OFFSET:
+                       // Note: SwiftShader has no actual texel offset limit, so this limit can be modified if required.
+                       // In any case, any behavior outside the specified range is valid since the spec mentions:
+                       // (see OpenGL ES 3.0.5, 3.8.10.1 Scale Factor and Level of Detail, p.153)
+                       // "If any of the offset values are outside the range of the  implementation-defined values
+                       //  MIN_PROGRAM_TEXEL_OFFSET and MAX_PROGRAM_TEXEL_OFFSET, results of the texture lookup are
+                       //  undefined."
+                       *params = MIN_PROGRAM_TEXEL_OFFSET;
+                       return true;
+               case GL_MINOR_VERSION:
+                       *params = 0;
+                       return true;
+               case GL_NUM_EXTENSIONS:
+                       GLuint numExtensions;
+                       getExtensions(0, &numExtensions);
+                       *params = numExtensions;
+                       return true;
+               case GL_NUM_PROGRAM_BINARY_FORMATS:
+                       *params = NUM_PROGRAM_BINARY_FORMATS;
+                       return true;
+               case GL_PACK_ROW_LENGTH:
+                       *params = mState.packParameters.rowLength;
+                       return true;
+               case GL_PACK_SKIP_PIXELS:
+                       *params = mState.packParameters.skipPixels;
+                       return true;
+               case GL_PACK_SKIP_ROWS:
+                       *params = mState.packParameters.skipRows;
+                       return true;
+               case GL_PIXEL_PACK_BUFFER_BINDING:
+                       *params = mState.pixelPackBuffer.name();
+                       return true;
+               case GL_PIXEL_UNPACK_BUFFER_BINDING:
+                       *params = mState.pixelUnpackBuffer.name();
+                       return true;
+               case GL_PROGRAM_BINARY_FORMATS:
+                       // Since NUM_PROGRAM_BINARY_FORMATS is 0, the input
+                       // should be a 0 sized array, so don't write to params
+                       return true;
+               case GL_READ_BUFFER:
                        {
-                               return false;
+                               Framebuffer* framebuffer = getReadFramebuffer();
+                               *params = framebuffer ? framebuffer->getReadBuffer() : GL_NONE;
                        }
-               }
-               break;
-       case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING:
-               {
-                       TransformFeedback* transformFeedback = getTransformFeedback(mState.transformFeedback);
-                       if(transformFeedback)
+                       return true;
+               case GL_SAMPLER_BINDING:
+                       *params = mState.sampler[mState.activeSampler].name();
+                       return true;
+               case GL_UNIFORM_BUFFER_BINDING:
+                       *params = mState.genericUniformBuffer.name();
+                       return true;
+               case GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT:
+                       *params = UNIFORM_BUFFER_OFFSET_ALIGNMENT;
+                       return true;
+               case GL_UNIFORM_BUFFER_SIZE:
+                       *params = static_cast<T>(mState.genericUniformBuffer->size());
+                       return true;
+               case GL_UNIFORM_BUFFER_START:
+                       *params = static_cast<T>(mState.genericUniformBuffer->offset());
+                       return true;
+               case GL_UNPACK_IMAGE_HEIGHT:
+                       *params = mState.unpackParameters.imageHeight;
+                       return true;
+               case GL_UNPACK_ROW_LENGTH:
+                       *params = mState.unpackParameters.rowLength;
+                       return true;
+               case GL_UNPACK_SKIP_IMAGES:
+                       *params = mState.unpackParameters.skipImages;
+                       return true;
+               case GL_UNPACK_SKIP_PIXELS:
+                       *params = mState.unpackParameters.skipPixels;
+                       return true;
+               case GL_UNPACK_SKIP_ROWS:
+                       *params = mState.unpackParameters.skipRows;
+                       return true;
+               case GL_VERTEX_ARRAY_BINDING:
+                       *params = getCurrentVertexArray()->name;
+                       return true;
+               case GL_TRANSFORM_FEEDBACK_BINDING:
                        {
-                               *params = transformFeedback->getGenericBufferName();
+                               TransformFeedback* transformFeedback = getTransformFeedback(mState.transformFeedback);
+                               if(transformFeedback)
+                               {
+                                       *params = transformFeedback->name;
+                               }
+                               else
+                               {
+                                       return false;
+                               }
                        }
-                       else
+                       return true;
+               case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING:
                        {
-                               return false;
+                               TransformFeedback* transformFeedback = getTransformFeedback(mState.transformFeedback);
+                               if(transformFeedback)
+                               {
+                                       *params = transformFeedback->getGenericBufferName();
+                               }
+                               else
+                               {
+                                       return false;
+                               }
                        }
+                       return true;
+               default:
+                       break;
                }
-               break;
-       default:
-               return false;
        }
 
-       return true;
+       return false;
 }
 
 template bool Context::getTransformFeedbackiv<GLint>(GLuint index, GLenum pname, GLint *param) const;
@@ -2396,6 +2459,20 @@ template bool Context::getUniformBufferiv<GLint64>(GLuint index, GLenum pname, G
 
 template<typename T> bool Context::getUniformBufferiv(GLuint index, GLenum pname, T *param) const
 {
+       switch(pname)
+       {
+       case GL_UNIFORM_BUFFER_BINDING:
+       case GL_UNIFORM_BUFFER_SIZE:
+       case GL_UNIFORM_BUFFER_START:
+               if(index >= MAX_UNIFORM_BUFFER_BINDINGS)
+               {
+                       return error(GL_INVALID_VALUE, true);
+               }
+               break;
+       default:
+               break;
+       }
+
        const BufferBinding& uniformBuffer = mState.uniformBuffers[index];
 
        switch(pname)
@@ -2450,14 +2527,15 @@ bool Context::getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *nu
        case GL_NUM_SHADER_BINARY_FORMATS:
        case GL_NUM_COMPRESSED_TEXTURE_FORMATS:
        case GL_ARRAY_BUFFER_BINDING:
-       case GL_FRAMEBUFFER_BINDING: // Same as GL_DRAW_FRAMEBUFFER_BINDING_ANGLE
-       case GL_READ_FRAMEBUFFER_BINDING_ANGLE:
+       case GL_FRAMEBUFFER_BINDING:        // Same as GL_DRAW_FRAMEBUFFER_BINDING_ANGLE
+       case GL_READ_FRAMEBUFFER_BINDING:   // Same as GL_READ_FRAMEBUFFER_BINDING_ANGLE
        case GL_RENDERBUFFER_BINDING:
        case GL_CURRENT_PROGRAM:
        case GL_PACK_ALIGNMENT:
        case GL_UNPACK_ALIGNMENT:
        case GL_GENERATE_MIPMAP_HINT:
        case GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES:
+       case GL_TEXTURE_FILTERING_HINT_CHROMIUM:
        case GL_RED_BITS:
        case GL_GREEN_BITS:
        case GL_BLUE_BITS:
@@ -2493,12 +2571,14 @@ bool Context::getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *nu
        case GL_SUBPIXEL_BITS:
        case GL_MAX_TEXTURE_SIZE:
        case GL_MAX_CUBE_MAP_TEXTURE_SIZE:
+       case GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB:
        case GL_SAMPLE_BUFFERS:
        case GL_SAMPLES:
        case GL_IMPLEMENTATION_COLOR_READ_TYPE:
        case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
        case GL_TEXTURE_BINDING_2D:
        case GL_TEXTURE_BINDING_CUBE_MAP:
+       case GL_TEXTURE_BINDING_RECTANGLE_ARB:
        case GL_TEXTURE_BINDING_EXTERNAL_OES:
        case GL_TEXTURE_BINDING_3D_OES:
        case GL_COPY_READ_BUFFER_BINDING:
@@ -2575,7 +2655,7 @@ bool Context::getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *nu
                        *numParams = 1;
                }
                break;
-       case GL_MAX_SAMPLES_ANGLE:
+       case GL_MAX_SAMPLES:
                {
                        *type = GL_INT;
                        *numParams = 1;
@@ -2679,7 +2759,7 @@ bool Context::applyRenderTarget()
        Framebuffer *framebuffer = getDrawFramebuffer();
        int width, height, samples;
 
-       if(!framebuffer || framebuffer->completeness(width, height, samples) != GL_FRAMEBUFFER_COMPLETE)
+       if(!framebuffer || (framebuffer->completeness(width, height, samples) != GL_FRAMEBUFFER_COMPLETE))
        {
                return error(GL_INVALID_FRAMEBUFFER_OPERATION, false);
        }
@@ -2689,21 +2769,24 @@ bool Context::applyRenderTarget()
                if(framebuffer->getDrawBuffer(i) != GL_NONE)
                {
                        egl::Image *renderTarget = framebuffer->getRenderTarget(i);
-                       device->setRenderTarget(i, renderTarget);
+                       GLint layer = framebuffer->getColorbufferLayer(i);
+                       device->setRenderTarget(i, renderTarget, layer);
                        if(renderTarget) renderTarget->release();
                }
                else
                {
-                       device->setRenderTarget(i, nullptr);
+                       device->setRenderTarget(i, nullptr, 0);
                }
        }
 
        egl::Image *depthBuffer = framebuffer->getDepthBuffer();
-       device->setDepthBuffer(depthBuffer);
+       GLint dLayer = framebuffer->getDepthbufferLayer();
+       device->setDepthBuffer(depthBuffer, dLayer);
        if(depthBuffer) depthBuffer->release();
 
        egl::Image *stencilBuffer = framebuffer->getStencilBuffer();
-       device->setStencilBuffer(stencilBuffer);
+       GLint sLayer = framebuffer->getStencilbufferLayer();
+       device->setStencilBuffer(stencilBuffer, sLayer);
        if(stencilBuffer) stencilBuffer->release();
 
        Viewport viewport;
@@ -2873,7 +2956,7 @@ void Context::applyState(GLenum drawMode)
                        if(depthbuffer)
                        {
                                device->setSlopeDepthBias(mState.polygonOffsetFactor);
-                               float depthBias = ldexp(mState.polygonOffsetUnits, -(int)(depthbuffer->getDepthSize()));
+                               float depthBias = ldexp(mState.polygonOffsetUnits, -23);   // We use 32-bit floating-point for all depth formats, with 23 mantissa bits.
                                device->setDepthBias(depthBias);
                        }
                }
@@ -2988,7 +3071,7 @@ GLenum Context::applyVertexBuffer(GLint base, GLint first, GLsizei count, GLsize
 // Applies the indices and element array bindings
 GLenum Context::applyIndexBuffer(const void *indices, GLuint start, GLuint end, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo)
 {
-       GLenum err = mIndexDataManager->prepareIndexData(type, start, end, count, getCurrentVertexArray()->getElementArrayBuffer(), indices, indexInfo);
+       GLenum err = mIndexDataManager->prepareIndexData(mode, type, start, end, count, getCurrentVertexArray()->getElementArrayBuffer(), indices, indexInfo, isPrimitiveRestartFixedIndexEnabled());
 
        if(err == GL_NO_ERROR)
        {
@@ -3014,9 +3097,9 @@ void Context::applyShaders()
                mAppliedProgramSerial = programObject->getSerial();
        }
 
-       programObject->applyTransformFeedback(getTransformFeedback());
-       programObject->applyUniformBuffers(mState.uniformBuffers);
-       programObject->applyUniforms();
+       programObject->applyTransformFeedback(device, getTransformFeedback());
+       programObject->applyUniformBuffers(device, mState.uniformBuffers);
+       programObject->applyUniforms(device);
 }
 
 void Context::applyTextures()
@@ -3043,8 +3126,8 @@ void Context::applyTextures(sw::SamplerType samplerType)
 
                        if(texture->isSamplerComplete())
                        {
-                               GLenum wrapS, wrapT, wrapR, minFilter, magFilter;
-                               GLfloat minLOD, maxLOD;
+                               GLenum wrapS, wrapT, wrapR, minFilter, magFilter, compFunc, compMode;
+                               GLfloat minLOD, maxLOD, maxAnisotropy;
 
                                Sampler *samplerObject = mState.sampler[textureUnit];
                                if(samplerObject)
@@ -3056,6 +3139,9 @@ void Context::applyTextures(sw::SamplerType samplerType)
                                        magFilter = samplerObject->getMagFilter();
                                        minLOD = samplerObject->getMinLod();
                                        maxLOD = samplerObject->getMaxLod();
+                                       compFunc = samplerObject->getCompareFunc();
+                                       compMode = samplerObject->getCompareMode();
+                                       maxAnisotropy = samplerObject->getMaxAnisotropy();
                                }
                                else
                                {
@@ -3066,8 +3152,10 @@ void Context::applyTextures(sw::SamplerType samplerType)
                                        magFilter = texture->getMagFilter();
                                        minLOD = texture->getMinLOD();
                                        maxLOD = texture->getMaxLOD();
+                                       compFunc = texture->getCompareFunc();
+                                       compMode = texture->getCompareMode();
+                                       maxAnisotropy = texture->getMaxAnisotropy();
                                }
-                               GLfloat maxAnisotropy = texture->getMaxAnisotropy();
 
                                GLint baseLevel = texture->getBaseLevel();
                                GLint maxLevel = texture->getMaxLevel();
@@ -3079,6 +3167,7 @@ void Context::applyTextures(sw::SamplerType samplerType)
                                device->setAddressingModeU(samplerType, samplerIndex, es2sw::ConvertTextureWrap(wrapS));
                                device->setAddressingModeV(samplerType, samplerIndex, es2sw::ConvertTextureWrap(wrapT));
                                device->setAddressingModeW(samplerType, samplerIndex, es2sw::ConvertTextureWrap(wrapR));
+                               device->setCompareFunc(samplerType, samplerIndex, es2sw::ConvertCompareFunc(compFunc, compMode));
                                device->setSwizzleR(samplerType, samplerIndex, es2sw::ConvertSwizzleType(swizzleR));
                                device->setSwizzleG(samplerType, samplerIndex, es2sw::ConvertSwizzleType(swizzleG));
                                device->setSwizzleB(samplerType, samplerIndex, es2sw::ConvertSwizzleType(swizzleB));
@@ -3087,10 +3176,10 @@ void Context::applyTextures(sw::SamplerType samplerType)
                                device->setMaxLod(samplerType, samplerIndex, maxLOD);
                                device->setBaseLevel(samplerType, samplerIndex, baseLevel);
                                device->setMaxLevel(samplerType, samplerIndex, maxLevel);
-
                                device->setTextureFilter(samplerType, samplerIndex, es2sw::ConvertTextureFilter(minFilter, magFilter, maxAnisotropy));
                                device->setMipmapFilter(samplerType, samplerIndex, es2sw::ConvertMipMapFilter(minFilter));
                                device->setMaxAnisotropy(samplerType, samplerIndex, maxAnisotropy);
+                               device->setHighPrecisionFiltering(samplerType, samplerIndex, mState.textureFilteringHint == GL_NICEST);
 
                                applyTexture(samplerType, samplerIndex, texture);
                        }
@@ -3122,7 +3211,7 @@ void Context::applyTexture(sw::SamplerType type, int index, Texture *baseTexture
        }
        else UNREACHABLE(type);
 
-       sw::Resource *resource = 0;
+       sw::Resource *resource = nullptr;
 
        if(baseTexture && textureUsed)
        {
@@ -3133,96 +3222,96 @@ void Context::applyTexture(sw::SamplerType type, int index, Texture *baseTexture
 
        if(baseTexture && textureUsed)
        {
-               int levelCount = baseTexture->getLevelCount();
+               int baseLevel = baseTexture->getBaseLevel();
+               int maxLevel = std::min(baseTexture->getTopLevel(), baseTexture->getMaxLevel());
+               GLenum target = baseTexture->getTarget();
 
-               if(baseTexture->getTarget() == GL_TEXTURE_2D || baseTexture->getTarget() == GL_TEXTURE_EXTERNAL_OES)
+               switch(target)
                {
-                       Texture2D *texture = static_cast<Texture2D*>(baseTexture);
-
-                       for(int mipmapLevel = 0; mipmapLevel < sw::MIPMAP_LEVELS; mipmapLevel++)
+               case GL_TEXTURE_2D:
+               case GL_TEXTURE_EXTERNAL_OES:
+               case GL_TEXTURE_RECTANGLE_ARB:
                        {
-                               int surfaceLevel = mipmapLevel;
+                               Texture2D *texture = static_cast<Texture2D*>(baseTexture);
 
-                               if(surfaceLevel < 0)
-                               {
-                                       surfaceLevel = 0;
-                               }
-                               else if(surfaceLevel >= levelCount)
+                               for(int mipmapLevel = 0; mipmapLevel < sw::MIPMAP_LEVELS; mipmapLevel++)
                                {
-                                       surfaceLevel = levelCount - 1;
-                               }
+                                       int surfaceLevel = mipmapLevel + baseLevel;
 
-                               egl::Image *surface = texture->getImage(surfaceLevel);
-                               device->setTextureLevel(sampler, 0, mipmapLevel, surface, sw::TEXTURE_2D);
-                       }
-               }
-               else if(baseTexture->getTarget() == GL_TEXTURE_3D_OES)
-               {
-                       Texture3D *texture = static_cast<Texture3D*>(baseTexture);
+                                       if(surfaceLevel > maxLevel)
+                                       {
+                                               surfaceLevel = maxLevel;
+                                       }
 
-                       for(int mipmapLevel = 0; mipmapLevel < sw::MIPMAP_LEVELS; mipmapLevel++)
+                                       egl::Image *surface = texture->getImage(surfaceLevel);
+                                       device->setTextureLevel(sampler, 0, mipmapLevel, surface,
+                                                               (target == GL_TEXTURE_RECTANGLE_ARB) ? sw::TEXTURE_RECTANGLE : sw::TEXTURE_2D);
+                               }
+                       }
+                       break;
+               case GL_TEXTURE_3D:
                        {
-                               int surfaceLevel = mipmapLevel;
+                               Texture3D *texture = static_cast<Texture3D*>(baseTexture);
 
-                               if(surfaceLevel < 0)
-                               {
-                                       surfaceLevel = 0;
-                               }
-                               else if(surfaceLevel >= levelCount)
+                               for(int mipmapLevel = 0; mipmapLevel < sw::MIPMAP_LEVELS; mipmapLevel++)
                                {
-                                       surfaceLevel = levelCount - 1;
-                               }
+                                       int surfaceLevel = mipmapLevel + baseLevel;
 
-                               egl::Image *surface = texture->getImage(surfaceLevel);
-                               device->setTextureLevel(sampler, 0, mipmapLevel, surface, sw::TEXTURE_3D);
-                       }
-               }
-               else if(baseTexture->getTarget() == GL_TEXTURE_2D_ARRAY)
-               {
-                       Texture2DArray *texture = static_cast<Texture2DArray*>(baseTexture);
+                                       if(surfaceLevel > maxLevel)
+                                       {
+                                               surfaceLevel = maxLevel;
+                                       }
 
-                       for(int mipmapLevel = 0; mipmapLevel < sw::MIPMAP_LEVELS; mipmapLevel++)
+                                       egl::Image *surface = texture->getImage(surfaceLevel);
+                                       device->setTextureLevel(sampler, 0, mipmapLevel, surface, sw::TEXTURE_3D);
+                               }
+                       }
+                       break;
+               case GL_TEXTURE_2D_ARRAY:
                        {
-                               int surfaceLevel = mipmapLevel;
+                               Texture2DArray *texture = static_cast<Texture2DArray*>(baseTexture);
 
-                               if(surfaceLevel < 0)
-                               {
-                                       surfaceLevel = 0;
-                               }
-                               else if(surfaceLevel >= levelCount)
+                               for(int mipmapLevel = 0; mipmapLevel < sw::MIPMAP_LEVELS; mipmapLevel++)
                                {
-                                       surfaceLevel = levelCount - 1;
-                               }
+                                       int surfaceLevel = mipmapLevel + baseLevel;
 
-                               egl::Image *surface = texture->getImage(surfaceLevel);
-                               device->setTextureLevel(sampler, 0, mipmapLevel, surface, sw::TEXTURE_2D_ARRAY);
+                                       if(surfaceLevel > maxLevel)
+                                       {
+                                               surfaceLevel = maxLevel;
+                                       }
+
+                                       egl::Image *surface = texture->getImage(surfaceLevel);
+                                       device->setTextureLevel(sampler, 0, mipmapLevel, surface, sw::TEXTURE_2D_ARRAY);
+                               }
                        }
-               }
-               else if(baseTexture->getTarget() == GL_TEXTURE_CUBE_MAP)
-               {
-                       for(int face = 0; face < 6; face++)
+                       break;
+               case GL_TEXTURE_CUBE_MAP:
                        {
                                TextureCubeMap *cubeTexture = static_cast<TextureCubeMap*>(baseTexture);
 
                                for(int mipmapLevel = 0; mipmapLevel < sw::MIPMAP_LEVELS; mipmapLevel++)
                                {
-                                       int surfaceLevel = mipmapLevel;
+                                       cubeTexture->updateBorders(mipmapLevel);
 
-                                       if(surfaceLevel < 0)
+                                       for(int face = 0; face < 6; face++)
                                        {
-                                               surfaceLevel = 0;
-                                       }
-                                       else if(surfaceLevel >= levelCount)
-                                       {
-                                               surfaceLevel = levelCount - 1;
-                                       }
+                                               int surfaceLevel = mipmapLevel + baseLevel;
 
-                                       egl::Image *surface = cubeTexture->getImage(face, surfaceLevel);
-                                       device->setTextureLevel(sampler, face, mipmapLevel, surface, sw::TEXTURE_CUBE);
+                                               if(surfaceLevel > maxLevel)
+                                               {
+                                                       surfaceLevel = maxLevel;
+                                               }
+
+                                               egl::Image *surface = cubeTexture->getImage(face, surfaceLevel);
+                                               device->setTextureLevel(sampler, face, mipmapLevel, surface, sw::TEXTURE_CUBE);
+                                       }
                                }
                        }
+                       break;
+               default:
+                       UNIMPLEMENTED();
+                       break;
                }
-               else UNIMPLEMENTED();
        }
        else
        {
@@ -3235,7 +3324,7 @@ void Context::readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum
        Framebuffer *framebuffer = getReadFramebuffer();
        int framebufferWidth, framebufferHeight, framebufferSamples;
 
-       if(framebuffer->completeness(framebufferWidth, framebufferHeight, framebufferSamples) != GL_FRAMEBUFFER_COMPLETE)
+       if(!framebuffer || (framebuffer->completeness(framebufferWidth, framebufferHeight, framebufferSamples) != GL_FRAMEBUFFER_COMPLETE))
        {
                return error(GL_INVALID_FRAMEBUFFER_OPERATION);
        }
@@ -3245,30 +3334,16 @@ void Context::readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum
                return error(GL_INVALID_OPERATION);
        }
 
-       GLenum readFormat = GL_NONE;
-       GLenum readType = GL_NONE;
-       switch(format)
-       {
-       case GL_DEPTH_COMPONENT:
-               readFormat = framebuffer->getDepthReadFormat();
-               readType = framebuffer->getDepthReadType();
-               break;
-       default:
-               readFormat = framebuffer->getImplementationColorReadFormat();
-               readType = framebuffer->getImplementationColorReadType();
-               break;
-       }
-
-       if(!(readFormat == format && readType == type) && !ValidReadPixelsFormatType(readFormat, readType, format, type, clientVersion))
+       if(!IsValidReadPixelsFormatType(framebuffer, format, type, clientVersion))
        {
                return error(GL_INVALID_OPERATION);
        }
 
-       GLsizei outputWidth = (mState.packRowLength > 0) ? mState.packRowLength : width;
-       GLsizei outputPitch = egl::ComputePitch(outputWidth, format, type, mState.packAlignment);
-       GLsizei outputHeight = (mState.packImageHeight == 0) ? height : mState.packImageHeight;
+       GLsizei outputWidth = (mState.packParameters.rowLength > 0) ? mState.packParameters.rowLength : width;
+       GLsizei outputPitch = gl::ComputePitch(outputWidth, format, type, mState.packParameters.alignment);
+       GLsizei outputHeight = (mState.packParameters.imageHeight == 0) ? height : mState.packParameters.imageHeight;
        pixels = getPixelPackBuffer() ? (unsigned char*)getPixelPackBuffer()->data() + (ptrdiff_t)pixels : (unsigned char*)pixels;
-       pixels = ((char*)pixels) + egl::ComputePackingOffset(format, type, outputWidth, outputHeight, mState.packAlignment, mState.packSkipImages, mState.packSkipRows, mState.packSkipPixels);
+       pixels = ((char*)pixels) + gl::ComputePackingOffset(format, type, outputWidth, outputHeight, mState.packParameters);
 
        // Sized query sanity check
        if(bufSize)
@@ -3283,7 +3358,7 @@ void Context::readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum
        egl::Image *renderTarget = nullptr;
        switch(format)
        {
-       case GL_DEPTH_COMPONENT:
+       case GL_DEPTH_COMPONENT:   // GL_NV_read_depth
                renderTarget = framebuffer->getDepthBuffer();
                break;
        default:
@@ -3296,14 +3371,15 @@ void Context::readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum
                return error(GL_INVALID_OPERATION);
        }
 
-       sw::Rect rect = {x, y, x + width, y + height};
-       sw::Rect dstRect = { 0, 0, width, height };
-       rect.clip(0, 0, renderTarget->getWidth(), renderTarget->getHeight());
+       sw::RectF rect((float)x, (float)y, (float)(x + width), (float)(y + height));
+       sw::Rect dstRect(0, 0, width, height);
+       rect.clip(0.0f, 0.0f, (float)renderTarget->getWidth(), (float)renderTarget->getHeight());
 
-       sw::Surface externalSurface(width, height, 1, egl::ConvertFormatType(format, type), pixels, outputPitch, outputPitch * outputHeight);
-       sw::SliceRect sliceRect(rect);
+       sw::Surface *externalSurface = sw::Surface::create(width, height, 1, gl::ConvertReadFormatType(format, type), pixels, outputPitch, outputPitch * outputHeight);
+       sw::SliceRectF sliceRect(rect);
        sw::SliceRect dstSliceRect(dstRect);
-       device->blit(renderTarget, sliceRect, &externalSurface, dstSliceRect, false);
+       device->blit(renderTarget, sliceRect, externalSurface, dstSliceRect, false, false, false);
+       delete externalSurface;
 
        renderTarget->release();
 }
@@ -3317,7 +3393,7 @@ void Context::clear(GLbitfield mask)
 
        Framebuffer *framebuffer = getDrawFramebuffer();
 
-       if(!framebuffer || framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
+       if(!framebuffer || (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE))
        {
                return error(GL_INVALID_FRAMEBUFFER_OPERATION);
        }
@@ -3362,11 +3438,15 @@ void Context::clearColorBuffer(GLint drawbuffer, void *value, sw::Format format)
        if(rgbaMask && !mState.rasterizerDiscardEnabled)
        {
                Framebuffer *framebuffer = getDrawFramebuffer();
+               if(!framebuffer)
+               {
+                       return error(GL_INVALID_FRAMEBUFFER_OPERATION);
+               }
                egl::Image *colorbuffer = framebuffer->getRenderTarget(drawbuffer);
 
                if(colorbuffer)
                {
-                       sw::SliceRect clearRect = colorbuffer->getRect();
+                       sw::Rect clearRect = colorbuffer->getRect();
 
                        if(mState.scissorTestEnabled)
                        {
@@ -3400,12 +3480,16 @@ void Context::clearDepthBuffer(const GLfloat value)
        if(mState.depthMask && !mState.rasterizerDiscardEnabled)
        {
                Framebuffer *framebuffer = getDrawFramebuffer();
+               if(!framebuffer)
+               {
+                       return error(GL_INVALID_FRAMEBUFFER_OPERATION);
+               }
                egl::Image *depthbuffer = framebuffer->getDepthBuffer();
 
                if(depthbuffer)
                {
                        float depth = clamp01(value);
-                       sw::SliceRect clearRect = depthbuffer->getRect();
+                       sw::Rect clearRect = depthbuffer->getRect();
 
                        if(mState.scissorTestEnabled)
                        {
@@ -3424,12 +3508,16 @@ void Context::clearStencilBuffer(const GLint value)
        if(mState.stencilWritemask && !mState.rasterizerDiscardEnabled)
        {
                Framebuffer *framebuffer = getDrawFramebuffer();
+               if(!framebuffer)
+               {
+                       return error(GL_INVALID_FRAMEBUFFER_OPERATION);
+               }
                egl::Image *stencilbuffer = framebuffer->getStencilBuffer();
 
                if(stencilbuffer)
                {
                        unsigned char stencil = value < 0 ? 0 : static_cast<unsigned char>(value & 0x000000FF);
-                       sw::SliceRect clearRect = stencilbuffer->getRect();
+                       sw::Rect clearRect = stencilbuffer->getRect();
 
                        if(mState.scissorTestEnabled)
                        {
@@ -3445,9 +3533,14 @@ void Context::clearStencilBuffer(const GLint value)
 
 void Context::drawArrays(GLenum mode, GLint first, GLsizei count, GLsizei instanceCount)
 {
-       if(!mState.currentProgram)
+       if(!applyRenderTarget())
        {
-               return error(GL_INVALID_OPERATION);
+               return;
+       }
+
+       if(mState.currentProgram == 0)
+       {
+               return;   // Nothing to process.
        }
 
        sw::DrawType primitiveType;
@@ -3455,16 +3548,8 @@ void Context::drawArrays(GLenum mode, GLint first, GLsizei count, GLsizei instan
        int verticesPerPrimitive;
 
        if(!es2sw::ConvertPrimitiveType(mode, count, GL_NONE, primitiveType, primitiveCount, verticesPerPrimitive))
-               return error(GL_INVALID_ENUM);
-
-       if(primitiveCount <= 0)
-       {
-               return;
-       }
-
-       if(!applyRenderTarget())
        {
-               return;
+               return error(GL_INVALID_ENUM);
        }
 
        applyState(mode);
@@ -3487,6 +3572,11 @@ void Context::drawArrays(GLenum mode, GLint first, GLsizei count, GLsizei instan
                        return error(GL_INVALID_OPERATION);
                }
 
+               if(primitiveCount <= 0)
+               {
+                       return;
+               }
+
                TransformFeedback* transformFeedback = getTransformFeedback();
                if(!cullSkipsDraw(mode) || (transformFeedback->isActive() && !transformFeedback->isPaused()))
                {
@@ -3501,9 +3591,14 @@ void Context::drawArrays(GLenum mode, GLint first, GLsizei count, GLsizei instan
 
 void Context::drawElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLsizei instanceCount)
 {
-       if(!mState.currentProgram)
+       if(!applyRenderTarget())
        {
-               return error(GL_INVALID_OPERATION);
+               return;
+       }
+
+       if(mState.currentProgram == 0)
+       {
+               return;   // Nothing to process.
        }
 
        if(!indices && !getCurrentVertexArray()->getElementArrayBuffer())
@@ -3511,36 +3606,46 @@ void Context::drawElements(GLenum mode, GLuint start, GLuint end, GLsizei count,
                return error(GL_INVALID_OPERATION);
        }
 
+       GLenum internalMode = mode;
+       if(isPrimitiveRestartFixedIndexEnabled())
+       {
+               switch(mode)
+               {
+               case GL_TRIANGLE_FAN:
+               case GL_TRIANGLE_STRIP:
+                       internalMode = GL_TRIANGLES;
+                       break;
+               case GL_LINE_LOOP:
+               case GL_LINE_STRIP:
+                       internalMode = GL_LINES;
+                       break;
+               default:
+                       break;
+               }
+       }
+
        sw::DrawType primitiveType;
        int primitiveCount;
        int verticesPerPrimitive;
 
-       if(!es2sw::ConvertPrimitiveType(mode, count, type, primitiveType, primitiveCount, verticesPerPrimitive))
-               return error(GL_INVALID_ENUM);
-
-       if(primitiveCount <= 0)
+       if(!es2sw::ConvertPrimitiveType(internalMode, count, type, primitiveType, primitiveCount, verticesPerPrimitive))
        {
-               return;
+               return error(GL_INVALID_ENUM);
        }
 
-       if(!applyRenderTarget())
+       TranslatedIndexData indexInfo(primitiveCount);
+       GLenum err = applyIndexBuffer(indices, start, end, count, mode, type, &indexInfo);
+       if(err != GL_NO_ERROR)
        {
-               return;
+               return error(err);
        }
 
-       applyState(mode);
+       applyState(internalMode);
 
        for(int i = 0; i < instanceCount; ++i)
        {
                device->setInstanceID(i);
 
-               TranslatedIndexData indexInfo;
-               GLenum err = applyIndexBuffer(indices, start, end, count, mode, type, &indexInfo);
-               if(err != GL_NO_ERROR)
-               {
-                       return error(err);
-               }
-
                GLsizei vertexCount = indexInfo.maxIndex - indexInfo.minIndex + 1;
                err = applyVertexBuffer(-(int)indexInfo.minIndex, indexInfo.minIndex, vertexCount, i);
                if(err != GL_NO_ERROR)
@@ -3556,18 +3661,29 @@ void Context::drawElements(GLenum mode, GLuint start, GLuint end, GLsizei count,
                        return error(GL_INVALID_OPERATION);
                }
 
+               if(primitiveCount <= 0)
+               {
+                       return;
+               }
+
                TransformFeedback* transformFeedback = getTransformFeedback();
-               if(!cullSkipsDraw(mode) || (transformFeedback->isActive() && !transformFeedback->isPaused()))
+               if(!cullSkipsDraw(internalMode) || (transformFeedback->isActive() && !transformFeedback->isPaused()))
                {
-                       device->drawIndexedPrimitive(primitiveType, indexInfo.indexOffset, primitiveCount);
+                       device->drawIndexedPrimitive(primitiveType, indexInfo.indexOffset, indexInfo.primitiveCount);
                }
                if(transformFeedback)
                {
-                       transformFeedback->addVertexOffset(primitiveCount * verticesPerPrimitive);
+                       transformFeedback->addVertexOffset(indexInfo.primitiveCount * verticesPerPrimitive);
                }
        }
 }
 
+void Context::blit(sw::Surface *source, const sw::SliceRect &sRect, sw::Surface *dest, const sw::SliceRect &dRect)
+{
+       sw::SliceRectF sRectF((float)sRect.x0, (float)sRect.y0, (float)sRect.x1, (float)sRect.y1, sRect.slice);
+       device->blit(source, sRectF, dest, dRect, false);
+}
+
 void Context::finish()
 {
        device->finish();
@@ -3881,8 +3997,8 @@ void Context::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1
        int readBufferWidth, readBufferHeight, readBufferSamples;
        int drawBufferWidth, drawBufferHeight, drawBufferSamples;
 
-       if(!readFramebuffer || readFramebuffer->completeness(readBufferWidth, readBufferHeight, readBufferSamples) != GL_FRAMEBUFFER_COMPLETE ||
-          !drawFramebuffer || drawFramebuffer->completeness(drawBufferWidth, drawBufferHeight, drawBufferSamples) != GL_FRAMEBUFFER_COMPLETE)
+       if(!readFramebuffer || (readFramebuffer->completeness(readBufferWidth, readBufferHeight, readBufferSamples) != GL_FRAMEBUFFER_COMPLETE) ||
+          !drawFramebuffer || (drawFramebuffer->completeness(drawBufferWidth, drawBufferHeight, drawBufferSamples) != GL_FRAMEBUFFER_COMPLETE))
        {
                return error(GL_INVALID_FRAMEBUFFER_OPERATION);
        }
@@ -3895,7 +4011,7 @@ void Context::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1
        sw::SliceRect sourceRect;
        sw::SliceRect destRect;
        bool flipX = (srcX0 < srcX1) ^ (dstX0 < dstX1);
-       bool flipy = (srcY0 < srcY1) ^ (dstY0 < dstY1);
+       bool flipY = (srcY0 < srcY1) ^ (dstY0 < dstY1);
 
        if(srcX0 < srcX1)
        {
@@ -3941,100 +4057,26 @@ void Context::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1
                destRect.y1 = dstY0;
        }
 
-       sw::Rect sourceScissoredRect = sourceRect;
+       sw::RectF sourceScissoredRect(static_cast<float>(sourceRect.x0), static_cast<float>(sourceRect.y0),
+                                     static_cast<float>(sourceRect.x1), static_cast<float>(sourceRect.y1));
        sw::Rect destScissoredRect = destRect;
 
        if(mState.scissorTestEnabled)   // Only write to parts of the destination framebuffer which pass the scissor test
        {
-               if(destRect.x0 < mState.scissorX)
-               {
-                       int xDiff = mState.scissorX - destRect.x0;
-                       destScissoredRect.x0 = mState.scissorX;
-                       sourceScissoredRect.x0 += xDiff;
-               }
-
-               if(destRect.x1 > mState.scissorX + mState.scissorWidth)
-               {
-                       int xDiff = destRect.x1 - (mState.scissorX + mState.scissorWidth);
-                       destScissoredRect.x1 = mState.scissorX + mState.scissorWidth;
-                       sourceScissoredRect.x1 -= xDiff;
-               }
-
-               if(destRect.y0 < mState.scissorY)
-               {
-                       int yDiff = mState.scissorY - destRect.y0;
-                       destScissoredRect.y0 = mState.scissorY;
-                       sourceScissoredRect.y0 += yDiff;
-               }
-
-               if(destRect.y1 > mState.scissorY + mState.scissorHeight)
-               {
-                       int yDiff = destRect.y1 - (mState.scissorY + mState.scissorHeight);
-                       destScissoredRect.y1 = mState.scissorY + mState.scissorHeight;
-                       sourceScissoredRect.y1 -= yDiff;
-               }
-       }
-
-       sw::Rect sourceTrimmedRect = sourceScissoredRect;
-       sw::Rect destTrimmedRect = destScissoredRect;
-
-       // The source & destination rectangles also may need to be trimmed if they fall out of the bounds of
-       // the actual draw and read surfaces.
-       if(sourceTrimmedRect.x0 < 0)
-       {
-               int xDiff = 0 - sourceTrimmedRect.x0;
-               sourceTrimmedRect.x0 = 0;
-               destTrimmedRect.x0 += xDiff;
+               sw::Rect scissorRect(mState.scissorX, mState.scissorY, mState.scissorX + mState.scissorWidth, mState.scissorY + mState.scissorHeight);
+               Device::ClipDstRect(sourceScissoredRect, destScissoredRect, scissorRect, flipX, flipY);
        }
 
-       if(sourceTrimmedRect.x1 > readBufferWidth)
-       {
-               int xDiff = sourceTrimmedRect.x1 - readBufferWidth;
-               sourceTrimmedRect.x1 = readBufferWidth;
-               destTrimmedRect.x1 -= xDiff;
-       }
+       sw::SliceRectF sourceTrimmedRect = sourceScissoredRect;
+       sw::SliceRect destTrimmedRect = destScissoredRect;
 
-       if(sourceTrimmedRect.y0 < 0)
-       {
-               int yDiff = 0 - sourceTrimmedRect.y0;
-               sourceTrimmedRect.y0 = 0;
-               destTrimmedRect.y0 += yDiff;
-       }
+       // The source & destination rectangles also may need to be trimmed if
+       // they fall out of the bounds of the actual draw and read surfaces.
+       sw::Rect sourceTrimRect(0, 0, readBufferWidth, readBufferHeight);
+       Device::ClipSrcRect(sourceTrimmedRect, destTrimmedRect, sourceTrimRect, flipX, flipY);
 
-       if(sourceTrimmedRect.y1 > readBufferHeight)
-       {
-               int yDiff = sourceTrimmedRect.y1 - readBufferHeight;
-               sourceTrimmedRect.y1 = readBufferHeight;
-               destTrimmedRect.y1 -= yDiff;
-       }
-
-       if(destTrimmedRect.x0 < 0)
-       {
-               int xDiff = 0 - destTrimmedRect.x0;
-               destTrimmedRect.x0 = 0;
-               sourceTrimmedRect.x0 += xDiff;
-       }
-
-       if(destTrimmedRect.x1 > drawBufferWidth)
-       {
-               int xDiff = destTrimmedRect.x1 - drawBufferWidth;
-               destTrimmedRect.x1 = drawBufferWidth;
-               sourceTrimmedRect.x1 -= xDiff;
-       }
-
-       if(destTrimmedRect.y0 < 0)
-       {
-               int yDiff = 0 - destTrimmedRect.y0;
-               destTrimmedRect.y0 = 0;
-               sourceTrimmedRect.y0 += yDiff;
-       }
-
-       if(destTrimmedRect.y1 > drawBufferHeight)
-       {
-               int yDiff = destTrimmedRect.y1 - drawBufferHeight;
-               destTrimmedRect.y1 = drawBufferHeight;
-               sourceTrimmedRect.y1 -= yDiff;
-       }
+       sw::Rect destTrimRect(0, 0, drawBufferWidth, drawBufferHeight);
+       Device::ClipDstRect(sourceTrimmedRect, destTrimmedRect, destTrimRect, flipX, flipY);
 
        bool partialBufferCopy = false;
 
@@ -4054,10 +4096,10 @@ void Context::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1
 
        if(mask & GL_COLOR_BUFFER_BIT)
        {
-               GLenum readColorbufferType = readFramebuffer->getColorbufferType(getReadFramebufferColorIndex());
+               GLenum readColorbufferType = readFramebuffer->getReadBufferType();
                GLenum drawColorbufferType = drawFramebuffer->getColorbufferType(0);
-               const bool validReadType = readColorbufferType == GL_TEXTURE_2D || Framebuffer::IsRenderbuffer(readColorbufferType);
-               const bool validDrawType = drawColorbufferType == GL_TEXTURE_2D || Framebuffer::IsRenderbuffer(drawColorbufferType);
+               const bool validReadType = readColorbufferType == GL_TEXTURE_2D || readColorbufferType == GL_TEXTURE_RECTANGLE_ARB || Framebuffer::IsRenderbuffer(readColorbufferType);
+               const bool validDrawType = drawColorbufferType == GL_TEXTURE_2D || drawColorbufferType == GL_TEXTURE_RECTANGLE_ARB || Framebuffer::IsRenderbuffer(drawColorbufferType);
                if(!validReadType || !validDrawType)
                {
                        return error(GL_INVALID_OPERATION);
@@ -4068,6 +4110,56 @@ void Context::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1
                        return error(GL_INVALID_OPERATION);
                }
 
+               // The GL ES 3.0.2 spec (pg 193) states that:
+               // 1) If the read buffer is fixed point format, the draw buffer must be as well
+               // 2) If the read buffer is an unsigned integer format, the draw buffer must be
+               // as well
+               // 3) If the read buffer is a signed integer format, the draw buffer must be as
+               // well
+               es2::Renderbuffer *readRenderbuffer = readFramebuffer->getReadColorbuffer();
+               es2::Renderbuffer *drawRenderbuffer = drawFramebuffer->getColorbuffer(0);
+               GLint readFormat = readRenderbuffer->getFormat();
+               GLint drawFormat = drawRenderbuffer->getFormat();
+               GLenum readComponentType = GetComponentType(readFormat, GL_COLOR_ATTACHMENT0);
+               GLenum drawComponentType = GetComponentType(drawFormat, GL_COLOR_ATTACHMENT0);
+               bool readFixedPoint = ((readComponentType == GL_UNSIGNED_NORMALIZED) ||
+                                      (readComponentType == GL_SIGNED_NORMALIZED));
+               bool drawFixedPoint = ((drawComponentType == GL_UNSIGNED_NORMALIZED) ||
+                                      (drawComponentType == GL_SIGNED_NORMALIZED));
+               bool readFixedOrFloat = (readFixedPoint || (readComponentType == GL_FLOAT));
+               bool drawFixedOrFloat = (drawFixedPoint || (drawComponentType == GL_FLOAT));
+
+               if(readFixedOrFloat != drawFixedOrFloat)
+               {
+                       return error(GL_INVALID_OPERATION);
+               }
+
+               if((readComponentType == GL_UNSIGNED_INT) && (drawComponentType != GL_UNSIGNED_INT))
+               {
+                       return error(GL_INVALID_OPERATION);
+               }
+
+               if((readComponentType == GL_INT) && (drawComponentType != GL_INT))
+               {
+                       return error(GL_INVALID_OPERATION);
+               }
+
+               // Cannot filter integer data
+               if(((readComponentType == GL_UNSIGNED_INT) || (readComponentType == GL_INT)) && filter)
+               {
+                       return error(GL_INVALID_OPERATION);
+               }
+
+               if((readRenderbuffer->getSamples() > 0) && (readFormat != drawFormat))
+               {
+                       // RGBA8 and BGRA8 should be interchangeable here
+                       if(!(((readFormat == GL_RGBA8) && (drawFormat == GL_BGRA8_EXT)) ||
+                                ((readFormat == GL_BGRA8_EXT) && (drawFormat == GL_RGBA8))))
+                       {
+                               return error(GL_INVALID_OPERATION);
+                       }
+               }
+
                blitRenderTarget = true;
        }
 
@@ -4091,6 +4183,11 @@ void Context::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1
                                blitDepth = true;
                                readDSBuffer = readFramebuffer->getDepthbuffer();
                                drawDSBuffer = drawFramebuffer->getDepthbuffer();
+
+                               if(readDSBuffer->getFormat() != drawDSBuffer->getFormat())
+                               {
+                                       return error(GL_INVALID_OPERATION);
+                               }
                        }
                }
 
@@ -4109,6 +4206,11 @@ void Context::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1
                                blitStencil = true;
                                readDSBuffer = readFramebuffer->getStencilbuffer();
                                drawDSBuffer = drawFramebuffer->getStencilbuffer();
+
+                               if(readDSBuffer->getFormat() != drawDSBuffer->getFormat())
+                               {
+                                       return error(GL_INVALID_OPERATION);
+                               }
                        }
                }
 
@@ -4120,7 +4222,7 @@ void Context::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1
 
                // OpenGL ES 3.0.4 spec, p.199:
                // ...an INVALID_OPERATION error is generated if the formats of the read
-               // and draw framebuffers are not identical or if the source and destination 
+               // and draw framebuffers are not identical or if the source and destination
                // rectangles are not defined with the same(X0, Y 0) and (X1, Y 1) bounds.
                // If SAMPLE_BUFFERS for the draw framebuffer is greater than zero, an
                // INVALID_OPERATION error is generated.
@@ -4134,21 +4236,21 @@ void Context::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1
 
        if(blitRenderTarget || blitDepth || blitStencil)
        {
+               if(flipX)
+               {
+                       swap(destTrimmedRect.x0, destTrimmedRect.x1);
+               }
+               if(flipY)
+               {
+                       swap(destTrimmedRect.y0, destTrimmedRect.y1);
+               }
+
                if(blitRenderTarget)
                {
                        egl::Image *readRenderTarget = readFramebuffer->getReadRenderTarget();
                        egl::Image *drawRenderTarget = drawFramebuffer->getRenderTarget(0);
 
-                       if(flipX)
-                       {
-                               swap(destRect.x0, destRect.x1);
-                       }
-                       if(flipy)
-                       {
-                               swap(destRect.y0, destRect.y1);
-                       }
-
-                       bool success = device->stretchRect(readRenderTarget, &sourceRect, drawRenderTarget, &destRect, (filter ? Device::USE_FILTER : 0) | Device::COLOR_BUFFER);
+                       bool success = device->stretchRect(readRenderTarget, &sourceTrimmedRect, drawRenderTarget, &destTrimmedRect, (filter ? Device::USE_FILTER : 0) | Device::COLOR_BUFFER);
 
                        readRenderTarget->release();
                        drawRenderTarget->release();
@@ -4165,7 +4267,7 @@ void Context::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1
                        egl::Image *readRenderTarget = readFramebuffer->getDepthBuffer();
                        egl::Image *drawRenderTarget = drawFramebuffer->getDepthBuffer();
 
-                       bool success = device->stretchRect(readRenderTarget, &sourceRect, drawRenderTarget, &destRect, (filter ? Device::USE_FILTER : 0) | Device::DEPTH_BUFFER);
+                       bool success = device->stretchRect(readRenderTarget, &sourceTrimmedRect, drawRenderTarget, &destTrimmedRect, (filter ? Device::USE_FILTER : 0) | Device::DEPTH_BUFFER);
 
                        readRenderTarget->release();
                        drawRenderTarget->release();
@@ -4182,7 +4284,7 @@ void Context::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1
                        egl::Image *readRenderTarget = readFramebuffer->getStencilBuffer();
                        egl::Image *drawRenderTarget = drawFramebuffer->getStencilBuffer();
 
-                       bool success = device->stretchRect(readRenderTarget, &sourceRect, drawRenderTarget, &destRect, (filter ? Device::USE_FILTER : 0) | Device::STENCIL_BUFFER);
+                       bool success = device->stretchRect(readRenderTarget, &sourceTrimmedRect, drawRenderTarget, &destTrimmedRect, (filter ? Device::USE_FILTER : 0) | Device::STENCIL_BUFFER);
 
                        readRenderTarget->release();
                        drawRenderTarget->release();
@@ -4196,9 +4298,10 @@ void Context::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1
        }
 }
 
-void Context::bindTexImage(egl::Surface *surface)
+void Context::bindTexImage(gl::Surface *surface)
 {
-       es2::Texture2D *textureObject = getTexture2D();
+       bool isRect = (surface->getTextureTarget() == EGL_TEXTURE_RECTANGLE_ANGLE);
+       es2::Texture2D *textureObject = isRect ? getTexture2DRect() : getTexture2D();
 
        if(textureObject)
        {
@@ -4253,7 +4356,7 @@ EGLenum Context::validateSharedImage(EGLenum target, GLuint name, GLuint texture
                        return EGL_BAD_PARAMETER;
                }
 
-               if(textureLevel == 0 && !(texture->isSamplerComplete() && texture->getLevelCount() == 1))
+               if(textureLevel == 0 && !(texture->isSamplerComplete() && texture->getTopLevel() == 0))
                {
                        return EGL_BAD_PARAMETER;
                }
@@ -4319,84 +4422,106 @@ Device *Context::getDevice()
        return device;
 }
 
-const GLubyte* Context::getExtensions(GLuint index, GLuint* numExt) const
+const GLubyte *Context::getExtensions(GLuint index, GLuint *numExt) const
 {
        // Keep list sorted in following order:
        // OES extensions
        // EXT extensions
        // Vendor extensions
-       static const GLubyte* extensions[] = {
-               (const GLubyte*)"GL_OES_compressed_ETC1_RGB8_texture",
-               (const GLubyte*)"GL_OES_depth24",
-               (const GLubyte*)"GL_OES_depth32",
-               (const GLubyte*)"GL_OES_depth_texture",
-               (const GLubyte*)"GL_OES_depth_texture_cube_map",
-               (const GLubyte*)"GL_OES_EGL_image",
-               (const GLubyte*)"GL_OES_EGL_image_external",
-               (const GLubyte*)"GL_OES_EGL_sync",
-               (const GLubyte*)"GL_OES_element_index_uint",
-               (const GLubyte*)"GL_OES_framebuffer_object",
-               (const GLubyte*)"GL_OES_packed_depth_stencil",
-               (const GLubyte*)"GL_OES_rgb8_rgba8",
-               (const GLubyte*)"GL_OES_standard_derivatives",
-               (const GLubyte*)"GL_OES_texture_float",
-               (const GLubyte*)"GL_OES_texture_float_linear",
-               (const GLubyte*)"GL_OES_texture_half_float",
-               (const GLubyte*)"GL_OES_texture_half_float_linear",
-               (const GLubyte*)"GL_OES_texture_npot",
-               (const GLubyte*)"GL_OES_texture_3D",
-               (const GLubyte*)"GL_EXT_blend_minmax",
-               (const GLubyte*)"GL_EXT_color_buffer_half_float",
-               (const GLubyte*)"GL_EXT_draw_buffers",
-               (const GLubyte*)"GL_EXT_occlusion_query_boolean",
-               (const GLubyte*)"GL_EXT_read_format_bgra",
-#if (S3TC_SUPPORT)
-               (const GLubyte*)"GL_EXT_texture_compression_dxt1",
-#endif
-               (const GLubyte*)"GL_EXT_texture_filter_anisotropic",
-               (const GLubyte*)"GL_EXT_texture_format_BGRA8888",
-               (const GLubyte*)"GL_ANGLE_framebuffer_blit",
-               (const GLubyte*)"GL_NV_framebuffer_blit",
-               (const GLubyte*)"GL_ANGLE_framebuffer_multisample",
-#if (S3TC_SUPPORT)
-               (const GLubyte*)"GL_ANGLE_texture_compression_dxt3",
-               (const GLubyte*)"GL_ANGLE_texture_compression_dxt5",
+       static const char *es2extensions[] =
+       {
+               "GL_OES_compressed_ETC1_RGB8_texture",
+               "GL_OES_depth24",
+               "GL_OES_depth32",
+               "GL_OES_depth_texture",
+               "GL_OES_depth_texture_cube_map",
+               "GL_OES_EGL_image",
+               "GL_OES_EGL_image_external",
+               "GL_OES_EGL_sync",
+               "GL_OES_element_index_uint",
+               "GL_OES_framebuffer_object",
+               "GL_OES_packed_depth_stencil",
+               "GL_OES_rgb8_rgba8",
+               "GL_OES_standard_derivatives",
+               "GL_OES_surfaceless_context",
+               "GL_OES_texture_float",
+               "GL_OES_texture_float_linear",
+               "GL_OES_texture_half_float",
+               "GL_OES_texture_half_float_linear",
+               "GL_OES_texture_npot",
+               "GL_OES_texture_3D",
+               "GL_OES_vertex_array_object",
+               "GL_OES_vertex_half_float",
+               "GL_EXT_blend_minmax",
+               "GL_EXT_color_buffer_half_float",
+               "GL_EXT_draw_buffers",
+               "GL_EXT_instanced_arrays",
+               "GL_EXT_occlusion_query_boolean",
+               "GL_EXT_read_format_bgra",
+               "GL_EXT_texture_compression_dxt1",
+               "GL_EXT_texture_filter_anisotropic",
+               "GL_EXT_texture_format_BGRA8888",
+               "GL_EXT_texture_rg",
+#if (ASTC_SUPPORT)
+               "GL_KHR_texture_compression_astc_hdr",
+               "GL_KHR_texture_compression_astc_ldr",
 #endif
-               (const GLubyte*)"GL_NV_fence",
-               (const GLubyte*)"GL_NV_read_depth",
-               (const GLubyte*)"GL_EXT_instanced_arrays",
-               (const GLubyte*)"GL_ANGLE_instanced_arrays",
+               "GL_ARB_texture_rectangle",
+               "GL_ANGLE_framebuffer_blit",
+               "GL_ANGLE_framebuffer_multisample",
+               "GL_ANGLE_instanced_arrays",
+               "GL_ANGLE_texture_compression_dxt3",
+               "GL_ANGLE_texture_compression_dxt5",
+               "GL_APPLE_texture_format_BGRA8888",
+               "GL_CHROMIUM_color_buffer_float_rgba", // A subset of EXT_color_buffer_float on top of OpenGL ES 2.0
+               "GL_CHROMIUM_texture_filtering_hint",
+               "GL_NV_fence",
+               "GL_NV_framebuffer_blit",
+               "GL_NV_read_depth",
        };
-       static const GLuint numExtensions = sizeof(extensions) / sizeof(*extensions);
+
+       // Extensions exclusive to OpenGL ES 3.0 and above.
+       static const char *es3extensions[] =
+       {
+               "GL_EXT_color_buffer_float",
+       };
+
+       GLuint numES2extensions = sizeof(es2extensions) / sizeof(es2extensions[0]);
+       GLuint numExtensions = numES2extensions;
+
+       if(clientVersion >= 3)
+       {
+               numExtensions += sizeof(es3extensions) / sizeof(es3extensions[0]);
+       }
 
        if(numExt)
        {
                *numExt = numExtensions;
+
                return nullptr;
        }
 
        if(index == GL_INVALID_INDEX)
        {
-               static GLubyte* extensionsCat = nullptr;
-               if(!extensionsCat && (numExtensions > 0))
+               static std::string extensionsCat;
+
+               if(extensionsCat.empty() && (numExtensions > 0))
                {
-                       size_t totalLength = numExtensions; // 1 space between each extension name + terminating null
-                       for(unsigned int i = 0; i < numExtensions; i++)
+                       for(const char *extension : es2extensions)
                        {
-                               totalLength += strlen(reinterpret_cast<const char*>(extensions[i]));
+                               extensionsCat += std::string(extension) + " ";
                        }
-                       extensionsCat = new GLubyte[totalLength];
-                       extensionsCat[0] = '\0';
-                       for(unsigned int i = 0; i < numExtensions; i++)
+
+                       if(clientVersion >= 3)
                        {
-                               if(i != 0)
+                               for(const char *extension : es3extensions)
                                {
-                                       strcat(reinterpret_cast<char*>(extensionsCat), " ");
+                                       extensionsCat += std::string(extension) + " ";
                                }
-                               strcat(reinterpret_cast<char*>(extensionsCat), reinterpret_cast<const char*>(extensions[i]));
                        }
                }
-               return extensionsCat;
+
+               return (const GLubyte*)extensionsCat.c_str();
        }
 
        if(index >= numExtensions)
@@ -4404,13 +4529,20 @@ const GLubyte* Context::getExtensions(GLuint index, GLuint* numExt) const
                return nullptr;
        }
 
-       return extensions[index];
+       if(index < numES2extensions)
+       {
+               return (const GLubyte*)es2extensions[index];
+       }
+       else
+       {
+               return (const GLubyte*)es3extensions[index - numES2extensions];
+       }
 }
 
 }
 
-egl::Context *es2CreateContext(egl::Display *display, const egl::Context *shareContext, int clientVersion)
+NO_SANITIZE_FUNCTION egl::Context *es2CreateContext(egl::Display *display, const egl::Context *shareContext, int clientVersion, const egl::Config *config)
 {
        ASSERT(!shareContext || shareContext->getClientVersion() == clientVersion);   // Should be checked by eglCreateContext
-       return new es2::Context(display, static_cast<const es2::Context*>(shareContext), clientVersion);
+       return new es2::Context(display, static_cast<const es2::Context*>(shareContext), clientVersion, config);
 }