ShaderManager.cpp   ShaderManager.cpp 
skipping to change at line 30 skipping to change at line 30
#include "StelOpenGL.hpp" #include "StelOpenGL.hpp"
#include "ShaderManager.hpp" #include "ShaderManager.hpp"
#include "StelFileMgr.hpp" #include "StelFileMgr.hpp"
#include <QDir> #include <QDir>
#include <QOpenGLShaderProgram> #include <QOpenGLShaderProgram>
#include <QCryptographicHash> #include <QCryptographicHash>
#include <QDebug> #include <QDebug>
Q_LOGGING_CATEGORY(shaderMgr, "stel.plugin.scenery3d.shadermgr")
ShaderMgr::t_UniformStrings ShaderMgr::uniformStrings; ShaderMgr::t_UniformStrings ShaderMgr::uniformStrings;
ShaderMgr::t_FeatureFlagStrings ShaderMgr::featureFlagsStrings; ShaderMgr::t_FeatureFlagStrings ShaderMgr::featureFlagsStrings;
ShaderMgr::ShaderMgr() ShaderMgr::ShaderMgr()
{ {
if(uniformStrings.size()==0) if(uniformStrings.size()==0)
{ {
//initialize the strings //initialize the strings
uniformStrings["u_mModelView"] = UNIFORM_MAT_MODELVIEW; uniformStrings["u_mModelView"] = UNIFORM_MAT_MODELVIEW;
uniformStrings["u_mProjection"] = UNIFORM_MAT_PROJECTION; uniformStrings["u_mProjection"] = UNIFORM_MAT_PROJECTION;
skipping to change at line 116 skipping to change at line 118
} }
} }
ShaderMgr::~ShaderMgr() ShaderMgr::~ShaderMgr()
{ {
clearCache(); clearCache();
} }
void ShaderMgr::clearCache() void ShaderMgr::clearCache()
{ {
qDebug()<<"[ShaderMgr] Clearing"<<m_shaderContentCache.size()<<"shad ers"; qCDebug(shaderMgr)<<"Clearing"<<m_shaderContentCache.size()<<"shader s";
//iterate over the shaderContentCache - this contains the same amoun t of shaders as actually exist! //iterate over the shaderContentCache - this contains the same amoun t of shaders as actually exist!
//the shaderCache could contain duplicate entries //the shaderCache could contain duplicate entries
for(t_ShaderContentCache::iterator it = m_shaderContentCache.begin() ;it!=m_shaderContentCache.end();++it) for(t_ShaderContentCache::iterator it = m_shaderContentCache.begin() ;it!=m_shaderContentCache.end();++it)
{ {
if((*it)) if((*it))
delete (*it); delete (*it);
} }
m_shaderCache.clear(); m_shaderCache.clear();
m_uniformCache.clear(); m_uniformCache.clear();
m_shaderContentCache.clear(); m_shaderContentCache.clear();
} }
QOpenGLShaderProgram* ShaderMgr::findOrLoadShader(uint flags) QOpenGLShaderProgram* ShaderMgr::findOrLoadShader(uint flags)
{ {
t_ShaderCache::iterator it = m_shaderCache.find(flags); t_ShaderCache::iterator it = m_shaderCache.find(flags);
// This may also return NULL if the load failed. // This may also return Q_NULLPTR if the load failed.
//We wait until user explictly forces shader reload until we try aga in to avoid spamming errors. //We wait until user explictly forces shader reload until we try aga in to avoid spamming errors.
if(it!=m_shaderCache.end()) if(it!=m_shaderCache.end())
return *it; return *it;
//get shader file names //get shader file names
QString vShaderFile = getVShaderName(flags); QString vShaderFile = getVShaderName(flags);
QString gShaderFile = getGShaderName(flags); QString gShaderFile = getGShaderName(flags);
QString fShaderFile = getFShaderName(flags); QString fShaderFile = getFShaderName(flags);
qDebug()<<"[ShaderMgr] Loading Scenery3d shader: flags:"<<flags<<", vs:"<<vShaderFile<<", gs:"<<gShaderFile<<", fs:"<<fShaderFile<<""; qCDebug(shaderMgr)<<"Loading Scenery3d shader: flags:"<<flags<<", vs :"<<vShaderFile<<", gs:"<<gShaderFile<<", fs:"<<fShaderFile<<"";
//load shader files & preprocess //load shader files & preprocess
QByteArray vShader,gShader,fShader; QByteArray vShader,gShader,fShader;
QOpenGLShaderProgram *prog = NULL; QOpenGLShaderProgram *prog = Q_NULLPTR;
if(preprocessShader(vShaderFile,flags,vShader) && if(preprocessShader(vShaderFile,flags,vShader) &&
preprocessShader(gShaderFile,flags,gShader) && preprocessShader(gShaderFile,flags,gShader) &&
preprocessShader(fShaderFile,flags,fShader) preprocessShader(fShaderFile,flags,fShader)
) )
{ {
//check if this content-hash was already created for optimiz ation //check if this content-hash was already created for optimiz ation
//(so that shaders with different flags, but identical imple mentation use the same program) //(so that shaders with different flags, but identical imple mentation use the same program)
QCryptographicHash hash(QCryptographicHash::Sha256); QCryptographicHash hash(QCryptographicHash::Sha256);
hash.addData(vShader); hash.addData(vShader);
hash.addData(gShader); hash.addData(gShader);
hash.addData(fShader); hash.addData(fShader);
QByteArray contentHash = hash.result(); QByteArray contentHash = hash.result();
if(m_shaderContentCache.contains(contentHash)) if(m_shaderContentCache.contains(contentHash))
{ {
#ifndef NDEBUG #ifndef NDEBUG
qDebug()<<"[ShaderMgr] Using existing shader with co ntent-hash"<<contentHash.toHex(); //qCDebug(shaderMgr)<<"Using existing shader with co ntent-hash"<<contentHash.toHex();
#endif #endif
prog = m_shaderContentCache[contentHash]; prog = m_shaderContentCache[contentHash];
} }
else else
{ {
//we have to compile the shader //we have to compile the shader
prog = new QOpenGLShaderProgram(); prog = new QOpenGLShaderProgram();
if(!loadShader(*prog,vShader,gShader,fShader)) if(!loadShader(*prog,vShader,gShader,fShader))
{ {
delete prog; delete prog;
prog = NULL; prog = Q_NULLPTR;
qCritical()<<"[ShaderMgr] ERROR: Shader '"<< qCCritical(shaderMgr)<<"ERROR: Shader '"<<fl
flags<<"' could not be compiled. Fix errors and reload shaders or restart p ags<<"' could not be compiled. Fix errors and reload shaders or restart pro
rogram."; gram.";
} }
#ifndef NDEBUG #ifndef NDEBUG
else else
{ {
qDebug()<<"[ShaderMgr] Shader '"<<flags<<"' created, content-hash"<<contentHash.toHex(); //qCDebug(shaderMgr)<<"Shader '"<<flags<<"' created, content-hash"<<contentHash.toHex();
} }
#endif #endif
m_shaderContentCache[contentHash] = prog; m_shaderContentCache[contentHash] = prog;
} }
} }
else else
{ {
qCritical()<<"[ShaderMgr] ERROR: Shader '"<<flags<<"' could not be loaded/preprocessed."; qCCritical(shaderMgr)<<"ERROR: Shader '"<<flags<<"' could no t be loaded/preprocessed.";
} }
//may put null in cache on fail! //may put null in cache on fail!
m_shaderCache[flags] = prog; m_shaderCache[flags] = prog;
return prog; return prog;
} }
QString ShaderMgr::getVShaderName(uint flags) QString ShaderMgr::getVShaderName(uint flags)
{ {
skipping to change at line 291 skipping to change at line 293
//no shader of this type //no shader of this type
return true; return true;
} }
QDir dir("data/shaders/"); QDir dir("data/shaders/");
QString filePath = StelFileMgr::findFile(dir.filePath(fileName),Stel FileMgr::File); QString filePath = StelFileMgr::findFile(dir.filePath(fileName),Stel FileMgr::File);
//open and load file //open and load file
QFile file(filePath); QFile file(filePath);
#ifndef NDEBUG #ifndef NDEBUG
qDebug()<<"File path:"<<filePath; //qCDebug(shaderMgr)<<"File path:"<<filePath;
#endif #endif
if(!file.open(QFile::ReadOnly)) if(!file.open(QFile::ReadOnly))
{ {
qCritical()<<"Could not open file"<<filePath; qCCritical(shaderMgr)<<"Could not open file"<<filePath;
return false; return false;
} }
processedSource.clear(); processedSource.clear();
processedSource.reserve(file.size()); processedSource.reserve(file.size());
//use a text stream for "parsing" //use a text stream for "parsing"
QTextStream in(&file),lineStream; QTextStream in(&file),lineStream;
QString line,word; QString line,word;
skipping to change at line 330 skipping to change at line 332
//try to find it in our flags list //try to find it in our flags list
t_FeatureFlagStrings::iterator it = featureFlagsStri ngs.find(word); t_FeatureFlagStrings::iterator it = featureFlagsStri ngs.find(word);
if(it!=featureFlagsStrings.end()) if(it!=featureFlagsStrings.end())
{ {
bool val = it.value() & flags; bool val = it.value() & flags;
write = "#define " + word + (val?" 1":" 0"); write = "#define " + word + (val?" 1":" 0");
#ifdef NDEBUG #ifdef NDEBUG
} }
#else #else
//output matches for debugging //output matches for debugging
qDebug()<<"preprocess match: "<<line <<" --> "<<write; //qCDebug(shaderMgr)<<"preprocess match: "<< line <<" --> "<<write;
} }
else else
{ {
qDebug()<<"unknown define, ignoring: "<<line ; //qCDebug(shaderMgr)<<"unknown define, ignor ing: "<<line;
} }
#endif #endif
} }
//write output //write output
processedSource.append(write); processedSource.append(write);
processedSource.append('\n'); processedSource.append('\n');
} }
return true; return true;
} }
bool ShaderMgr::loadShader(QOpenGLShaderProgram& program, const QByteArray& vShader, const QByteArray& gShader, const QByteArray& fShader) bool ShaderMgr::loadShader(QOpenGLShaderProgram& program, const QByteArray& vShader, const QByteArray& gShader, const QByteArray& fShader)
{ {
//clear old shader data, if exists //clear old shader data, if exists
program.removeAllShaders(); program.removeAllShaders();
if(!vShader.isEmpty()) if(!vShader.isEmpty())
{ {
if(!program.addShaderFromSourceCode(QOpenGLShader::Vertex,vS hader)) if(!program.addShaderFromSourceCode(QOpenGLShader::Vertex,vS hader))
{ {
qCritical() << "[ShaderMgr] Unable to compile vertex qCCritical(shaderMgr) << "Unable to compile vertex s
shader"; hader";
qCritical() << program.log(); qCCritical(shaderMgr) << program.log();
return false; return false;
} }
else else
{ {
//TODO Qt wrapper does not seem to provide warnings (regardless of what its doc says)! //TODO Qt wrapper does not seem to provide warnings (regardless of what its doc says)!
//Raise a bug with them or handle shader loading our selves? //Raise a bug with them or handle shader loading our selves?
QString log = program.log().trimmed(); QString log = program.log().trimmed();
if(!log.isEmpty()) if(!log.isEmpty())
{ {
qWarning()<<"[ShaderMgr] Vertex shader warni qCWarning(shaderMgr)<<"Vertex shader warning
ngs:"; s:";
qWarning()<<log; qCWarning(shaderMgr)<<log;
} }
} }
} }
if(!gShader.isEmpty()) if(!gShader.isEmpty())
{ {
if(!program.addShaderFromSourceCode(QOpenGLShader::Geometry, gShader)) if(!program.addShaderFromSourceCode(QOpenGLShader::Geometry, gShader))
{ {
qCritical() << "[ShaderMgr] Unable to compile geomet qCCritical(shaderMgr) << "Unable to compile geometry
ry shader"; shader";
qCritical() << program.log(); qCCritical(shaderMgr) << program.log();
return false; return false;
} }
else else
{ {
//TODO Qt wrapper does not seem to provide warnings (regardless of what its doc says)! //TODO Qt wrapper does not seem to provide warnings (regardless of what its doc says)!
//Raise a bug with them or handle shader loading our selves? //Raise a bug with them or handle shader loading our selves?
QString log = program.log().trimmed(); QString log = program.log().trimmed();
if(!log.isEmpty()) if(!log.isEmpty())
{ {
qWarning()<<"[ShaderMgr] Geometry shader war qCWarning(shaderMgr)<<"Geometry shader warni
nings:"; ngs:";
qWarning()<<log; qCWarning(shaderMgr)<<log;
} }
} }
} }
if(!fShader.isEmpty()) if(!fShader.isEmpty())
{ {
if(!program.addShaderFromSourceCode(QOpenGLShader::Fragment, fShader)) if(!program.addShaderFromSourceCode(QOpenGLShader::Fragment, fShader))
{ {
qCritical() << "[ShaderMgr] Unable to compile fragme qCCritical(shaderMgr) << "Unable to compile fragment
nt shader"; shader";
qCritical() << program.log(); qCCritical(shaderMgr) << program.log();
return false; return false;
} }
else else
{ {
//TODO Qt wrapper does not seem to provide warnings (regardless of what its doc says)! //TODO Qt wrapper does not seem to provide warnings (regardless of what its doc says)!
//Raise a bug with them or handle shader loading our selves? //Raise a bug with them or handle shader loading our selves?
QString log = program.log().trimmed(); QString log = program.log().trimmed();
if(!log.isEmpty()) if(!log.isEmpty())
{ {
qWarning()<<"[ShaderMgr] Fragment shader war qCWarning(shaderMgr)<<"Fragment shader warni
nings:"; ngs:";
qWarning()<<log; qCWarning(shaderMgr)<<log;
} }
} }
} }
//Set attribute locations to hardcoded locations. //Set attribute locations to hardcoded locations.
//This enables us to use a single VAO configuration for all shaders! //This enables us to use a single VAO configuration for all shaders!
program.bindAttributeLocation("a_vertex",ATTLOC_VERTEX); program.bindAttributeLocation("a_vertex",StelOpenGLArray::ATTLOC_VER
program.bindAttributeLocation("a_normal", ATTLOC_NORMAL); TEX);
program.bindAttributeLocation("a_texcoord",ATTLOC_TEXCOORD); program.bindAttributeLocation("a_normal", StelOpenGLArray::ATTLOC_NO
program.bindAttributeLocation("a_tangent",ATTLOC_TANGENT); RMAL);
program.bindAttributeLocation("a_bitangent",ATTLOC_BITANGENT); program.bindAttributeLocation("a_texcoord",StelOpenGLArray::ATTLOC_T
EXCOORD);
program.bindAttributeLocation("a_tangent",StelOpenGLArray::ATTLOC_TA
NGENT);
program.bindAttributeLocation("a_bitangent",StelOpenGLArray::ATTLOC_
BITANGENT);
//link program //link program
if(!program.link()) if(!program.link())
{ {
qCritical()<<"[ShaderMgr] unable to link shader"; qCCritical(shaderMgr)<<"[ShaderMgr] unable to link shader";
qCritical()<<program.log(); qCCritical(shaderMgr)<<program.log();
return false; return false;
} }
buildUniformCache(program); buildUniformCache(program);
return true; return true;
} }
void ShaderMgr::buildUniformCache(QOpenGLShaderProgram &program) void ShaderMgr::buildUniformCache(QOpenGLShaderProgram &program)
{ {
//this enumerates all available uniforms of this shader, and stores their locations in a map //this enumerates all available uniforms of this shader, and stores their locations in a map
skipping to change at line 450 skipping to change at line 452
QOpenGLFunctions* gl = QOpenGLContext::currentContext()->functions() ; QOpenGLFunctions* gl = QOpenGLContext::currentContext()->functions() ;
GL(gl->glGetProgramiv(prog, GL_ACTIVE_UNIFORMS, &numUniforms)); GL(gl->glGetProgramiv(prog, GL_ACTIVE_UNIFORMS, &numUniforms));
GL(gl->glGetProgramiv(prog, GL_ACTIVE_UNIFORM_MAX_LENGTH, &bufSize)) ; GL(gl->glGetProgramiv(prog, GL_ACTIVE_UNIFORM_MAX_LENGTH, &bufSize)) ;
QByteArray buf(bufSize,'\0'); QByteArray buf(bufSize,'\0');
GLsizei length; GLsizei length;
GLint size; GLint size;
GLenum type; GLenum type;
#ifndef NDEBUG #ifndef NDEBUG
qDebug()<<"[ShaderMgr] Shader has"<<numUniforms<<"uniforms"; //qCDebug(shaderMgr)<<"Shader has"<<numUniforms<<"uniforms";
#endif #endif
for(int i =0;i<numUniforms;++i) for(int i =0;i<numUniforms;++i)
{ {
GL(gl->glGetActiveUniform(prog,i,bufSize,&length,&size,&type ,buf.data())); GL(gl->glGetActiveUniform(prog,i,bufSize,&length,&size,&type ,buf.data()));
QString str(buf); QString str(buf);
str = str.trimmed(); // no idea if this is required str = str.trimmed(); // no idea if this is required
GLint loc = program.uniformLocation(str); GLint loc = program.uniformLocation(str);
t_UniformStrings::iterator it = uniformStrings.find(str); t_UniformStrings::iterator it = uniformStrings.find(str);
// This may also return NULL if the load failed. // 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. //We wait until user explictly forces shader reload until we try again to avoid spamming errors.
if(it!=uniformStrings.end()) if(it!=uniformStrings.end())
{ {
//this is uniform we recognize //this is uniform we recognize
//need to get the uniforms location (!= index) //need to get the uniforms location (!= index)
m_uniformCache[&program][*it] = loc; m_uniformCache[&program][*it] = loc;
#ifdef NDEBUG
}
#else
//output mapping for debugging //output mapping for debugging
qDebug()<<i<<loc<<str<<size<<type<<" mapped to "<<*i t; //qCDebug(shaderMgr)<<i<<loc<<str<<size<<type<<" map ped to "<<*it;
} }
else else
{ {
qWarning()<<i<<loc<<str<<size<<type<<" --- unknown - --"; qCWarning(shaderMgr)<<i<<loc<<str<<size<<type<<" --- unknown uniform! ---";
} }
#endif
} }
} }
 End of changes. 27 change blocks. 
48 lines changed or deleted 51 lines changed or added

This html diff was produced by rfcdiff 1.41. The latest version is available from http://tools.ietf.org/tools/rfcdiff/