gl_VertexID implementation

This cl implements support for gl_VertexID.

Passes the functional.shaders.builtin_variable.vertex_id test.

Change-Id: I5550e3ecba30e29f1e38ace608d730833a1e9598
Reviewed-on: https://swiftshader-review.googlesource.com/10958
Tested-by: Alexis Hétu <sugoi@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/src/OpenGL/compiler/BaseTypes.h b/src/OpenGL/compiler/BaseTypes.h
index 58c0856..01f9948 100644
--- a/src/OpenGL/compiler/BaseTypes.h
+++ b/src/OpenGL/compiler/BaseTypes.h
@@ -369,6 +369,7 @@
 	EvqPosition,
 	EvqPointSize,
 	EvqInstanceID,
+	EvqVertexID,
 
 	// built-ins read by fragment shader
 	EvqFragCoord,
@@ -446,6 +447,7 @@
 	case EvqPosition:       return "Position";       break;
 	case EvqPointSize:      return "PointSize";      break;
 	case EvqInstanceID:     return "InstanceID";     break;
+	case EvqVertexID:       return "VertexID";       break;
 	case EvqFragCoord:      return "FragCoord";      break;
 	case EvqFrontFacing:    return "FrontFacing";    break;
 	case EvqFragColor:      return "FragColor";      break;
diff --git a/src/OpenGL/compiler/Initialize.cpp b/src/OpenGL/compiler/Initialize.cpp
index 1948a57..c374531 100644
--- a/src/OpenGL/compiler/Initialize.cpp
+++ b/src/OpenGL/compiler/Initialize.cpp
@@ -471,6 +471,7 @@
 		symbolTable.insert(COMMON_BUILTINS, *new TVariable(NewPoolTString("gl_Position"), TType(EbtFloat, EbpHigh, EvqPosition,    4)));
 		symbolTable.insert(COMMON_BUILTINS, *new TVariable(NewPoolTString("gl_PointSize"), TType(EbtFloat, EbpMedium, EvqPointSize,   1)));
 		symbolTable.insert(ESSL3_BUILTINS, *new TVariable(NewPoolTString("gl_InstanceID"), TType(EbtInt, EbpHigh, EvqInstanceID, 1)));
+		symbolTable.insert(ESSL3_BUILTINS, *new TVariable(NewPoolTString("gl_VertexID"), TType(EbtInt, EbpHigh, EvqVertexID, 1)));
 		break;
 	default: assert(false && "Language not supported");
 	}
diff --git a/src/OpenGL/compiler/OutputASM.cpp b/src/OpenGL/compiler/OutputASM.cpp
index 8a84692..2c8222e 100644
--- a/src/OpenGL/compiler/OutputASM.cpp
+++ b/src/OpenGL/compiler/OutputASM.cpp
@@ -2554,6 +2554,7 @@
 		case EvqPosition:            return sw::Shader::PARAMETER_OUTPUT;
 		case EvqPointSize:           return sw::Shader::PARAMETER_OUTPUT;
 		case EvqInstanceID:          return sw::Shader::PARAMETER_MISCTYPE;
+		case EvqVertexID:            return sw::Shader::PARAMETER_MISCTYPE;
 		case EvqFragCoord:           return sw::Shader::PARAMETER_MISCTYPE;
 		case EvqFrontFacing:         return sw::Shader::PARAMETER_MISCTYPE;
 		case EvqPointCoord:          return sw::Shader::PARAMETER_INPUT;
@@ -2606,9 +2607,10 @@
 		case EvqConstReadOnly:       return temporaryRegister(operand);
 		case EvqPosition:            return varyingRegister(operand);
 		case EvqPointSize:           return varyingRegister(operand);
-		case EvqInstanceID:          vertexShader->declareInstanceId(); return 0;
-		case EvqFragCoord:           pixelShader->declareVPos();  return 0;
-		case EvqFrontFacing:         pixelShader->declareVFace(); return 1;
+		case EvqInstanceID:          vertexShader->declareInstanceId(); return sw::Shader::InstanceIDIndex;
+		case EvqVertexID:            vertexShader->declareVertexId(); return sw::Shader::VertexIDIndex;
+		case EvqFragCoord:           pixelShader->declareVPos();  return sw::Shader::VPosIndex;
+		case EvqFrontFacing:         pixelShader->declareVFace(); return sw::Shader::VFaceIndex;
 		case EvqPointCoord:          return varyingRegister(operand);
 		case EvqFragColor:           return 0;
 		case EvqFragData:            return fragmentOutputRegister(operand);
diff --git a/src/OpenGL/compiler/ParseHelper.cpp b/src/OpenGL/compiler/ParseHelper.cpp
index 83f58ce..7cca42c 100644
--- a/src/OpenGL/compiler/ParseHelper.cpp
+++ b/src/OpenGL/compiler/ParseHelper.cpp
@@ -406,6 +406,7 @@
 	case EvqFrontFacing:    message = "can't modify gl_FrontFacing"; break;
 	case EvqPointCoord:     message = "can't modify gl_PointCoord";  break;
 	case EvqInstanceID:     message = "can't modify gl_InstanceID";  break;
+	case EvqVertexID:       message = "can't modify gl_VertexID";    break;
 	default:
 
 		//
diff --git a/src/Shader/PixelProgram.cpp b/src/Shader/PixelProgram.cpp
index ecf164f..948f103 100644
--- a/src/Shader/PixelProgram.cpp
+++ b/src/Shader/PixelProgram.cpp
@@ -846,8 +846,8 @@
 			reg = v[2 + i];
 			break;
 		case Shader::PARAMETER_MISCTYPE:
-			if(src.index == 0) reg = vPos;
-			if(src.index == 1) reg = vFace;
+			if(src.index == Shader::VPosIndex) reg = vPos;
+			if(src.index == Shader::VFaceIndex) reg = vFace;
 			break;
 		case Shader::PARAMETER_SAMPLER:
 			if(src.rel.type == Shader::PARAMETER_VOID)
diff --git a/src/Shader/PixelShader.cpp b/src/Shader/PixelShader.cpp
index 0b78c14..c659248 100644
--- a/src/Shader/PixelShader.cpp
+++ b/src/Shader/PixelShader.cpp
@@ -700,11 +700,11 @@
 					{
 						unsigned char index = instruction[i]->dst.index;
 
-						if(index == 0)
+						if(index == Shader::VPosIndex)
 						{
 							vPosDeclared = true;
 						}
-						else if(index == 1)
+						else if(index == Shader::VFaceIndex)
 						{
 							vFaceDeclared = true;
 						}
diff --git a/src/Shader/Shader.cpp b/src/Shader/Shader.cpp
index c861069..ff1482e 100644
--- a/src/Shader/Shader.cpp
+++ b/src/Shader/Shader.cpp
@@ -1059,9 +1059,14 @@
 		case PARAMETER_LOOP:			return "aL";
 	//	case PARAMETER_TEMPFLOAT16:		return "";
 		case PARAMETER_MISCTYPE:
-			if(index == 0)				return "vPos";
-			else if(index == 1)			return "vFace";
-			else						ASSERT(false);
+			switch(index)
+			{
+			case VPosIndex:				return "vPos";
+			case VFaceIndex:			return "vFace";
+			case InstanceIDIndex:		return "iID";
+			case VertexIDIndex:			return "vID";
+			default: ASSERT(false);
+			}
 		case PARAMETER_LABEL:			return "l";
 		case PARAMETER_PREDICATE:		return "p0";
 		case PARAMETER_FLOAT4LITERAL:	return "";
diff --git a/src/Shader/Shader.hpp b/src/Shader/Shader.hpp
index f41d514..ee69e8b 100644
--- a/src/Shader/Shader.hpp
+++ b/src/Shader/Shader.hpp
@@ -358,6 +358,14 @@
 			PARAMETER_VOID
 		};
 
+		enum MiscParameterIndex
+		{
+			VPosIndex = 0,
+			VFaceIndex = 1,
+			InstanceIDIndex = 2,
+			VertexIDIndex = 3,
+		};
+
 		enum Modifier
 		{
 			MODIFIER_NONE,
diff --git a/src/Shader/VertexPipeline.cpp b/src/Shader/VertexPipeline.cpp
index 8db3ca0..8792884 100644
--- a/src/Shader/VertexPipeline.cpp
+++ b/src/Shader/VertexPipeline.cpp
@@ -158,7 +158,7 @@
 		return dst;
 	}
 
-	void VertexPipeline::pipeline()
+	void VertexPipeline::pipeline(UInt &index)
 	{
 		Vector4f position;
 		Vector4f normal;
diff --git a/src/Shader/VertexPipeline.hpp b/src/Shader/VertexPipeline.hpp
index e8b954c..e3c0cbe 100644
--- a/src/Shader/VertexPipeline.hpp
+++ b/src/Shader/VertexPipeline.hpp
@@ -30,7 +30,7 @@
 		virtual ~VertexPipeline();
 
 	private:
-		void pipeline() override;
+		void pipeline(UInt &index) override;
 		void processTextureCoordinate(int stage, Vector4f &normal, Vector4f &position);
 		void processPointSize();
 
diff --git a/src/Shader/VertexProgram.cpp b/src/Shader/VertexProgram.cpp
index 26d61e0..c9ed8aa 100644
--- a/src/Shader/VertexProgram.cpp
+++ b/src/Shader/VertexProgram.cpp
@@ -64,7 +64,7 @@
 		}
 	}
 
-	void VertexProgram::pipeline()
+	void VertexProgram::pipeline(UInt& index)
 	{
 		for(int i = 0; i < VERTEX_TEXTURE_IMAGE_UNITS; i++)
 		{
@@ -73,7 +73,7 @@
 
 		if(!state.preTransformed)
 		{
-			program();
+			program(index);
 		}
 		else
 		{
@@ -81,7 +81,7 @@
 		}
 	}
 
-	void VertexProgram::program()
+	void VertexProgram::program(UInt& index)
 	{
 	//	shader->print("VertexShader-%0.8X.txt", state.shaderID);
 
@@ -95,6 +95,21 @@
 			enableLeave = Int4(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF);
 		}
 
+		if(shader->isVertexIdDeclared())
+		{
+			if(state.textureSampling)
+			{
+				vertexID = Int4(index);
+			}
+			else
+			{
+				vertexID = Insert(vertexID, As<Int>(index), 0);
+				vertexID = Insert(vertexID, As<Int>(index + 1), 1);
+				vertexID = Insert(vertexID, As<Int>(index + 2), 2);
+				vertexID = Insert(vertexID, As<Int>(index + 3), 3);
+			}
+		}
+
 		// Create all call site return blocks up front
 		for(size_t i = 0; i < shader->getLength(); i++)
 		{
@@ -721,7 +736,15 @@
 			}
 			break;
 		case Shader::PARAMETER_MISCTYPE:
-			reg.x = As<Float>(Int(instanceID));
+			if(src.index == Shader::InstanceIDIndex)
+			{
+				reg.x = As<Float>(instanceID);
+			}
+			else if(src.index == Shader::VertexIDIndex)
+			{
+				reg.x = As<Float4>(vertexID);
+			}
+			else ASSERT(false);
 			return reg;
 		default:
 			ASSERT(false);
@@ -861,7 +884,17 @@
 				case Shader::PARAMETER_INPUT:    a = v[src.rel.index][component]; break;
 				case Shader::PARAMETER_OUTPUT:   a = o[src.rel.index][component]; break;
 				case Shader::PARAMETER_CONST:    a = *Pointer<Float>(uniformAddress(src.bufferIndex, src.rel.index) + component * sizeof(float)); break;
-				case Shader::PARAMETER_MISCTYPE: a = As<Float4>(Int4(instanceID)); break;
+				case Shader::PARAMETER_MISCTYPE:
+					if(src.rel.index == Shader::InstanceIDIndex)
+					{
+						a = As<Float4>(Int4(instanceID)); break;
+					}
+					else if(src.rel.index == Shader::VertexIDIndex)
+					{
+						a = As<Float4>(vertexID); break;
+					}
+					else ASSERT(false);
+					break;
 				default: ASSERT(false);
 				}
 
diff --git a/src/Shader/VertexProgram.hpp b/src/Shader/VertexProgram.hpp
index bcf4a20..b537af3 100644
--- a/src/Shader/VertexProgram.hpp
+++ b/src/Shader/VertexProgram.hpp
@@ -56,14 +56,15 @@
 		Int4 enableLeave;
 
 		Int instanceID;
+		Int4 vertexID;
 
 		typedef Shader::DestinationParameter Dst;
 		typedef Shader::SourceParameter Src;
 		typedef Shader::Control Control;
 		typedef Shader::Usage Usage;
 
-		void pipeline() override;
-		void program();
+		void pipeline(UInt &index) override;
+		void program(UInt &index);
 		void passThrough();
 
 		Vector4f fetchRegister(const Src &src, unsigned int offset = 0);
diff --git a/src/Shader/VertexRoutine.cpp b/src/Shader/VertexRoutine.cpp
index 42faa80..0f1ccdf 100644
--- a/src/Shader/VertexRoutine.cpp
+++ b/src/Shader/VertexRoutine.cpp
@@ -62,7 +62,7 @@
 				*Pointer<UInt>(tagCache + tagIndex) = indexQ;
 
 				readInput(indexQ);
-				pipeline();
+				pipeline(indexQ);
 				postTransform();
 				computeClipFlags();
 
diff --git a/src/Shader/VertexRoutine.hpp b/src/Shader/VertexRoutine.hpp
index dd4bf13..905118b 100644
--- a/src/Shader/VertexRoutine.hpp
+++ b/src/Shader/VertexRoutine.hpp
@@ -54,7 +54,7 @@
 		const VertexProcessor::State &state;
 
 	private:
-		virtual void pipeline() = 0;
+		virtual void pipeline(UInt &index) = 0;
 
 		typedef VertexProcessor::State::Input Stream;
 
diff --git a/src/Shader/VertexShader.cpp b/src/Shader/VertexShader.cpp
index a98932b..361c76f 100644
--- a/src/Shader/VertexShader.cpp
+++ b/src/Shader/VertexShader.cpp
@@ -27,6 +27,7 @@
 		positionRegister = Pos;
 		pointSizeRegister = Unused;
 		instanceIdDeclared = false;
+		vertexIdDeclared = false;
 		textureSampling = false;
 
 		for(int i = 0; i < MAX_VERTEX_INPUTS; i++)
@@ -48,6 +49,7 @@
 			positionRegister = vs->positionRegister;
 			pointSizeRegister = vs->pointSizeRegister;
 			instanceIdDeclared = vs->instanceIdDeclared;
+			vertexIdDeclared = vs->vertexIdDeclared;
 			usedSamplers = vs->usedSamplers;
 
 			optimize();
@@ -62,6 +64,7 @@
 		positionRegister = Pos;
 		pointSizeRegister = Unused;
 		instanceIdDeclared = false;
+		vertexIdDeclared = false;
 		textureSampling = false;
 
 		for(int i = 0; i < MAX_VERTEX_INPUTS; i++)
diff --git a/src/Shader/VertexShader.hpp b/src/Shader/VertexShader.hpp
index 0ca7b93..9a9a0a6 100644
--- a/src/Shader/VertexShader.hpp
+++ b/src/Shader/VertexShader.hpp
@@ -45,6 +45,7 @@
 		void setPositionRegister(int posReg);
 		void setPointSizeRegister(int ptSizeReg);
 		void declareInstanceId() { instanceIdDeclared = true; }
+		void declareVertexId() { vertexIdDeclared = true; }
 
 		const Semantic& getInput(int inputIdx) const;
 		const Semantic& getOutput(int outputIdx, int component) const;
@@ -52,6 +53,7 @@
 		int getPositionRegister() const { return positionRegister; }
 		int getPointSizeRegister() const { return pointSizeRegister; }
 		bool isInstanceIdDeclared() const { return instanceIdDeclared; }
+		bool isVertexIdDeclared() const { return vertexIdDeclared; }
 
 	private:
 		void analyze();
@@ -68,6 +70,7 @@
 		int pointSizeRegister;
 
 		bool instanceIdDeclared;
+		bool vertexIdDeclared;
 		bool textureSampling;
 	};
 }