51 #include "ShaderCache.hh"
61 #include <QTextStream>
63 #include <ACG/GL/GLError.hh>
64 #include <ACG/ShaderUtils/GLSLShader.hh>
70 ShaderCache::ShaderCache():
80 for (CacheList::iterator it =
cache_.begin(); it !=
cache_.end(); ++it)
99 std::vector<unsigned int> dummy;
100 return getProgram(_desc, dummy);
111 newEntry.desc = *_desc;
112 newEntry.mods = _mods;
114 if (!_desc->fragmentTemplateFile.isEmpty())
116 newEntry.strFragmentTemplate = _desc->fragmentTemplateFile;
117 newEntry.fragmentFileLastMod = QFileInfo(newEntry.strFragmentTemplate).lastModified();
120 if (!_desc->tessControlTemplateFile.isEmpty())
122 newEntry.strTessControlTemplate = _desc->tessControlTemplateFile;
123 newEntry.tessControlFileLastMod = QFileInfo(newEntry.strTessControlTemplate).lastModified();
126 if (!_desc->tessEvaluationTemplateFile.isEmpty())
128 newEntry.strTessEvaluationTemplate = _desc->tessEvaluationTemplateFile;
129 newEntry.tessEvaluationFileLastMod = QFileInfo(newEntry.strTessEvaluationTemplate).lastModified();
132 if (!_desc->geometryTemplateFile.isEmpty())
134 newEntry.strGeometryTemplate = _desc->geometryTemplateFile;
135 newEntry.geometryFileLastMod = QFileInfo(newEntry.strGeometryTemplate).lastModified();
138 if (!_desc->vertexTemplateFile.isEmpty())
140 newEntry.strVertexTemplate = _desc->vertexTemplateFile;
141 newEntry.vertexFileLastMod = QFileInfo(newEntry.strVertexTemplate).lastModified();
144 CacheList::iterator oldCache = cache_.end();
146 for (CacheList::iterator it = cache_.begin(); it != cache_.end(); ++it)
149 if (!compareShaderGenDescs(&it->first, &newEntry))
151 if ( timeCheck_ && !compareTimeStamp(&it->first, &newEntry))
161 if (!dbgOutputDir_.isEmpty())
163 static int counter = 0;
166 fileName.sprintf(
"shader_%02d.glsl", counter++);
167 fileName = dbgOutputDir_ + QDir::separator() + fileName;
169 QFile fileOut(fileName);
170 if (fileOut.open(QFile::WriteOnly | QFile::Truncate))
172 QTextStream outStrm(&fileOut);
175 outStrm <<
"\nmods: ";
177 for (
size_t i = 0; i < _mods.size(); ++i)
178 outStrm << _mods[i] << (i+1 < _mods.size() ?
", " :
"");
182 outStrm <<
"\n---------------------vertex-shader--------------------\n\n";
189 outStrm <<
"\n---------------------tesscontrol-shader--------------------\n\n";
197 outStrm <<
"\n---------------------tesseval-shader--------------------\n\n";
205 outStrm <<
"\n---------------------geometry-shader--------------------\n\n";
211 outStrm <<
"\n---------------------fragment-shader--------------------\n\n";
244 GLSL::Shader* tessControlShader = 0, *tessEvalShader = 0;
246 #ifdef GL_ARB_tessellation_shader
247 tessControlShader =
new GLSL::TessControlShader();
248 tessEvalShader =
new GLSL::TessEvaluationShader();
249 #endif // GL_ARB_tessellation_shader
255 prog->
attach(tessControlShader);
261 tessEvalShader->compile();
262 prog->
attach(tessEvalShader);
270 if (oldCache != cache_.end())
275 return oldCache->second;
279 cache_.erase(oldCache);
283 cache_.push_back(std::pair<CacheEntry, GLSL::Program*>(newEntry, prog));
289 const char* _tessControlShaderFile,
290 const char* _tessEvalShaderFile,
291 const char* _geometryShaderFile,
292 const char* _fragmentShaderFile,
293 QStringList* _macros,
bool _verbose )
301 QFileInfo fileInfo(_fragmentShaderFile);
302 if (fileInfo.isRelative())
305 fileInfo = QFileInfo(absFilename);
307 newEntry.strFragmentTemplate = absFilename;
308 newEntry.fragmentFileLastMod = fileInfo.lastModified();
312 newEntry.strFragmentTemplate = _fragmentShaderFile;
313 newEntry.fragmentFileLastMod = fileInfo.lastModified();
317 fileInfo = QFileInfo(_vertexShaderFile);
318 if (fileInfo.isRelative())
321 fileInfo = QFileInfo(absFilename);
323 newEntry.strVertexTemplate = absFilename;
324 newEntry.vertexFileLastMod = fileInfo.lastModified();
328 newEntry.strVertexTemplate = _vertexShaderFile;
329 newEntry.vertexFileLastMod = fileInfo.lastModified();
334 if (_geometryShaderFile)
336 fileInfo = QFileInfo(_geometryShaderFile);
337 if (fileInfo.isRelative())
340 fileInfo = QFileInfo(absFilename);
342 newEntry.strGeometryTemplate = absFilename;
343 newEntry.geometryFileLastMod = fileInfo.lastModified();
347 newEntry.strGeometryTemplate = _geometryShaderFile;
348 newEntry.geometryFileLastMod = fileInfo.lastModified();
353 if (_tessControlShaderFile)
355 fileInfo = QFileInfo(_tessControlShaderFile);
356 if (fileInfo.isRelative())
359 fileInfo = QFileInfo(absFilename);
361 newEntry.strTessControlTemplate = absFilename;
362 newEntry.tessControlFileLastMod = fileInfo.lastModified();
366 newEntry.strTessControlTemplate = _tessControlShaderFile;
367 newEntry.tessControlFileLastMod = fileInfo.lastModified();
372 if (_tessEvalShaderFile)
374 fileInfo = QFileInfo(_tessEvalShaderFile);
375 if (fileInfo.isRelative())
378 fileInfo = QFileInfo(absFilename);
380 newEntry.strTessEvaluationTemplate = absFilename;
381 newEntry.tessEvaluationFileLastMod = fileInfo.lastModified();
385 newEntry.strTessEvaluationTemplate = _tessEvalShaderFile;
386 newEntry.tessEvaluationFileLastMod = fileInfo.lastModified();
393 newEntry.macros = *_macros;
395 CacheList::iterator oldCache = cacheStatic_.end();
397 for (CacheList::iterator it = cacheStatic_.begin(); it != cacheStatic_.end(); ++it)
400 if (!compareShaderGenDescs(&it->first, &newEntry))
402 if ( timeCheck_ && !compareTimeStamp(&it->first, &newEntry))
412 GLSL::StringList glslMacros;
416 for (QStringList::const_iterator it = _macros->constBegin(); it != _macros->constEnd(); ++it)
417 glslMacros.push_back(it->toStdString());
421 GLSL::Program* prog =
GLSL::loadProgram(_vertexShaderFile, _tessControlShaderFile, _tessEvalShaderFile, _geometryShaderFile, _fragmentShaderFile, &glslMacros, _verbose);
424 if (oldCache != cacheStatic_.end())
429 return oldCache->second;
433 cacheStatic_.erase(oldCache);
437 cacheStatic_.push_back(std::pair<CacheEntry, GLSL::Program*>(newEntry, prog));
444 return getProgram(_vertexShaderFile, 0, 0, 0, _fragmentShaderFile, _macros, _verbose);
453 QFileInfo fileInfo(_computeShaderFile);
454 if (fileInfo.isRelative())
457 fileInfo = QFileInfo(absFilename);
459 newEntry.strVertexTemplate = absFilename;
460 newEntry.vertexFileLastMod = fileInfo.lastModified();
464 newEntry.strVertexTemplate = _computeShaderFile;
465 newEntry.vertexFileLastMod = fileInfo.lastModified();
469 newEntry.macros = *_macros;
471 CacheList::iterator oldCache = cacheComputeShaders_.end();
473 for (CacheList::iterator it = cacheComputeShaders_.begin(); it != cacheComputeShaders_.end(); ++it)
476 if (!compareShaderGenDescs(&it->first, &newEntry))
478 if ( ( timeCheck_ && !compareTimeStamp(&it->first, &newEntry)) || !it->second || !it->second->isLinked())
488 GLSL::StringList glslMacros;
492 for (QStringList::const_iterator it = _macros->constBegin(); it != _macros->constEnd(); ++it)
493 glslMacros.push_back(it->toStdString());
500 if (oldCache != cacheComputeShaders_.end())
508 if (!glslMacros.empty() && !dbgOutputDir_.isEmpty())
510 GLSL::StringList shaderSrc =
GLSL::loadShader(newEntry.strVertexTemplate.toUtf8(), &glslMacros);
514 unsigned int fnv_prime = 16777619;
515 unsigned int fnv_hash = 2166136261;
517 for (GLSL::StringList::iterator it = shaderSrc.begin(); it != shaderSrc.end(); ++it)
519 for (
size_t i = 0; i < it->length(); ++i)
521 fnv_hash *= fnv_prime;
522 fnv_hash ^=
static_cast<unsigned char>((*it)[i]);
527 fnv_string.sprintf(
"%X", fnv_hash);
529 std::string dumpFilename = QString(dbgOutputDir_ + QDir::separator() + fileInfo.fileName() + fnv_string).toStdString();
531 std::ofstream dumpStream(dumpFilename.c_str());
532 if (dumpStream.is_open())
534 for (GLSL::StringList::iterator it = shaderSrc.begin(); it != shaderSrc.end(); ++it)
535 dumpStream << it->c_str();
540 return oldCache->second;
544 cacheComputeShaders_.erase(oldCache);
548 cacheComputeShaders_.push_back(std::pair<CacheEntry, GLSL::Program*>(newEntry, prog));
555 if (_a->vertexFileLastMod != _b->vertexFileLastMod)
558 if (_a->geometryFileLastMod != _b->geometryFileLastMod)
561 if (_a->fragmentFileLastMod != _b->fragmentFileLastMod)
564 if (_a->tessControlFileLastMod != _b->tessControlFileLastMod)
567 if (_a->tessEvaluationFileLastMod != _b->tessEvaluationFileLastMod)
574 if (_a->mods != _b->mods)
580 if (_a->strFragmentTemplate != _b->strFragmentTemplate)
583 if (_a->strGeometryTemplate != _b->strGeometryTemplate)
586 if (_a->strVertexTemplate != _b->strVertexTemplate)
589 if (_a->strTessControlTemplate != _b->strTessControlTemplate)
592 if (_a->strTessEvaluationTemplate != _b->strTessEvaluationTemplate)
595 if (_a->macros != _b->macros)
599 return *a == *b ? 0 : -1;
606 cacheStatic_.clear();
607 cacheComputeShaders_.clear();
612 dbgOutputDir_ = _outputDir;
GLSL::StringList loadShader(const char *filename, const GLSL::StringList *macros, bool appendNewLineChar, GLSL::StringList *outIncludes)
Loads the shader source.
GLSL::PtrProgram loadComputeProgram(const char *computeShaderFile, const GLSL::StringList *macros, bool verbose)
virtual ~ShaderCache()
Destructor.
const QStringList & getVertexShaderCode()
Returns generated vertex shader code.
Namespace providing different geometric functions concerning angles.
void setSource(const StringList &source)
Upload the source of the shader.
GLSL::Program * getComputeProgram(const char *_computeShaderFile, QStringList *_macros=0, bool _verbose=true)
Query a static compute shader program from cache.
const QStringList & getFragmentShaderCode()
Returns generated fragment shader code.
const QStringList & getTessEvaluationShaderCode()
Returns generated tessellation control shader code.
GLSL::PtrProgram loadProgram(const char *vertexShaderFile, const char *tessControlShaderFile, const char *tessEvaluationShaderFile, const char *geometryShaderFile, const char *fragmentShaderFile, const GLSL::StringList *macros, bool verbose)
CacheList cacheComputeShaders_
cache for static compute shaders
CacheList cacheStatic_
cache containing static shaders loaded from files (separate from dynamic cache to reduce access time)...
QString toString() const
convert ShaderGenDesc to string format for debugging
GLSL::Program * getProgram(const ShaderGenDesc *_desc, const std::vector< unsigned int > &_mods)
Query a dynamically generated program from cache.
bool hasTessControlShader() const
check whether there is a tess-control shader present
A generic shader base class.
int compareShaderGenDescs(const CacheEntry *_a, const CacheEntry *_b)
Returns true, if the shaders are not equal.
bool isLinked()
Returns if the program object has been succesfully linked.
bool compile(bool verbose=true)
Compile the shader object.
void link()
Links the shader objects to the program.
bool compareTimeStamp(const CacheEntry *_a, const CacheEntry *_b)
Returns true, if the shaders have the timestamp.
static ShaderCache * getInstance()
Return instance of the ShaderCache singleton.
void clearCache()
Delete all cached shaders.
bool hasTessEvaluationShader() const
check whether there is a tess-evaluation shader present
CacheList cache_
cache containing dynamic shaders from ShaderProgGenerator
const QStringList & getGeometryShaderCode()
Returns generated tessellation evaluation shader code.
void setDebugOutputDir(const char *_outputDir)
Enable debug output of generated shaders to specified directory.
const QStringList & getTessControlShaderCode()
Returns generated vertex shader code.
void attach(PtrConstShader _shader)
Attaches a shader object to the program object.
static QString getShaderDir()
bool hasGeometryShader() const
check whether there is a geometry shader present