Prechádzať zdrojové kódy

New GL parameter system actually works!

Marko Pintera 13 rokov pred
rodič
commit
e53164ef4c

+ 20 - 14
CamelotClient/CamelotClient.cpp

@@ -96,23 +96,29 @@ int _tmain(int argc, _TCHAR* argv[])
 	//vertProg =  HighLevelGpuProgram::create(vertShaderCode, "vs_main", "cg", GPT_VERTEX_PROGRAM, GPP_VS_2_0);
 	//vertProg =  HighLevelGpuProgram::create(vertShaderCode, "vs_main", "cg", GPT_VERTEX_PROGRAM, GPP_VS_2_0);
 
 
 	///////////////// GLSL SHADERS ////////////////////////////
 	///////////////// GLSL SHADERS ////////////////////////////
-	String fragShaderCode = "uniform sampler2D tex; \
-								void main() \
-								  {\
-								  vec4 texColor = texture2D(tex,gl_TexCoord[0].st);\
-								  gl_FragColor = texColor; \
-								  }";
+	String fragShaderCode = " #version 330 \n \
+							  uniform sampler2D tex; \
+							  in vec2 texcoord0; \
+							  out vec4 fragColor; \
+							  void main() \
+							  {\
+								  vec4 texColor = texture2D(tex, texcoord0.st);\
+								  fragColor = texColor; \
+							  }";
 
 
 	fragProg = HighLevelGpuProgram::create(fragShaderCode, "main", "glsl", GPT_FRAGMENT_PROGRAM, GPP_PS_2_0);
 	fragProg = HighLevelGpuProgram::create(fragShaderCode, "main", "glsl", GPT_FRAGMENT_PROGRAM, GPP_PS_2_0);
 
 
-	// TODO - Ogres GLSL parsing requires some strict parameter naming, can that be avoided?
-	String vertShaderCode = "uniform mat4 matViewProjection; \
-								  attribute vec4 vertex; \
-							void main() \
-								  { \
-								  gl_TexCoord[0] = gl_MultiTexCoord0; \
-								  gl_Position = matViewProjection * vertex; \
-								  }";
+	// TODO - Make sure to document the strict input parameter naming. (Exact supported names are in GLSLParamParser)
+	String vertShaderCode = "#version 330 \n \
+							 uniform mat4 matViewProjection; \
+							 in vec4 cm_position; \
+							 in vec2 cm_texcoord0; \
+							 out vec2 texcoord0; \
+							 void main() \
+							 { \
+								texcoord0 = cm_texcoord0; \
+								gl_Position = matViewProjection * cm_position; \
+							 }";
 
 
 	vertProg = HighLevelGpuProgram::create(vertShaderCode, "main", "glsl", GPT_VERTEX_PROGRAM, GPP_VS_2_0);
 	vertProg = HighLevelGpuProgram::create(vertShaderCode, "main", "glsl", GPT_VERTEX_PROGRAM, GPP_VS_2_0);
 
 

+ 2 - 0
CamelotGLRenderer/CamelotGLRenderer.vcxproj

@@ -178,6 +178,7 @@
     <ClInclude Include="Source\GLSL\include\CmGLSLPreprocessor.h" />
     <ClInclude Include="Source\GLSL\include\CmGLSLPreprocessor.h" />
     <ClInclude Include="Source\GLSL\include\CmGLSLProgram.h" />
     <ClInclude Include="Source\GLSL\include\CmGLSLProgram.h" />
     <ClInclude Include="Source\GLSL\include\CmGLSLProgramFactory.h" />
     <ClInclude Include="Source\GLSL\include\CmGLSLProgramFactory.h" />
+    <ClInclude Include="Source\GLSL\include\CmGLSLProgramPipelineManager.h" />
     <ClInclude Include="Source\win32\CmGLUtil.h" />
     <ClInclude Include="Source\win32\CmGLUtil.h" />
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
@@ -209,6 +210,7 @@
     <ClCompile Include="Source\GLSL\src\CmGLSLPreprocessor.cpp" />
     <ClCompile Include="Source\GLSL\src\CmGLSLPreprocessor.cpp" />
     <ClCompile Include="Source\GLSL\src\CmGLSLProgram.cpp" />
     <ClCompile Include="Source\GLSL\src\CmGLSLProgram.cpp" />
     <ClCompile Include="Source\GLSL\src\CmGLSLProgramFactory.cpp" />
     <ClCompile Include="Source\GLSL\src\CmGLSLProgramFactory.cpp" />
+    <ClCompile Include="Source\GLSL\src\CmGLSLProgramPipelineManager.cpp" />
     <ClCompile Include="Source\win32\CmWin32Context.cpp" />
     <ClCompile Include="Source\win32\CmWin32Context.cpp" />
   </ItemGroup>
   </ItemGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

+ 6 - 0
CamelotGLRenderer/CamelotGLRenderer.vcxproj.filters

@@ -120,6 +120,9 @@
     <ClInclude Include="Source\GLSL\include\CmGLSLParamParser.h">
     <ClInclude Include="Source\GLSL\include\CmGLSLParamParser.h">
       <Filter>Header Files</Filter>
       <Filter>Header Files</Filter>
     </ClInclude>
     </ClInclude>
+    <ClInclude Include="Source\GLSL\include\CmGLSLProgramPipelineManager.h">
+      <Filter>GLSL</Filter>
+    </ClInclude>
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\GLSL\src\CmGLSLExtSupport.cpp">
     <ClCompile Include="Source\GLSL\src\CmGLSLExtSupport.cpp">
@@ -209,5 +212,8 @@
     <ClCompile Include="Source\CmGLGpuParamBlock.cpp">
     <ClCompile Include="Source\CmGLGpuParamBlock.cpp">
       <Filter>Source Files</Filter>
       <Filter>Source Files</Filter>
     </ClCompile>
     </ClCompile>
+    <ClCompile Include="Source\GLSL\src\CmGLSLProgramPipelineManager.cpp">
+      <Filter>GLSL</Filter>
+    </ClCompile>
   </ItemGroup>
   </ItemGroup>
 </Project>
 </Project>

+ 3 - 1
CamelotGLRenderer/Include/CmGLPrerequisites.h

@@ -36,12 +36,14 @@ namespace CamelotEngine {
     class GLRenderSystem;
     class GLRenderSystem;
     class GLTexture;
     class GLTexture;
     class GLTextureManager;
     class GLTextureManager;
-    class GLGpuProgram;
+    class GLSLGpuProgram;
     class GLContext;
     class GLContext;
     class GLRTTManager;
     class GLRTTManager;
     class GLHardwarePixelBuffer;
     class GLHardwarePixelBuffer;
     class GLRenderBuffer;
     class GLRenderBuffer;
 	class GLGpuParamBlock;
 	class GLGpuParamBlock;
+	struct GLSLProgramPipeline;
+	class GLSLProgramPipelineManager;
 
 
 	typedef std::shared_ptr<GLHardwarePixelBuffer> GLHardwarePixelBufferPtr;
 	typedef std::shared_ptr<GLHardwarePixelBuffer> GLHardwarePixelBufferPtr;
 	typedef std::shared_ptr<GLRenderBuffer> GLRenderBufferPtr;
 	typedef std::shared_ptr<GLRenderBuffer> GLRenderBufferPtr;

+ 3 - 0
CamelotGLRenderer/Include/CmGLRenderSystem.h

@@ -243,6 +243,7 @@ namespace CamelotEngine {
 
 
 		GLSLProgramFactory* mGLSLProgramFactory;
 		GLSLProgramFactory* mGLSLProgramFactory;
 		CgProgramFactory* mCgProgramFactory;
 		CgProgramFactory* mCgProgramFactory;
+		GLSLProgramPipelineManager* mProgramPipelineManager;
 
 
         GLuint getCombinedMinMipFilter(void) const;
         GLuint getCombinedMinMipFilter(void) const;
 
 
@@ -252,6 +253,8 @@ namespace CamelotEngine {
 		GLSLGpuProgram* mCurrentHullProgram;
 		GLSLGpuProgram* mCurrentHullProgram;
 		GLSLGpuProgram* mCurrentDomainProgram;
 		GLSLGpuProgram* mCurrentDomainProgram;
 
 
+		const GLSLProgramPipeline* mActivePipeline;
+
 		UINT32 mFragmentTexOffset;
 		UINT32 mFragmentTexOffset;
 		UINT32 mVertexTexOffset;
 		UINT32 mVertexTexOffset;
 		UINT32 mGeometryTexOffset;
 		UINT32 mGeometryTexOffset;

+ 2 - 1
CamelotGLRenderer/Source/CmGLHardwareBufferManager.cpp

@@ -29,6 +29,7 @@ THE SOFTWARE.
 #include "CmGLHardwareVertexBuffer.h"
 #include "CmGLHardwareVertexBuffer.h"
 #include "CmGLHardwareIndexBuffer.h"
 #include "CmGLHardwareIndexBuffer.h"
 #include "CmHardwareBuffer.h"
 #include "CmHardwareBuffer.h"
+#include "CmGLGpuParamBlock.h"
 #include "CmRenderSystem.h"
 #include "CmRenderSystem.h"
 #include "CmRenderSystemCapabilities.h"
 #include "CmRenderSystemCapabilities.h"
 
 
@@ -106,7 +107,7 @@ namespace CamelotEngine {
 	//---------------------------------------------------------------------
 	//---------------------------------------------------------------------
 	GpuParamBlockPtr GLHardwareBufferManagerBase::createGpuParamBlock(const GpuParamBlockDesc& paramDesc)
 	GpuParamBlockPtr GLHardwareBufferManagerBase::createGpuParamBlock(const GpuParamBlockDesc& paramDesc)
 	{
 	{
-		return GpuParamBlockPtr(new GpuParamBlock(paramDesc));
+		return GpuParamBlockPtr(new GLGpuParamBlock(paramDesc));
 	}
 	}
     //---------------------------------------------------------------------
     //---------------------------------------------------------------------
     GLenum GLHardwareBufferManagerBase::getGLUsage(unsigned int usage)
     GLenum GLHardwareBufferManagerBase::getGLUsage(unsigned int usage)

+ 70 - 56
CamelotGLRenderer/Source/CmGLRenderSystem.cpp

@@ -47,6 +47,7 @@ THE SOFTWARE.s
 #include "CmDepthStencilState.h"
 #include "CmDepthStencilState.h"
 #include "CmGLRenderTexture.h"
 #include "CmGLRenderTexture.h"
 #include "CmGLRenderWindowManager.h"
 #include "CmGLRenderWindowManager.h"
+#include "CmGLSLProgramPipelineManager.h"
 #include "CmGpuParams.h"
 #include "CmGpuParams.h"
 #include "CmDebug.h"
 #include "CmDebug.h"
 
 
@@ -71,8 +72,10 @@ namespace CamelotEngine
 
 
 	GLRenderSystem::GLRenderSystem()
 	GLRenderSystem::GLRenderSystem()
 		: mDepthWrite(true),
 		: mDepthWrite(true),
-		mGLSLProgramFactory(0),
-		mCgProgramFactory(0),
+		mGLSLProgramFactory(nullptr),
+		mCgProgramFactory(nullptr),
+		mProgramPipelineManager(nullptr),
+		mActivePipeline(nullptr),
 		mActiveTextureUnit(0),
 		mActiveTextureUnit(0),
 		mScissorTop(0), mScissorBottom(720), mScissorLeft(0), mScissorRight(1280),
 		mScissorTop(0), mScissorBottom(720), mScissorLeft(0), mScissorRight(1280),
 		mStencilReadMask(0xFFFFFFFF),
 		mStencilReadMask(0xFFFFFFFF),
@@ -105,12 +108,17 @@ namespace CamelotEngine
 		mCurrentFragmentProgram = nullptr;
 		mCurrentFragmentProgram = nullptr;
 		mCurrentHullProgram = nullptr;
 		mCurrentHullProgram = nullptr;
 		mCurrentDomainProgram = nullptr;
 		mCurrentDomainProgram = nullptr;
+
+		mProgramPipelineManager = new GLSLProgramPipelineManager();
 	}
 	}
 
 
 	GLRenderSystem::~GLRenderSystem()
 	GLRenderSystem::~GLRenderSystem()
 	{
 	{
 		destroy_internal();
 		destroy_internal();
 
 
+		if(mProgramPipelineManager != nullptr)
+			delete mProgramPipelineManager;
+
 		// Destroy render windows
 		// Destroy render windows
 		for (auto i = mRenderTargets.begin(); i != mRenderTargets.end(); ++i)
 		for (auto i = mRenderTargets.begin(); i != mRenderTargets.end(); ++i)
 		{
 		{
@@ -384,6 +392,8 @@ namespace CamelotEngine
 			}
 			}
 			else
 			else
 			{
 			{
+
+
 				CM_EXCEPT(NotImplementedException, "Support for uniform blocks not implemented yet");
 				CM_EXCEPT(NotImplementedException, "Support for uniform blocks not implemented yet");
 			}
 			}
 		}
 		}
@@ -615,12 +625,24 @@ namespace CamelotEngine
 	{
 	{
 		THROW_IF_NOT_RENDER_THREAD;
 		THROW_IF_NOT_RENDER_THREAD;
 
 
-		// TODO - Generate pipeline and bind program
+		const GLSLProgramPipeline* pipeline = mProgramPipelineManager->getPipeline(mCurrentVertexProgram, 
+			mCurrentFragmentProgram, mCurrentGeometryProgram, mCurrentHullProgram, mCurrentDomainProgram);
 
 
+		if(mActivePipeline != pipeline)
+		{
+			glBindProgramPipeline(pipeline->glHandle);
+			mActivePipeline = pipeline;
+		}
 
 
 		// Call super class
 		// Call super class
 		RenderSystem::render(op);
 		RenderSystem::render(op);
 
 
+		if(mCurrentVertexProgram == nullptr)
+		{
+			LOGWRN("Cannot render without a set vertex shader.");
+			return;
+		}
+
 		void* pBufferData = 0;
 		void* pBufferData = 0;
 
 
         const VertexDeclaration::VertexElementList& decl = op.vertexData->vertexDeclaration->getElements();
         const VertexDeclaration::VertexElementList& decl = op.vertexData->vertexDeclaration->getElements();
@@ -628,15 +650,33 @@ namespace CamelotEngine
         elemEnd = decl.end();
         elemEnd = decl.end();
 		vector<GLuint>::type attribsBound;
 		vector<GLuint>::type attribsBound;
 
 
+		const VertexDeclaration::VertexElementList& inputAttributes = mCurrentVertexProgram->getGLSLProgram()->getInputAttributes().getElements();
+
 		for (elem = decl.begin(); elem != elemEnd; ++elem)
 		for (elem = decl.begin(); elem != elemEnd; ++elem)
 		{
 		{
 			if (!op.vertexData->vertexBufferBinding->isBufferBound(elem->getSource()))
 			if (!op.vertexData->vertexBufferBinding->isBufferBound(elem->getSource()))
 				continue; // skip unbound elements
 				continue; // skip unbound elements
 
 
-			HardwareVertexBufferPtr vertexBuffer = 
-				op.vertexData->vertexBufferBinding->getBuffer(elem->getSource());
+			bool foundSemantic = false; 
+			GLint attribLocation = 0;
+			for(auto iter = inputAttributes.begin(); iter != inputAttributes.end(); ++iter)
+			{
+				if(iter->getSemantic() == elem->getSemantic() && iter->getIndex() == elem->getIndex())
+				{
+					foundSemantic = true;
+					attribLocation = iter->getOffset();
+					break;
+				}
+			}
+
+			if(!foundSemantic) // Shader needs to have a matching input attribute, otherwise we skip it
+				continue;
+
+			// TODO - We might also want to check the size of input and buffer, and make sure they match? Or does OpenGL handle that internally?
+
+			HardwareVertexBufferPtr vertexBuffer = op.vertexData->vertexBufferBinding->getBuffer(elem->getSource());
 
 
-			glBindBufferARB(GL_ARRAY_BUFFER_ARB, static_cast<const GLHardwareVertexBuffer*>(vertexBuffer.get())->getGLBufferId());
+			glBindBuffer(GL_ARRAY_BUFFER, static_cast<const GLHardwareVertexBuffer*>(vertexBuffer.get())->getGLBufferId());
 			pBufferData = VBO_BUFFER_OFFSET(elem->getOffset());
 			pBufferData = VBO_BUFFER_OFFSET(elem->getOffset());
 
 
 			if (op.vertexData->vertexStart)
 			if (op.vertexData->vertexStart)
@@ -647,55 +687,30 @@ namespace CamelotEngine
 			unsigned int i = 0;
 			unsigned int i = 0;
 			VertexElementSemantic sem = elem->getSemantic();
 			VertexElementSemantic sem = elem->getSemantic();
 
 
+			unsigned short typeCount = VertexElement::getTypeCount(elem->getType());
+			GLboolean normalised = GL_FALSE;
+			switch(elem->getType())
+			{
+			case VET_COLOR:
+			case VET_COLOR_ABGR:
+			case VET_COLOR_ARGB:
+				normalised = GL_TRUE;
+				break;
+			default:
+				break;
+			};
 
 
+			glVertexAttribPointerARB(
+				attribLocation,
+				typeCount, 
+				GLHardwareBufferManager::getGLType(elem->getType()), 
+				normalised, 
+				static_cast<GLsizei>(vertexBuffer->getVertexSize()), 
+				pBufferData);
 
 
+			glEnableVertexAttribArray(attribLocation);
 
 
-
-			// TODO - Vertex elem not set
-			
-
-
-
-
-
- 			//bool isCustomAttrib = false;
- 			//if (mCurrentVertexProgram)
- 			//	isCustomAttrib = mCurrentVertexProgram->isAttributeValid(sem, elem->getIndex());
- 
- 			//// Custom attribute support
- 			//// tangents, binormals, blendweights etc always via this route
- 			//// builtins may be done this way too
- 			//if (isCustomAttrib)
- 			//{
- 			//	GLint attrib = mCurrentVertexProgram->getAttributeIndex(sem, elem->getIndex());
-				//unsigned short typeCount = VertexElement::getTypeCount(elem->getType());
-				//GLboolean normalised = GL_FALSE;
-				//switch(elem->getType())
-				//{
-				//case VET_COLOR:
-				//case VET_COLOR_ABGR:
-				//case VET_COLOR_ARGB:
-				//	// Because GL takes these as a sequence of single unsigned bytes, count needs to be 4
-				//	// VertexElement::getTypeCount treats them as 1 (RGBA)
-				//	// Also need to normalise the fixed-point data
-				//	typeCount = 4;
-				//	normalised = GL_TRUE;
-				//	break;
-				//default:
-				//	break;
-				//};
-
- 			//	glVertexAttribPointerARB(
- 			//		attrib,
- 			//		typeCount, 
-  		//			GLHardwareBufferManager::getGLType(elem->getType()), 
- 			//		normalised, 
-  		//			static_cast<GLsizei>(vertexBuffer->getVertexSize()), 
-  		//			pBufferData);
- 			//	glEnableVertexAttribArrayARB(attrib);
- 
- 			//	attribsBound.push_back(attrib);
- 			//}
+			attribsBound.push_back(attribLocation);
         }
         }
 
 
 		// Find the correct type to render
 		// Find the correct type to render
@@ -727,12 +742,11 @@ namespace CamelotEngine
 
 
 		if (op.useIndexes)
 		if (op.useIndexes)
 		{
 		{
-			glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 
+			glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 
 				static_cast<GLHardwareIndexBuffer*>(
 				static_cast<GLHardwareIndexBuffer*>(
 				op.indexData->indexBuffer.get())->getGLBufferId());
 				op.indexData->indexBuffer.get())->getGLBufferId());
 
 
-			pBufferData = VBO_BUFFER_OFFSET(
-				op.indexData->indexStart * op.indexData->indexBuffer->getIndexSize());
+			pBufferData = VBO_BUFFER_OFFSET(op.indexData->indexStart * op.indexData->indexBuffer->getIndexSize());
 
 
 			GLenum indexType = (op.indexData->indexBuffer->getType() == HardwareIndexBuffer::IT_16BIT) ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT;
 			GLenum indexType = (op.indexData->indexBuffer->getType() == HardwareIndexBuffer::IT_16BIT) ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT;
 
 
@@ -746,7 +760,7 @@ namespace CamelotEngine
  		// unbind any custom attributes
  		// unbind any custom attributes
 		for (vector<GLuint>::type::iterator ai = attribsBound.begin(); ai != attribsBound.end(); ++ai)
 		for (vector<GLuint>::type::iterator ai = attribsBound.begin(); ai != attribsBound.end(); ++ai)
  		{
  		{
- 			glDisableVertexAttribArrayARB(*ai); 
+ 			glDisableVertexAttribArray(*ai); 
   		}
   		}
 		
 		
 		glColor4f(1,1,1,1);
 		glColor4f(1,1,1,1);

+ 2 - 2
CamelotGLRenderer/Source/GLSL/include/CmGLSLExtSupport.h

@@ -64,13 +64,13 @@ namespace CamelotEngine
 	@param msg the info log message string is appended to this string
 	@param msg the info log message string is appended to this string
 	@param obj the GL shader object that is used to retrieve the info log
 	@param obj the GL shader object that is used to retrieve the info log
 	*/
 	*/
-	String logShaderInfo(const String& msg, const GLuint obj);
+	bool logShaderInfo(String& msg, const GLuint obj);
 
 
 	/** if there is a message in GL info log then post it in the engine Log
 	/** if there is a message in GL info log then post it in the engine Log
 	@param msg the info log message string is appended to this string
 	@param msg the info log message string is appended to this string
 	@param obj the GL program object that is used to retrieve the info log
 	@param obj the GL program object that is used to retrieve the info log
 	*/
 	*/
-	String logProgramInfo(const String& msg, const GLuint obj);
+	bool logProgramInfo(String& msg, const GLuint obj);
 
 
 
 
 } // namespace CamelotEngine
 } // namespace CamelotEngine

+ 31 - 17
CamelotGLRenderer/Source/GLSL/include/CmGLSLParamParser.h

@@ -29,7 +29,7 @@ namespace CamelotEngine
 			if(name.substr(0, mName.length()) == mName)
 			if(name.substr(0, mName.length()) == mName)
 			{
 			{
 				String indexStr = name.substr(mName.length(), name.length());
 				String indexStr = name.substr(mName.length(), name.length());
-				return parseUnsignedInt(indexStr, -1);
+				return parseUnsignedInt(indexStr, 0);
 			}
 			}
 		}
 		}
 
 
@@ -64,7 +64,6 @@ namespace CamelotEngine
 		glGetProgramiv(glProgram, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxNameSize);
 		glGetProgramiv(glProgram, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxNameSize);
 
 
 		GLchar* attributeName = new GLchar[maxNameSize];
 		GLchar* attributeName = new GLchar[maxNameSize];
-		UINT32 offset = 0;
 
 
 		for(GLint i = 0; i < numAttributes; i++)
 		for(GLint i = 0; i < numAttributes; i++)
 		{
 		{
@@ -78,8 +77,7 @@ namespace CamelotEngine
 			{
 			{
 				VertexElementType type = glTypeToAttributeType(attribType);
 				VertexElementType type = glTypeToAttributeType(attribType);
 
 
-				declaration.addElement(index, offset, type, semantic, index);
-				offset += attribSize;
+				declaration.addElement(0, i, type, semantic, index);
 			}
 			}
 			else
 			else
 			{
 			{
@@ -111,14 +109,14 @@ namespace CamelotEngine
 	{
 	{
 		static GLSLAttribute attributes[] = 
 		static GLSLAttribute attributes[] = 
 		{
 		{
-			GLSLAttribute("position", VES_POSITION),
-			GLSLAttribute("normal", VES_NORMAL),
-			GLSLAttribute("tangent", VES_TANGENT),
-			GLSLAttribute("bitangent", VES_BITANGENT),
-			GLSLAttribute("texcoord", VES_TEXCOORD),
-			GLSLAttribute("color", VES_COLOR),
-			GLSLAttribute("blendweights", VES_BLEND_WEIGHTS),
-			GLSLAttribute("blendindices", VES_BLEND_INDICES)
+			GLSLAttribute("cm_position", VES_POSITION),
+			GLSLAttribute("cm_normal", VES_NORMAL),
+			GLSLAttribute("cm_tangent", VES_TANGENT),
+			GLSLAttribute("cm_bitangent", VES_BITANGENT),
+			GLSLAttribute("cm_texcoord", VES_TEXCOORD),
+			GLSLAttribute("cm_color", VES_COLOR),
+			GLSLAttribute("cm_blendweights", VES_BLEND_WEIGHTS),
+			GLSLAttribute("cm_blendindices", VES_BLEND_INDICES)
 		};
 		};
 
 
 		static const UINT32 numAttribs = sizeof(attributes) / sizeof(attributes[0]);
 		static const UINT32 numAttribs = sizeof(attributes) / sizeof(attributes[0]);
@@ -151,14 +149,15 @@ namespace CamelotEngine
 
 
 		GLchar* uniformName = new GLchar[maxBufferSize];
 		GLchar* uniformName = new GLchar[maxBufferSize];
 
 
-		GpuParamBlockDesc globalBlockDesc;
-		globalBlockDesc.slot = 0;
-		globalBlockDesc.name = "CM_INTERNAL_Globals";
-		globalBlockDesc.blockSize = 0;
+		GpuParamBlockDesc newGlobalBlockDesc;
+		newGlobalBlockDesc.slot = 0;
+		newGlobalBlockDesc.name = "CM_INTERNAL_Globals";
+		newGlobalBlockDesc.blockSize = 0;
 
 
 		UINT32 textureSlot = 0;
 		UINT32 textureSlot = 0;
 
 
-		returnParamDesc.paramBlocks[globalBlockDesc.name] = globalBlockDesc;
+		returnParamDesc.paramBlocks[newGlobalBlockDesc.name] = newGlobalBlockDesc;
+		GpuParamBlockDesc& globalBlockDesc = returnParamDesc.paramBlocks[newGlobalBlockDesc.name];
 
 
 		GLint uniformBlockCount = 0;
 		GLint uniformBlockCount = 0;
 		glGetProgramiv(glProgram, GL_ACTIVE_UNIFORM_BLOCKS, &uniformBlockCount);
 		glGetProgramiv(glProgram, GL_ACTIVE_UNIFORM_BLOCKS, &uniformBlockCount);
@@ -289,6 +288,21 @@ namespace CamelotEngine
 			}
 			}
 		}
 		}
 
 
+#if CM_DEBUG_MODE
+		// Check if manually calculated and OpenGL buffer sizes match
+		for(auto iter = returnParamDesc.paramBlocks.begin(); iter != returnParamDesc.paramBlocks.end(); ++iter)
+		{
+			if(iter->second.slot == 0)
+				continue;
+
+			GLint blockSize = 0;
+			glGetActiveUniformBlockiv(glProgram, iter->second.slot - 1, GL_UNIFORM_BLOCK_DATA_SIZE, &blockSize);
+
+			if(iter->second.blockSize != blockSize)
+				CM_EXCEPT(InternalErrorException, "OpenGL specified and manual uniform block buffer sizes don't match!");
+		}
+#endif
+
 		delete[] uniformName;
 		delete[] uniformName;
 	}
 	}
 
 

+ 2 - 0
CamelotGLRenderer/Source/GLSL/include/CmGLSLProgram.h

@@ -96,6 +96,8 @@ namespace CamelotEngine {
 		virtual void setMaxOutputVertices(int maxOutputVertices) 
 		virtual void setMaxOutputVertices(int maxOutputVertices) 
 		{ mMaxOutputVertices = maxOutputVertices; }
 		{ mMaxOutputVertices = maxOutputVertices; }
 
 
+		const VertexDeclaration& getInputAttributes() const { return mVertexDeclaration; }
+
 	protected:
 	protected:
 		friend class GLSLProgramFactory;
 		friend class GLSLProgramFactory;
 
 

+ 43 - 0
CamelotGLRenderer/Source/GLSL/include/CmGLSLProgramPipelineManager.h

@@ -0,0 +1,43 @@
+#pragma once
+
+#include "CmGLPrerequisites.h"
+
+namespace CamelotEngine
+{
+	struct GLSLProgramPipeline
+	{
+		GLuint glHandle;
+	};
+
+	class GLSLProgramPipelineManager
+	{
+	public:
+		const GLSLProgramPipeline* getPipeline(GLSLGpuProgram* vertexProgram, GLSLGpuProgram* fragmentProgram, 
+			GLSLGpuProgram* geometryProgram, GLSLGpuProgram* hullProgram, GLSLGpuProgram* domainProgram);
+
+	private:
+		struct ProgramPipelineKey
+		{
+			UINT32 vertexProgKey;
+			UINT32 fragmentProgKey;
+			UINT32 geometryProgKey;
+			UINT32 hullProgKey;
+			UINT32 domainProgKey;
+		};
+
+		class ProgramPipelineKeyHashFunction 
+		{
+		public:
+			::std::size_t operator()(const ProgramPipelineKey &key) const;
+		};
+
+		class ProgramPipelineKeyEqual 
+		{
+		public:
+			bool operator()(const ProgramPipelineKey &a, const ProgramPipelineKey &b) const;
+		};
+
+		typedef std::unordered_map<ProgramPipelineKey, GLSLProgramPipeline, ProgramPipelineKeyHashFunction, ProgramPipelineKeyEqual> ProgramPipelineMap;
+		ProgramPipelineMap mPipelines;
+	};
+}

+ 22 - 10
CamelotGLRenderer/Source/GLSL/src/CmGLSLExtSupport.cpp

@@ -57,10 +57,11 @@ namespace CamelotEngine
 		if (errorsFound || forceInfoLog)
 		if (errorsFound || forceInfoLog)
 		{
 		{
 			// if shader or program object then get the log message and send to the log manager
 			// if shader or program object then get the log message and send to the log manager
+			bool infoLogMessageExists = false;
 			if(objectType == GLSLOT_SHADER)
 			if(objectType == GLSLOT_SHADER)
-				msg += logShaderInfo(msg, obj);
+				infoLogMessageExists = logShaderInfo(msg, obj);
 			else if(objectType == GLSLOT_PROGRAM)
 			else if(objectType == GLSLOT_PROGRAM)
-				msg += logProgramInfo(msg, obj);
+				infoLogMessageExists = logProgramInfo(msg, obj);
 
 
             if (forceException) 
             if (forceException) 
 			{
 			{
@@ -68,12 +69,19 @@ namespace CamelotEngine
 			}
 			}
 			else
 			else
 			{
 			{
-				LOGWRN(msg);
+				if(errorsFound)
+				{
+					LOGWRN(msg);
+				}
+				else if(infoLogMessageExists)
+				{
+					LOGINFO(msg);
+				}
 			}
 			}
 		}
 		}
     }
     }
 
 
-	String logShaderInfo(const String& msg, const GLuint obj)
+	bool logShaderInfo(String& msg, const GLuint obj)
 	{
 	{
 		String logMessage = msg;
 		String logMessage = msg;
 
 
@@ -93,16 +101,17 @@ namespace CamelotEngine
 				logMessage += String(infoLog);
 				logMessage += String(infoLog);
 
 
 				delete [] infoLog;
 				delete [] infoLog;
+
+				if(charsWritten > 0)
+					return true;
 			}
 			}
 		}
 		}
 
 
-		return logMessage;
+		return false;
 	}
 	}
 
 
-	String logProgramInfo(const String& msg, const GLuint obj)
+	bool logProgramInfo(String& msg, const GLuint obj)
 	{
 	{
-		String logMessage = msg;
-
 		if (obj > 0)
 		if (obj > 0)
 		{
 		{
 			GLint infologLength = 0;
 			GLint infologLength = 0;
@@ -116,13 +125,16 @@ namespace CamelotEngine
 				GLchar* infoLog = new GLchar[infologLength];
 				GLchar* infoLog = new GLchar[infologLength];
 
 
 				glGetProgramInfoLog(obj, infologLength, &charsWritten, infoLog);
 				glGetProgramInfoLog(obj, infologLength, &charsWritten, infoLog);
-				logMessage += String(infoLog);
+				msg += String(infoLog);
 
 
 				delete [] infoLog;
 				delete [] infoLog;
+
+				if(charsWritten > 0)
+					return true;
 			}
 			}
 		}
 		}
 
 
-		return logMessage;
+		return false;
 	}
 	}
 
 
 } // namespace CamelotEngine
 } // namespace CamelotEngine

+ 1 - 1
CamelotGLRenderer/Source/GLSL/src/CmGLSLProgram.cpp

@@ -162,7 +162,7 @@ namespace CamelotEngine
 			const char *source = mSource.c_str();
 			const char *source = mSource.c_str();
 			mGLHandle = glCreateShaderProgramv(shaderType, 1, &source);
 			mGLHandle = glCreateShaderProgramv(shaderType, 1, &source);
 			// check for load errors
 			// check for load errors
-			checkForGLSLError( "GLSLProgram::loadFromSource", "Cannot load GLSL high-level shader source : ", 0, GLSLOT_PROGRAM);
+			checkForGLSLError( "GLSLProgram::loadFromSource", "Cannot load GLSL high-level shader source : ", mGLHandle, GLSLOT_PROGRAM, true);
 		}
 		}
 
 
 		mAssemblerProgram = GpuProgramPtr(new GLSLGpuProgram(this, mSource, mEntryPoint, mSyntaxCode, mType, mProfile));
 		mAssemblerProgram = GpuProgramPtr(new GLSLGpuProgram(this, mSource, mEntryPoint, mSyntaxCode, mType, mProfile));

+ 84 - 0
CamelotGLRenderer/Source/GLSL/src/CmGLSLProgramPipelineManager.cpp

@@ -0,0 +1,84 @@
+#include "CmGLSLProgramPipelineManager.h"
+#include "CmGLSLGpuProgram.h"
+#include "CmGLSLProgram.h"
+
+namespace CamelotEngine
+{
+	template <class T>
+	inline void hash_combine(std::size_t& seed, const T& v)
+	{
+		std::hash<T> hasher;
+		seed ^= hasher(v) + 0x9e3779b9 + (seed<<6) + (seed>>2);
+	}
+
+	::std::size_t GLSLProgramPipelineManager::ProgramPipelineKeyHashFunction::operator()
+		(const GLSLProgramPipelineManager::ProgramPipelineKey &key) const
+	{
+		std::size_t seed = 0;
+		hash_combine(seed, key.vertexProgKey);
+		hash_combine(seed, key.fragmentProgKey);
+		hash_combine(seed, key.geometryProgKey);
+		hash_combine(seed, key.hullProgKey);
+		hash_combine(seed, key.domainProgKey);
+
+		return seed;
+	}
+
+	bool GLSLProgramPipelineManager::ProgramPipelineKeyEqual::operator()
+		(const GLSLProgramPipelineManager::ProgramPipelineKey &a, const GLSLProgramPipelineManager::ProgramPipelineKey &b) const
+	{
+		return a.vertexProgKey == b.vertexProgKey && a.fragmentProgKey == b.fragmentProgKey && a.geometryProgKey == b.geometryProgKey &&
+			a.hullProgKey == b.hullProgKey && a.domainProgKey == b.domainProgKey;
+	}
+
+	const GLSLProgramPipeline* GLSLProgramPipelineManager::getPipeline(GLSLGpuProgram* vertexProgram, GLSLGpuProgram* fragmentProgram, 
+		GLSLGpuProgram* geometryProgram, GLSLGpuProgram* hullProgram, GLSLGpuProgram* domainProgram)
+	{
+		ProgramPipelineKey key;
+		key.vertexProgKey = vertexProgram != nullptr ? vertexProgram->getProgramID() : 0;
+		key.fragmentProgKey = fragmentProgram != nullptr ? fragmentProgram->getProgramID() : 0;
+		key.geometryProgKey = geometryProgram != nullptr ? geometryProgram->getProgramID() : 0;
+		key.hullProgKey = hullProgram != nullptr ? hullProgram->getProgramID() : 0;
+		key.domainProgKey = domainProgram != nullptr ? domainProgram->getProgramID() : 0;
+
+		auto iterFind = mPipelines.find(key);
+
+		if(iterFind == mPipelines.end())
+		{
+			GLSLProgramPipeline newPipeline;
+
+			glGenProgramPipelines(1, &newPipeline.glHandle);
+
+			if(vertexProgram != nullptr)
+			{
+				glUseProgramStages(newPipeline.glHandle, GL_VERTEX_SHADER_BIT, vertexProgram->getGLSLProgram()->getGLHandle());
+			}
+
+			if(fragmentProgram != nullptr)
+			{
+				glUseProgramStages(newPipeline.glHandle, GL_FRAGMENT_SHADER_BIT, fragmentProgram->getGLSLProgram()->getGLHandle());
+			}
+
+			if(geometryProgram != nullptr)
+			{
+				glUseProgramStages(newPipeline.glHandle, GL_GEOMETRY_SHADER_BIT, geometryProgram->getGLSLProgram()->getGLHandle());
+			}
+
+			if(hullProgram != nullptr)
+			{
+				glUseProgramStages(newPipeline.glHandle, GL_TESS_CONTROL_SHADER_BIT, hullProgram->getGLSLProgram()->getGLHandle());
+			}
+
+			if(domainProgram != nullptr)
+			{
+				glUseProgramStages(newPipeline.glHandle, GL_TESS_EVALUATION_SHADER_BIT, domainProgram->getGLSLProgram()->getGLHandle());
+			}
+
+			mPipelines[key] = newPipeline;
+
+			return &mPipelines[key];
+		}
+		else
+			return &iterFind->second;
+	}
+}

+ 1 - 1
CamelotRenderer/Source/CmVertexDeclaration.cpp

@@ -54,7 +54,7 @@ namespace CamelotEngine
 		case VET_COLOR:
 		case VET_COLOR:
 		case VET_COLOR_ABGR:
 		case VET_COLOR_ABGR:
 		case VET_COLOR_ARGB:
 		case VET_COLOR_ARGB:
-			return 1;
+			return 4;
 		case VET_FLOAT1:
 		case VET_FLOAT1:
 			return 1;
 			return 1;
 		case VET_FLOAT2:
 		case VET_FLOAT2:

+ 0 - 36
CamelotRenderer/TODO.txt

@@ -27,42 +27,6 @@ Assign vertex attributes
  - When rendering, compare mesh vertec decl and shader decl and use only overlapping attribs
  - When rendering, compare mesh vertec decl and shader decl and use only overlapping attribs
 Assign uniform buffers
 Assign uniform buffers
 
 
-LinkProgramKey key;
-key.vertexProgKey = mActiveVertexGpuProgram != nullptr ? mActiveVertexGpuProgram->getProgramID() : 0;
-key.fragmentProgKey = mActiveFragmentGpuProgram != nullptr ? mActiveFragmentGpuProgram->getProgramID() : 0;
-key.geometryProgKey = mActiveGeometryGpuProgram != nullptr ? mActiveGeometryGpuProgram->getProgramID() : 0;
-key.hullProgKey = mActiveHullGpuProgram != nullptr ? mActiveHullGpuProgram->getProgramID() : 0;
-key.domainProgKey = mActiveDomainGpuProgram != nullptr ? mActiveDomainGpuProgram->getProgramID() : 0;
-
-template <class T>
-inline void hash_combine(std::size_t& seed, const T& v)
-{
-	std::hash<T> hasher;
-	seed ^= hasher(v) + 0x9e3779b9 + (seed<<6) + (seed>>2);
-}
-
-::std::size_t GLSLLinkProgramManager::LinkProgramKeyHashFunction::operator()(const GLSLLinkProgramManager::LinkProgramKey &key) const
-{
-	std::size_t seed = 0;
-	hash_combine(seed, key.vertexProgKey);
-	hash_combine(seed, key.fragmentProgKey);
-	hash_combine(seed, key.geometryProgKey);
-	hash_combine(seed, key.hullProgKey);
-	hash_combine(seed, key.domainProgKey);
-
-	return seed;
-}
-
-bool GLSLLinkProgramManager::LinkProgramKeyEqual::operator()(const GLSLLinkProgramManager::LinkProgramKey &a, const GLSLLinkProgramManager::LinkProgramKey &b) const
-{
-	return a.vertexProgKey == b.vertexProgKey && a.fragmentProgKey == b.fragmentProgKey && a.geometryProgKey == b.geometryProgKey &&
-		a.hullProgKey == b.hullProgKey && a.domainProgKey == b.domainProgKey;
-}
-
-typedef std::unordered_map<LinkProgramKey, GLSLLinkProgram*, LinkProgramKeyHashFunction, LinkProgramKeyEqual> LinkProgramMap;
-
-
-
 
 
 
 
 Get through capabilities and remove bool/int/float constant counters and instead add uniform, uniform block, input/output component counters
 Get through capabilities and remove bool/int/float constant counters and instead add uniform, uniform block, input/output component counters

+ 1 - 1
CamelotUtility/Include/CmDebug.h

@@ -33,7 +33,7 @@ namespace CamelotEngine
 	}
 	}
 
 
 #define LOGDBG(x) CamelotEngine::gDebug().logDebug((x));
 #define LOGDBG(x) CamelotEngine::gDebug().logDebug((x));
-#define LOGMSG(x) CamelotEngine::gDebug().logInfo((x));
+#define LOGINFO(x) CamelotEngine::gDebug().logInfo((x));
 #define LOGWRN(x) CamelotEngine::gDebug().logWarning((x));
 #define LOGWRN(x) CamelotEngine::gDebug().logWarning((x));
 #define LOGERR(x) CamelotEngine::gDebug().logError((x));
 #define LOGERR(x) CamelotEngine::gDebug().logError((x));