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;
160 fileName.sprintf(
"shader_%02d.glsl", counter++);
161 fileName = dbgOutputDir_ + QDir::separator() + fileName;
163 QFile fileOut(fileName);
164 if (fileOut.open(QFile::WriteOnly | QFile::Truncate))
166 QTextStream outStrm(&fileOut);
169 outStrm <<
"\nmods: ";
171 for (
size_t i = 0; i < _mods.size(); ++i)
172 outStrm << _mods[i] << (i+1 < _mods.size() ?
", " :
"");
176 outStrm <<
"\n---------------------vertex-shader--------------------\n\n";
183 outStrm <<
"\n---------------------tesscontrol-shader--------------------\n\n";
191 outStrm <<
"\n---------------------tesseval-shader--------------------\n\n";
199 outStrm <<
"\n---------------------geometry-shader--------------------\n\n";
205 outStrm <<
"\n---------------------fragment-shader--------------------\n\n";
238 GLSL::Shader* tessControlShader = 0, *tessEvalShader = 0;
240 #ifdef GL_ARB_tessellation_shader 241 tessControlShader =
new GLSL::TessControlShader();
242 tessEvalShader =
new GLSL::TessEvaluationShader();
243 #endif // GL_ARB_tessellation_shader 249 prog->
attach(tessControlShader);
255 tessEvalShader->compile();
256 prog->
attach(tessEvalShader);
264 if (oldCache != cache_.end())
269 return oldCache->second;
273 cache_.erase(oldCache);
277 cache_.push_back(std::pair<CacheEntry, GLSL::Program*>(newEntry, prog));
283 const char* _tessControlShaderFile,
284 const char* _tessEvalShaderFile,
285 const char* _geometryShaderFile,
286 const char* _fragmentShaderFile,
287 QStringList* _macros,
bool _verbose )
295 QFileInfo fileInfo(_fragmentShaderFile);
296 if (fileInfo.isRelative())
299 fileInfo = QFileInfo(absFilename);
301 newEntry.strFragmentTemplate = absFilename;
302 newEntry.fragmentFileLastMod = fileInfo.lastModified();
306 newEntry.strFragmentTemplate = _fragmentShaderFile;
307 newEntry.fragmentFileLastMod = fileInfo.lastModified();
311 fileInfo = QFileInfo(_vertexShaderFile);
312 if (fileInfo.isRelative())
315 fileInfo = QFileInfo(absFilename);
317 newEntry.strVertexTemplate = absFilename;
318 newEntry.vertexFileLastMod = fileInfo.lastModified();
322 newEntry.strVertexTemplate = _vertexShaderFile;
323 newEntry.vertexFileLastMod = fileInfo.lastModified();
328 if (_geometryShaderFile)
330 fileInfo = QFileInfo(_geometryShaderFile);
331 if (fileInfo.isRelative())
334 fileInfo = QFileInfo(absFilename);
336 newEntry.strGeometryTemplate = absFilename;
337 newEntry.geometryFileLastMod = fileInfo.lastModified();
341 newEntry.strGeometryTemplate = _geometryShaderFile;
342 newEntry.geometryFileLastMod = fileInfo.lastModified();
347 if (_tessControlShaderFile)
349 fileInfo = QFileInfo(_tessControlShaderFile);
350 if (fileInfo.isRelative())
353 fileInfo = QFileInfo(absFilename);
355 newEntry.strTessControlTemplate = absFilename;
356 newEntry.tessControlFileLastMod = fileInfo.lastModified();
360 newEntry.strTessControlTemplate = _tessControlShaderFile;
361 newEntry.tessControlFileLastMod = fileInfo.lastModified();
366 if (_tessEvalShaderFile)
368 fileInfo = QFileInfo(_tessEvalShaderFile);
369 if (fileInfo.isRelative())
372 fileInfo = QFileInfo(absFilename);
374 newEntry.strTessEvaluationTemplate = absFilename;
375 newEntry.tessEvaluationFileLastMod = fileInfo.lastModified();
379 newEntry.strTessEvaluationTemplate = _tessEvalShaderFile;
380 newEntry.tessEvaluationFileLastMod = fileInfo.lastModified();
387 newEntry.macros = *_macros;
389 CacheList::iterator oldCache = cacheStatic_.end();
391 for (CacheList::iterator it = cacheStatic_.begin(); it != cacheStatic_.end(); ++it)
394 if (!compareShaderGenDescs(&it->first, &newEntry))
396 if ( timeCheck_ && !compareTimeStamp(&it->first, &newEntry))
406 GLSL::StringList glslMacros;
410 for (QStringList::const_iterator it = _macros->constBegin(); it != _macros->constEnd(); ++it)
411 glslMacros.push_back(it->toStdString());
415 GLSL::Program* prog =
GLSL::loadProgram(_vertexShaderFile, _tessControlShaderFile, _tessEvalShaderFile, _geometryShaderFile, _fragmentShaderFile, &glslMacros, _verbose);
418 if (oldCache != cacheStatic_.end())
423 return oldCache->second;
427 cacheStatic_.erase(oldCache);
431 cacheStatic_.push_back(std::pair<CacheEntry, GLSL::Program*>(newEntry, prog));
438 return getProgram(_vertexShaderFile, 0, 0, 0, _fragmentShaderFile, _macros, _verbose);
447 QFileInfo fileInfo(_computeShaderFile);
448 if (fileInfo.isRelative())
451 fileInfo = QFileInfo(absFilename);
453 newEntry.strVertexTemplate = absFilename;
454 newEntry.vertexFileLastMod = fileInfo.lastModified();
458 newEntry.strVertexTemplate = _computeShaderFile;
459 newEntry.vertexFileLastMod = fileInfo.lastModified();
463 newEntry.macros = *_macros;
465 CacheList::iterator oldCache = cacheComputeShaders_.end();
467 for (CacheList::iterator it = cacheComputeShaders_.begin(); it != cacheComputeShaders_.end(); ++it)
470 if (!compareShaderGenDescs(&it->first, &newEntry))
472 if ( ( timeCheck_ && !compareTimeStamp(&it->first, &newEntry)) || !it->second || !it->second->isLinked())
482 GLSL::StringList glslMacros;
486 for (QStringList::const_iterator it = _macros->constBegin(); it != _macros->constEnd(); ++it)
487 glslMacros.push_back(it->toStdString());
494 if (oldCache != cacheComputeShaders_.end())
502 if (!glslMacros.empty() && !dbgOutputDir_.isEmpty())
504 GLSL::StringList shaderSrc =
GLSL::loadShader(newEntry.strVertexTemplate.toUtf8(), &glslMacros);
508 unsigned int fnv_prime = 16777619;
509 unsigned int fnv_hash = 2166136261;
511 for (GLSL::StringList::iterator it = shaderSrc.begin(); it != shaderSrc.end(); ++it)
513 for (
size_t i = 0; i < it->length(); ++i)
515 fnv_hash *= fnv_prime;
516 fnv_hash ^=
static_cast<unsigned char>((*it)[i]);
521 fnv_string.sprintf(
"%X", fnv_hash);
523 std::string dumpFilename = QString(dbgOutputDir_ + QDir::separator() + fileInfo.fileName() + fnv_string).toStdString();
525 std::ofstream dumpStream(dumpFilename.c_str());
526 if (dumpStream.is_open())
528 for (GLSL::StringList::iterator it = shaderSrc.begin(); it != shaderSrc.end(); ++it)
529 dumpStream << it->c_str();
534 return oldCache->second;
538 cacheComputeShaders_.erase(oldCache);
542 cacheComputeShaders_.push_back(std::pair<CacheEntry, GLSL::Program*>(newEntry, prog));
549 if (_a->vertexFileLastMod != _b->vertexFileLastMod)
552 if (_a->geometryFileLastMod != _b->geometryFileLastMod)
555 if (_a->fragmentFileLastMod != _b->fragmentFileLastMod)
558 if (_a->tessControlFileLastMod != _b->tessControlFileLastMod)
561 if (_a->tessEvaluationFileLastMod != _b->tessEvaluationFileLastMod)
568 if (_a->mods != _b->mods)
574 if (_a->strFragmentTemplate != _b->strFragmentTemplate)
577 if (_a->strGeometryTemplate != _b->strGeometryTemplate)
580 if (_a->strVertexTemplate != _b->strVertexTemplate)
583 if (_a->strTessControlTemplate != _b->strTessControlTemplate)
586 if (_a->strTessEvaluationTemplate != _b->strTessEvaluationTemplate)
589 if (_a->macros != _b->macros)
593 return *a == *b ? 0 : -1;
600 cacheStatic_.clear();
601 cacheComputeShaders_.clear();
606 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.