void OsmAnd::GPUAPI_OpenGLES2::preprocessFragmentShader(QString& code) { const auto& fragmentShaderAdditionalPrologue = QString::fromLatin1( // Make some extensions required "#ifdef GL_EXT_shader_texture_lod ""\n" "#extension GL_EXT_shader_texture_lod : require ""\n" "#endif // GL_EXT_shader_texture_lod ""\n" " ""\n" // Fragment shader output declaration "#define FRAGMENT_COLOR_OUTPUT gl_FragColor ""\n" " ""\n" // It have been reported that GL_FRAGMENT_PRECISION_HIGH may not be defined in some cases "#ifndef GL_FRAGMENT_PRECISION_HIGH ""\n" "#if %HighPrecisionSupported% ""\n" "#define GL_FRAGMENT_PRECISION_HIGH 1 ""\n" "#endif ""\n" "#endif ""\n" " ""\n" // Set default precisions (this should be the default, but never trust mobile drivers) "#ifdef GL_FRAGMENT_PRECISION_HIGH ""\n" "precision highp float; ""\n" "precision highp int; ""\n" "#else ""\n" "precision highp float; ""\n" "precision highp int; ""\n" "#endif ""\n" " ""\n"); auto fragmentShaderAdditionalProloguePreprocessed = fragmentShaderAdditionalPrologue; fragmentShaderAdditionalProloguePreprocessed.replace("%HighPrecisionSupported%", QString::number( supportedFragmentShaderPrecisionFormats.contains(GL_HIGH_FLOAT) && supportedFragmentShaderPrecisionFormats.contains(GL_HIGH_INT) ? 1 : 0)); code.prepend(fragmentShaderAdditionalProloguePreprocessed); preprocessShader(code); }
void OsmAnd::GPUAPI_OpenGLES2::preprocessVertexShader(QString& code) { const auto& vertexShaderAdditionalPrologue = QString::fromLatin1( // Set default precisions (this should be the default, but never trust mobile drivers) "precision highp float; ""\n" "precision highp int; ""\n" " ""\n"); code.prepend(vertexShaderAdditionalPrologue); preprocessShader(code); }
QOpenGLShaderProgram* ShaderMgr::findOrLoadShader(uint flags) { auto it = m_shaderCache.find(flags); // This may also return Q_NULLPTR if the load failed. //We wait until user explictly forces shader reload until we try again to avoid spamming errors. if(it!=m_shaderCache.end()) return *it; //get shader file names QString vShaderFile = getVShaderName(flags); QString gShaderFile = getGShaderName(flags); QString fShaderFile = getFShaderName(flags); qCDebug(shaderMgr)<<"Loading Scenery3d shader: flags:"<<flags<<", vs:"<<vShaderFile<<", gs:"<<gShaderFile<<", fs:"<<fShaderFile<<""; //load shader files & preprocess QByteArray vShader,gShader,fShader; QOpenGLShaderProgram *prog = Q_NULLPTR; if(preprocessShader(vShaderFile,flags,vShader) && preprocessShader(gShaderFile,flags,gShader) && preprocessShader(fShaderFile,flags,fShader) ) { //check if this content-hash was already created for optimization //(so that shaders with different flags, but identical implementation use the same program) QCryptographicHash hash(QCryptographicHash::Sha256); hash.addData(vShader); hash.addData(gShader); hash.addData(fShader); QByteArray contentHash = hash.result(); if(m_shaderContentCache.contains(contentHash)) { #ifndef NDEBUG //qCDebug(shaderMgr)<<"Using existing shader with content-hash"<<contentHash.toHex(); #endif prog = m_shaderContentCache[contentHash]; } else { //we have to compile the shader prog = new QOpenGLShaderProgram(); if(!loadShader(*prog,vShader,gShader,fShader)) { delete prog; prog = Q_NULLPTR; qCCritical(shaderMgr)<<"ERROR: Shader '"<<flags<<"' could not be compiled. Fix errors and reload shaders or restart program."; } #ifndef NDEBUG else { //qCDebug(shaderMgr)<<"Shader '"<<flags<<"' created, content-hash"<<contentHash.toHex(); } #endif m_shaderContentCache[contentHash] = prog; } } else { qCCritical(shaderMgr)<<"ERROR: Shader '"<<flags<<"' could not be loaded/preprocessed."; } //may put null in cache on fail! m_shaderCache[flags] = prog; return prog; }