@@ -74,22 +74,6 @@ namespace
7474 += static_cast <int >(std::count (source.begin () + lineDirectivePosition, source.begin () + foundPos, ' \n ' ));
7575 return lineNumber;
7676 }
77- }
78-
79- namespace Shader
80- {
81-
82- ShaderManager::ShaderManager ()
83- {
84- mHotReloadManager = std::make_unique<HotReloadManager>();
85- }
86-
87- ShaderManager::~ShaderManager () = default ;
88-
89- void ShaderManager::setShaderPath (const std::filesystem::path& path)
90- {
91- mPath = path;
92- }
9377
9478 bool addLineDirectivesAfterConditionalBlocks (std::string& source)
9579 {
@@ -122,7 +106,7 @@ namespace Shader
122106 // Adjusts #line statements accordingly and detects cyclic includes.
123107 // cycleIncludeChecker is the set of files that include this file directly or indirectly, and is intentionally not a
124108 // reference to allow automatic cleanup.
125- static bool parseIncludes (const std::filesystem::path& shaderPath, std::string& source, const std::string& fileName,
109+ bool parseIncludes (const std::filesystem::path& shaderPath, std::string& source, const std::string& fileName,
126110 int & fileNumber, std::set<std::filesystem::path> cycleIncludeChecker,
127111 std::set<std::filesystem::path>& includedFiles)
128112 {
@@ -195,6 +179,127 @@ namespace Shader
195179 }
196180 return true ;
197181 }
182+ }
183+
184+ namespace Shader
185+ {
186+ struct HotReloadManager
187+ {
188+ using KeysHolder = std::set<ShaderManager::MapKey>;
189+
190+ std::unordered_map<std::string, KeysHolder> mShaderFiles ;
191+ std::unordered_map<std::string, std::set<std::filesystem::path>> templateIncludedFiles;
192+ std::filesystem::file_time_type mLastAutoRecompileTime ;
193+ bool mHotReloadEnabled ;
194+ bool mTriggerReload ;
195+
196+ HotReloadManager ()
197+ {
198+ mTriggerReload = false ;
199+ mHotReloadEnabled = false ;
200+ mLastAutoRecompileTime = std::filesystem::file_time_type::clock::now ();
201+ }
202+
203+ void addShaderFiles (const std::string& templateName, const ShaderManager::DefineMap& defines)
204+ {
205+ const std::set<std::filesystem::path>& shaderFiles = templateIncludedFiles[templateName];
206+ for (const std::filesystem::path& file : shaderFiles)
207+ {
208+ mShaderFiles [Files::pathToUnicodeString (file)].insert (std::make_pair (templateName, defines));
209+ }
210+ }
211+
212+ void update (ShaderManager& manager, osgViewer::Viewer& viewer)
213+ {
214+ auto timeSinceLastCheckMillis = std::chrono::duration_cast<std::chrono::milliseconds>(
215+ std::filesystem::file_time_type::clock::now () - mLastAutoRecompileTime );
216+ if ((mHotReloadEnabled && timeSinceLastCheckMillis.count () > 200 ) || mTriggerReload == true )
217+ {
218+ reloadTouchedShaders (manager, viewer);
219+ }
220+ mTriggerReload = false ;
221+ }
222+
223+ void reloadTouchedShaders (ShaderManager& manager, osgViewer::Viewer& viewer)
224+ {
225+ bool threadsRunningToStop = false ;
226+ for (auto & [pathShaderToTest, shaderKeys] : mShaderFiles )
227+ {
228+ const std::filesystem::file_time_type writeTime = std::filesystem::last_write_time (pathShaderToTest);
229+ if (writeTime.time_since_epoch () > mLastAutoRecompileTime .time_since_epoch ())
230+ {
231+ if (!threadsRunningToStop)
232+ {
233+ threadsRunningToStop = viewer.areThreadsRunning ();
234+ if (threadsRunningToStop)
235+ viewer.stopThreading ();
236+ }
237+
238+ for (const auto & [templateName, shaderDefines] : shaderKeys)
239+ {
240+ ShaderManager::ShaderMap::iterator shaderIt
241+ = manager.mShaders .find (std::make_pair (templateName, shaderDefines));
242+ if (shaderIt == manager.mShaders .end ())
243+ {
244+ Log (Debug::Error) << " Failed to find shader " << templateName;
245+ continue ;
246+ }
247+
248+ ShaderManager::TemplateMap::iterator templateIt = manager.mShaderTemplates .find (
249+ templateName); // Can't be Null, if we're here it means the template was added
250+ assert (templateIt != manager.mShaderTemplates .end ());
251+ std::string& shaderSource = templateIt->second ;
252+ std::set<std::filesystem::path> insertedPaths;
253+ std::filesystem::path path = (std::filesystem::path (manager.mPath ) / templateName);
254+ std::ifstream stream;
255+ stream.open (path);
256+ if (stream.fail ())
257+ {
258+ Log (Debug::Error)
259+ << " Failed to open " << path << " : " << std::generic_category ().message (errno);
260+ continue ;
261+ }
262+ std::stringstream buffer;
263+ buffer << stream.rdbuf ();
264+
265+ // parse includes
266+ int fileNumber = 1 ;
267+ std::string source = buffer.str ();
268+ if (!addLineDirectivesAfterConditionalBlocks (source)
269+ || !parseIncludes (std::filesystem::path (manager.mPath ), source, templateName, fileNumber,
270+ {}, insertedPaths))
271+ {
272+ break ;
273+ }
274+ shaderSource = std::move (source);
275+
276+ std::vector<std::string> linkedShaderNames;
277+ if (!manager.createSourceFromTemplate (
278+ shaderSource, linkedShaderNames, templateName, shaderDefines))
279+ {
280+ break ;
281+ }
282+ shaderIt->second ->setShaderSource (shaderSource);
283+ }
284+ }
285+ }
286+ if (threadsRunningToStop)
287+ viewer.startThreading ();
288+ mLastAutoRecompileTime = std::filesystem::file_time_type::clock::now ();
289+ }
290+ };
291+
292+ ShaderManager::ShaderManager ()
293+ {
294+ mHotReloadManager = std::make_unique<HotReloadManager>();
295+ }
296+
297+ ShaderManager::~ShaderManager () = default ;
298+
299+ void ShaderManager::setShaderPath (const std::filesystem::path& path)
300+ {
301+ mPath = path;
302+ }
198303
199304 bool parseForeachDirective (std::string& source, const std::string& templateName, size_t foundPos)
200305 {
@@ -399,112 +504,6 @@ namespace Shader
399504 return true ;
400505 }
401506
402- struct HotReloadManager
403- {
404- using KeysHolder = std::set<ShaderManager::MapKey>;
405-
406- std::unordered_map<std::string, KeysHolder> mShaderFiles ;
407- std::unordered_map<std::string, std::set<std::filesystem::path>> templateIncludedFiles;
408- std::filesystem::file_time_type mLastAutoRecompileTime ;
409- bool mHotReloadEnabled ;
410- bool mTriggerReload ;
411-
412- HotReloadManager ()
413- {
414- mTriggerReload = false ;
415- mHotReloadEnabled = false ;
416- mLastAutoRecompileTime = std::filesystem::file_time_type::clock::now ();
417- }
418-
419- void addShaderFiles (const std::string& templateName, const ShaderManager::DefineMap& defines)
420- {
421- const std::set<std::filesystem::path>& shaderFiles = templateIncludedFiles[templateName];
422- for (const std::filesystem::path& file : shaderFiles)
423- {
424- mShaderFiles [Files::pathToUnicodeString (file)].insert (std::make_pair (templateName, defines));
425- }
426- }
427-
428- void update (ShaderManager& manager, osgViewer::Viewer& viewer)
429- {
430- auto timeSinceLastCheckMillis = std::chrono::duration_cast<std::chrono::milliseconds>(
431- std::filesystem::file_time_type::clock::now () - mLastAutoRecompileTime );
432- if ((mHotReloadEnabled && timeSinceLastCheckMillis.count () > 200 ) || mTriggerReload == true )
433- {
434- reloadTouchedShaders (manager, viewer);
435- }
436- mTriggerReload = false ;
437- }
438-
439- void reloadTouchedShaders (ShaderManager& manager, osgViewer::Viewer& viewer)
440- {
441- bool threadsRunningToStop = false ;
442- for (auto & [pathShaderToTest, shaderKeys] : mShaderFiles )
443- {
444- const std::filesystem::file_time_type writeTime = std::filesystem::last_write_time (pathShaderToTest);
445- if (writeTime.time_since_epoch () > mLastAutoRecompileTime .time_since_epoch ())
446- {
447- if (!threadsRunningToStop)
448- {
449- threadsRunningToStop = viewer.areThreadsRunning ();
450- if (threadsRunningToStop)
451- viewer.stopThreading ();
452- }
453-
454- for (const auto & [templateName, shaderDefines] : shaderKeys)
455- {
456- ShaderManager::ShaderMap::iterator shaderIt
457- = manager.mShaders .find (std::make_pair (templateName, shaderDefines));
458- if (shaderIt == manager.mShaders .end ())
459- {
460- Log (Debug::Error) << " Failed to find shader " << templateName;
461- continue ;
462- }
463-
464- ShaderManager::TemplateMap::iterator templateIt = manager.mShaderTemplates .find (
465- templateName); // Can't be Null, if we're here it means the template was added
466- assert (templateIt != manager.mShaderTemplates .end ());
467- std::string& shaderSource = templateIt->second ;
468- std::set<std::filesystem::path> insertedPaths;
469- std::filesystem::path path = (std::filesystem::path (manager.mPath ) / templateName);
470- std::ifstream stream;
471- stream.open (path);
472- if (stream.fail ())
473- {
474- Log (Debug::Error)
475- << " Failed to open " << path << " : " << std::generic_category ().message (errno);
476- continue ;
477- }
478- std::stringstream buffer;
479- buffer << stream.rdbuf ();
480-
481- // parse includes
482- int fileNumber = 1 ;
483- std::string source = buffer.str ();
484- if (!addLineDirectivesAfterConditionalBlocks (source)
485- || !parseIncludes (std::filesystem::path (manager.mPath ), source, templateName, fileNumber,
486- {}, insertedPaths))
487- {
488- break ;
489- }
490- shaderSource = std::move (source);
491-
492- std::vector<std::string> linkedShaderNames;
493- if (!manager.createSourceFromTemplate (
494- shaderSource, linkedShaderNames, templateName, shaderDefines))
495- {
496- break ;
497- }
498- shaderIt->second ->setShaderSource (shaderSource);
499- }
500- }
501- }
502- if (threadsRunningToStop)
503- viewer.startThreading ();
504- mLastAutoRecompileTime = std::filesystem::file_time_type::clock::now ();
505- }
506- };
507-
508507 osg::ref_ptr<osg::Shader> ShaderManager::getShader (
509508 std::string templateName, const ShaderManager::DefineMap& defines, std::optional<osg::Shader::Type> type)
510509 {
0 commit comments