Added support for sampler2DRect in ESSL3

Being able to sample from sampler2DRect using the "texture" function is required for Chromium on Mac.

Change-Id: Iea8970aaec29734a251bcfc19a03223d0ebfbc7e
Reviewed-on: https://swiftshader-review.googlesource.com/17572
Reviewed-by: Alexis Hétu <sugoi@google.com>
Tested-by: Alexis Hétu <sugoi@google.com>
diff --git a/src/OpenGL/compiler/Initialize.cpp b/src/OpenGL/compiler/Initialize.cpp
index 57ba870..23bc792 100644
--- a/src/OpenGL/compiler/Initialize.cpp
+++ b/src/OpenGL/compiler/Initialize.cpp
@@ -250,6 +250,9 @@
 		symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DRect", sampler2DRect, float2);
 		symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DRectProj", sampler2DRect, float3);
 		symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DRectProj", sampler2DRect, float4);
+		symbolTable.insertBuiltIn(ESSL3_BUILTINS, float4, "texture", sampler2DRect, float2);
+		symbolTable.insertBuiltIn(ESSL3_BUILTINS, float4, "textureProj", sampler2DRect, float3);
+		symbolTable.insertBuiltIn(ESSL3_BUILTINS, float4, "textureProj", sampler2DRect, float4);
 	}
 
 	if(resources.OES_EGL_image_external)
diff --git a/src/OpenGL/compiler/OutputASM.cpp b/src/OpenGL/compiler/OutputASM.cpp
index fea45f9..b3385c2 100644
--- a/src/OpenGL/compiler/OutputASM.cpp
+++ b/src/OpenGL/compiler/OutputASM.cpp
@@ -421,11 +421,11 @@
 	{
 		TString name = TFunction::unmangleName(nodeName);
 
-		if(name == "texture2D" || name == "textureCube" || name == "texture" || name == "texture3D")
+		if(name == "texture2D" || name == "textureCube" || name == "texture" || name == "texture3D" || name == "texture2DRect")
 		{
 			method = IMPLICIT;
 		}
-		else if(name == "texture2DProj" || name == "textureProj")
+		else if(name == "texture2DProj" || name == "textureProj" || name == "texture2DRectProj")
 		{
 			method = IMPLICIT;
 			proj = true;
@@ -494,15 +494,6 @@
 			proj = true;
 			offset = true;
 		}
-		else if(name == "texture2DRect")
-		{
-			method = RECT;
-		}
-		else if(name == "texture2DRectProj")
-		{
-			method = RECT;
-			proj = true;
-		}
 		else UNREACHABLE(0);
 	}
 
@@ -1470,9 +1461,6 @@
 						}
 						else UNREACHABLE(argumentCount);
 						break;
-					case TextureFunction::RECT:
-						emit(sw::Shader::OPCODE_TEXRECT, result, &coord, s);
-						break;
 					case TextureFunction::SIZE:
 						emit(sw::Shader::OPCODE_TEXSIZE, result, arg[1], s);
 						break;
diff --git a/src/OpenGL/compiler/OutputASM.h b/src/OpenGL/compiler/OutputASM.h
index 2cffff3..3391035 100644
--- a/src/OpenGL/compiler/OutputASM.h
+++ b/src/OpenGL/compiler/OutputASM.h
@@ -246,7 +246,6 @@
 				SIZE,   // textureSize()
 				FETCH,
 				GRAD,
-				RECT,
 			};
 
 			Method method;
diff --git a/src/OpenGL/libGLESv2/Context.cpp b/src/OpenGL/libGLESv2/Context.cpp
index fa081c5..cc2dbc6 100644
--- a/src/OpenGL/libGLESv2/Context.cpp
+++ b/src/OpenGL/libGLESv2/Context.cpp
@@ -3170,8 +3170,9 @@
 	{
 		int baseLevel = baseTexture->getBaseLevel();
 		int maxLevel = std::min(baseTexture->getTopLevel(), baseTexture->getMaxLevel());
+		GLenum target = baseTexture->getTarget();
 
-		switch(baseTexture->getTarget())
+		switch(target)
 		{
 		case GL_TEXTURE_2D:
 		case GL_TEXTURE_EXTERNAL_OES:
@@ -3189,7 +3190,8 @@
 					}
 
 					egl::Image *surface = texture->getImage(surfaceLevel);
-					device->setTextureLevel(sampler, 0, mipmapLevel, surface, sw::TEXTURE_2D);
+					device->setTextureLevel(sampler, 0, mipmapLevel, surface,
+					                        (target == GL_TEXTURE_RECTANGLE_ARB) ? sw::TEXTURE_RECTANGLE : sw::TEXTURE_2D);
 				}
 			}
 			break;
diff --git a/src/Renderer/Sampler.hpp b/src/Renderer/Sampler.hpp
index 9918acf..c73721d 100644
--- a/src/Renderer/Sampler.hpp
+++ b/src/Renderer/Sampler.hpp
@@ -69,6 +69,7 @@
 	{
 		TEXTURE_NULL,
 		TEXTURE_2D,
+		TEXTURE_RECTANGLE,
 		TEXTURE_CUBE,
 		TEXTURE_3D,
 		TEXTURE_2D_ARRAY,
diff --git a/src/Shader/PixelProgram.cpp b/src/Shader/PixelProgram.cpp
index 59a6982..0f0f6bd 100644
--- a/src/Shader/PixelProgram.cpp
+++ b/src/Shader/PixelProgram.cpp
@@ -297,7 +297,6 @@
 			case Shader::OPCODE_TEXGRADOFFSET: TEXGRADOFFSET(d, s0, src1, s2, s3, s4);     break;
 			case Shader::OPCODE_TEXBIAS:    TEXBIAS(d, s0, src1, s2.x);                    break;
 			case Shader::OPCODE_TEXOFFSETBIAS: TEXOFFSETBIAS(d, s0, src1, s2, s3.x);       break;
-			case Shader::OPCODE_TEXRECT:    TEXRECT(d, s0, src1);                          break;
 			case Shader::OPCODE_DISCARD:    DISCARD(cMask, instruction);                   break;
 			case Shader::OPCODE_DFDX:       DFDX(d, s0);                                   break;
 			case Shader::OPCODE_DFDY:       DFDY(d, s0);                                   break;
@@ -1179,11 +1178,6 @@
 		dst = sampleTexture(src1, src0, lod, (src0), (src0), (src0), Lod);
 	}
 
-	void PixelProgram::TEXRECT(Vector4f &dst, Vector4f &src0, const Src &src1)
-	{
-		dst = sampleTexture(src1, src0, (src0.x), (src0), (src0), (src0), Rectangle);
-	}
-
 	void PixelProgram::TEXSIZE(Vector4f &dst, Float4 &lod, const Src &src1)
 	{
 		Pointer<Byte> texture = data + OFFSET(DrawData, mipmap) + src1.index * sizeof(Texture);
diff --git a/src/Shader/PixelProgram.hpp b/src/Shader/PixelProgram.hpp
index d7b7767..951e147 100644
--- a/src/Shader/PixelProgram.hpp
+++ b/src/Shader/PixelProgram.hpp
@@ -118,7 +118,6 @@
 		void TEXELFETCHOFFSET(Vector4f &dst, Vector4f &src, const Src &, Vector4f &offset, Float4 &lod);
 		void TEXGRAD(Vector4f &dst, Vector4f &src0, const Src &src1, Vector4f &dsx, Vector4f &dsy);
 		void TEXGRADOFFSET(Vector4f &dst, Vector4f &src, const Src &, Vector4f &dsx, Vector4f &dsy, Vector4f &offset);
-		void TEXRECT(Vector4f &dst, Vector4f &src0, const Src &src1);
 		void DISCARD(Int cMask[4], const Shader::Instruction *instruction);
 		void DFDX(Vector4f &dst, Vector4f &src);
 		void DFDY(Vector4f &dst, Vector4f &src);
diff --git a/src/Shader/PixelShader.cpp b/src/Shader/PixelShader.cpp
index 6813b3f..9e281d9 100644
--- a/src/Shader/PixelShader.cpp
+++ b/src/Shader/PixelShader.cpp
@@ -323,7 +323,6 @@
 						case Shader::OPCODE_TEXELFETCHOFFSET:
 						case Shader::OPCODE_TEXGRAD:
 						case Shader::OPCODE_TEXGRADOFFSET:
-						case Shader::OPCODE_TEXRECT:
 							{
 								int sampler = inst->src[1].index;
 
diff --git a/src/Shader/SamplerCore.cpp b/src/Shader/SamplerCore.cpp
index 90aa984..8fa378f 100644
--- a/src/Shader/SamplerCore.cpp
+++ b/src/Shader/SamplerCore.cpp
@@ -299,7 +299,7 @@
 			// FIXME: YUV is not supported by the floating point path
 			bool forceFloatFiltering = state.highPrecisionFiltering && !hasYuvFormat() && (state.textureFilter != FILTER_POINT);
 			bool seamlessCube = (state.addressingModeU == ADDRESSING_SEAMLESS);
-			bool rectangleTexture = (function == Rectangle);
+			bool rectangleTexture = (state.textureType == TEXTURE_RECTANGLE);
 			if(hasFloatTexture() || hasUnnormalizedIntegerTexture() || forceFloatFiltering || seamlessCube || rectangleTexture)   // FIXME: Mostly identical to integer sampling
 			{
 				Float4 uuuu = u;
@@ -2368,7 +2368,7 @@
 
 			Float4 coord = uvw;
 
-			if(function == Rectangle)
+			if(state.textureType == TEXTURE_RECTANGLE)
 			{
 				coord = Min(Max(coord, Float4(0.0f)), Float4(dim - Int4(1)));
 			}
diff --git a/src/Shader/SamplerCore.hpp b/src/Shader/SamplerCore.hpp
index a72bbdc..684c1a7 100644
--- a/src/Shader/SamplerCore.hpp
+++ b/src/Shader/SamplerCore.hpp
@@ -27,7 +27,6 @@
 		Lod,       // Use provided LOD.
 		Grad,      // Use provided gradients.
 		Fetch,     // Use provided integer coordinates.
-		Rectangle, // Use non normalized texture coordinates.
 		Base       // Sample base level.
 	};
 
diff --git a/src/Shader/Shader.cpp b/src/Shader/Shader.cpp
index c5ce0b9..025b5d5 100644
--- a/src/Shader/Shader.cpp
+++ b/src/Shader/Shader.cpp
@@ -904,7 +904,6 @@
 		case OPCODE_TEXELFETCHOFFSET: return "texelfetchoffset";
 		case OPCODE_TEXGRAD:         return "texgrad";
 		case OPCODE_TEXGRADOFFSET:   return "texgradoffset";
-		case OPCODE_TEXRECT:         return "texrect";
 		case OPCODE_BREAKP:          return "breakp";
 		case OPCODE_TEXSIZE:         return "texsize";
 		case OPCODE_PHASE:           return "phase";
@@ -1851,7 +1850,6 @@
 			case OPCODE_TEXELFETCHOFFSET:
 			case OPCODE_TEXGRAD:
 			case OPCODE_TEXGRADOFFSET:
-			case OPCODE_TEXRECT:
 				{
 					Parameter &dst = inst->dst;
 					Parameter &src1 = inst->src[1];
diff --git a/src/Shader/Shader.hpp b/src/Shader/Shader.hpp
index 2556cdd..6755cd4 100644
--- a/src/Shader/Shader.hpp
+++ b/src/Shader/Shader.hpp
@@ -214,7 +214,6 @@
 			OPCODE_TEXBIAS,
 			OPCODE_TEXLOD,
 			OPCODE_TEXOFFSETBIAS,
-			OPCODE_TEXRECT,
 			OPCODE_TEXSIZE,
 			OPCODE_FLOATBITSTOINT,
 			OPCODE_FLOATBITSTOUINT,
diff --git a/src/Shader/VertexProgram.cpp b/src/Shader/VertexProgram.cpp
index 71a38d3..4f8ba1a 100644
--- a/src/Shader/VertexProgram.cpp
+++ b/src/Shader/VertexProgram.cpp
@@ -336,7 +336,6 @@
 			case Shader::OPCODE_TEXELFETCHOFFSET: TEXELFETCHOFFSET(d, s0, src1, s2, s3.x); break;
 			case Shader::OPCODE_TEXGRAD:    TEXGRAD(d, s0, src1, s2, s3);   break;
 			case Shader::OPCODE_TEXGRADOFFSET: TEXGRADOFFSET(d, s0, src1, s2, s3, s4); break;
-			case Shader::OPCODE_TEXRECT:    TEXRECT(d, s0, src1);           break;
 			case Shader::OPCODE_TEXSIZE:    TEXSIZE(d, s0.x, src1);         break;
 			case Shader::OPCODE_END:                                        break;
 			default:
@@ -1553,11 +1552,6 @@
 		dst = sampleTexture(src1, src0, (src0.x), dsx, dsy, offset, {Grad, Offset});
 	}
 
-	void VertexProgram::TEXRECT(Vector4f &dst, Vector4f &src0, const Src &src1)
-	{
-		dst = sampleTexture(src1, src0, (src0.x), (src0), (src0), (src0), Rectangle);
-	}
-
 	void VertexProgram::TEXSIZE(Vector4f &dst, Float4 &lod, const Src &src1)
 	{
 		Pointer<Byte> texture = data + OFFSET(DrawData, mipmap[TEXTURE_IMAGE_UNITS]) + src1.index * sizeof(Texture);
diff --git a/src/Shader/VertexProgram.hpp b/src/Shader/VertexProgram.hpp
index 0462ab7..c42ab71 100644
--- a/src/Shader/VertexProgram.hpp
+++ b/src/Shader/VertexProgram.hpp
@@ -115,7 +115,6 @@
 		void TEXELFETCHOFFSET(Vector4f &dst, Vector4f &src, const Src&, Vector4f &offset, Float4 &lod);
 		void TEXGRAD(Vector4f &dst, Vector4f &src, const Src&, Vector4f &dsx, Vector4f &dsy);
 		void TEXGRADOFFSET(Vector4f &dst, Vector4f &src, const Src&, Vector4f &dsx, Vector4f &dsy, Vector4f &offset);
-		void TEXRECT(Vector4f &dst, Vector4f &src0, const Src &src1);
 		void TEXSIZE(Vector4f &dst, Float4 &lod, const Src&);
 
 		Vector4f sampleTexture(const Src &s, Vector4f &uvwq, Float4 &lod, Vector4f &dsx, Vector4f &dsy, Vector4f &offset, SamplerFunction function);
diff --git a/tests/unittests/unittests.cpp b/tests/unittests/unittests.cpp
index 9fcb19b..7391e13 100644
--- a/tests/unittests/unittests.cpp
+++ b/tests/unittests/unittests.cpp
@@ -530,6 +530,99 @@
 	Uninitialize();
 }
 
+// Test sampling from a rectangle texture
+TEST_F(SwiftShaderTest, TextureRectangle_SamplingFromRectangleESSL3)
+{
+	Initialize(3, false);
+
+	GLuint tex = 1;
+	glBindTexture(GL_TEXTURE_RECTANGLE_ARB, tex);
+	EXPECT_EQ(GL_NONE, glGetError());
+
+	unsigned char green[4] = { 0, 255, 0, 255 };
+	glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, green);
+	EXPECT_EQ(GL_NONE, glGetError());
+
+	const std::string vs =
+		"#version 300 es\n"
+		"in vec4 position;\n"
+		"void main()\n"
+		"{\n"
+		"    gl_Position = vec4(position.xy, 0.0, 1.0);\n"
+		"}\n";
+
+	const std::string fs =
+		"#version 300 es\n"
+		"#extension GL_ARB_texture_rectangle : require\n"
+		"precision mediump float;\n"
+		"uniform sampler2DRect tex;\n"
+		"out vec4 fragColor;\n"
+		"void main()\n"
+		"{\n"
+		"    fragColor = texture(tex, vec2(0, 0));\n"
+		"}\n";
+
+	GLuint program = glCreateProgram();
+	EXPECT_EQ(GL_NONE, glGetError());
+
+	GLuint vsShader = glCreateShader(GL_VERTEX_SHADER);
+	const char* vsSource[1] = { vs.c_str() };
+	glShaderSource(vsShader, 1, vsSource, nullptr);
+	glCompileShader(vsShader);
+	EXPECT_EQ(GL_NONE, glGetError());
+
+	GLuint fsShader = glCreateShader(GL_FRAGMENT_SHADER);
+	const char* fsSource[1] = { fs.c_str() };
+	glShaderSource(fsShader, 1, fsSource, nullptr);
+	glCompileShader(fsShader);
+	EXPECT_EQ(GL_NONE, glGetError());
+
+	glAttachShader(program, vsShader);
+	glAttachShader(program, fsShader);
+	glLinkProgram(program);
+	EXPECT_EQ(GL_NONE, glGetError());
+
+	glUseProgram(program);
+	GLint location = glGetUniformLocation(program, "tex");
+	ASSERT_NE(-1, location);
+	glUniform1i(location, 0);
+
+	glClearColor(0.0, 0.0, 0.0, 0.0);
+	glClear(GL_COLOR_BUFFER_BIT);
+	EXPECT_EQ(GL_NONE, glGetError());
+
+	GLint prevProgram = 0;
+	glGetIntegerv(GL_CURRENT_PROGRAM, &prevProgram);
+
+	glUseProgram(program);
+	EXPECT_EQ(GL_NONE, glGetError());
+
+	GLint posLoc = glGetAttribLocation(program, "position");
+	EXPECT_EQ(GL_NONE, glGetError());
+
+	float vertices[18] = { -1.0f,  1.0f, 0.5f,
+						   -1.0f, -1.0f, 0.5f,
+							1.0f, -1.0f, 0.5f,
+						   -1.0f,  1.0f, 0.5f,
+							1.0f, -1.0f, 0.5f,
+							1.0f,  1.0f, 0.5f };
+	glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, 0, vertices);
+	glEnableVertexAttribArray(posLoc);
+	glDrawArrays(GL_TRIANGLES, 0, 6);
+	EXPECT_EQ(GL_NONE, glGetError());
+
+	glVertexAttribPointer(posLoc, 4, GL_FLOAT, GL_FALSE, 0, nullptr);
+	glDisableVertexAttribArray(posLoc);
+	glUseProgram(prevProgram);
+	EXPECT_EQ(GL_NONE, glGetError());
+
+	compareColor(green);
+
+	EXPECT_EQ(GL_NONE, glGetError());
+
+	Uninitialize();
+}
+
 // Test attaching a rectangle texture and rendering to it.
 TEST_F(SwiftShaderTest, TextureRectangle_RenderToRectangle)
 {