45 #include "ShaderCache.hh" 55 #include <QTextStream> 57 #include <ACG/GL/GLError.hh> 58 #include <ACG/ShaderUtils/GLSLShader.hh> 64 ShaderCache::ShaderCache():
74 for (CacheList::iterator it = cache_.begin(); it != cache_.end(); ++it)
77 for (CacheList::iterator it = cacheStatic_.begin(); it != cacheStatic_.end(); ++it)
80 for (CacheList::iterator it = cacheComputeShaders_.begin(); it != cacheComputeShaders_.end(); ++it)
93 std::vector<unsigned int> dummy;
94 return getProgram(_desc, dummy);
105 newEntry.desc = *_desc;
106 newEntry.mods = _mods;
108 if (!_desc->fragmentTemplateFile.isEmpty())
110 newEntry.strFragmentTemplate = _desc->fragmentTemplateFile;
111 newEntry.fragmentFileLastMod = QFileInfo(newEntry.strFragmentTemplate).lastModified();
114 if (!_desc->tessControlTemplateFile.isEmpty())
116 newEntry.strTessControlTemplate = _desc->tessControlTemplateFile;
117 newEntry.tessControlFileLastMod = QFileInfo(newEntry.strTessControlTemplate).lastModified();
120 if (!_desc->tessEvaluationTemplateFile.isEmpty())
122 newEntry.strTessEvaluationTemplate = _desc->tessEvaluationTemplateFile;
123 newEntry.tessEvaluationFileLastMod = QFileInfo(newEntry.strTessEvaluationTemplate).lastModified();
126 if (!_desc->geometryTemplateFile.isEmpty())
128 newEntry.strGeometryTemplate = _desc->geometryTemplateFile;
129 newEntry.geometryFileLastMod = QFileInfo(newEntry.strGeometryTemplate).lastModified();
132 if (!_desc->vertexTemplateFile.isEmpty())
134 newEntry.strVertexTemplate = _desc->vertexTemplateFile;
135 newEntry.vertexFileLastMod = QFileInfo(newEntry.strVertexTemplate).lastModified();
138 CacheList::iterator oldCache = cache_.end();
140 for (CacheList::iterator it = cache_.begin(); it != cache_.end(); ++it)
143 if (!compareShaderGenDescs(&it->first, &newEntry))
145 if ( timeCheck_ && !compareTimeStamp(&it->first, &newEntry))
155 if (!dbgOutputDir_.isEmpty())
157 static int counter = 0;
159 QString fileName = QString(
"shader_%1.glsl").arg(counter++,2,10,QLatin1Char(
'0')) ;
160 fileName = dbgOutputDir_ + QDir::separator() + fileName;
162 QFile fileOut(fileName);
163 if (fileOut.open(QFile::WriteOnly | QFile::Truncate))
165 QTextStream outStrm(&fileOut);
168 outStrm <<
"\nmods: ";
170 for (
size_t i = 0; i < _mods.size(); ++i)
171 outStrm << _mods[i] << (i+1 < _mods.size() ?
", " :
"");
175 outStrm <<
"\n---------------------vertex-shader--------------------\n\n";
182 outStrm <<
"\n---------------------tesscontrol-shader--------------------\n\n";
190 outStrm <<
"\n---------------------tesseval-shader--------------------\n\n";
198 outStrm <<
"\n---------------------geometry-shader--------------------\n\n";
204 outStrm <<
"\n---------------------fragment-shader--------------------\n\n";
237 GLSL::Shader* tessControlShader = 0, *tessEvalShader = 0;
239 #ifdef GL_ARB_tessellation_shader 240 tessControlShader =
new GLSL::TessControlShader();
241 tessEvalShader =
new GLSL::TessEvaluationShader();
242 #endif // GL_ARB_tessellation_shader 248 prog->
attach(tessControlShader);
254 tessEvalShader->compile();
255 prog->
attach(tessEvalShader);
263 if (oldCache != cache_.end())
268 return oldCache->second;
272 cache_.erase(oldCache);
276 cache_.push_back(std::pair<CacheEntry, GLSL::Program*>(newEntry, prog));
282 const char* _tessControlShaderFile,
283 const char* _tessEvalShaderFile,
284 const char* _geometryShaderFile,
285 const char* _fragmentShaderFile,
286 QStringList* _macros,
bool _verbose )
294 QFileInfo fileInfo(_fragmentShaderFile);
295 if (fileInfo.isRelative())
298 fileInfo = QFileInfo(absFilename);
300 newEntry.strFragmentTemplate = absFilename;
301 newEntry.fragmentFileLastMod = fileInfo.lastModified();
305 newEntry.strFragmentTemplate = _fragmentShaderFile;
306 newEntry.fragmentFileLastMod = fileInfo.lastModified();
310 fileInfo = QFileInfo(_vertexShaderFile);
311 if (fileInfo.isRelative())
314 fileInfo = QFileInfo(absFilename);
316 newEntry.strVertexTemplate = absFilename;
317 newEntry.vertexFileLastMod = fileInfo.lastModified();
321 newEntry.strVertexTemplate = _vertexShaderFile;
322 newEntry.vertexFileLastMod = fileInfo.lastModified();
327 if (_geometryShaderFile)
329 fileInfo = QFileInfo(_geometryShaderFile);
330 if (fileInfo.isRelative())
333 fileInfo = QFileInfo(absFilename);
335 newEntry.strGeometryTemplate = absFilename;
336 newEntry.geometryFileLastMod = fileInfo.lastModified();
340 newEntry.strGeometryTemplate = _geometryShaderFile;
341 newEntry.geometryFileLastMod = fileInfo.lastModified();
346 if (_tessControlShaderFile)
348 fileInfo = QFileInfo(_tessControlShaderFile);
349 if (fileInfo.isRelative())
352 fileInfo = QFileInfo(absFilename);
354 newEntry.strTessControlTemplate = absFilename;
355 newEntry.tessControlFileLastMod = fileInfo.lastModified();
359 newEntry.strTessControlTemplate = _tessControlShaderFile;
360 newEntry.tessControlFileLastMod = fileInfo.lastModified();
365 if (_tessEvalShaderFile)
367 fileInfo = QFileInfo(_tessEvalShaderFile);
368 if (fileInfo.isRelative())
371 fileInfo = QFileInfo(absFilename);
373 newEntry.strTessEvaluationTemplate = absFilename;
374 newEntry.tessEvaluationFileLastMod = fileInfo.lastModified();
378 newEntry.strTessEvaluationTemplate = _tessEvalShaderFile;
379 newEntry.tessEvaluationFileLastMod = fileInfo.lastModified();
386 newEntry.macros = *_macros;
388 CacheList::iterator oldCache = cacheStatic_.end();
390 for (CacheList::iterator it = cacheStatic_.begin(); it != cacheStatic_.end(); ++it)
393 if (!compareShaderGenDescs(&it->first, &newEntry))
395 if ( timeCheck_ && !compareTimeStamp(&it->first, &newEntry))
405 GLSL::StringList glslMacros;
409 for (QStringList::const_iterator it = _macros->constBegin(); it != _macros->constEnd(); ++it)
410 glslMacros.push_back(it->toStdString());
414 GLSL::Program* prog =
GLSL::loadProgram(_vertexShaderFile, _tessControlShaderFile, _tessEvalShaderFile, _geometryShaderFile, _fragmentShaderFile, &glslMacros, _verbose);
417 if (oldCache != cacheStatic_.end())
422 return oldCache->second;
426 cacheStatic_.erase(oldCache);
430 cacheStatic_.push_back(std::pair<CacheEntry, GLSL::Program*>(newEntry, prog));
437 return getProgram(_vertexShaderFile, 0, 0, 0, _fragmentShaderFile, _macros, _verbose);
446 QFileInfo fileInfo(_computeShaderFile);
447 if (fileInfo.isRelative())
450 fileInfo = QFileInfo(absFilename);
452 newEntry.strVertexTemplate = absFilename;
453 newEntry.vertexFileLastMod = fileInfo.lastModified();
457 newEntry.strVertexTemplate = _computeShaderFile;
458 newEntry.vertexFileLastMod = fileInfo.lastModified();
462 newEntry.macros = *_macros;
464 CacheList::iterator oldCache = cacheComputeShaders_.end();
466 for (CacheList::iterator it = cacheComputeShaders_.begin(); it != cacheComputeShaders_.end(); ++it)
469 if (!compareShaderGenDescs(&it->first, &newEntry))
471 if ( ( timeCheck_ && !compareTimeStamp(&it->first, &newEntry)) || !it->second || !it->second->isLinked())
481 GLSL::StringList glslMacros;
485 for (QStringList::const_iterator it = _macros->constBegin(); it != _macros->constEnd(); ++it)
486 glslMacros.push_back(it->toStdString());
493 if (oldCache != cacheComputeShaders_.end())
501 if (!glslMacros.empty() && !dbgOutputDir_.isEmpty())
503 GLSL::StringList shaderSrc =
GLSL::loadShader(newEntry.strVertexTemplate.toUtf8(), &glslMacros);
507 unsigned int fnv_prime = 16777619;
508 unsigned int fnv_hash = 2166136261;
510 for (GLSL::StringList::iterator it = shaderSrc.begin(); it != shaderSrc.end(); ++it)
512 for (
size_t i = 0; i < it->length(); ++i)
514 fnv_hash *= fnv_prime;
515 fnv_hash ^=
static_cast<unsigned char>((*it)[i]);
519 QString fnv_string = QString::number(fnv_hash,16).toUpper();
521 std::string dumpFilename = QString(dbgOutputDir_ + QDir::separator() + fileInfo.fileName() + fnv_string).toStdString();
523 std::ofstream dumpStream(dumpFilename.c_str());
524 if (dumpStream.is_open())
526 for (GLSL::StringList::iterator it = shaderSrc.begin(); it != shaderSrc.end(); ++it)
527 dumpStream << it->c_str();
532 return oldCache->second;
536 cacheComputeShaders_.erase(oldCache);
540 cacheComputeShaders_.push_back(std::pair<CacheEntry, GLSL::Program*>(newEntry, prog));
547 if (_a->vertexFileLastMod != _b->vertexFileLastMod)
550 if (_a->geometryFileLastMod != _b->geometryFileLastMod)
553 if (_a->fragmentFileLastMod != _b->fragmentFileLastMod)
556 if (_a->tessControlFileLastMod != _b->tessControlFileLastMod)
559 if (_a->tessEvaluationFileLastMod != _b->tessEvaluationFileLastMod)
566 if (_a->mods != _b->mods)
572 if (_a->strFragmentTemplate != _b->strFragmentTemplate)
575 if (_a->strGeometryTemplate != _b->strGeometryTemplate)
578 if (_a->strVertexTemplate != _b->strVertexTemplate)
581 if (_a->strTessControlTemplate != _b->strTessControlTemplate)
584 if (_a->strTessEvaluationTemplate != _b->strTessEvaluationTemplate)
587 if (_a->macros != _b->macros)
591 return *a == *b ? 0 : -1;
598 cacheStatic_.clear();
599 cacheComputeShaders_.clear();
604 dbgOutputDir_ = _outputDir;
static QString getShaderDir()
GLSL::Program * getComputeProgram(const char *_computeShaderFile, QStringList *_macros=0, bool _verbose=true)
Query a static compute shader program from cache.
void setSource(const StringList &source)
Upload the source of the shader.
const QStringList & getTessEvaluationShaderCode()
Returns generated tessellation control shader code.
bool hasTessControlShader() const
check whether there is a tess-control shader present
void setDebugOutputDir(const char *_outputDir)
Enable debug output of generated shaders to specified directory.
Namespace providing different geometric functions concerning angles.
bool compile(bool verbose=true)
Compile the shader object.
const QStringList & getTessControlShaderCode()
Returns generated vertex shader code.
GLSL::PtrProgram loadComputeProgram(const char *computeShaderFile, const GLSL::StringList *macros, bool verbose)
const QStringList & getFragmentShaderCode()
Returns generated fragment shader code.
bool hasTessEvaluationShader() const
check whether there is a tess-evaluation shader present
GLSL::StringList loadShader(const char *filename, const GLSL::StringList *macros, bool appendNewLineChar, GLSL::StringList *outIncludes)
Loads the shader source.
bool isLinked()
Returns if the program object has been succesfully linked.
void attach(PtrConstShader _shader)
Attaches a shader object to the program object.
GLSL::PtrProgram loadProgram(const char *vertexShaderFile, const char *tessControlShaderFile, const char *tessEvaluationShaderFile, const char *geometryShaderFile, const char *fragmentShaderFile, const GLSL::StringList *macros, bool verbose)
static ShaderCache * getInstance()
Return instance of the ShaderCache singleton.
virtual ~ShaderCache()
Destructor.
GLSL::Program * getProgram(const ShaderGenDesc *_desc, const std::vector< unsigned int > &_mods)
Query a dynamically generated program from cache.
void clearCache()
Delete all cached shaders.
const QStringList & getGeometryShaderCode()
Returns generated tessellation evaluation shader code.
int compareShaderGenDescs(const CacheEntry *_a, const CacheEntry *_b)
Returns true, if the shaders are not equal.
QString toString() const
convert ShaderGenDesc to string format for debugging
A generic shader base class.
const QStringList & getVertexShaderCode()
Returns generated vertex shader code.
bool hasGeometryShader() const
check whether there is a geometry shader present
bool compareTimeStamp(const CacheEntry *_a, const CacheEntry *_b)
Returns true, if the shaders have the timestamp.
void link()
Links the shader objects to the program.