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-2014 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 "OgreGLSLESLinkProgram.h"
30 #include "OgreGLSLESProgram.h"
31 #include "OgreGLSLESProgramManager.h"
32 #include "OgreGLES2HardwareUniformBuffer.h"
33 #include "OgreLogManager.h"
34 #include "OgreGpuProgramManager.h"
35 #include "OgreStringConverter.h"
36 #include "OgreRoot.h"
37 #include "OgreGLUtil.h"
38 #include "OgreGLES2RenderSystem.h"
39 #include "OgreGLNativeSupport.h"
40 
41 namespace Ogre {
42 
43     //-----------------------------------------------------------------------
GLSLESLinkProgram(GLSLESProgram * vertexProgram,GLSLESProgram * fragmentProgram)44     GLSLESLinkProgram::GLSLESLinkProgram(GLSLESProgram* vertexProgram, GLSLESProgram* fragmentProgram)
45     : GLSLESProgramCommon(vertexProgram, fragmentProgram)
46     {
47         if ((!getVertexProgram() || !mFragmentProgram))
48         {
49             OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR,
50                         "Attempted to create a shader program without both a vertex and fragment program.",
51                         "GLSLESLinkProgram::GLSLESLinkProgram");
52         }
53     }
54 
55     //-----------------------------------------------------------------------
~GLSLESLinkProgram(void)56     GLSLESLinkProgram::~GLSLESLinkProgram(void)
57     {
58         OGRE_CHECK_GL_ERROR(glDeleteProgram(mGLProgramHandle));
59     }
60 
61 #if OGRE_PLATFORM == OGRE_PLATFORM_ANDROID || OGRE_PLATFORM == OGRE_PLATFORM_EMSCRIPTEN
notifyOnContextLost()62     void GLSLESLinkProgram::notifyOnContextLost()
63     {
64         OGRE_CHECK_GL_ERROR(glDeleteProgram(mGLProgramHandle));
65         mGLProgramHandle = 0;
66         GLSLESProgramCommon::notifyOnContextLost();
67     }
68 #endif
69     //-----------------------------------------------------------------------
activate(void)70     void GLSLESLinkProgram::activate(void)
71     {
72         if (!mLinked)
73         {
74             glGetError(); // Clean up the error. Otherwise will flood log.
75 
76             OGRE_CHECK_GL_ERROR(mGLProgramHandle = glCreateProgram());
77 
78             uint32 hash = 0;
79             GpuProgram* progs[] = {mVertexShader, mFragmentProgram};
80             for(auto p : progs)
81             {
82                 if(!p) continue;
83                 hash = p->_getHash(hash);
84             }
85 
86             if (!getMicrocodeFromCache(hash, mGLProgramHandle))
87             {
88 #if !OGRE_NO_GLES2_GLSL_OPTIMISER
89                 // Check CmdParams for each shader type to see if we should optimize
90                 if(mVertexProgram)
91                 {
92                     String paramStr = mVertexProgram->getGLSLProgram()->getParameter("use_optimiser");
93                     if((paramStr == "true") || paramStr.empty())
94                     {
95                         GLSLESLinkProgramManager::getSingleton().optimiseShaderSource(mVertexProgram);
96                     }
97                 }
98 
99                 if(mFragmentProgram)
100                 {
101                     String paramStr = mFragmentProgram->getGLSLProgram()->getParameter("use_optimiser");
102                     if((paramStr == "true") || paramStr.empty())
103                     {
104                         GLSLESLinkProgramManager::getSingleton().optimiseShaderSource(mFragmentProgram);
105                     }
106                 }
107 #endif
108                 compileAndLink();
109 
110 #if !OGRE_NO_GLES2_GLSL_OPTIMISER
111                 // TODO: we will never reach this - move to GLSLESProgram
112                 // Try it again when we used the optimised versions
113                 if(mVertexProgram->getGLSLProgram()->getOptimiserEnabled() &&
114                     mFragmentProgram->getGLSLProgram()->getOptimiserEnabled())
115                 {
116                     LogManager::getSingleton().stream() << "Try not optimised shader.";
117                     mVertexProgram->getGLSLProgram()->setOptimiserEnabled(false);
118                     mFragmentProgram->getGLSLProgram()->setOptimiserEnabled(false);
119                     compileAndLink();
120                 }
121 #endif
122             }
123 
124             extractLayoutQualifiers();
125             buildGLUniformReferences();
126         }
127 
128         if (mLinked)
129         {
130             OGRE_CHECK_GL_ERROR(glUseProgram( mGLProgramHandle ));
131         }
132     }
133 
134     //-----------------------------------------------------------------------
compileAndLink()135     void GLSLESLinkProgram::compileAndLink()
136     {
137         uint32 hash = 0;
138         GpuProgram* progs[] = {mVertexShader, mFragmentProgram};
139         for(auto p : progs)
140         {
141             if(!p) continue;
142             hash = p->_getHash(hash);
143         }
144 
145         // attach Vertex Program
146         getVertexProgram()->attachToProgramObject(mGLProgramHandle);
147         setSkeletalAnimationIncluded(getVertexProgram()->isSkeletalAnimationIncluded());
148 
149         // attach Fragment Program
150         mFragmentProgram->attachToProgramObject(mGLProgramHandle);
151 
152         bindFixedAttributes( mGLProgramHandle );
153 
154         // The link
155         OGRE_CHECK_GL_ERROR(glLinkProgram( mGLProgramHandle ));
156         OGRE_CHECK_GL_ERROR(glGetProgramiv( mGLProgramHandle, GL_LINK_STATUS, &mLinked ));
157 
158         GLSLES::logObjectInfo( getCombinedName() + String("GLSL link result : "), mGLProgramHandle );
159 
160         const RenderSystemCapabilities* caps = Root::getSingleton().getRenderSystem()->getCapabilities();
161 
162         if(caps->hasCapability(RSC_SEPARATE_SHADER_OBJECTS))
163         {
164             if(glIsProgramPipelineEXT(mGLProgramHandle))
165                 glValidateProgramPipelineEXT(mGLProgramHandle);
166         }
167         else if(glIsProgram(mGLProgramHandle))
168         {
169             glValidateProgram(mGLProgramHandle);
170         }
171 
172         GLSLES::logObjectInfo( getCombinedName() + String(" GLSL validation result : "), mGLProgramHandle );
173 
174         if(mLinked)
175         {
176             _writeToCache(hash, mGLProgramHandle);
177         }
178     }
179 
180     //-----------------------------------------------------------------------
buildGLUniformReferences(void)181     void GLSLESLinkProgram::buildGLUniformReferences(void)
182     {
183         if (!mUniformRefsBuilt)
184         {
185             const GpuConstantDefinitionMap* vertParams = 0;
186             const GpuConstantDefinitionMap* fragParams = 0;
187             if (getVertexProgram())
188             {
189                 vertParams = &(getVertexProgram()->getConstantDefinitions().map);
190             }
191             if (mFragmentProgram)
192             {
193                 fragParams = &(mFragmentProgram->getConstantDefinitions().map);
194             }
195 
196             GLSLESProgramManager::extractUniforms(mGLProgramHandle, vertParams, fragParams,
197                                                   mGLUniformReferences, mGLUniformBufferReferences);
198 
199             mUniformRefsBuilt = true;
200         }
201     }
202 
203     //-----------------------------------------------------------------------
updateUniforms(GpuProgramParametersSharedPtr params,uint16 mask,GpuProgramType fromProgType)204     void GLSLESLinkProgram::updateUniforms(GpuProgramParametersSharedPtr params,
205         uint16 mask, GpuProgramType fromProgType)
206     {
207         // Iterate through uniform reference list and update uniform values
208         GLUniformReferenceIterator currentUniform = mGLUniformReferences.begin();
209         GLUniformReferenceIterator endUniform = mGLUniformReferences.end();
210 
211         for (;currentUniform != endUniform; ++currentUniform)
212         {
213             // Only pull values from buffer it's supposed to be in (vertex or fragment)
214             // This method will be called twice, once for vertex program params,
215             // and once for fragment program params.
216             if (fromProgType == currentUniform->mSourceProgType)
217             {
218                 const GpuConstantDefinition* def = currentUniform->mConstantDef;
219                 if (def->variability & mask)
220                 {
221                     GLsizei glArraySize = (GLsizei)def->arraySize;
222 
223                     bool shouldUpdate = true;
224 
225                     // this is a monolitic program so we can use the cache of any attached shader
226                     GLUniformCache* uniformCache =  mVertexShader->getUniformCache();
227                     switch (def->constType)
228                     {
229                         case GCT_INT1:
230                         case GCT_INT2:
231                         case GCT_INT3:
232                         case GCT_INT4:
233                         case GCT_SAMPLER1D:
234                         case GCT_SAMPLER1DSHADOW:
235                         case GCT_SAMPLER2D:
236                         case GCT_SAMPLER2DSHADOW:
237                         case GCT_SAMPLER3D:
238                         case GCT_SAMPLERCUBE:
239                             shouldUpdate = uniformCache->updateUniform(currentUniform->mLocation,
240                                                                        params->getIntPointer(def->physicalIndex),
241                                                                        static_cast<GLsizei>(def->elementSize * glArraySize * sizeof(int)));
242                             break;
243                         default:
244                             shouldUpdate = uniformCache->updateUniform(currentUniform->mLocation,
245                                                                        params->getFloatPointer(def->physicalIndex),
246                                                                        static_cast<GLsizei>(def->elementSize * glArraySize * sizeof(float)));
247                             break;
248                     }
249 
250                     if(!shouldUpdate)
251                         continue;
252 
253                     // Get the index in the parameter real list
254                     switch (def->constType)
255                     {
256                     case GCT_FLOAT1:
257                         OGRE_CHECK_GL_ERROR(glUniform1fv(currentUniform->mLocation, glArraySize,
258                                                          params->getFloatPointer(def->physicalIndex)));
259                         break;
260                     case GCT_FLOAT2:
261                         OGRE_CHECK_GL_ERROR(glUniform2fv(currentUniform->mLocation, glArraySize,
262                                                          params->getFloatPointer(def->physicalIndex)));
263                         break;
264                     case GCT_FLOAT3:
265                         OGRE_CHECK_GL_ERROR(glUniform3fv(currentUniform->mLocation, glArraySize,
266                                                          params->getFloatPointer(def->physicalIndex)));
267                         break;
268                     case GCT_FLOAT4:
269                         OGRE_CHECK_GL_ERROR(glUniform4fv(currentUniform->mLocation, glArraySize,
270                                                          params->getFloatPointer(def->physicalIndex)));
271                         break;
272                     case GCT_MATRIX_2X2:
273                         OGRE_CHECK_GL_ERROR(glUniformMatrix2fv(currentUniform->mLocation, glArraySize,
274                                                                GL_FALSE, params->getFloatPointer(def->physicalIndex)));
275                         break;
276                     case GCT_MATRIX_3X3:
277                         OGRE_CHECK_GL_ERROR(glUniformMatrix3fv(currentUniform->mLocation, glArraySize,
278                                                                GL_FALSE, params->getFloatPointer(def->physicalIndex)));
279                         break;
280                     case GCT_MATRIX_4X4:
281                         OGRE_CHECK_GL_ERROR(glUniformMatrix4fv(currentUniform->mLocation, glArraySize,
282                                                                GL_FALSE, params->getFloatPointer(def->physicalIndex)));
283                         break;
284                     case GCT_MATRIX_2X3:
285                         OGRE_CHECK_GL_ERROR(glUniformMatrix2x3fv(currentUniform->mLocation, glArraySize,
286                                                                  GL_FALSE, params->getFloatPointer(def->physicalIndex)));
287                         break;
288                     case GCT_MATRIX_2X4:
289                         OGRE_CHECK_GL_ERROR(glUniformMatrix2x4fv(currentUniform->mLocation, glArraySize,
290                                                                  GL_FALSE, params->getFloatPointer(def->physicalIndex)));
291                         break;
292                     case GCT_MATRIX_3X2:
293                         OGRE_CHECK_GL_ERROR(glUniformMatrix3x2fv(currentUniform->mLocation, glArraySize,
294                                                                  GL_FALSE, params->getFloatPointer(def->physicalIndex)));
295                         break;
296                     case GCT_MATRIX_3X4:
297                         OGRE_CHECK_GL_ERROR(glUniformMatrix3x4fv(currentUniform->mLocation, glArraySize,
298                                                                  GL_FALSE, params->getFloatPointer(def->physicalIndex)));
299                         break;
300                     case GCT_MATRIX_4X2:
301                         OGRE_CHECK_GL_ERROR(glUniformMatrix4x2fv(currentUniform->mLocation, glArraySize,
302                                                                  GL_FALSE, params->getFloatPointer(def->physicalIndex)));
303                         break;
304                     case GCT_MATRIX_4X3:
305                         OGRE_CHECK_GL_ERROR(glUniformMatrix4x3fv(currentUniform->mLocation, glArraySize,
306                                                                  GL_FALSE, params->getFloatPointer(def->physicalIndex)));
307                         break;
308                     case GCT_INT1:
309                         OGRE_CHECK_GL_ERROR(glUniform1iv(currentUniform->mLocation, glArraySize,
310                                                          (GLint*)params->getIntPointer(def->physicalIndex)));
311                         break;
312                     case GCT_INT2:
313                         OGRE_CHECK_GL_ERROR(glUniform2iv(currentUniform->mLocation, glArraySize,
314                                                          (GLint*)params->getIntPointer(def->physicalIndex)));
315                         break;
316                     case GCT_INT3:
317                         OGRE_CHECK_GL_ERROR(glUniform3iv(currentUniform->mLocation, glArraySize,
318                                                          (GLint*)params->getIntPointer(def->physicalIndex)));
319                         break;
320                     case GCT_INT4:
321                         OGRE_CHECK_GL_ERROR(glUniform4iv(currentUniform->mLocation, glArraySize,
322                                                          (GLint*)params->getIntPointer(def->physicalIndex)));
323                         break;
324                     case GCT_SAMPLER1D:
325                     case GCT_SAMPLER1DSHADOW:
326                     case GCT_SAMPLER2D:
327                     case GCT_SAMPLER2DSHADOW:
328                     case GCT_SAMPLER3D:
329                     case GCT_SAMPLERCUBE:
330                     case GCT_SAMPLER2DARRAY:
331                         // Samplers handled like 1-element ints
332                         OGRE_CHECK_GL_ERROR(glUniform1iv(currentUniform->mLocation, 1,
333                                                          (GLint*)params->getIntPointer(def->physicalIndex)));
334                         break;
335                     case GCT_UNKNOWN:
336                     case GCT_SUBROUTINE:
337                     case GCT_DOUBLE1:
338                     case GCT_DOUBLE2:
339                     case GCT_DOUBLE3:
340                     case GCT_DOUBLE4:
341                     case GCT_SAMPLERRECT:
342                     case GCT_MATRIX_DOUBLE_2X2:
343                     case GCT_MATRIX_DOUBLE_2X3:
344                     case GCT_MATRIX_DOUBLE_2X4:
345                     case GCT_MATRIX_DOUBLE_3X2:
346                     case GCT_MATRIX_DOUBLE_3X3:
347                     case GCT_MATRIX_DOUBLE_3X4:
348                     case GCT_MATRIX_DOUBLE_4X2:
349                     case GCT_MATRIX_DOUBLE_4X3:
350                     case GCT_MATRIX_DOUBLE_4X4:
351                     default:
352                         break;
353 
354                     } // End switch
355                 } // Variability & mask
356             } // fromProgType == currentUniform->mSourceProgType
357 
358         } // End for
359     }
360     //-----------------------------------------------------------------------
updateUniformBlocks(GpuProgramParametersSharedPtr params,uint16 mask,GpuProgramType fromProgType)361     void GLSLESLinkProgram::updateUniformBlocks(GpuProgramParametersSharedPtr params,
362                                               uint16 mask, GpuProgramType fromProgType)
363     {
364 #if OGRE_NO_GLES3_SUPPORT == 0
365         // Iterate through the list of uniform buffers and update them as needed
366         GLUniformBufferIterator currentBuffer = mGLUniformBufferReferences.begin();
367         GLUniformBufferIterator endBuffer = mGLUniformBufferReferences.end();
368 
369         const GpuProgramParameters::GpuSharedParamUsageList& sharedParams = params->getSharedParameters();
370 
371         GpuProgramParameters::GpuSharedParamUsageList::const_iterator it, end = sharedParams.end();
372         for (it = sharedParams.begin(); it != end; ++it)
373         {
374             for (;currentBuffer != endBuffer; ++currentBuffer)
375             {
376                 GLES2HardwareUniformBuffer* hwGlBuffer = static_cast<GLES2HardwareUniformBuffer*>(currentBuffer->get());
377                 GpuSharedParametersPtr paramsPtr = it->getSharedParams();
378 
379                 // Block name is stored in mSharedParams->mName of GpuSharedParamUsageList items
380                 GLint UniformTransform;
381                 OGRE_CHECK_GL_ERROR(UniformTransform = glGetUniformBlockIndex(mGLProgramHandle, it->getName().c_str()));
382                 OGRE_CHECK_GL_ERROR(glUniformBlockBinding(mGLProgramHandle, UniformTransform, hwGlBuffer->getGLBufferBinding()));
383 
384                 hwGlBuffer->writeData(0, hwGlBuffer->getSizeInBytes(), &paramsPtr->getFloatConstantList().front());
385             }
386         }
387 #endif
388     }
389     //-----------------------------------------------------------------------
updatePassIterationUniforms(GpuProgramParametersSharedPtr params)390     void GLSLESLinkProgram::updatePassIterationUniforms(GpuProgramParametersSharedPtr params)
391     {
392         if (params->hasPassIterationNumber())
393         {
394             size_t index = params->getPassIterationNumberIndex();
395 
396             GLUniformReferenceIterator currentUniform = mGLUniformReferences.begin();
397             GLUniformReferenceIterator endUniform = mGLUniformReferences.end();
398 
399             // Need to find the uniform that matches the multi pass entry
400             for (;currentUniform != endUniform; ++currentUniform)
401             {
402                 // Get the index in the parameter real list
403                 if (index == currentUniform->mConstantDef->physicalIndex)
404                 {
405                     OGRE_CHECK_GL_ERROR(glUniform1fv(currentUniform->mLocation, 1, params->getFloatPointer(index)));
406                     // There will only be one multipass entry
407                     return;
408                 }
409             }
410         }
411     }
412 } // namespace Ogre
413