Transform feedback varyings API

Implemented the API functions to set and get
the varyings used for transform feedback.

Change-Id: I0d6451cfbd4a4b1b96dd9c064bb9b310b46764c4
Reviewed-on: https://swiftshader-review.googlesource.com/3462
Tested-by: Alexis Hétu <sugoi@google.com>
Reviewed-by: Nicolas Capens <capn@google.com>
diff --git a/src/OpenGL/libGLESv2/Program.cpp b/src/OpenGL/libGLESv2/Program.cpp
index 2482f8d..3d13afe 100644
--- a/src/OpenGL/libGLESv2/Program.cpp
+++ b/src/OpenGL/libGLESv2/Program.cpp
@@ -92,6 +92,16 @@
 	{

 	}

 

+	LinkedVarying::LinkedVarying()

+	{

+	}

+

+	LinkedVarying::LinkedVarying(const std::string &name, GLenum type, GLsizei size, const std::string &semanticName,

+	                             unsigned int semanticIndex, unsigned int semanticIndexCount)

+	 : name(name), type(type), size(size), semanticName(semanticName), semanticIndex(semanticIndex), semanticIndexCount(semanticIndexCount)

+	{

+	}

+

 	Program::Program(ResourceManager *manager, GLuint handle) : resourceManager(manager), handle(handle), serial(issueSerial())

 	{

 		device = getDevice();

@@ -2579,6 +2589,80 @@
 		return maxLength;

 	}

 

+	void Program::setTransformFeedbackVaryings(GLsizei count, const GLchar *const *varyings, GLenum bufferMode)

+	{

+		transformFeedbackVaryings.resize(count);

+		for(GLsizei i = 0; i < count; i++)

+		{

+			transformFeedbackVaryings[i] = varyings[i];

+		}

+

+		transformFeedbackBufferMode = bufferMode;

+	}

+

+	void Program::getTransformFeedbackVarying(GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name) const

+	{

+		if(linked)

+		{

+			ASSERT(index < transformFeedbackLinkedVaryings.size());

+			const LinkedVarying &varying = transformFeedbackLinkedVaryings[index];

+			GLsizei lastNameIdx = std::min(bufSize - 1, static_cast<GLsizei>(varying.name.length()));

+			if(length)

+			{

+				*length = lastNameIdx;

+			}

+			if(size)

+			{

+				*size = varying.size;

+			}

+			if(type)

+			{

+				*type = varying.type;

+			}

+			if(name)

+			{

+				memcpy(name, varying.name.c_str(), lastNameIdx);

+				name[lastNameIdx] = '\0';

+			}

+		}

+	}

+

+	GLsizei Program::getTransformFeedbackVaryingCount() const

+	{

+		if(linked)

+		{

+			return static_cast<GLsizei>(transformFeedbackLinkedVaryings.size());

+		}

+		else

+		{

+			return 0;

+		}

+	}

+

+	GLsizei Program::getTransformFeedbackVaryingMaxLength() const

+	{

+		if(linked)

+		{

+			GLsizei maxSize = 0;

+			for(size_t i = 0; i < transformFeedbackLinkedVaryings.size(); i++)

+			{

+				const LinkedVarying &varying = transformFeedbackLinkedVaryings[i];

+				maxSize = std::max(maxSize, static_cast<GLsizei>(varying.name.length() + 1));

+			}

+

+			return maxSize;

+		}

+		else

+		{

+			return 0;

+		}

+	}

+

+	GLenum Program::getTransformFeedbackBufferMode() const

+	{

+		return transformFeedbackBufferMode;

+	}

+

 	void Program::flagForDeletion()

 	{

 		orphaned = true;

diff --git a/src/OpenGL/libGLESv2/Program.h b/src/OpenGL/libGLESv2/Program.h
index 0550819..5a1284f 100644
--- a/src/OpenGL/libGLESv2/Program.h
+++ b/src/OpenGL/libGLESv2/Program.h
@@ -104,6 +104,24 @@
 		unsigned int index;

 	};

 

+	struct LinkedVarying

+	{

+		LinkedVarying();

+		LinkedVarying(const std::string &name, GLenum type, GLsizei size, const std::string &semanticName,

+		              unsigned int semanticIndex, unsigned int semanticIndexCount);

+

+		// Original GL name

+		std::string name;

+

+		GLenum type;

+		GLsizei size;

+

+		// DirectX semantic information

+		std::string semanticName;

+		unsigned int semanticIndex;

+		unsigned int semanticIndexCount;

+	};

+

 	class Program

 	{

 	public:

@@ -180,6 +198,12 @@
 		GLint getActiveUniformBlockCount() const;

 		GLint getActiveUniformBlockMaxLength() const;

 

+		void setTransformFeedbackVaryings(GLsizei count, const GLchar *const *varyings, GLenum bufferMode);

+		void getTransformFeedbackVarying(GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name) const;

+		GLsizei getTransformFeedbackVaryingCount() const;

+		GLsizei getTransformFeedbackVaryingMaxLength() const;

+		GLenum getTransformFeedbackBufferMode() const;

+

 		void addRef();

 		void release();

 		unsigned int getRefCount() const;

@@ -253,6 +277,9 @@
 

 		GLuint uniformBlockBindings[MAX_UNIFORM_BUFFER_BINDINGS];

 

+		std::vector<std::string> transformFeedbackVaryings;

+		GLenum transformFeedbackBufferMode;

+

 		struct Sampler

 		{

 			bool active;

@@ -269,6 +296,8 @@
 		UniformIndex uniformIndex;

 		typedef std::vector<UniformBlock*> UniformBlockArray;

 		UniformBlockArray uniformBlocks;

+		typedef std::vector<LinkedVarying> LinkedVaryingArray;

+		LinkedVaryingArray transformFeedbackLinkedVaryings;

 

 		bool linked;

 		bool orphaned;   // Flag to indicate that the program can be deleted when no longer in use

diff --git a/src/OpenGL/libGLESv2/libGLESv2.cpp b/src/OpenGL/libGLESv2/libGLESv2.cpp
index c05bd3a..c6c7ef8 100644
--- a/src/OpenGL/libGLESv2/libGLESv2.cpp
+++ b/src/OpenGL/libGLESv2/libGLESv2.cpp
@@ -3196,6 +3196,33 @@
 				return;

 			}

 			else return error(GL_INVALID_ENUM);

+		case GL_TRANSFORM_FEEDBACK_BUFFER_MODE:

+			if(clientVersion >= 3)

+			{

+				*params = programObject->getTransformFeedbackBufferMode();

+				return;

+			}

+			else return error(GL_INVALID_ENUM);

+		case GL_TRANSFORM_FEEDBACK_VARYINGS:

+			if(clientVersion >= 3)

+			{

+				*params = programObject->getTransformFeedbackVaryingCount();

+				return;

+			}

+			else return error(GL_INVALID_ENUM);

+		case GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH:

+			if(clientVersion >= 3)

+			{

+				*params = programObject->getTransformFeedbackVaryingMaxLength();

+				return;

+			}

+			else return error(GL_INVALID_ENUM);

+		case GL_PROGRAM_BINARY_RETRIEVABLE_HINT:

+			if(clientVersion >= 3)

+			{

+				UNIMPLEMENTED();

+			}

+			else return error(GL_INVALID_ENUM);

 		default:

 			return error(GL_INVALID_ENUM);

 		}

diff --git a/src/OpenGL/libGLESv2/libGLESv3.cpp b/src/OpenGL/libGLESv2/libGLESv3.cpp
index 9a87b73..ea5a572 100644
--- a/src/OpenGL/libGLESv2/libGLESv3.cpp
+++ b/src/OpenGL/libGLESv2/libGLESv3.cpp
@@ -1971,9 +1971,9 @@
 		{

 			return error(GL_INVALID_VALUE);

 		}

-	}

 

-	UNIMPLEMENTED();

+		programObject->setTransformFeedbackVaryings(count, varyings, bufferMode);

+	}

 }

 

 GL_APICALL void GL_APIENTRY glGetTransformFeedbackVarying(GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name)

@@ -1981,6 +1981,11 @@
 	TRACE("(GLuint program = %d, GLuint index = %d, GLsizei bufSize = %d, GLsizei *length = %p, GLsizei *size = %p, GLenum *type = %p, GLchar *name = %p)",

 	      program, index, bufSize, length, size, type, name);

 

+	if(bufSize < 0)

+	{

+		return error(GL_INVALID_VALUE);

+	}

+

 	es2::Context *context = es2::getContext();

 

 	if(context)

@@ -1991,9 +1996,14 @@
 		{

 			return error(GL_INVALID_VALUE);

 		}

-	}

 

-	UNIMPLEMENTED();

+		if(index >= static_cast<GLuint>(programObject->getTransformFeedbackVaryingCount()))

+		{

+			return error(GL_INVALID_VALUE);

+		}

+

+		programObject->getTransformFeedbackVarying(index, bufSize, length, size, type, name);

+	}

 }

 

 GL_APICALL void GL_APIENTRY glVertexAttribIPointer(GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer)