void GLSLProgramObject::Reload(bool reloadFromDisk, bool validate) { const auto oldSrcHash = curSrcHash; bool oldValid = IsValid(); const GLuint oldProgID = objID; // reload shader from disk? reloadFromDisk = reloadFromDisk || !oldValid || (oldProgID == 0); if (reloadFromDisk) { bool sourceChanged = false; for (IShaderObject*& so: GetAttachedShaderObjs()) { sourceChanged |= so->ReloadFromDisk(); } } // log = ""; valid = false; // create shader source hash curFlagsHash = GetHash(); curSrcHash = curFlagsHash; for (const IShaderObject* so: GetAttachedShaderObjs()) { curSrcHash ^= so->GetHash(); } // clear all uniform locations for (auto& us_pair: uniformStates) { us_pair.second.SetLocation(GL_INVALID_INDEX); } // early-exit: empty program // TODO delete existing program if exists? if (GetAttachedShaderObjs().empty()) return; // push old program to cache and pop new if available const bool useShaderCache = oldValid && configHandler->GetBool("UseShaderCache"); bool deleteOldShader = true; objID = 0; if (useShaderCache) { CShaderHandler::ShaderCache& shadersCache = shaderHandler->GetShaderCache(); deleteOldShader = !shadersCache.Push(oldSrcHash, oldProgID); objID = shadersCache.Find(curSrcHash); } // recompile if not found in cache (id 0) if (objID == 0) { objID = glCreateProgram(); bool shadersValid = true; for (IShaderObject*& so: GetAttachedShaderObjs()) { assert(dynamic_cast<GLSLShaderObject*>(so)); auto gso = static_cast<GLSLShaderObject*>(so); auto obj = gso->CompileShaderObject(); if (obj->valid) { glAttachShader(objID, obj->id); } else { shadersValid = false; } } if (!shadersValid) return; Link(); } else { valid = true; } // /* if (validate) { Validate(); //FIXME: fails on ATI, see https://springrts.com/mantis/view.php?id=4715 } */ // copy full program state from old to new program (uniforms etc.) if (IsValid()) { GLSLCopyState(objID, oldValid ? oldProgID : 0, &uniformStates); } // delete old program when not further used if (deleteOldShader) glDeleteProgram(oldProgID); }
GLhandleARB P3DShaderLoader::GetProgramHandle (bool HaveDiffuseTex, bool HaveNormalMap, bool TwoSided) const { GLhandleARB ProgHandle; GLhandleARB ShaderHandle; const GLcharARB *SourceStrings[ShaderSrcHeaderLineCount + 1]; GLint LinkStatus; bool ShaderOk; ProgHandle = FindByProps(HaveDiffuseTex,HaveNormalMap,TwoSided); if (ProgHandle != 0) { return(ProgHandle); } #ifdef USE_OPENGL_20 ProgHandle = glCreateProgram(); #else ProgHandle = glCreateProgramObjectARB(); #endif if (ProgHandle != 0) { SourceStrings[0] = HaveDiffuseTex ? ShaderSrcDefineHaveDiffuseTex : ShaderSrcEmptyLine; SourceStrings[1] = HaveNormalMap ? ShaderSrcDefineHaveNormalMap : ShaderSrcEmptyLine; SourceStrings[2] = TwoSided ? ShaderSrcDefineTwoSided : ShaderSrcEmptyLine; SourceStrings[3] = ShaderSrcLineNumberSetup; ShaderOk = true; if (VertexProgramSrc != 0) { SourceStrings[ShaderSrcHeaderLineCount] = VertexProgramSrc; #ifdef USE_OPENGL_20 ShaderOk = CompileShaderObject(&ShaderHandle,GL_VERTEX_SHADER,ShaderSrcHeaderLineCount + 1,SourceStrings); #else ShaderOk = CompileShaderObject(&ShaderHandle,GL_VERTEX_SHADER_ARB,ShaderSrcHeaderLineCount + 1,SourceStrings); #endif if (ShaderOk) { #ifdef USE_OPENGL_20 glAttachShader(ProgHandle,ShaderHandle); glDeleteShader(ShaderHandle); #else glAttachObjectARB(ProgHandle,ShaderHandle); glDeleteObjectARB(ShaderHandle); #endif } } if (ShaderOk) { if (FragmentProgramSrc != 0) { SourceStrings[ShaderSrcHeaderLineCount] = FragmentProgramSrc; #ifdef USE_OPENGL_20 ShaderOk = CompileShaderObject(&ShaderHandle,GL_FRAGMENT_SHADER,ShaderSrcHeaderLineCount + 1,SourceStrings); #else ShaderOk = CompileShaderObject(&ShaderHandle,GL_FRAGMENT_SHADER_ARB,ShaderSrcHeaderLineCount + 1,SourceStrings); #endif if (ShaderOk) { #ifdef USE_OPENGL_20 glAttachShader(ProgHandle,ShaderHandle); glDeleteShader(ShaderHandle); #else glAttachObjectARB(ProgHandle,ShaderHandle); glDeleteObjectARB(ShaderHandle); #endif } } } if (ShaderOk) { #ifdef USE_OPENGL_20 glLinkProgram(ProgHandle); #else glLinkProgramARB(ProgHandle); #endif #ifdef USE_OPENGL_20 glGetProgramiv( ProgHandle,GL_LINK_STATUS,&LinkStatus); #else glGetObjectParameterivARB( ProgHandle, GL_OBJECT_LINK_STATUS_ARB, &LinkStatus); #endif DumpInfoLog(ProgHandle); if (LinkStatus) { GLhandleARB CurrProgHandle; #ifdef USE_OPENGL_20 glGetIntegerv(GL_CURRENT_PROGRAM,(GLint*)&CurrProgHandle); #else CurrProgHandle = glGetHandleARB(GL_PROGRAM_OBJECT_ARB); #endif #ifdef USE_OPENGL_20 glUseProgram(ProgHandle); #else glUseProgramObjectARB(ProgHandle); #endif GLint Location; #ifdef USE_OPENGL_20 Location = glGetUniformLocation(ProgHandle,"DiffuseTexSampler"); #else Location = glGetUniformLocationARB(ProgHandle,"DiffuseTexSampler"); #endif if (Location != -1) { #ifdef USE_OPENGL_20 glUniform1i(Location,0); #else glUniform1iARB(Location,0); #endif } #ifdef USE_OPENGL_20 Location = glGetUniformLocation(ProgHandle,"NormalMapSampler"); #else Location = glGetUniformLocationARB(ProgHandle,"NormalMapSampler"); #endif if (Location != -1) { #ifdef USE_OPENGL_20 glUniform1i(Location,1); #else glUniform1iARB(Location,1); #endif } #ifdef USE_OPENGL_20 glUseProgram(CurrProgHandle); #else glUseProgramObjectARB(CurrProgHandle); #endif } else { fprintf(stderr,"error: shader linkage failed\n"); #ifdef USE_OPENGL_20 glDeleteProgram(ProgHandle); #else glDeleteObjectARB(ProgHandle); #endif ProgHandle = 0; } } else { #ifdef USE_OPENGL_20 glDeleteProgram(ProgHandle); #else glDeleteObjectARB(ProgHandle); #endif ProgHandle = 0; } } else { fprintf(stderr,"error: unable to create GLSL program object\n"); } if (ProgHandle != 0) { P3DShaderEntry Entry; Entry.ProgramHandle = ProgHandle; Entry.HaveDiffuseTex = HaveDiffuseTex; Entry.HaveNormalMap = HaveNormalMap; Entry.TwoSided = TwoSided; ShaderSet.push_back(Entry); } return(ProgHandle); }