1 /*
2  -----------------------------------------------------------------------------
3  This source file is part of OGRE
4  (Object-oriented Graphics Rendering Engine)
5  For the latest info, see http://www.ogre3d.org/
6 
7  Copyright (c) 2000-2013 Torus Knot Software Ltd
8 
9  Permission is hereby granted, free of charge, to any person obtaining a copy
10  of this software and associated documentation files (the "Software"), to deal
11  in the Software without restriction, including without limitation the rights
12  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13  copies of the Software, and to permit persons to whom the Software is
14  furnished to do so, subject to the following conditions:
15 
16  The above copyright notice and this permission notice shall be included in
17  all copies or substantial portions of the Software.
18 
19  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25  THE SOFTWARE.
26  -----------------------------------------------------------------------------
27  */
28 
29 #include "OgreGLSLESProgramPipeline.h"
30 #include "OgreStringConverter.h"
31 #include "OgreGLSLESGpuProgram.h"
32 #include "OgreGLSLESProgram.h"
33 #include "OgreGLSLESProgramPipelineManager.h"
34 #include "OgreGpuProgramManager.h"
35 #include "OgreGLES2RenderSystem.h"
36 #include "OgreGLES2UniformCache.h"
37 #include "OgreGLES2HardwareUniformBuffer.h"
38 #include "OgreHardwareBufferManager.h"
39 #include "OgreGLES2Util.h"
40 #include "OgreRoot.h"
41 
42 namespace Ogre
43 {
GLSLESProgramPipeline(GLSLESGpuProgram * vertexProgram,GLSLESGpuProgram * fragmentProgram)44     GLSLESProgramPipeline::GLSLESProgramPipeline(GLSLESGpuProgram* vertexProgram, GLSLESGpuProgram* fragmentProgram) :
45     GLSLESProgramCommon(vertexProgram, fragmentProgram) { }
46 
~GLSLESProgramPipeline()47     GLSLESProgramPipeline::~GLSLESProgramPipeline()
48     {
49 #if OGRE_PLATFORM != OGRE_PLATFORM_NACL
50         OGRE_IF_IOS_VERSION_IS_GREATER_THAN(5.0)
51             OGRE_CHECK_GL_ERROR(glDeleteProgramPipelinesEXT(1, &mGLProgramPipelineHandle));
52 #endif
53     }
54 
compileAndLink()55     void GLSLESProgramPipeline::compileAndLink()
56 	{
57 #if OGRE_PLATFORM != OGRE_PLATFORM_NACL
58         GLint linkStatus = 0;
59 
60         OGRE_CHECK_GL_ERROR(glGenProgramPipelinesEXT(1, &mGLProgramPipelineHandle));
61         OGRE_CHECK_GL_ERROR(glBindProgramPipelineEXT(mGLProgramPipelineHandle));
62 
63 		// Compile and attach Vertex Program
64         if(mVertexProgram && !mVertexProgram->isLinked())
65         {
66             try
67             {
68                 mVertexProgram->getGLSLProgram()->compile(true);
69             }
70             catch (Exception& e)
71             {
72 				LogManager::getSingleton().stream() << e.getDescription();
73                 mTriedToLinkAndFailed = true;
74                 return;
75             }
76             GLuint programHandle = mVertexProgram->getGLSLProgram()->getGLProgramHandle();
77             OGRE_CHECK_GL_ERROR(glProgramParameteriEXT(programHandle, GL_PROGRAM_SEPARABLE_EXT, GL_TRUE));
78             mVertexProgram->getGLSLProgram()->attachToProgramObject(programHandle);
79             OGRE_CHECK_GL_ERROR(glLinkProgram(programHandle));
80             OGRE_CHECK_GL_ERROR(glGetProgramiv(programHandle, GL_LINK_STATUS, &linkStatus));
81 
82             if(linkStatus)
83             {
84                 mVertexProgram->setLinked(linkStatus);
85                 mLinked |= VERTEX_PROGRAM_LINKED;
86             }
87 
88             mTriedToLinkAndFailed = !linkStatus;
89 
90             logObjectInfo( getCombinedName() + String("GLSL vertex program result : "), programHandle );
91 
92             setSkeletalAnimationIncluded(mVertexProgram->isSkeletalAnimationIncluded());
93         }
94 
95 		// Compile and attach Fragment Program
96         if(mFragmentProgram && !mFragmentProgram->isLinked())
97         {
98             try
99             {
100                 mFragmentProgram->getGLSLProgram()->compile(true);
101             }
102             catch (Exception& e)
103             {
104 				LogManager::getSingleton().stream() << e.getDescription();
105                 mTriedToLinkAndFailed = true;
106                 return;
107             }
108 
109             GLuint programHandle = mFragmentProgram->getGLSLProgram()->getGLProgramHandle();
110             OGRE_CHECK_GL_ERROR(glProgramParameteriEXT(programHandle, GL_PROGRAM_SEPARABLE_EXT, GL_TRUE));
111             mFragmentProgram->getGLSLProgram()->attachToProgramObject(programHandle);
112             OGRE_CHECK_GL_ERROR(glLinkProgram(programHandle));
113             OGRE_CHECK_GL_ERROR(glGetProgramiv(programHandle, GL_LINK_STATUS, &linkStatus));
114 
115             if(linkStatus)
116             {
117                 mFragmentProgram->setLinked(linkStatus);
118                 mLinked |= FRAGMENT_PROGRAM_LINKED;
119             }
120 
121             mTriedToLinkAndFailed = !linkStatus;
122 
123             logObjectInfo( getCombinedName() + String("GLSL fragment program result : "), programHandle );
124         }
125 
126 		if(mLinked)
127 		{
128             if(mVertexProgram && mVertexProgram->isLinked())
129             {
130                 OGRE_CHECK_GL_ERROR(glUseProgramStagesEXT(mGLProgramPipelineHandle, GL_VERTEX_SHADER_BIT_EXT, mVertexProgram->getGLSLProgram()->getGLProgramHandle()));
131             }
132             if(mFragmentProgram && mFragmentProgram->isLinked())
133             {
134                 OGRE_CHECK_GL_ERROR(glUseProgramStagesEXT(mGLProgramPipelineHandle, GL_FRAGMENT_SHADER_BIT_EXT, mFragmentProgram->getGLSLProgram()->getGLProgramHandle()));
135             }
136 
137             // Validate pipeline
138             logObjectInfo( getCombinedName() + String("GLSL program pipeline result : "), mGLProgramPipelineHandle );
139 #if OGRE_PLATFORM != OGRE_PLATFORM_NACL
140             if(mVertexProgram && mFragmentProgram)
141                 OGRE_IF_IOS_VERSION_IS_GREATER_THAN(5.0)
142                     glLabelObjectEXT(GL_PROGRAM_PIPELINE_OBJECT_EXT, mGLProgramPipelineHandle, 0,
143                                  (mVertexProgram->getName() + "/" + mFragmentProgram->getName()).c_str());
144 #endif
145 		}
146 #endif
147 	}
148 
_useProgram(void)149     void GLSLESProgramPipeline::_useProgram(void)
150     {
151 		if (mLinked)
152 		{
153 #if OGRE_PLATFORM != OGRE_PLATFORM_NACL
154             OGRE_CHECK_GL_ERROR(glBindProgramPipelineEXT(mGLProgramPipelineHandle));
155 #endif
156 		}
157     }
158 
159 	//-----------------------------------------------------------------------
getAttributeIndex(VertexElementSemantic semantic,uint index)160 	GLint GLSLESProgramPipeline::getAttributeIndex(VertexElementSemantic semantic, uint index)
161 	{
162 		GLint res = mCustomAttributesIndexes[semantic-1][index];
163 		if (res == NULL_CUSTOM_ATTRIBUTES_INDEX)
164 		{
165             GLuint handle = mVertexProgram->getGLSLProgram()->getGLProgramHandle();
166 			const char * attString = getAttributeSemanticString(semantic);
167 			GLint attrib;
168             OGRE_CHECK_GL_ERROR(attrib = glGetAttribLocation(handle, attString));
169 
170 			// Sadly position is a special case
171 			if (attrib == NOT_FOUND_CUSTOM_ATTRIBUTES_INDEX && semantic == VES_POSITION)
172 			{
173 				OGRE_CHECK_GL_ERROR(attrib = glGetAttribLocation(handle, "position"));
174 			}
175 
176 			// For uv and other case the index is a part of the name
177 			if (attrib == NOT_FOUND_CUSTOM_ATTRIBUTES_INDEX)
178 			{
179 				String attStringWithSemantic = String(attString) + StringConverter::toString(index);
180 				OGRE_CHECK_GL_ERROR(attrib = glGetAttribLocation(handle, attStringWithSemantic.c_str()));
181 			}
182 
183 			// Update mCustomAttributesIndexes with the index we found (or didn't find)
184 			mCustomAttributesIndexes[semantic-1][index] = attrib;
185 			res = attrib;
186 		}
187 
188 		return res;
189 	}
190 
191     //-----------------------------------------------------------------------
activate(void)192 	void GLSLESProgramPipeline::activate(void)
193 	{
194 		if (!mLinked && !mTriedToLinkAndFailed)
195 		{
196 			glGetError(); // Clean up the error. Otherwise will flood log.
197 
198 #if !OGRE_NO_GLES2_GLSL_OPTIMISER
199             // Check CmdParams for each shader type to see if we should optimise
200             if(mVertexProgram)
201             {
202                 String paramStr = mVertexProgram->getGLSLProgram()->getParameter("use_optimiser");
203                 if((paramStr == "true") || paramStr.empty())
204                 {
205                     GLSLESProgramPipelineManager::getSingleton().optimiseShaderSource(mVertexProgram);
206                 }
207             }
208 
209             if(mFragmentProgram)
210             {
211                 String paramStr = mFragmentProgram->getGLSLProgram()->getParameter("use_optimiser");
212                 if((paramStr == "true") || paramStr.empty())
213                 {
214                     GLSLESProgramPipelineManager::getSingleton().optimiseShaderSource(mFragmentProgram);
215                 }
216             }
217 #endif
218             compileAndLink();
219 
220             extractLayoutQualifiers();
221 
222 			buildGLUniformReferences();
223 		}
224 
225         _useProgram();
226 	}
227 
228     //-----------------------------------------------------------------------
buildGLUniformReferences(void)229 	void GLSLESProgramPipeline::buildGLUniformReferences(void)
230 	{
231 		if (!mUniformRefsBuilt)
232 		{
233 			const GpuConstantDefinitionMap* vertParams = 0;
234 			const GpuConstantDefinitionMap* fragParams = 0;
235 			if (mVertexProgram)
236 			{
237 				vertParams = &(mVertexProgram->getGLSLProgram()->getConstantDefinitions().map);
238                 GLSLESProgramPipelineManager::getSingleton().extractUniforms(mVertexProgram->getGLSLProgram()->getGLProgramHandle(),
239 					vertParams, NULL, mGLUniformReferences, mGLUniformBufferReferences);
240 			}
241 			if (mFragmentProgram)
242 			{
243 				fragParams = &(mFragmentProgram->getGLSLProgram()->getConstantDefinitions().map);
244                 GLSLESProgramPipelineManager::getSingleton().extractUniforms(mFragmentProgram->getGLSLProgram()->getGLProgramHandle(),
245                                                                          NULL, fragParams, mGLUniformReferences, mGLUniformBufferReferences);
246 			}
247 
248 			mUniformRefsBuilt = true;
249 		}
250 	}
251 
252 	//-----------------------------------------------------------------------
updateUniforms(GpuProgramParametersSharedPtr params,uint16 mask,GpuProgramType fromProgType)253 	void GLSLESProgramPipeline::updateUniforms(GpuProgramParametersSharedPtr params,
254                                            uint16 mask, GpuProgramType fromProgType)
255 	{
256 		// Iterate through uniform reference list and update uniform values
257 		GLUniformReferenceIterator currentUniform = mGLUniformReferences.begin();
258 		GLUniformReferenceIterator endUniform = mGLUniformReferences.end();
259 #if OGRE_PLATFORM != OGRE_PLATFORM_NACL
260         GLuint progID = 0;
261         if(fromProgType == GPT_VERTEX_PROGRAM)
262         {
263             progID = mVertexProgram->getGLSLProgram()->getGLProgramHandle();
264         }
265         else if(fromProgType == GPT_FRAGMENT_PROGRAM)
266         {
267             progID = mFragmentProgram->getGLSLProgram()->getGLProgramHandle();
268         }
269 
270 		for (;currentUniform != endUniform; ++currentUniform)
271 		{
272 			// Only pull values from buffer it's supposed to be in (vertex or fragment)
273 			// This method will be called twice, once for vertex program params,
274 			// and once for fragment program params.
275 			if (fromProgType == currentUniform->mSourceProgType)
276 			{
277 				const GpuConstantDefinition* def = currentUniform->mConstantDef;
278 				if (def->variability & mask)
279 				{
280 					GLsizei glArraySize = (GLsizei)def->arraySize;
281                     bool shouldUpdate = true;
282                     switch (def->constType)
283                     {
284                         case GCT_INT1:
285                         case GCT_INT2:
286                         case GCT_INT3:
287                         case GCT_INT4:
288                         case GCT_SAMPLER1D:
289                         case GCT_SAMPLER1DSHADOW:
290                         case GCT_SAMPLER2D:
291                         case GCT_SAMPLER2DSHADOW:
292                         case GCT_SAMPLER3D:
293                         case GCT_SAMPLERCUBE:
294 #if OGRE_NO_GLES3_SUPPORT == 0
295                         case GCT_SAMPLER2DARRAY:
296 #endif
297                             shouldUpdate = mUniformCache->updateUniform(currentUniform->mLocation,
298                                                                         params->getIntPointer(def->physicalIndex),
299                                                                         static_cast<GLsizei>(def->elementSize * def->arraySize * sizeof(int)));
300                             break;
301                         default:
302                             shouldUpdate = mUniformCache->updateUniform(currentUniform->mLocation,
303                                                                         params->getFloatPointer(def->physicalIndex),
304                                                                         static_cast<GLsizei>(def->elementSize * def->arraySize * sizeof(float)));
305                             break;
306                     }
307 
308                     if(!shouldUpdate)
309                         continue;
310 
311 					// Get the index in the parameter real list
312 					switch (def->constType)
313 					{
314                         case GCT_FLOAT1:
315                             OGRE_CHECK_GL_ERROR(glProgramUniform1fvEXT(progID, currentUniform->mLocation, glArraySize,
316                                                                        params->getFloatPointer(def->physicalIndex)));
317                             break;
318                         case GCT_FLOAT2:
319                             OGRE_CHECK_GL_ERROR(glProgramUniform2fvEXT(progID, currentUniform->mLocation, glArraySize,
320                                                                        params->getFloatPointer(def->physicalIndex)));
321                             break;
322                         case GCT_FLOAT3:
323                             OGRE_CHECK_GL_ERROR(glProgramUniform3fvEXT(progID, currentUniform->mLocation, glArraySize,
324                                                                        params->getFloatPointer(def->physicalIndex)));
325                             break;
326                         case GCT_FLOAT4:
327                             OGRE_CHECK_GL_ERROR(glProgramUniform4fvEXT(progID, currentUniform->mLocation, glArraySize,
328                                                                        params->getFloatPointer(def->physicalIndex)));
329                             break;
330                         case GCT_MATRIX_2X2:
331                             OGRE_CHECK_GL_ERROR(glProgramUniformMatrix2fvEXT(progID, currentUniform->mLocation, glArraySize,
332                                                                              GL_FALSE, params->getFloatPointer(def->physicalIndex)));
333                             break;
334                         case GCT_MATRIX_3X3:
335                             OGRE_CHECK_GL_ERROR(glProgramUniformMatrix3fvEXT(progID, currentUniform->mLocation, glArraySize,
336                                                                              GL_FALSE, params->getFloatPointer(def->physicalIndex)));
337                             break;
338                         case GCT_MATRIX_4X4:
339                             OGRE_CHECK_GL_ERROR(glProgramUniformMatrix4fvEXT(progID, currentUniform->mLocation, glArraySize,
340                                                                              GL_FALSE, params->getFloatPointer(def->physicalIndex)));
341                             break;
342                         case GCT_INT1:
343                             OGRE_CHECK_GL_ERROR(glProgramUniform1ivEXT(progID, currentUniform->mLocation, glArraySize,
344                                                                        params->getIntPointer(def->physicalIndex)));
345                             break;
346                         case GCT_INT2:
347                             OGRE_CHECK_GL_ERROR(glProgramUniform2ivEXT(progID, currentUniform->mLocation, glArraySize,
348                                                                        params->getIntPointer(def->physicalIndex)));
349                             break;
350                         case GCT_INT3:
351                             OGRE_CHECK_GL_ERROR(glProgramUniform3ivEXT(progID, currentUniform->mLocation, glArraySize,
352                                                                        params->getIntPointer(def->physicalIndex)));
353                             break;
354                         case GCT_INT4:
355                             OGRE_CHECK_GL_ERROR(glProgramUniform4ivEXT(progID, currentUniform->mLocation, glArraySize,
356                                                                        params->getIntPointer(def->physicalIndex)));
357                             break;
358                         case GCT_SAMPLER1D:
359                         case GCT_SAMPLER1DSHADOW:
360                         case GCT_SAMPLER2D:
361                         case GCT_SAMPLER2DSHADOW:
362                         case GCT_SAMPLER3D:
363                         case GCT_SAMPLERCUBE:
364 #if OGRE_NO_GLES3_SUPPORT == 0
365                         case GCT_SAMPLER2DARRAY:
366 #endif
367                             // Samplers handled like 1-element ints
368                             OGRE_CHECK_GL_ERROR(glProgramUniform1ivEXT(progID, currentUniform->mLocation, 1,
369                                                                        params->getIntPointer(def->physicalIndex)));
370                             break;
371 #if OGRE_NO_GLES3_SUPPORT == 0
372                         case GCT_MATRIX_2X3:
373                             OGRE_CHECK_GL_ERROR(glProgramUniformMatrix2x3fvEXT(progID, currentUniform->mLocation, glArraySize,
374                                                                             GL_FALSE, params->getFloatPointer(def->physicalIndex)));
375                             break;
376                         case GCT_MATRIX_2X4:
377                             OGRE_CHECK_GL_ERROR(glProgramUniformMatrix2x4fvEXT(progID, currentUniform->mLocation, glArraySize,
378                                                                             GL_FALSE, params->getFloatPointer(def->physicalIndex)));
379                             break;
380                         case GCT_MATRIX_3X2:
381                             OGRE_CHECK_GL_ERROR(glProgramUniformMatrix3x2fvEXT(progID, currentUniform->mLocation, glArraySize,
382                                                                             GL_FALSE, params->getFloatPointer(def->physicalIndex)));
383                             break;
384                         case GCT_MATRIX_3X4:
385                             OGRE_CHECK_GL_ERROR(glProgramUniformMatrix3x4fvEXT(progID, currentUniform->mLocation, glArraySize,
386                                                                             GL_FALSE, params->getFloatPointer(def->physicalIndex)));
387                             break;
388                         case GCT_MATRIX_4X2:
389                             OGRE_CHECK_GL_ERROR(glProgramUniformMatrix4x2fvEXT(progID, currentUniform->mLocation, glArraySize,
390                                                                             GL_FALSE, params->getFloatPointer(def->physicalIndex)));
391                             break;
392                         case GCT_MATRIX_4X3:
393                             OGRE_CHECK_GL_ERROR(glProgramUniformMatrix4x3fvEXT(progID, currentUniform->mLocation, glArraySize,
394                                                                             GL_FALSE, params->getFloatPointer(def->physicalIndex)));
395                             break;
396 #else
397                         case GCT_MATRIX_2X3:
398                         case GCT_MATRIX_2X4:
399                         case GCT_MATRIX_3X2:
400                         case GCT_MATRIX_3X4:
401                         case GCT_MATRIX_4X2:
402                         case GCT_MATRIX_4X3:
403                         case GCT_SAMPLER2DARRAY:
404 #endif
405                         case GCT_UNKNOWN:
406                         case GCT_SUBROUTINE:
407                         case GCT_DOUBLE1:
408                         case GCT_DOUBLE2:
409                         case GCT_DOUBLE3:
410                         case GCT_DOUBLE4:
411                         case GCT_SAMPLERRECT:
412                         case GCT_MATRIX_DOUBLE_2X2:
413                         case GCT_MATRIX_DOUBLE_2X3:
414                         case GCT_MATRIX_DOUBLE_2X4:
415                         case GCT_MATRIX_DOUBLE_3X2:
416                         case GCT_MATRIX_DOUBLE_3X3:
417                         case GCT_MATRIX_DOUBLE_3X4:
418                         case GCT_MATRIX_DOUBLE_4X2:
419                         case GCT_MATRIX_DOUBLE_4X3:
420                         case GCT_MATRIX_DOUBLE_4X4:
421                             break;
422 
423 					} // End switch
424 				} // Variability & mask
425 			} // fromProgType == currentUniform->mSourceProgType
426 
427   		} // End for
428 #endif
429 	}
430     //-----------------------------------------------------------------------
updateUniformBlocks(GpuProgramParametersSharedPtr params,uint16 mask,GpuProgramType fromProgType)431 	void GLSLESProgramPipeline::updateUniformBlocks(GpuProgramParametersSharedPtr params,
432                                                   uint16 mask, GpuProgramType fromProgType)
433 	{
434 #if OGRE_NO_GLES3_SUPPORT == 0
435         // Iterate through the list of uniform buffers and update them as needed
436 		GLUniformBufferIterator currentBuffer = mGLUniformBufferReferences.begin();
437 		GLUniformBufferIterator endBuffer = mGLUniformBufferReferences.end();
438 
439         const GpuProgramParameters::GpuSharedParamUsageList& sharedParams = params->getSharedParameters();
440 
441 		GpuProgramParameters::GpuSharedParamUsageList::const_iterator it, end = sharedParams.end();
442 		for (it = sharedParams.begin(); it != end; ++it)
443         {
444             for (;currentBuffer != endBuffer; ++currentBuffer)
445             {
446                 GLES2HardwareUniformBuffer* hwGlBuffer = static_cast<GLES2HardwareUniformBuffer*>(currentBuffer->get());
447                 GpuSharedParametersPtr paramsPtr = it->getSharedParams();
448 
449                 // Block name is stored in mSharedParams->mName of GpuSharedParamUsageList items
450                 GLint UniformTransform;
451                 OGRE_CHECK_GL_ERROR(UniformTransform = glGetUniformBlockIndex(mGLProgramHandle, it->getName().c_str()));
452                 OGRE_CHECK_GL_ERROR(glUniformBlockBinding(mGLProgramHandle, UniformTransform, hwGlBuffer->getGLBufferBinding()));
453 
454                 hwGlBuffer->writeData(0, hwGlBuffer->getSizeInBytes(), &paramsPtr->getFloatConstantList().front());
455             }
456         }
457 #endif
458 	}
459 	//-----------------------------------------------------------------------
updatePassIterationUniforms(GpuProgramParametersSharedPtr params)460 	void GLSLESProgramPipeline::updatePassIterationUniforms(GpuProgramParametersSharedPtr params)
461 	{
462 		if (params->hasPassIterationNumber())
463 		{
464 			size_t index = params->getPassIterationNumberIndex();
465 
466 			GLUniformReferenceIterator currentUniform = mGLUniformReferences.begin();
467 			GLUniformReferenceIterator endUniform = mGLUniformReferences.end();
468 
469 			// Need to find the uniform that matches the multi pass entry
470 			for (;currentUniform != endUniform; ++currentUniform)
471 			{
472 				// Get the index in the parameter real list
473 				if (index == currentUniform->mConstantDef->physicalIndex)
474 				{
475 #if OGRE_PLATFORM != OGRE_PLATFORM_NACL
476 
477                     GLuint progID = 0;
478                     if (mVertexProgram && currentUniform->mSourceProgType == GPT_VERTEX_PROGRAM)
479                     {
480                         if(!mUniformCache->updateUniform(currentUniform->mLocation,
481                                                                              params->getFloatPointer(index),
482                                                                              static_cast<GLsizei>(currentUniform->mConstantDef->elementSize *
483                                                                              currentUniform->mConstantDef->arraySize *
484                                                                              sizeof(float))))
485                             return;
486 
487                         progID = mVertexProgram->getGLSLProgram()->getGLProgramHandle();
488                         OGRE_CHECK_GL_ERROR(glProgramUniform1fvEXT(progID, currentUniform->mLocation, 1, params->getFloatPointer(index)));
489                     }
490 
491                     if (mFragmentProgram && currentUniform->mSourceProgType == GPT_FRAGMENT_PROGRAM)
492                     {
493                         if(!mUniformCache->updateUniform(currentUniform->mLocation,
494                                                                                params->getFloatPointer(index),
495                                                                                static_cast<GLsizei>(currentUniform->mConstantDef->elementSize *
496                                                                                currentUniform->mConstantDef->arraySize *
497                                                                                sizeof(float))))
498                             return;
499                         progID = mFragmentProgram->getGLSLProgram()->getGLProgramHandle();
500                         OGRE_CHECK_GL_ERROR(glProgramUniform1fvEXT(progID, currentUniform->mLocation, 1, params->getFloatPointer(index)));
501                     }
502 #endif
503 					// There will only be one multipass entry
504 					return;
505 				}
506 			}
507 		}
508     }
509     //-----------------------------------------------------------------------
extractLayoutQualifiers(void)510     void GLSLESProgramPipeline::extractLayoutQualifiers(void)
511     {
512         // Format is:
513         //      layout(location = 0) attribute vec4 vertex;
514 
515         if(mVertexProgram)
516         {
517             String shaderSource = mVertexProgram->getGLSLProgram()->getSource();
518             String::size_type currPos = shaderSource.find("layout");
519             while (currPos != String::npos)
520             {
521                 VertexElementSemantic semantic;
522                 GLint index = 0;
523 
524                 String::size_type endPos = shaderSource.find(";", currPos);
525 				if (endPos == String::npos)
526 				{
527 					// Problem, missing semicolon, abort
528 					break;
529 				}
530 
531 				String line = shaderSource.substr(currPos, endPos - currPos);
532 
533                 // Skip over 'layout'
534                 currPos += 6;
535 
536                 // Skip until '='
537                 String::size_type eqPos = line.find("=");
538                 String::size_type parenPos = line.find(")");
539 
540                 // Skip past '=' up to a ')' which contains an integer(the position).  This could be a definition, does the preprocessor do replacement?
541                 String attrLocation = line.substr(eqPos + 1, parenPos - eqPos - 1);
542                 StringUtil::trim(attrLocation);
543                 GLint attrib = StringConverter::parseInt(attrLocation);
544 
545                 // The rest of the line is a standard attribute definition.
546                 // Erase up to it then split the remainder by spaces.
547                 line.erase (0, parenPos + 1);
548                 StringUtil::trim(line);
549 				StringVector parts = StringUtil::split(line, " ");
550 
551                 if(parts.size() < 3)
552                 {
553                     // This is a malformed attribute
554                     // It should contain 3 parts, i.e. "attribute vec4 vertex"
555                     break;
556                 }
557 
558                 String attrName = parts[2];
559 
560                 // Special case for attribute named position
561                 if(attrName == "position")
562                     semantic = getAttributeSemanticEnum("vertex");
563                 else
564                     semantic = getAttributeSemanticEnum(attrName);
565 
566                 // Find the texture unit index
567                 String::size_type uvPos = attrName.find("uv");
568                 if(uvPos != String::npos)
569                 {
570                     String uvIndex = attrName.substr(uvPos + 2, attrName.length() - 2);
571                     index = StringConverter::parseInt(uvIndex);
572                 }
573 
574                 mCustomAttributesIndexes[semantic-1][index] = attrib;
575 
576                 currPos = shaderSource.find("layout", currPos);
577             }
578         }
579     }
580 }
581