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(), ¶msPtr->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