Texture Rectangle implementation

This adds support for GL_ARB_texture_rectangle, as it is used in Chromium.
This is required in order to use EGL/GLES on MacOS using IOSurface,
in order to be able to run Chromium on top of SwiftShader on MacOS.

Change-Id: I3c0b6a137892583bbfbc68149874d5bec3026b4a
Reviewed-on: https://swiftshader-review.googlesource.com/16368
Tested-by: Alexis Hétu <sugoi@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/src/OpenGL/libGLESv2/Context.cpp b/src/OpenGL/libGLESv2/Context.cpp
index 82d9bcf..5759467 100644
--- a/src/OpenGL/libGLESv2/Context.cpp
+++ b/src/OpenGL/libGLESv2/Context.cpp
@@ -142,6 +142,7 @@
 	mTexture3DZero = new Texture3D(0);
 	mTexture2DArrayZero = new Texture2DArray(0);
 	mTextureCubeMapZero = new TextureCubeMap(0);
+	mTexture2DRectZero = new Texture2DRect(0);
 	mTextureExternalZero = new TextureExternal(0);
 
 	mState.activeSampler = 0;
@@ -262,6 +263,7 @@
 	mTexture3DZero = nullptr;
 	mTexture2DArrayZero = nullptr;
 	mTextureCubeMapZero = nullptr;
+	mTexture2DRectZero = nullptr;
 	mTextureExternalZero = nullptr;
 
 	delete mVertexDataManager;
@@ -1209,6 +1211,13 @@
 	mState.samplerTexture[TEXTURE_2D_ARRAY][mState.activeSampler] = getTexture(texture);
 }
 
+void Context::bindTexture2DRect(GLuint texture)
+{
+	mResourceManager->checkTextureAllocation(texture, TEXTURE_2D_RECT);
+
+	mState.samplerTexture[TEXTURE_2D_RECT][mState.activeSampler] = getTexture(texture);
+}
+
 void Context::bindReadFramebuffer(GLuint framebuffer)
 {
 	if(!getFramebuffer(framebuffer))
@@ -1681,6 +1690,19 @@
 	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));
@@ -1696,6 +1718,11 @@
 	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));
@@ -1713,6 +1740,7 @@
 		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);
 		}
@@ -2113,6 +2141,15 @@
 
 		*params = mState.samplerTexture[TEXTURE_CUBE][mState.activeSampler].name();
 		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_2D_RECT][mState.activeSampler].name();
+		return true;
 	case GL_TEXTURE_BINDING_EXTERNAL_OES:
 		if(mState.activeSampler > MAX_COMBINED_TEXTURE_IMAGE_UNITS - 1)
 		{
@@ -2541,6 +2578,7 @@
 	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:
@@ -3186,7 +3224,11 @@
 		int baseLevel = baseTexture->getBaseLevel();
 		int maxLevel = std::min(baseTexture->getTopLevel(), baseTexture->getMaxLevel());
 
-		if(baseTexture->getTarget() == GL_TEXTURE_2D || baseTexture->getTarget() == GL_TEXTURE_EXTERNAL_OES)
+		switch(baseTexture->getTarget())
+		{
+		case GL_TEXTURE_2D:
+		case GL_TEXTURE_EXTERNAL_OES:
+		case GL_TEXTURE_RECTANGLE_ARB:
 		{
 			Texture2D *texture = static_cast<Texture2D*>(baseTexture);
 
@@ -3203,7 +3245,8 @@
 				device->setTextureLevel(sampler, 0, mipmapLevel, surface, sw::TEXTURE_2D);
 			}
 		}
-		else if(baseTexture->getTarget() == GL_TEXTURE_3D)
+		break;
+		case GL_TEXTURE_3D:
 		{
 			Texture3D *texture = static_cast<Texture3D*>(baseTexture);
 
@@ -3220,7 +3263,8 @@
 				device->setTextureLevel(sampler, 0, mipmapLevel, surface, sw::TEXTURE_3D);
 			}
 		}
-		else if(baseTexture->getTarget() == GL_TEXTURE_2D_ARRAY)
+		break;
+		case GL_TEXTURE_2D_ARRAY:
 		{
 			Texture2DArray *texture = static_cast<Texture2DArray*>(baseTexture);
 
@@ -3237,7 +3281,8 @@
 				device->setTextureLevel(sampler, 0, mipmapLevel, surface, sw::TEXTURE_2D_ARRAY);
 			}
 		}
-		else if(baseTexture->getTarget() == GL_TEXTURE_CUBE_MAP)
+		break;
+		case GL_TEXTURE_CUBE_MAP:
 		{
 			TextureCubeMap *cubeTexture = static_cast<TextureCubeMap*>(baseTexture);
 
@@ -3259,7 +3304,11 @@
 				}
 			}
 		}
-		else UNIMPLEMENTED();
+		break;
+		default:
+			UNIMPLEMENTED();
+			break;
+		}
 	}
 	else
 	{
@@ -4397,6 +4446,7 @@
 		"GL_KHR_texture_compression_astc_hdr",
 		"GL_KHR_texture_compression_astc_ldr",
 #endif
+		"GL_ARB_texture_rectangle",
 		"GL_ANGLE_framebuffer_blit",
 		"GL_ANGLE_framebuffer_multisample",
 		"GL_ANGLE_instanced_arrays",
diff --git a/src/OpenGL/libGLESv2/Context.h b/src/OpenGL/libGLESv2/Context.h
index e2b517d..c42a12a 100644
--- a/src/OpenGL/libGLESv2/Context.h
+++ b/src/OpenGL/libGLESv2/Context.h
@@ -53,6 +53,7 @@
 class Texture3D;
 class Texture2DArray;
 class TextureCubeMap;
+class Texture2DRect;
 class TextureExternal;
 class Framebuffer;
 class Renderbuffer;
@@ -598,6 +599,7 @@
 	void bindTextureExternal(GLuint texture);
 	void bindTexture3D(GLuint texture);
 	void bindTexture2DArray(GLuint texture);
+	void bindTexture2DRect(GLuint texture);
 	void bindReadFramebuffer(GLuint framebuffer);
 	void bindDrawFramebuffer(GLuint framebuffer);
 	void bindRenderbuffer(GLuint renderbuffer);
@@ -651,9 +653,11 @@
 	bool getBuffer(GLenum target, es2::Buffer **buffer) const;
 	Program *getCurrentProgram() const;
 	Texture2D *getTexture2D() const;
+	Texture2D *getTexture2D(GLenum target) const;
 	Texture3D *getTexture3D() const;
 	Texture2DArray *getTexture2DArray() const;
 	TextureCubeMap *getTextureCubeMap() const;
+	Texture2DRect *getTexture2DRect() const;
 	TextureExternal *getTextureExternal() const;
 	Texture *getSamplerTexture(unsigned int sampler, TextureType type) const;
 	Framebuffer *getReadFramebuffer() const;
@@ -743,6 +747,7 @@
 	gl::BindingPointer<Texture3D> mTexture3DZero;
 	gl::BindingPointer<Texture2DArray> mTexture2DArrayZero;
 	gl::BindingPointer<TextureCubeMap> mTextureCubeMapZero;
+	gl::BindingPointer<Texture2DRect> mTexture2DRectZero;
 	gl::BindingPointer<TextureExternal> mTextureExternalZero;
 
 	gl::NameSpace<Framebuffer> mFramebufferNameSpace;
diff --git a/src/OpenGL/libGLESv2/Program.cpp b/src/OpenGL/libGLESv2/Program.cpp
index b93bd2a..d2cff33 100644
--- a/src/OpenGL/libGLESv2/Program.cpp
+++ b/src/OpenGL/libGLESv2/Program.cpp
@@ -1153,6 +1153,7 @@
 				case GL_FLOAT_MAT4:   applyUniformMatrix4fv(device, location, size, f);   break;
 				case GL_SAMPLER_2D:
 				case GL_SAMPLER_CUBE:
+				case GL_SAMPLER_2D_RECT_ARB:
 				case GL_SAMPLER_EXTERNAL_OES:
 				case GL_SAMPLER_3D_OES:
 				case GL_SAMPLER_2D_ARRAY:
@@ -1761,6 +1762,7 @@
 						case GL_INT_SAMPLER_3D:
 						case GL_UNSIGNED_INT_SAMPLER_3D:
 						case GL_SAMPLER_3D_OES:       samplersVS[index].textureType = TEXTURE_3D;       break;
+						case GL_SAMPLER_2D_RECT_ARB:  samplersVS[index].textureType = TEXTURE_2D_RECT;  break;
 						case GL_SAMPLER_EXTERNAL_OES: samplersVS[index].textureType = TEXTURE_EXTERNAL; break;
 						case GL_INT_SAMPLER_2D_ARRAY:
 						case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
@@ -1796,6 +1798,7 @@
 						case GL_INT_SAMPLER_3D:
 						case GL_UNSIGNED_INT_SAMPLER_3D:
 						case GL_SAMPLER_3D_OES:       samplersPS[index].textureType = TEXTURE_3D;       break;
+						case GL_SAMPLER_2D_RECT_ARB:  samplersPS[index].textureType = TEXTURE_2D_RECT;  break;
 						case GL_SAMPLER_EXTERNAL_OES: samplersPS[index].textureType = TEXTURE_EXTERNAL; break;
 						case GL_INT_SAMPLER_2D_ARRAY:
 						case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
diff --git a/src/OpenGL/libGLESv2/ResourceManager.cpp b/src/OpenGL/libGLESv2/ResourceManager.cpp
index 04e1f0d..51a7bc1 100644
--- a/src/OpenGL/libGLESv2/ResourceManager.cpp
+++ b/src/OpenGL/libGLESv2/ResourceManager.cpp
@@ -308,6 +308,10 @@
 		{
 			textureObject = new Texture2DArray(texture);
 		}
+		else if(type == TEXTURE_2D_RECT)
+		{
+			textureObject = new Texture2DRect(texture);
+		}
 		else
 		{
 			UNREACHABLE(type);
diff --git a/src/OpenGL/libGLESv2/ResourceManager.h b/src/OpenGL/libGLESv2/ResourceManager.h
index efd0e20..c076653 100644
--- a/src/OpenGL/libGLESv2/ResourceManager.h
+++ b/src/OpenGL/libGLESv2/ResourceManager.h
@@ -40,6 +40,7 @@
 	TEXTURE_3D,
 	TEXTURE_2D_ARRAY,
 	TEXTURE_CUBE,
+	TEXTURE_2D_RECT,
 	TEXTURE_EXTERNAL,
 
 	TEXTURE_TYPE_COUNT,
diff --git a/src/OpenGL/libGLESv2/Shader.cpp b/src/OpenGL/libGLESv2/Shader.cpp
index fe1b830..9cb6bd5 100644
--- a/src/OpenGL/libGLESv2/Shader.cpp
+++ b/src/OpenGL/libGLESv2/Shader.cpp
@@ -181,6 +181,7 @@
 	resources.OES_fragment_precision_high = 1;
 	resources.OES_EGL_image_external = 1;
 	resources.EXT_draw_buffers = 1;
+	resources.ARB_texture_rectangle = 1;
 	resources.MaxCallStackDepth = 64;
 	assembler->Init(resources);
 
diff --git a/src/OpenGL/libGLESv2/Texture.cpp b/src/OpenGL/libGLESv2/Texture.cpp
index c2665e7..9b3a5f0 100644
--- a/src/OpenGL/libGLESv2/Texture.cpp
+++ b/src/OpenGL/libGLESv2/Texture.cpp
@@ -22,6 +22,7 @@
 #include "mathutil.h"
 #include "Framebuffer.h"
 #include "Device.hpp"
+#include "Shader.h"
 #include "libEGL/Display.h"
 #include "common/Surface.hpp"
 #include "common/debug.h"
@@ -577,25 +578,25 @@
 
 GLsizei Texture2D::getWidth(GLenum target, GLint level) const
 {
-	ASSERT(target == GL_TEXTURE_2D);
+	ASSERT(target == getTarget());
 	return image[level] ? image[level]->getWidth() : 0;
 }
 
 GLsizei Texture2D::getHeight(GLenum target, GLint level) const
 {
-	ASSERT(target == GL_TEXTURE_2D);
+	ASSERT(target == getTarget());
 	return image[level] ? image[level]->getHeight() : 0;
 }
 
 GLenum Texture2D::getFormat(GLenum target, GLint level) const
 {
-	ASSERT(target == GL_TEXTURE_2D);
+	ASSERT(target == getTarget());
 	return image[level] ? image[level]->getFormat() : GL_NONE;
 }
 
 GLenum Texture2D::getType(GLenum target, GLint level) const
 {
-	ASSERT(target == GL_TEXTURE_2D);
+	ASSERT(target == getTarget());
 	return image[level] ? image[level]->getType() : GL_NONE;
 }
 
@@ -913,7 +914,7 @@
 
 Renderbuffer *Texture2D::getRenderbuffer(GLenum target, GLint level)
 {
-	if(target != GL_TEXTURE_2D)
+	if(target != getTarget())
 	{
 		return error(GL_INVALID_OPERATION, (Renderbuffer*)nullptr);
 	}
@@ -932,7 +933,7 @@
 
 egl::Image *Texture2D::getRenderTarget(GLenum target, unsigned int level)
 {
-	ASSERT(target == GL_TEXTURE_2D);
+	ASSERT(target == getTarget());
 	ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
 
 	if(image[level])
@@ -945,7 +946,7 @@
 
 bool Texture2D::isShared(GLenum target, unsigned int level) const
 {
-	ASSERT(target == GL_TEXTURE_2D);
+	ASSERT(target == getTarget());
 	ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
 
 	if(mSurface)   // Bound to an EGLSurface
@@ -961,6 +962,15 @@
 	return image[level]->isShared();
 }
 
+Texture2DRect::Texture2DRect(GLuint name) : Texture2D(name)
+{
+}
+
+GLenum Texture2DRect::getTarget() const
+{
+	return GL_TEXTURE_RECTANGLE_ARB;
+}
+
 TextureCubeMap::TextureCubeMap(GLuint name) : Texture(name)
 {
 	for(int f = 0; f < 6; f++)
diff --git a/src/OpenGL/libGLESv2/Texture.h b/src/OpenGL/libGLESv2/Texture.h
index 53b4bfb..026c75a 100644
--- a/src/OpenGL/libGLESv2/Texture.h
+++ b/src/OpenGL/libGLESv2/Texture.h
@@ -203,6 +203,14 @@
 	unsigned int mProxyRefs;
 };
 
+class Texture2DRect : public Texture2D
+{
+public:
+	explicit Texture2DRect(GLuint name);
+
+	GLenum getTarget() const override;
+};
+
 class TextureCubeMap : public Texture
 {
 public:
diff --git a/src/OpenGL/libGLESv2/libGLESv2.cpp b/src/OpenGL/libGLESv2/libGLESv2.cpp
index 6db0a79..aa743e7 100644
--- a/src/OpenGL/libGLESv2/libGLESv2.cpp
+++ b/src/OpenGL/libGLESv2/libGLESv2.cpp
@@ -389,6 +389,9 @@
 		case GL_TEXTURE_3D:
 			context->bindTexture3D(texture);
 			break;
+		case GL_TEXTURE_RECTANGLE_ARB:
+			context->bindTexture2DRect(texture);
+			break;
 		default:
 			return error(GL_INVALID_ENUM);
 		}
@@ -836,6 +839,7 @@
 		switch(target)
 		{
 		case GL_TEXTURE_2D:
+		case GL_TEXTURE_RECTANGLE_ARB:
 			if(width > (es2::IMPLEMENTATION_MAX_TEXTURE_SIZE >> level) ||
 			   height > (es2::IMPLEMENTATION_MAX_TEXTURE_SIZE >> level))
 			{
@@ -868,9 +872,9 @@
 			return error(GL_INVALID_VALUE);
 		}
 
-		if(target == GL_TEXTURE_2D)
+		if(target == GL_TEXTURE_2D || target == GL_TEXTURE_RECTANGLE_ARB)
 		{
-			es2::Texture2D *texture = context->getTexture2D();
+			es2::Texture2D *texture = context->getTexture2D(target);
 
 			if(!texture)
 			{
@@ -958,9 +962,9 @@
 
 		GLenum sizedInternalFormat = GetSizedInternalFormat(format, GL_NONE);
 
-		if(target == GL_TEXTURE_2D)
+		if(target == GL_TEXTURE_2D || target == GL_TEXTURE_RECTANGLE_ARB)
 		{
-			es2::Texture2D *texture = context->getTexture2D();
+			es2::Texture2D *texture = context->getTexture2D(target);
 
 			GLenum validationError = ValidateSubImageParams(true, false, target, level, xoffset, yoffset, width, height, format, GL_NONE, texture, context->getClientVersion());
 			if(validationError != GL_NONE)
@@ -1021,6 +1025,7 @@
 		switch(target)
 		{
 		case GL_TEXTURE_2D:
+		case GL_TEXTURE_RECTANGLE_ARB:
 			if(width > (es2::IMPLEMENTATION_MAX_TEXTURE_SIZE >> level) ||
 			   height > (es2::IMPLEMENTATION_MAX_TEXTURE_SIZE >> level))
 			{
@@ -1069,9 +1074,9 @@
 			return;
 		}
 
-		if(target == GL_TEXTURE_2D)
+		if(target == GL_TEXTURE_2D || target == GL_TEXTURE_RECTANGLE_ARB)
 		{
-			es2::Texture2D *texture = context->getTexture2D();
+			es2::Texture2D *texture = context->getTexture2D(target);
 
 			if(!texture)
 			{
@@ -1141,9 +1146,9 @@
 
 		es2::Texture *texture = nullptr;
 
-		if(target == GL_TEXTURE_2D)
+		if(target == GL_TEXTURE_2D || target == GL_TEXTURE_RECTANGLE_ARB)
 		{
-			texture = context->getTexture2D();
+			texture = context->getTexture2D(target);
 		}
 		else if(es2::IsCubemapTextureTarget(target))
 		{
@@ -2097,6 +2102,12 @@
 					return error(GL_INVALID_OPERATION);
 				}
 				break;
+			case GL_TEXTURE_RECTANGLE_ARB:
+				if(tex->getTarget() != GL_TEXTURE_RECTANGLE_ARB)
+				{
+					return error(GL_INVALID_OPERATION);
+				}
+				break;
 			case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
 			case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
 			case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
@@ -2285,6 +2296,9 @@
 		case GL_TEXTURE_3D:
 			texture = context->getTexture3D();
 			break;
+		case GL_TEXTURE_RECTANGLE_ARB:
+			texture = context->getTexture2DRect();
+			break;
 		default:
 			return error(GL_INVALID_ENUM);
 		}
@@ -3588,6 +3602,9 @@
 		case GL_TEXTURE_3D:
 			texture = context->getTexture3D();
 			break;
+		case GL_TEXTURE_RECTANGLE_ARB:
+			texture = context->getTexture2DRect();
+			break;
 		default:
 			return error(GL_INVALID_ENUM);
 		}
@@ -3741,6 +3758,9 @@
 		case GL_TEXTURE_3D:
 			texture = context->getTexture3D();
 			break;
+		case GL_TEXTURE_RECTANGLE_ARB:
+			texture = context->getTexture2DRect();
+			break;
 		default:
 			return error(GL_INVALID_ENUM);
 		}
@@ -5042,6 +5062,7 @@
 		switch(target)
 		{
 		case GL_TEXTURE_2D:
+		case GL_TEXTURE_RECTANGLE_ARB:
 			if(width > (es2::IMPLEMENTATION_MAX_TEXTURE_SIZE >> level) ||
 			   height > (es2::IMPLEMENTATION_MAX_TEXTURE_SIZE >> level))
 			{
@@ -5077,9 +5098,9 @@
 			return error(validationError);
 		}
 
-		if(target == GL_TEXTURE_2D)
+		if(target == GL_TEXTURE_2D || target == GL_TEXTURE_RECTANGLE_ARB)
 		{
-			es2::Texture2D *texture = context->getTexture2D();
+			es2::Texture2D *texture = context->getTexture2D(target);
 
 			if(!texture)
 			{
@@ -5138,6 +5159,9 @@
 		case GL_TEXTURE_EXTERNAL_OES:
 			texture = context->getTextureExternal();
 			break;
+		case GL_TEXTURE_RECTANGLE_ARB:
+			texture = context->getTexture2DRect();
+			break;
 		default:
 			return error(GL_INVALID_ENUM);
 		}
@@ -5287,6 +5311,9 @@
 		case GL_TEXTURE_EXTERNAL_OES:
 			texture = context->getTextureExternal();
 			break;
+		case GL_TEXTURE_RECTANGLE_ARB:
+			texture = context->getTexture2DRect();
+			break;
 		default:
 			return error(GL_INVALID_ENUM);
 		}
@@ -5432,9 +5459,9 @@
 
 	if(context)
 	{
-		if(target == GL_TEXTURE_2D)
+		if(target == GL_TEXTURE_2D || target == GL_TEXTURE_RECTANGLE_ARB)
 		{
-			es2::Texture2D *texture = context->getTexture2D();
+			es2::Texture2D *texture = context->getTexture2D(target);
 
 			GLenum validationError = ValidateSubImageParams(false, false, target, level, xoffset, yoffset, width, height, format, type, texture, context->getClientVersion());
 			if(validationError != GL_NONE)
@@ -6676,6 +6703,7 @@
 	switch(target)
 	{
 	case GL_TEXTURE_2D:
+	case GL_TEXTURE_RECTANGLE_ARB:
 	case GL_TEXTURE_EXTERNAL_OES:
 		break;
 	default:
@@ -6686,14 +6714,7 @@
 
 	if(context)
 	{
-		es2::Texture2D *texture = nullptr;
-
-		switch(target)
-		{
-		case GL_TEXTURE_2D:           texture = context->getTexture2D();       break;
-		case GL_TEXTURE_EXTERNAL_OES: texture = context->getTextureExternal(); break;
-		default:                      UNREACHABLE(target);
-		}
+		es2::Texture2D *texture = context->getTexture2D(target);
 
 		if(!texture)
 		{
diff --git a/src/OpenGL/libGLESv2/libGLESv3.cpp b/src/OpenGL/libGLESv2/libGLESv3.cpp
index 056ef53..0a880ad 100644
--- a/src/OpenGL/libGLESv2/libGLESv3.cpp
+++ b/src/OpenGL/libGLESv2/libGLESv3.cpp
@@ -3937,41 +3937,42 @@
 		switch(target)
 		{
 		case GL_TEXTURE_2D:
+		case GL_TEXTURE_RECTANGLE_ARB:
+		{
+			es2::Texture2D *texture = context->getTexture2D(target);
+			if(!texture || texture->name == 0 || texture->getImmutableFormat() == GL_TRUE)
 			{
-				es2::Texture2D *texture = context->getTexture2D();
-				if(!texture || texture->name == 0 || texture->getImmutableFormat() == GL_TRUE)
-				{
-					return error(GL_INVALID_OPERATION);
-				}
+				return error(GL_INVALID_OPERATION);
+			}
 
 				for(int level = 0; level < levels; level++)
-				{
+			{
 					texture->setImage(context, level, width, height, sizedInternalFormat, sizedInternalFormat, type, context->getUnpackInfo(), nullptr);
-					width = std::max(1, (width / 2));
-					height = std::max(1, (height / 2));
-				}
-				texture->makeImmutable(levels);
+				width = std::max(1, (width / 2));
+				height = std::max(1, (height / 2));
 			}
+			texture->makeImmutable(levels);
+		}
 			break;
 		case GL_TEXTURE_CUBE_MAP:
+		{
+			es2::TextureCubeMap *texture = context->getTextureCubeMap();
+			if(!texture || texture->name == 0 || texture->getImmutableFormat())
 			{
-				es2::TextureCubeMap *texture = context->getTextureCubeMap();
-				if(!texture || texture->name == 0 || texture->getImmutableFormat())
-				{
-					return error(GL_INVALID_OPERATION);
-				}
+				return error(GL_INVALID_OPERATION);
+			}
 
 				for(int level = 0; level < levels; level++)
-				{
+			{
 					for(int face = GL_TEXTURE_CUBE_MAP_POSITIVE_X; face <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z; face++)
-					{
+				{
 						texture->setImage(context, face, level, width, height, sizedInternalFormat, sizedInternalFormat, type, context->getUnpackInfo(), nullptr);
-					}
-					width = std::max(1, (width / 2));
-					height = std::max(1, (height / 2));
 				}
-				texture->makeImmutable(levels);
+				width = std::max(1, (width / 2));
+				height = std::max(1, (height / 2));
 			}
+			texture->makeImmutable(levels);
+		}
 			break;
 		default:
 			return error(GL_INVALID_ENUM);
@@ -4003,52 +4004,52 @@
 		switch(target)
 		{
 		case GL_TEXTURE_3D:
+		{
+			if(levels > es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS || levels > (log2(std::max(std::max(width, height), depth)) + 1))
 			{
-				if(levels > es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS || levels > (log2(std::max(std::max(width, height), depth)) + 1))
-				{
-					return error(GL_INVALID_OPERATION);
-				}
+				return error(GL_INVALID_OPERATION);
+			}
 
-				es2::Texture3D *texture = context->getTexture3D();
-				if(!texture || texture->name == 0 || texture->getImmutableFormat() == GL_TRUE)
-				{
-					return error(GL_INVALID_OPERATION);
-				}
+			es2::Texture3D *texture = context->getTexture3D();
+			if(!texture || texture->name == 0 || texture->getImmutableFormat() == GL_TRUE)
+			{
+				return error(GL_INVALID_OPERATION);
+			}
 
 				for(int level = 0; level < levels; level++)
-				{
+			{
 					texture->setImage(context, level, width, height, depth, sizedInternalFormat, sizedInternalFormat, type, context->getUnpackInfo(), nullptr);
-					width = std::max(1, (width / 2));
-					height = std::max(1, (height / 2));
-					depth = std::max(1, (depth / 2));
-				}
-				texture->makeImmutable(levels);
+				width = std::max(1, (width / 2));
+				height = std::max(1, (height / 2));
+				depth = std::max(1, (depth / 2));
 			}
+			texture->makeImmutable(levels);
+		}
 			break;
 		case GL_TEXTURE_2D_ARRAY:
+		{
+			if(levels > es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS || levels > (log2(std::max(width, height)) + 1))
 			{
-				if(levels > es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS || levels > (log2(std::max(width, height)) + 1))
-				{
-					return error(GL_INVALID_OPERATION);
-				}
+				return error(GL_INVALID_OPERATION);
+			}
 
-				es2::Texture3D *texture = context->getTexture2DArray();
-				if(!texture || texture->name == 0 || texture->getImmutableFormat())
-				{
-					return error(GL_INVALID_OPERATION);
-				}
+			es2::Texture3D *texture = context->getTexture2DArray();
+			if(!texture || texture->name == 0 || texture->getImmutableFormat())
+			{
+				return error(GL_INVALID_OPERATION);
+			}
 
 				for(int level = 0; level < levels; level++)
-				{
+			{
 					for(int face = GL_TEXTURE_CUBE_MAP_POSITIVE_X; face <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z; face++)
-					{
+				{
 						texture->setImage(context, level, width, height, depth, sizedInternalFormat, sizedInternalFormat, type, context->getUnpackInfo(), nullptr);
-					}
-					width = std::max(1, (width / 2));
-					height = std::max(1, (height / 2));
 				}
-				texture->makeImmutable(levels);
+				width = std::max(1, (width / 2));
+				height = std::max(1, (height / 2));
 			}
+			texture->makeImmutable(levels);
+		}
 			break;
 		default:
 			return error(GL_INVALID_ENUM);
diff --git a/src/OpenGL/libGLESv2/utilities.cpp b/src/OpenGL/libGLESv2/utilities.cpp
index 2318057..96c83d4 100644
--- a/src/OpenGL/libGLESv2/utilities.cpp
+++ b/src/OpenGL/libGLESv2/utilities.cpp
@@ -20,6 +20,7 @@
 #include "main.h"
 #include "mathutil.h"
 #include "Context.h"
+#include "Shader.h"
 #include "common/debug.h"
 
 #include <limits>
@@ -183,6 +184,7 @@
 		case GL_UNSIGNED_INT:
 		case GL_SAMPLER_2D:
 		case GL_SAMPLER_CUBE:
+		case GL_SAMPLER_2D_RECT_ARB:
 		case GL_SAMPLER_EXTERNAL_OES:
 		case GL_SAMPLER_3D_OES:
 		case GL_SAMPLER_2D_ARRAY:
@@ -260,6 +262,7 @@
 		case GL_INT:
 		case GL_SAMPLER_2D:
 		case GL_SAMPLER_CUBE:
+		case GL_SAMPLER_2D_RECT_ARB:
 		case GL_SAMPLER_EXTERNAL_OES:
 		case GL_SAMPLER_3D_OES:
 		case GL_SAMPLER_2D_ARRAY:
@@ -309,6 +312,7 @@
 		{
 		case GL_SAMPLER_2D:
 		case GL_SAMPLER_CUBE:
+		case GL_SAMPLER_2D_RECT_ARB:
 		case GL_SAMPLER_EXTERNAL_OES:
 		case GL_SAMPLER_3D_OES:
 		case GL_SAMPLER_2D_ARRAY:
@@ -353,6 +357,7 @@
 		case GL_UNSIGNED_INT_VEC4:
 		case GL_SAMPLER_2D:
 		case GL_SAMPLER_CUBE:
+		case GL_SAMPLER_2D_RECT_ARB:
 		case GL_SAMPLER_EXTERNAL_OES:
 		case GL_SAMPLER_3D_OES:
 		case GL_SAMPLER_2D_ARRAY:
@@ -771,7 +776,7 @@
 
 	bool IsTextureTarget(GLenum target)
 	{
-		return target == GL_TEXTURE_2D || IsCubemapTextureTarget(target) || target == GL_TEXTURE_3D || target == GL_TEXTURE_2D_ARRAY;
+		return target == GL_TEXTURE_2D || IsCubemapTextureTarget(target) || target == GL_TEXTURE_3D || target == GL_TEXTURE_2D_ARRAY || target == GL_TEXTURE_RECTANGLE_ARB;
 	}
 
 	GLenum ValidateTextureFormatType(GLenum format, GLenum type, GLint internalformat, GLint clientVersion)