Enabling Transform Feedback

This cl enables transform feedback in Context by calling
Program::applyTransformFeedback(). It also adds the code
required to compute vertex offsets between different draw
calls, when multiple successive draw calls write into the
same transform feedback buffer(s).

Change-Id: Ib3bc4bdd1308486642f233f425d0088a55cb1333
Reviewed-on: https://swiftshader-review.googlesource.com/5301
Tested-by: Alexis Hétu <sugoi@google.com>
Reviewed-by: Nicolas Capens <capn@google.com>
diff --git a/src/OpenGL/libGLESv2/Context.cpp b/src/OpenGL/libGLESv2/Context.cpp
index da9aedd..de4626b 100644
--- a/src/OpenGL/libGLESv2/Context.cpp
+++ b/src/OpenGL/libGLESv2/Context.cpp
@@ -2171,16 +2171,14 @@
 		*params = 2;
 		break;
 	case GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS: // integer, at least 64
-		UNIMPLEMENTED();
-		*params = 64;
+		*params = sw::MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS;
 		break;
 	case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS: // integer, at least 4
 		UNIMPLEMENTED();
 		*params = MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS;
 		break;
 	case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS: // integer, at least 4
-		UNIMPLEMENTED();
-		*params = 4;
+		*params = sw::MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS;
 		break;
 	case GL_MAX_UNIFORM_BLOCK_SIZE: // integer, at least 16384
 		*params = MAX_UNIFORM_BLOCK_SIZE;
@@ -3012,6 +3010,7 @@
 		mAppliedProgramSerial = programObject->getSerial();
 	}
 
+	programObject->applyTransformFeedback(getTransformFeedback());
 	programObject->applyUniformBuffers(mState.uniformBuffers);
 	programObject->applyUniforms();
 }
@@ -3438,8 +3437,9 @@
 
 	sw::DrawType primitiveType;
 	int primitiveCount;
+	int verticesPerPrimitive;
 
-	if(!es2sw::ConvertPrimitiveType(mode, count, GL_NONE, primitiveType, primitiveCount))
+	if(!es2sw::ConvertPrimitiveType(mode, count, GL_NONE, primitiveType, primitiveCount, verticesPerPrimitive))
 		return error(GL_INVALID_ENUM);
 
 	if(primitiveCount <= 0)
@@ -3472,10 +3472,15 @@
 			return error(GL_INVALID_OPERATION);
 		}
 
-		if(!cullSkipsDraw(mode))
+		TransformFeedback* transformFeedback = getTransformFeedback();
+		if(!cullSkipsDraw(mode) || (transformFeedback->isActive() && !transformFeedback->isPaused()))
 		{
 			device->drawPrimitive(primitiveType, primitiveCount);
 		}
+		if(transformFeedback)
+		{
+			transformFeedback->addVertexOffset(primitiveCount * verticesPerPrimitive);
+		}
 	}
 }
 
@@ -3493,8 +3498,9 @@
 
 	sw::DrawType primitiveType;
 	int primitiveCount;
+	int verticesPerPrimitive;
 
-	if(!es2sw::ConvertPrimitiveType(mode, count, type, primitiveType, primitiveCount))
+	if(!es2sw::ConvertPrimitiveType(mode, count, type, primitiveType, primitiveCount, verticesPerPrimitive))
 		return error(GL_INVALID_ENUM);
 
 	if(primitiveCount <= 0)
@@ -3535,10 +3541,15 @@
 			return error(GL_INVALID_OPERATION);
 		}
 
-		if(!cullSkipsDraw(mode))
+		TransformFeedback* transformFeedback = getTransformFeedback();
+		if(!cullSkipsDraw(mode) || (transformFeedback->isActive() && !transformFeedback->isPaused()))
 		{
 			device->drawIndexedPrimitive(primitiveType, indexInfo.indexOffset, primitiveCount);
 		}
+		if(transformFeedback)
+		{
+			transformFeedback->addVertexOffset(primitiveCount * verticesPerPrimitive);
+		}
 	}
 }
 
diff --git a/src/OpenGL/libGLESv2/utilities.cpp b/src/OpenGL/libGLESv2/utilities.cpp
index 09e5975..1143546 100644
--- a/src/OpenGL/libGLESv2/utilities.cpp
+++ b/src/OpenGL/libGLESv2/utilities.cpp
@@ -1422,37 +1422,44 @@
 		}
 	}
 
-	bool ConvertPrimitiveType(GLenum primitiveType, GLsizei elementCount, GLenum elementType,  sw::DrawType &drawType, int &primitiveCount)
+	bool ConvertPrimitiveType(GLenum primitiveType, GLsizei elementCount, GLenum elementType, sw::DrawType &drawType, int &primitiveCount, int &verticesPerPrimitive)
 	{
 		switch(primitiveType)
 		{
 		case GL_POINTS:
 			drawType = sw::DRAW_POINTLIST;
 			primitiveCount = elementCount;
+			verticesPerPrimitive = 1;
 			break;
 		case GL_LINES:
 			drawType = sw::DRAW_LINELIST;
 			primitiveCount = elementCount / 2;
+			verticesPerPrimitive = 2;
 			break;
 		case GL_LINE_LOOP:
 			drawType = sw::DRAW_LINELOOP;
 			primitiveCount = elementCount;
+			verticesPerPrimitive = 2;
 			break;
 		case GL_LINE_STRIP:
 			drawType = sw::DRAW_LINESTRIP;
 			primitiveCount = elementCount - 1;
+			verticesPerPrimitive = 2;
 			break;
 		case GL_TRIANGLES:
 			drawType = sw::DRAW_TRIANGLELIST;
 			primitiveCount = elementCount / 3;
+			verticesPerPrimitive = 3;
 			break;
 		case GL_TRIANGLE_STRIP:
 			drawType = sw::DRAW_TRIANGLESTRIP;
 			primitiveCount = elementCount - 2;
+			verticesPerPrimitive = 3;
 			break;
 		case GL_TRIANGLE_FAN:
 			drawType = sw::DRAW_TRIANGLEFAN;
 			primitiveCount = elementCount - 2;
+			verticesPerPrimitive = 3;
 			break;
 		default:
 			return false;
diff --git a/src/OpenGL/libGLESv2/utilities.h b/src/OpenGL/libGLESv2/utilities.h
index 2aa983c..d2d9084 100644
--- a/src/OpenGL/libGLESv2/utilities.h
+++ b/src/OpenGL/libGLESv2/utilities.h
@@ -80,7 +80,7 @@
 	unsigned int ConvertColorMask(bool red, bool green, bool blue, bool alpha);
 	sw::MipmapType ConvertMipMapFilter(GLenum minFilter);
 	sw::FilterType ConvertTextureFilter(GLenum minFilter, GLenum magFilter, float maxAnisotropy);
-	bool ConvertPrimitiveType(GLenum primitiveType, GLsizei elementCount,  GLenum elementType, sw::DrawType &swPrimitiveType, int &primitiveCount);
+	bool ConvertPrimitiveType(GLenum primitiveType, GLsizei elementCount,  GLenum elementType, sw::DrawType &swPrimitiveType, int &primitiveCount, int &verticesPerPrimitive);
 	sw::Format ConvertRenderbufferFormat(GLenum format);
 }