Uniform blocks implementation

- Added support for uniform blocks in OutputASM::declareUniform
- Added basic implementation of Program::applyUniformBuffers()
  to be completed later on when uniform buffers are implemented

Change-Id: I919b59d4557bb10bb302e6b6bd0ada79553ca8bb
Reviewed-on: https://swiftshader-review.googlesource.com/3651
Tested-by: Alexis Hétu <sugoi@google.com>
Reviewed-by: Nicolas Capens <capn@google.com>
diff --git a/src/OpenGL/compiler/OutputASM.cpp b/src/OpenGL/compiler/OutputASM.cpp
index 782d2b0..da58281 100644
--- a/src/OpenGL/compiler/OutputASM.cpp
+++ b/src/OpenGL/compiler/OutputASM.cpp
@@ -75,13 +75,16 @@
 		ConstantUnion constants[4];

 	};

 

-	Uniform::Uniform(GLenum type, GLenum precision, const std::string &name, int arraySize, int registerIndex)

+	Uniform::Uniform(GLenum type, GLenum precision, const std::string &name, int arraySize, int registerIndex, int blockId) :

+		type(type), precision(precision), name(name), arraySize(arraySize), registerIndex(registerIndex), blockId(blockId)

 	{

-		this->type = type;

-		this->precision = precision;

-		this->name = name;

-		this->arraySize = arraySize;

-		this->registerIndex = registerIndex;

+	}

+

+	UniformBlock::UniformBlock(const std::string& name, const std::string& instanceName, unsigned int dataSize, unsigned int arraySize,

+	                           TLayoutBlockStorage layout, bool isRowMajorLayout, int registerIndex, int blockId) :

+		name(name), instanceName(instanceName), dataSize(dataSize), arraySize(arraySize), layout(layout),

+		isRowMajorLayout(isRowMajorLayout), registerIndex(registerIndex), blockId(blockId)

+	{

 	}

 

 	Attribute::Attribute()

@@ -2399,55 +2402,73 @@
 		}

 	}

 

-	void OutputASM::declareUniform(const TType &type, const TString &name, int index)

+	void OutputASM::declareUniform(const TType &type, const TString &name, int offset, int blockId)

 	{

 		const TStructure *structure = type.getStruct();

+		const TInterfaceBlock *block = (type.isInterfaceBlock() || (blockId == -1)) ? type.getInterfaceBlock() : nullptr;

 		ActiveUniforms &activeUniforms = shaderObject->activeUniforms;

 

-		if(!structure)

+		if(block)

 		{

-			activeUniforms.push_back(Uniform(glVariableType(type), glVariablePrecision(type), name.c_str(), type.getArraySize(), index));

+			ActiveUniformBlocks &activeUniformBlocks = shaderObject->activeUniformBlocks;

+			blockId = activeUniformBlocks.size();

+			unsigned int dataSize = block->objectSize() * 4; // FIXME: assuming 4 bytes per element

+			activeUniformBlocks.push_back(UniformBlock(block->name().c_str(), block->hasInstanceName() ? block->instanceName().c_str() : std::string(), dataSize,

+			                                           block->arraySize(), block->blockStorage(), block->matrixPacking() == EmpRowMajor, offset, blockId));

+		}

+

+		if(!structure && !block)

+		{

+			if(blockId >= 0)

+			{

+				shaderObject->activeUniformBlocks[blockId].fields.push_back(activeUniforms.size());

+			}

+			activeUniforms.push_back(Uniform(glVariableType(type), glVariablePrecision(type), name.c_str(), type.getArraySize(), offset, blockId));

 

 			if(isSamplerRegister(type))

 			{

 				for(int i = 0; i < type.totalRegisterCount(); i++)

 				{

-					shader->declareSampler(index + i);

+					shader->declareSampler(offset + i);

 				}

 			}

 		}

 		else

 		{

-			const TFieldList& fields = structure->fields();

+			const TFieldList& fields = structure ? structure->fields() : block->fields();

+			const bool containerHasName = structure || block->hasInstanceName();

+			const TString &containerName = structure ? name : (containerHasName ? block->instanceName() : TString());

 			if(type.isArray())

 			{

-				int elementIndex = index;

+				int elementOffset = offset;

 

 				for(int i = 0; i < type.getArraySize(); i++)

 				{

+					int fieldOffset = (blockId == -1) ? elementOffset : 0;

 					for(size_t j = 0; j < fields.size(); j++)

 					{

 						const TType &fieldType = *(fields[j]->type());

 						const TString &fieldName = fields[j]->name();

 

-						const TString uniformName = name + "[" + str(i) + "]." + fieldName;

-						declareUniform(fieldType, uniformName, elementIndex);

-						elementIndex += fieldType.totalRegisterCount();

+						const TString uniformName = containerHasName ? containerName + "[" + str(i) + "]." + fieldName : fieldName;

+						declareUniform(fieldType, uniformName, fieldOffset, blockId);

+						fieldOffset += fieldType.totalRegisterCount();

 					}

+					elementOffset = fieldOffset;

 				}

 			}

 			else

 			{

-				int fieldIndex = index;

+				int fieldOffset = (blockId == -1) ? offset : 0;

 

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

 				{

 					const TType &fieldType = *(fields[i]->type());

 					const TString &fieldName = fields[i]->name();

 

-					const TString uniformName = name + "." + fieldName;

-					declareUniform(fieldType, uniformName, fieldIndex);

-					fieldIndex += fieldType.totalRegisterCount();

+					const TString uniformName = containerHasName ? containerName + "." + fieldName : fieldName;

+					declareUniform(fieldType, uniformName, fieldOffset, blockId);

+					fieldOffset += fieldType.totalRegisterCount();

 				}

 			}

 		}

diff --git a/src/OpenGL/compiler/OutputASM.h b/src/OpenGL/compiler/OutputASM.h
index 43b0bd2..156fda5 100644
--- a/src/OpenGL/compiler/OutputASM.h
+++ b/src/OpenGL/compiler/OutputASM.h
@@ -32,7 +32,7 @@
 {

 	struct Uniform

 	{

-		Uniform(GLenum type, GLenum precision, const std::string &name, int arraySize, int registerIndex);

+		Uniform(GLenum type, GLenum precision, const std::string &name, int arraySize, int registerIndex, int blockId);

 

 		GLenum type;

 		GLenum precision;

@@ -40,10 +40,34 @@
 		int arraySize;

 	

 		int registerIndex;

+

+		int blockId;

 	};

 

 	typedef std::vector<Uniform> ActiveUniforms;

 

+	struct UniformBlock

+	{

+		UniformBlock(const std::string& name, const std::string& instanceName, unsigned int dataSize, unsigned int arraySize,

+		             TLayoutBlockStorage layout, bool isRowMajorLayout, int registerIndex, int blockId);

+

+		const std::string& getName() const { return (instanceName.length() > 0) ? instanceName : name; }

+

+		std::string name;

+		std::string instanceName;

+		unsigned int dataSize;

+		unsigned int arraySize;

+		TLayoutBlockStorage layout;

+		bool isRowMajorLayout;

+		std::vector<int> fields;

+

+		int registerIndex;

+

+		int blockId;

+	};

+

+	typedef std::vector<UniformBlock> ActiveUniformBlocks;

+

 	struct Attribute

 	{

 		Attribute();

@@ -99,6 +123,7 @@
 		VaryingList varyings;

 		ActiveUniforms activeUniforms;

 		ActiveAttributes activeAttributes;

+		ActiveUniformBlocks activeUniformBlocks;

 	};

 

 	struct Function

@@ -180,7 +205,7 @@
 		int allocate(VariableArray &list, TIntermTyped *variable);

 		void free(VariableArray &list, TIntermTyped *variable);

 

-		void declareUniform(const TType &type, const TString &name, int index);

+		void declareUniform(const TType &type, const TString &name, int offset, int blockId = -1);

 		GLenum glVariableType(const TType &type);

 		GLenum glVariablePrecision(const TType &type);

 

diff --git a/src/OpenGL/libGLESv2/Context.cpp b/src/OpenGL/libGLESv2/Context.cpp
index 6f33d6c..ae733d0 100644
--- a/src/OpenGL/libGLESv2/Context.cpp
+++ b/src/OpenGL/libGLESv2/Context.cpp
@@ -3031,6 +3031,7 @@
     }

 

     programObject->applyUniforms();

+    programObject->applyUniformBuffers();

 }

 

 void Context::applyTextures()

diff --git a/src/OpenGL/libGLESv2/Program.cpp b/src/OpenGL/libGLESv2/Program.cpp
index 1cb028a..4f17718 100644
--- a/src/OpenGL/libGLESv2/Program.cpp
+++ b/src/OpenGL/libGLESv2/Program.cpp
@@ -35,9 +35,30 @@
 		return buffer;

 	}

 

+	Uniform::BlockInfo::BlockInfo(const glsl::Uniform& uniform, int blockIndex, bool rowMajorLayout)

+	{

+		if(blockIndex >= 0)

+		{

+			index = blockIndex;

+			offset = uniform.registerIndex;

+			arrayStride = UniformTypeSize(uniform.type) * uniform.arraySize;

+			isRowMajorMatrix = rowMajorLayout;

+			int rowCount = VariableRowCount(uniform.type);

+			matrixStride = (rowCount > 1) ? (isRowMajorMatrix ? rowCount : VariableColumnCount(uniform.type)) * UniformTypeSize(UniformComponentType(uniform.type)) : 0;

+		}

+		else

+		{

+			index = -1;

+			offset = -1;

+			arrayStride = -1;

+			matrixStride = -1;

+			isRowMajorMatrix = false;

+		}

+	}

+

 	Uniform::Uniform(GLenum type, GLenum precision, const std::string &name, unsigned int arraySize,

-	                 const int blockIndex, const BlockMemberInfo &blockInfo)

-	 : type(type), precision(precision), name(name), arraySize(arraySize), blockIndex(blockIndex), blockInfo(blockInfo)

+	                 const BlockInfo &blockInfo)

+	 : type(type), precision(precision), name(name), arraySize(arraySize), blockInfo(blockInfo)

 	{

 		int bytes = UniformTypeSize(type) * size();

 		data = new unsigned char[bytes];

@@ -68,11 +89,26 @@
 		return size() * VariableRegisterCount(type);

 	}

 

-	UniformBlock::UniformBlock(const std::string &name, unsigned int elementIndex, unsigned int dataSize) :

-		name(name), elementIndex(elementIndex), dataSize(dataSize), psRegisterIndex(GL_INVALID_INDEX), vsRegisterIndex(GL_INVALID_INDEX)

+	UniformBlock::UniformBlock(const std::string &name, unsigned int elementIndex, unsigned int dataSize, std::vector<unsigned int> memberUniformIndexes) :

+		name(name), elementIndex(elementIndex), dataSize(dataSize), memberUniformIndexes(memberUniformIndexes), psRegisterIndex(GL_INVALID_INDEX), vsRegisterIndex(GL_INVALID_INDEX)

 	{

 	}

 

+	void UniformBlock::setRegisterIndex(GLenum shader, unsigned int registerIndex)

+	{

+		switch(shader)

+		{

+		case GL_VERTEX_SHADER:

+			vsRegisterIndex = registerIndex;

+			break;

+		case GL_FRAGMENT_SHADER:

+			psRegisterIndex = registerIndex;

+			break;

+		default:

+			UNREACHABLE(shader);

+		}

+	}

+

 	bool UniformBlock::isArrayElement() const

 	{

 		return elementIndex != GL_INVALID_INDEX;

@@ -348,7 +384,7 @@
 	{

 		ASSERT(uniformBlockIndex < getActiveUniformBlockCount());

 

-		const UniformBlock &uniformBlock = *uniformBlocks[uniformBlockIndex];

+		const UniformBlock &uniformBlock = uniformBlocks[uniformBlockIndex];

 

 		switch(pname)

 		{

@@ -387,7 +423,7 @@
 		unsigned int numUniformBlocks = getActiveUniformBlockCount();

 		for(unsigned int blockIndex = 0; blockIndex < numUniformBlocks; blockIndex++)

 		{

-			const UniformBlock &uniformBlock = *uniformBlocks[blockIndex];

+			const UniformBlock &uniformBlock = uniformBlocks[blockIndex];

 			if(uniformBlock.name == baseName)

 			{

 				const bool arrayElementZero = (subscript == GL_INVALID_INDEX && uniformBlock.elementIndex == 0);

@@ -1087,6 +1123,48 @@
 		}

 	}

 

+	void Program::applyUniformBuffers()

+	{

+		GLint vertexUniformBuffers[IMPLEMENTATION_MAX_UNIFORM_BUFFER_BINDINGS];

+		GLint fragmentUniformBuffers[IMPLEMENTATION_MAX_UNIFORM_BUFFER_BINDINGS];

+

+		for(unsigned int registerIndex = 0; registerIndex < IMPLEMENTATION_MAX_UNIFORM_BUFFER_BINDINGS; ++registerIndex)

+		{

+			vertexUniformBuffers[registerIndex] = -1;

+		}

+

+		for(unsigned int registerIndex = 0; registerIndex < IMPLEMENTATION_MAX_UNIFORM_BUFFER_BINDINGS; ++registerIndex)

+		{

+			fragmentUniformBuffers[registerIndex] = -1;

+		}

+

+		for(unsigned int uniformBlockIndex = 0; uniformBlockIndex < uniformBlocks.size(); uniformBlockIndex++)

+		{

+			UniformBlock &uniformBlock = uniformBlocks[uniformBlockIndex];

+			GLuint blockBinding = uniformBlockBindings[uniformBlockIndex];

+

+			// Unnecessary to apply an unreferenced standard or shared UBO

+			if(!uniformBlock.isReferencedByVertexShader() && !uniformBlock.isReferencedByFragmentShader())

+			{

+				continue;

+			}

+

+			if(uniformBlock.isReferencedByVertexShader())

+			{

+				unsigned int registerIndex = uniformBlock.vsRegisterIndex;

+				ASSERT(vertexUniformBuffers[registerIndex] == -1);

+				vertexUniformBuffers[registerIndex] = blockBinding;

+			}

+

+			if(uniformBlock.isReferencedByFragmentShader())

+			{

+				unsigned int registerIndex = uniformBlock.psRegisterIndex;

+				ASSERT(fragmentUniformBuffers[registerIndex] == -1);

+				fragmentUniformBuffers[registerIndex] = blockBinding;

+			}

+		}

+	}

+

 	bool Program::linkVaryings()

 	{

 		for(glsl::VaryingList::iterator input = fragmentShader->varyings.begin(); input != fragmentShader->varyings.end(); ++input)

@@ -1233,6 +1311,12 @@
 			return;

 		}

 

+		// Link uniform blocks before uniforms to make it easy to assign block indices to fields

+		if(!linkUniformBlocks(vertexShader, fragmentShader))

+		{

+			return;

+		}

+

 		if(!linkUniforms(fragmentShader))

 		{

 			return;

@@ -1345,7 +1429,18 @@
 		{

 			const glsl::Uniform &uniform = activeUniforms[uniformIndex];

 

-			if(!defineUniform(shader->getType(), uniform.type, uniform.precision, uniform.name, uniform.arraySize, uniform.registerIndex))

+			int blockIndex = -1;

+			bool isRowMajorMatrix = false;

+			if(uniform.blockId >= 0)

+			{

+				const glsl::ActiveUniformBlocks &activeUniformBlocks = shader->activeUniformBlocks;

+				ASSERT(static_cast<size_t>(uniform.blockId) < activeUniformBlocks.size());

+				UniformBlockArray::iterator it = std::find(uniformBlocks.begin(), uniformBlocks.end(), UniformBlock(activeUniformBlocks[uniform.blockId].getName(), GL_INVALID_INDEX, 0, std::vector<unsigned int>()));

+				ASSERT(it != uniformBlocks.end());

+				blockIndex = (it - uniformBlocks.begin()) / sizeof(UniformBlockArray::iterator);

+				isRowMajorMatrix = activeUniformBlocks[uniform.blockId].isRowMajorLayout;

+			}

+			if(!defineUniform(shader->getType(), uniform.type, uniform.precision, uniform.name, uniform.arraySize, uniform.registerIndex, Uniform::BlockInfo(uniform, blockIndex, isRowMajorMatrix)))

 			{

 				return false;

 			}

@@ -1354,7 +1449,7 @@
 		return true;

 	}

 

-	bool Program::defineUniform(GLenum shader, GLenum type, GLenum precision, const std::string &name, unsigned int arraySize, int registerIndex)

+	bool Program::defineUniform(GLenum shader, GLenum type, GLenum precision, const std::string &name, unsigned int arraySize, int registerIndex, const Uniform::BlockInfo& blockInfo)

 	{

 		if(IsSamplerUniform(type))

 	    {

@@ -1460,7 +1555,7 @@
 		}

 		else

 		{

-			uniform = new Uniform(type, precision, name, arraySize, -1, Uniform::BlockMemberInfo::getDefaultBlockInfo());

+			uniform = new Uniform(type, precision, name, arraySize, blockInfo);

 		}

 

 		if(!uniform)

@@ -1510,6 +1605,117 @@
 		return true;

 	}

 

+	bool Program::areMatchingUniformBlocks(const glsl::UniformBlock &block1, const glsl::UniformBlock &block2, const Shader *shader1, const Shader *shader2)

+	{

+		// validate blocks for the same member types

+		if(block1.fields.size() != block2.fields.size())

+		{

+			return false;

+		}

+		if(block1.arraySize != block2.arraySize)

+		{

+			return false;

+		}

+		if(block1.layout != block2.layout || block1.isRowMajorLayout != block2.isRowMajorLayout)

+		{

+			return false;

+		}

+		const unsigned int numBlockMembers = block1.fields.size();

+		for(unsigned int blockMemberIndex = 0; blockMemberIndex < numBlockMembers; blockMemberIndex++)

+		{

+			const glsl::Uniform& member1 = shader1->activeUniforms[block1.fields[blockMemberIndex]];

+			const glsl::Uniform& member2 = shader2->activeUniforms[block2.fields[blockMemberIndex]];

+			if(member1.name != member2.name ||

+			   member1.arraySize != member2.arraySize ||

+			   member1.precision != member2.precision ||

+			   member1.type != member2.type)

+			{

+				return false;

+			}

+		}

+		return true;

+	}

+

+	bool Program::linkUniformBlocks(const Shader *vertexShader, const Shader *fragmentShader)

+	{

+		const glsl::ActiveUniformBlocks &vertexUniformBlocks = vertexShader->activeUniformBlocks;

+		const glsl::ActiveUniformBlocks &fragmentUniformBlocks = fragmentShader->activeUniformBlocks;

+		// Check that interface blocks defined in the vertex and fragment shaders are identical

+		typedef std::map<std::string, const glsl::UniformBlock*> UniformBlockMap;

+		UniformBlockMap linkedUniformBlocks;

+		for(unsigned int blockIndex = 0; blockIndex < vertexUniformBlocks.size(); blockIndex++)

+		{

+			const glsl::UniformBlock &vertexUniformBlock = vertexUniformBlocks[blockIndex];

+			linkedUniformBlocks[vertexUniformBlock.name] = &vertexUniformBlock;

+		}

+		for(unsigned int blockIndex = 0; blockIndex < fragmentUniformBlocks.size(); blockIndex++)

+		{

+			const glsl::UniformBlock &fragmentUniformBlock = fragmentUniformBlocks[blockIndex];

+			UniformBlockMap::const_iterator entry = linkedUniformBlocks.find(fragmentUniformBlock.name);

+			if(entry != linkedUniformBlocks.end())

+			{

+				const glsl::UniformBlock &vertexUniformBlock = *entry->second;

+				if(!areMatchingUniformBlocks(vertexUniformBlock, fragmentUniformBlock, vertexShader, fragmentShader))

+				{

+					return false;

+				}

+			}

+		}

+		for(unsigned int blockIndex = 0; blockIndex < vertexUniformBlocks.size(); blockIndex++)

+		{

+			const glsl::UniformBlock &uniformBlock = vertexUniformBlocks[blockIndex];

+			if(!defineUniformBlock(vertexShader, uniformBlock))

+			{

+				return false;

+			}

+		}

+		for(unsigned int blockIndex = 0; blockIndex < fragmentUniformBlocks.size(); blockIndex++)

+		{

+			const glsl::UniformBlock &uniformBlock = fragmentUniformBlocks[blockIndex];

+			if(!defineUniformBlock(fragmentShader, uniformBlock))

+			{

+				return false;

+			}

+		}

+		return true;

+	}

+

+	bool Program::defineUniformBlock(const Shader *shader, const glsl::UniformBlock &block)

+	{

+		UniformBlockArray::iterator it = std::find(uniformBlocks.begin(), uniformBlocks.end(), UniformBlock(block.getName(), 0, 0, std::vector<unsigned int>()));

+

+		if(it == uniformBlocks.end())

+		{

+			const glsl::ActiveUniforms &activeUniforms = shader->activeUniforms;

+			const std::vector<int>& fields = block.fields;

+			std::vector<unsigned int> memberUniformIndexes;

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

+			{

+				memberUniformIndexes.push_back(activeUniforms[fields[i]].registerIndex);

+			}

+

+			if(block.arraySize > 0)

+			{

+				for(unsigned int i = 0; i < block.arraySize; ++i)

+				{

+					uniformBlocks.push_back(UniformBlock(block.getName(), i, block.dataSize, memberUniformIndexes));

+					uniformBlocks[uniformBlocks.size() - 1].setRegisterIndex(shader->getType(), block.registerIndex);

+				}

+			}

+			else

+			{

+				uniformBlocks.push_back(UniformBlock(block.getName(), GL_INVALID_INDEX, block.dataSize, memberUniformIndexes));

+				uniformBlocks[uniformBlocks.size() - 1].setRegisterIndex(shader->getType(), block.registerIndex);

+			}

+		}

+		else

+		{

+			it->setRegisterIndex(shader->getType(), block.registerIndex);

+		}

+

+		return true;

+	}

+

 	bool Program::applyUniform1bv(GLint location, GLsizei count, const GLboolean *v)

 	{

 		int vector[MAX_UNIFORM_VECTORS][4];

@@ -2336,6 +2542,7 @@
 			uniforms.pop_back();

 		}

 

+		uniformBlocks.clear();

 		uniformIndex.clear();

 		transformFeedbackLinkedVaryings.clear();

 

@@ -2571,7 +2778,7 @@
 		case GL_UNIFORM_TYPE:         return static_cast<GLint>(uniform.type);

 		case GL_UNIFORM_SIZE:         return static_cast<GLint>(uniform.size());

 		case GL_UNIFORM_NAME_LENGTH:  return static_cast<GLint>(uniform.name.size() + 1 + (uniform.isArray() ? 3 : 0));

-		case GL_UNIFORM_BLOCK_INDEX:  return uniform.blockIndex;

+		case GL_UNIFORM_BLOCK_INDEX:  return uniform.blockInfo.index;

 		case GL_UNIFORM_OFFSET:       return uniform.blockInfo.offset;

 		case GL_UNIFORM_ARRAY_STRIDE: return uniform.blockInfo.arrayStride;

 		case GL_UNIFORM_MATRIX_STRIDE: return uniform.blockInfo.matrixStride;

@@ -2587,7 +2794,7 @@
 	{

 		ASSERT(index < getActiveUniformBlockCount());

 

-		const UniformBlock &uniformBlock = *uniformBlocks[index];

+		const UniformBlock &uniformBlock = uniformBlocks[index];

 

 		if(bufSize > 0)

 		{

@@ -2624,7 +2831,7 @@
 			unsigned int numUniformBlocks = getActiveUniformBlockCount();

 			for(unsigned int uniformBlockIndex = 0; uniformBlockIndex < numUniformBlocks; uniformBlockIndex++)

 			{

-				const UniformBlock &uniformBlock = *uniformBlocks[uniformBlockIndex];

+				const UniformBlock &uniformBlock = uniformBlocks[uniformBlockIndex];

 				if(!uniformBlock.name.empty())

 				{

 					const int length = uniformBlock.name.length() + 1;

diff --git a/src/OpenGL/libGLESv2/Program.h b/src/OpenGL/libGLESv2/Program.h
index 48d691d..20ee05b 100644
--- a/src/OpenGL/libGLESv2/Program.h
+++ b/src/OpenGL/libGLESv2/Program.h
@@ -34,17 +34,11 @@
 	// Helper struct representing a single shader uniform

 	struct Uniform

 	{

-		struct BlockMemberInfo

+		struct BlockInfo

 		{

-			BlockMemberInfo(int offset, int arrayStride, int matrixStride, bool isRowMajorMatrix)

-			: offset(offset), arrayStride(arrayStride), matrixStride(matrixStride), isRowMajorMatrix(isRowMajorMatrix)

-			{}

+			BlockInfo(const glsl::Uniform& uniform, int blockIndex, bool rowMajorLayout);

 

-			static BlockMemberInfo getDefaultBlockInfo()

-			{

-				return BlockMemberInfo(-1, -1, -1, false);

-			}

-

+			int index;

 			int offset;

 			int arrayStride;

 			int matrixStride;

@@ -52,7 +46,7 @@
 		};

 

 		Uniform(GLenum type, GLenum precision, const std::string &name, unsigned int arraySize,

-		        const int blockIndex, const BlockMemberInfo &blockInfo);

+		        const BlockInfo &blockInfo);

 

 		~Uniform();

 

@@ -64,8 +58,7 @@
 		const GLenum precision;

 		const std::string name;

 		const unsigned int arraySize;

-		const int blockIndex;

-		const BlockMemberInfo blockInfo;

+		const BlockInfo blockInfo;

 

 		unsigned char *data;

 		bool dirty;

@@ -78,7 +71,12 @@
 	struct UniformBlock

 	{

 		// use GL_INVALID_INDEX for non-array elements

-		UniformBlock(const std::string &name, unsigned int elementIndex, unsigned int dataSize);

+		UniformBlock(const std::string &name, unsigned int elementIndex, unsigned int dataSize, std::vector<unsigned int> memberUniformIndexes);

+

+		void setRegisterIndex(GLenum shader, unsigned int registerIndex);

+

+		// For std::find on UniformBlockArray

+		inline bool operator==(const UniformBlock& other) const { return name == other.name; }

 

 		bool isArrayElement() const;

 		bool isReferencedByVertexShader() const;

@@ -172,6 +170,7 @@
 

 		void dirtyAllUniforms();

 		void applyUniforms();

+		void applyUniformBuffers();

 

 		void link();

 		bool isLinked() const;

@@ -225,7 +224,10 @@
 		int getAttributeBinding(const glsl::Attribute &attribute);

 

 		bool linkUniforms(const Shader *shader);

-		bool defineUniform(GLenum shader, GLenum type, GLenum precision, const std::string &_name, unsigned int arraySize, int registerIndex);

+		bool linkUniformBlocks(const Shader *vertexShader, const Shader *fragmentShader);

+		bool areMatchingUniformBlocks(const glsl::UniformBlock &block1, const glsl::UniformBlock &block2, const Shader *shader1, const Shader *shader2);

+		bool defineUniform(GLenum shader, GLenum type, GLenum precision, const std::string &_name, unsigned int arraySize, int registerIndex, const Uniform::BlockInfo& blockInfo);

+		bool defineUniformBlock(const Shader *shader, const glsl::UniformBlock &block);

 		bool applyUniform1bv(GLint location, GLsizei count, const GLboolean *v);

 		bool applyUniform2bv(GLint location, GLsizei count, const GLboolean *v);

 		bool applyUniform3bv(GLint location, GLsizei count, const GLboolean *v);

@@ -293,7 +295,7 @@
 		UniformArray uniforms;

 		typedef std::vector<UniformLocation> UniformIndex;

 		UniformIndex uniformIndex;

-		typedef std::vector<UniformBlock*> UniformBlockArray;

+		typedef std::vector<UniformBlock> UniformBlockArray;

 		UniformBlockArray uniformBlocks;

 		typedef std::vector<LinkedVarying> LinkedVaryingArray;

 		LinkedVaryingArray transformFeedbackLinkedVaryings;