1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-02-01 09:15:36 +00:00
openmw/components/shader/shadermanager.cpp

663 lines
28 KiB
C++
Raw Normal View History

#include "shadermanager.hpp"
#include <algorithm>
2017-05-06 21:05:13 +00:00
#include <sstream>
#include <regex>
Merge branch 'SHADER_HOT_RELOAD' into 'master' Shaders: Hot reload, togglable by lua debug command See merge request OpenMW/openmw!2238 (cherry picked from commit 4078f19c741685b7120c636108de7ded1ae6dbfd) 8d194a16 Shaders: rudimentary hot reloader on shaders 4e7c1c5b Added break when the operation failed 6b38d622 Added lua bindings to toggle hot reload (disabled by default) or to trigger a reload 31d41252 forgot memory include f78fa989 fixed include, cleaned comments and indentation fc8838c7 Renamed lua binding, and use action to avoid concurrency issue aa51d6de Missing chrono include ? 68d06989 Fixed cyclical included check b6d7293a Removed weird lines that I thought were necessary to please the compiler 9a475b0c fixed blank lines and missing breaks cdd95f78 replaced empty function body by default a1c8dc9d C++17 compat ? 7b78bf4b Fix files with different defines weren't added to the hot reload manager cc9d4364 includes now work when the same shader has different defines 15751c57 Lua debug api doc 3ab0a991 Hot reload done only once every 200 ms, no point in beeing faster df69fc76 Post processing shaders now use the same lua commands, no more launcher option... c71f3508 changed overview.rst of post processing 603b30e1 Added some variable names to make it clearer what their function was baadc06e Merge branch 'master' into 'SHADER_HOT_RELOAD' decfbc53 Fix threading issues b14cc673 adds missing decleration 16a4b571 adds missing include 166717d6 Makes sure threads are only stopped once ,and that they will be re-started 25c1f0ca Renamed variable to fix case issue
2022-08-21 09:08:27 +00:00
#include <set>
#include <unordered_map>
#include <chrono>
2022-09-09 08:13:47 +00:00
2016-02-17 14:04:05 +00:00
#include <osg/Program>
Merge branch 'SHADER_HOT_RELOAD' into 'master' Shaders: Hot reload, togglable by lua debug command See merge request OpenMW/openmw!2238 (cherry picked from commit 4078f19c741685b7120c636108de7ded1ae6dbfd) 8d194a16 Shaders: rudimentary hot reloader on shaders 4e7c1c5b Added break when the operation failed 6b38d622 Added lua bindings to toggle hot reload (disabled by default) or to trigger a reload 31d41252 forgot memory include f78fa989 fixed include, cleaned comments and indentation fc8838c7 Renamed lua binding, and use action to avoid concurrency issue aa51d6de Missing chrono include ? 68d06989 Fixed cyclical included check b6d7293a Removed weird lines that I thought were necessary to please the compiler 9a475b0c fixed blank lines and missing breaks cdd95f78 replaced empty function body by default a1c8dc9d C++17 compat ? 7b78bf4b Fix files with different defines weren't added to the hot reload manager cc9d4364 includes now work when the same shader has different defines 15751c57 Lua debug api doc 3ab0a991 Hot reload done only once every 200 ms, no point in beeing faster df69fc76 Post processing shaders now use the same lua commands, no more launcher option... c71f3508 changed overview.rst of post processing 603b30e1 Added some variable names to make it clearer what their function was baadc06e Merge branch 'master' into 'SHADER_HOT_RELOAD' decfbc53 Fix threading issues b14cc673 adds missing decleration 16a4b571 adds missing include 166717d6 Makes sure threads are only stopped once ,and that they will be re-started 25c1f0ca Renamed variable to fix case issue
2022-08-21 09:08:27 +00:00
#include <osgViewer/Viewer>
2022-09-09 08:13:47 +00:00
#include <boost/filesystem/fstream.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/path.hpp>
2018-08-14 15:42:41 +00:00
#include <components/debug/debuglog.hpp>
#include <components/misc/stringops.hpp>
2022-06-06 20:40:38 +00:00
#include <components/settings/settings.hpp>
2018-08-14 15:42:41 +00:00
namespace Shader
{
2021-03-02 07:30:54 +00:00
ShaderManager::ShaderManager()
2021-02-21 18:38:15 +00:00
{
Merge branch 'SHADER_HOT_RELOAD' into 'master' Shaders: Hot reload, togglable by lua debug command See merge request OpenMW/openmw!2238 (cherry picked from commit 4078f19c741685b7120c636108de7ded1ae6dbfd) 8d194a16 Shaders: rudimentary hot reloader on shaders 4e7c1c5b Added break when the operation failed 6b38d622 Added lua bindings to toggle hot reload (disabled by default) or to trigger a reload 31d41252 forgot memory include f78fa989 fixed include, cleaned comments and indentation fc8838c7 Renamed lua binding, and use action to avoid concurrency issue aa51d6de Missing chrono include ? 68d06989 Fixed cyclical included check b6d7293a Removed weird lines that I thought were necessary to please the compiler 9a475b0c fixed blank lines and missing breaks cdd95f78 replaced empty function body by default a1c8dc9d C++17 compat ? 7b78bf4b Fix files with different defines weren't added to the hot reload manager cc9d4364 includes now work when the same shader has different defines 15751c57 Lua debug api doc 3ab0a991 Hot reload done only once every 200 ms, no point in beeing faster df69fc76 Post processing shaders now use the same lua commands, no more launcher option... c71f3508 changed overview.rst of post processing 603b30e1 Added some variable names to make it clearer what their function was baadc06e Merge branch 'master' into 'SHADER_HOT_RELOAD' decfbc53 Fix threading issues b14cc673 adds missing decleration 16a4b571 adds missing include 166717d6 Makes sure threads are only stopped once ,and that they will be re-started 25c1f0ca Renamed variable to fix case issue
2022-08-21 09:08:27 +00:00
mHotReloadManager = std::make_unique<HotReloadManager>();
2021-02-21 18:38:15 +00:00
}
Merge branch 'SHADER_HOT_RELOAD' into 'master' Shaders: Hot reload, togglable by lua debug command See merge request OpenMW/openmw!2238 (cherry picked from commit 4078f19c741685b7120c636108de7ded1ae6dbfd) 8d194a16 Shaders: rudimentary hot reloader on shaders 4e7c1c5b Added break when the operation failed 6b38d622 Added lua bindings to toggle hot reload (disabled by default) or to trigger a reload 31d41252 forgot memory include f78fa989 fixed include, cleaned comments and indentation fc8838c7 Renamed lua binding, and use action to avoid concurrency issue aa51d6de Missing chrono include ? 68d06989 Fixed cyclical included check b6d7293a Removed weird lines that I thought were necessary to please the compiler 9a475b0c fixed blank lines and missing breaks cdd95f78 replaced empty function body by default a1c8dc9d C++17 compat ? 7b78bf4b Fix files with different defines weren't added to the hot reload manager cc9d4364 includes now work when the same shader has different defines 15751c57 Lua debug api doc 3ab0a991 Hot reload done only once every 200 ms, no point in beeing faster df69fc76 Post processing shaders now use the same lua commands, no more launcher option... c71f3508 changed overview.rst of post processing 603b30e1 Added some variable names to make it clearer what their function was baadc06e Merge branch 'master' into 'SHADER_HOT_RELOAD' decfbc53 Fix threading issues b14cc673 adds missing decleration 16a4b571 adds missing include 166717d6 Makes sure threads are only stopped once ,and that they will be re-started 25c1f0ca Renamed variable to fix case issue
2022-08-21 09:08:27 +00:00
ShaderManager::~ShaderManager() = default;
void ShaderManager::setShaderPath(const std::string &path)
{
mPath = path;
}
bool addLineDirectivesAfterConditionalBlocks(std::string& source)
{
for (size_t position = 0; position < source.length(); )
{
size_t foundPos = source.find("#endif", position);
foundPos = std::min(foundPos, source.find("#elif", position));
foundPos = std::min(foundPos, source.find("#else", position));
if (foundPos == std::string::npos)
break;
foundPos = source.find_first_of("\n\r", foundPos);
foundPos = source.find_first_not_of("\n\r", foundPos);
if (foundPos == std::string::npos)
break;
size_t lineDirectivePosition = source.rfind("#line", foundPos);
int lineNumber;
if (lineDirectivePosition != std::string::npos)
{
size_t lineNumberStart = lineDirectivePosition + std::string("#line ").length();
size_t lineNumberEnd = source.find_first_not_of("0123456789", lineNumberStart);
std::string lineNumberString = source.substr(lineNumberStart, lineNumberEnd - lineNumberStart);
lineNumber = std::stoi(lineNumberString) - 1;
}
else
{
lineDirectivePosition = 0;
lineNumber = 1;
}
lineNumber += std::count(source.begin() + lineDirectivePosition, source.begin() + foundPos, '\n');
source.replace(foundPos, 0, "#line " + std::to_string(lineNumber) + "\n");
position = foundPos;
}
return true;
}
// Recursively replaces include statements with the actual source of the included files.
// Adjusts #line statements accordingly and detects cyclic includes.
Merge branch 'SHADER_HOT_RELOAD' into 'master' Shaders: Hot reload, togglable by lua debug command See merge request OpenMW/openmw!2238 (cherry picked from commit 4078f19c741685b7120c636108de7ded1ae6dbfd) 8d194a16 Shaders: rudimentary hot reloader on shaders 4e7c1c5b Added break when the operation failed 6b38d622 Added lua bindings to toggle hot reload (disabled by default) or to trigger a reload 31d41252 forgot memory include f78fa989 fixed include, cleaned comments and indentation fc8838c7 Renamed lua binding, and use action to avoid concurrency issue aa51d6de Missing chrono include ? 68d06989 Fixed cyclical included check b6d7293a Removed weird lines that I thought were necessary to please the compiler 9a475b0c fixed blank lines and missing breaks cdd95f78 replaced empty function body by default a1c8dc9d C++17 compat ? 7b78bf4b Fix files with different defines weren't added to the hot reload manager cc9d4364 includes now work when the same shader has different defines 15751c57 Lua debug api doc 3ab0a991 Hot reload done only once every 200 ms, no point in beeing faster df69fc76 Post processing shaders now use the same lua commands, no more launcher option... c71f3508 changed overview.rst of post processing 603b30e1 Added some variable names to make it clearer what their function was baadc06e Merge branch 'master' into 'SHADER_HOT_RELOAD' decfbc53 Fix threading issues b14cc673 adds missing decleration 16a4b571 adds missing include 166717d6 Makes sure threads are only stopped once ,and that they will be re-started 25c1f0ca Renamed variable to fix case issue
2022-08-21 09:08:27 +00:00
// cycleIncludeChecker is the set of files that include this file directly or indirectly, and is intentionally not a reference to allow automatic cleanup.
2022-09-09 08:13:47 +00:00
static bool parseIncludes(const boost::filesystem::path& shaderPath, std::string& source, const std::string& fileName, int& fileNumber, std::set<boost::filesystem::path> cycleIncludeChecker,std::set<boost::filesystem::path>& includedFiles)
2016-02-17 22:29:07 +00:00
{
Merge branch 'SHADER_HOT_RELOAD' into 'master' Shaders: Hot reload, togglable by lua debug command See merge request OpenMW/openmw!2238 (cherry picked from commit 4078f19c741685b7120c636108de7ded1ae6dbfd) 8d194a16 Shaders: rudimentary hot reloader on shaders 4e7c1c5b Added break when the operation failed 6b38d622 Added lua bindings to toggle hot reload (disabled by default) or to trigger a reload 31d41252 forgot memory include f78fa989 fixed include, cleaned comments and indentation fc8838c7 Renamed lua binding, and use action to avoid concurrency issue aa51d6de Missing chrono include ? 68d06989 Fixed cyclical included check b6d7293a Removed weird lines that I thought were necessary to please the compiler 9a475b0c fixed blank lines and missing breaks cdd95f78 replaced empty function body by default a1c8dc9d C++17 compat ? 7b78bf4b Fix files with different defines weren't added to the hot reload manager cc9d4364 includes now work when the same shader has different defines 15751c57 Lua debug api doc 3ab0a991 Hot reload done only once every 200 ms, no point in beeing faster df69fc76 Post processing shaders now use the same lua commands, no more launcher option... c71f3508 changed overview.rst of post processing 603b30e1 Added some variable names to make it clearer what their function was baadc06e Merge branch 'master' into 'SHADER_HOT_RELOAD' decfbc53 Fix threading issues b14cc673 adds missing decleration 16a4b571 adds missing include 166717d6 Makes sure threads are only stopped once ,and that they will be re-started 25c1f0ca Renamed variable to fix case issue
2022-08-21 09:08:27 +00:00
includedFiles.insert(shaderPath / fileName);
// An include is cyclic if it is being included by itself
Merge branch 'SHADER_HOT_RELOAD' into 'master' Shaders: Hot reload, togglable by lua debug command See merge request OpenMW/openmw!2238 (cherry picked from commit 4078f19c741685b7120c636108de7ded1ae6dbfd) 8d194a16 Shaders: rudimentary hot reloader on shaders 4e7c1c5b Added break when the operation failed 6b38d622 Added lua bindings to toggle hot reload (disabled by default) or to trigger a reload 31d41252 forgot memory include f78fa989 fixed include, cleaned comments and indentation fc8838c7 Renamed lua binding, and use action to avoid concurrency issue aa51d6de Missing chrono include ? 68d06989 Fixed cyclical included check b6d7293a Removed weird lines that I thought were necessary to please the compiler 9a475b0c fixed blank lines and missing breaks cdd95f78 replaced empty function body by default a1c8dc9d C++17 compat ? 7b78bf4b Fix files with different defines weren't added to the hot reload manager cc9d4364 includes now work when the same shader has different defines 15751c57 Lua debug api doc 3ab0a991 Hot reload done only once every 200 ms, no point in beeing faster df69fc76 Post processing shaders now use the same lua commands, no more launcher option... c71f3508 changed overview.rst of post processing 603b30e1 Added some variable names to make it clearer what their function was baadc06e Merge branch 'master' into 'SHADER_HOT_RELOAD' decfbc53 Fix threading issues b14cc673 adds missing decleration 16a4b571 adds missing include 166717d6 Makes sure threads are only stopped once ,and that they will be re-started 25c1f0ca Renamed variable to fix case issue
2022-08-21 09:08:27 +00:00
if (cycleIncludeChecker.insert(shaderPath/fileName).second == false)
{
Log(Debug::Error) << "Shader " << fileName << " error: Detected cyclic #includes";
return false;
}
Misc::StringUtils::replaceAll(source, "\r\n", "\n");
2016-02-17 22:29:07 +00:00
size_t foundPos = 0;
while ((foundPos = source.find("#include")) != std::string::npos)
{
size_t start = source.find('"', foundPos);
if (start == std::string::npos || start == source.size() - 1)
2016-02-17 22:29:07 +00:00
{
Log(Debug::Error) << "Shader " << fileName << " error: Invalid #include";
2016-02-17 22:29:07 +00:00
return false;
}
size_t end = source.find('"', start + 1);
2016-02-17 22:29:07 +00:00
if (end == std::string::npos)
{
Log(Debug::Error) << "Shader " << fileName << " error: Invalid #include";
2016-02-17 22:29:07 +00:00
return false;
}
std::string includeFilename = source.substr(start + 1, end - (start + 1));
2022-09-09 08:13:47 +00:00
boost::filesystem::path includePath = shaderPath / includeFilename;
// Determine the line number that will be used for the #line directive following the included source
size_t lineDirectivePosition = source.rfind("#line", foundPos);
int lineNumber;
if (lineDirectivePosition != std::string::npos)
{
size_t lineNumberStart = lineDirectivePosition + std::string("#line ").length();
size_t lineNumberEnd = source.find_first_not_of("0123456789", lineNumberStart);
std::string lineNumberString = source.substr(lineNumberStart, lineNumberEnd - lineNumberStart);
lineNumber = std::stoi(lineNumberString) - 1;
}
else
{
lineDirectivePosition = 0;
lineNumber = 0;
}
lineNumber += std::count(source.begin() + lineDirectivePosition, source.begin() + foundPos, '\n');
// Include the file recursively
2022-09-09 08:13:47 +00:00
boost::filesystem::ifstream includeFstream;
includeFstream.open(includePath);
if (includeFstream.fail())
{
Log(Debug::Error) << "Shader " << fileName << " error: Failed to open include " << includePath.string();
return false;
}
int includedFileNumber = fileNumber++;
2016-02-17 22:29:07 +00:00
std::stringstream buffer;
buffer << includeFstream.rdbuf();
std::string stringRepresentation = buffer.str();
if (!addLineDirectivesAfterConditionalBlocks(stringRepresentation)
Merge branch 'SHADER_HOT_RELOAD' into 'master' Shaders: Hot reload, togglable by lua debug command See merge request OpenMW/openmw!2238 (cherry picked from commit 4078f19c741685b7120c636108de7ded1ae6dbfd) 8d194a16 Shaders: rudimentary hot reloader on shaders 4e7c1c5b Added break when the operation failed 6b38d622 Added lua bindings to toggle hot reload (disabled by default) or to trigger a reload 31d41252 forgot memory include f78fa989 fixed include, cleaned comments and indentation fc8838c7 Renamed lua binding, and use action to avoid concurrency issue aa51d6de Missing chrono include ? 68d06989 Fixed cyclical included check b6d7293a Removed weird lines that I thought were necessary to please the compiler 9a475b0c fixed blank lines and missing breaks cdd95f78 replaced empty function body by default a1c8dc9d C++17 compat ? 7b78bf4b Fix files with different defines weren't added to the hot reload manager cc9d4364 includes now work when the same shader has different defines 15751c57 Lua debug api doc 3ab0a991 Hot reload done only once every 200 ms, no point in beeing faster df69fc76 Post processing shaders now use the same lua commands, no more launcher option... c71f3508 changed overview.rst of post processing 603b30e1 Added some variable names to make it clearer what their function was baadc06e Merge branch 'master' into 'SHADER_HOT_RELOAD' decfbc53 Fix threading issues b14cc673 adds missing decleration 16a4b571 adds missing include 166717d6 Makes sure threads are only stopped once ,and that they will be re-started 25c1f0ca Renamed variable to fix case issue
2022-08-21 09:08:27 +00:00
|| !parseIncludes(shaderPath, stringRepresentation, includeFilename, fileNumber, cycleIncludeChecker, includedFiles))
2016-02-17 22:29:07 +00:00
{
Log(Debug::Error) << "In file included from " << fileName << "." << lineNumber;
2016-02-17 22:29:07 +00:00
return false;
}
std::stringstream toInsert;
toInsert << "#line 0 " << includedFileNumber << "\n" << stringRepresentation << "\n#line " << lineNumber << " 0\n";
source.replace(foundPos, (end - foundPos + 1), toInsert.str());
2016-02-17 22:29:07 +00:00
}
return true;
}
bool parseForeachDirective(std::string& source, const std::string& templateName, size_t foundPos)
{
size_t iterNameStart = foundPos + strlen("$foreach") + 1;
size_t iterNameEnd = source.find_first_of(" \n\r()[].;,", iterNameStart);
if (iterNameEnd == std::string::npos)
{
Log(Debug::Error) << "Shader " << templateName << " error: Unexpected EOF";
return false;
}
std::string iteratorName = "$" + source.substr(iterNameStart, iterNameEnd - iterNameStart);
size_t listStart = iterNameEnd + 1;
size_t listEnd = source.find_first_of("\n\r", listStart);
if (listEnd == std::string::npos)
{
Log(Debug::Error) << "Shader " << templateName << " error: Unexpected EOF";
return false;
}
std::string list = source.substr(listStart, listEnd - listStart);
std::vector<std::string> listElements;
if (list != "")
Misc::StringUtils::split(list, listElements, ",");
size_t contentStart = source.find_first_not_of("\n\r", listEnd);
size_t contentEnd = source.find("$endforeach", contentStart);
if (contentEnd == std::string::npos)
{
Log(Debug::Error) << "Shader " << templateName << " error: Unexpected EOF";
return false;
}
std::string content = source.substr(contentStart, contentEnd - contentStart);
size_t overallEnd = contentEnd + std::string("$endforeach").length();
size_t lineDirectivePosition = source.rfind("#line", overallEnd);
int lineNumber;
if (lineDirectivePosition != std::string::npos)
{
size_t lineNumberStart = lineDirectivePosition + std::string("#line ").length();
size_t lineNumberEnd = source.find_first_not_of("0123456789", lineNumberStart);
std::string lineNumberString = source.substr(lineNumberStart, lineNumberEnd - lineNumberStart);
lineNumber = std::stoi(lineNumberString);
}
else
{
lineDirectivePosition = 0;
lineNumber = 2;
}
lineNumber += std::count(source.begin() + lineDirectivePosition, source.begin() + overallEnd, '\n');
2022-05-04 20:33:39 +00:00
std::string replacement;
for (std::vector<std::string>::const_iterator element = listElements.cbegin(); element != listElements.cend(); element++)
{
std::string contentInstance = content;
size_t foundIterator;
while ((foundIterator = contentInstance.find(iteratorName)) != std::string::npos)
contentInstance.replace(foundIterator, iteratorName.length(), *element);
replacement += contentInstance;
}
replacement += "\n#line " + std::to_string(lineNumber);
source.replace(foundPos, overallEnd - foundPos, replacement);
return true;
}
bool parseLinkDirective(std::string& source, std::string& linkTarget, const std::string& templateName, size_t foundPos)
{
size_t endPos = foundPos + 5;
size_t lineEnd = source.find_first_of('\n', endPos);
// If lineEnd = npos, this is the last line, so no need to check
std::string linkStatement = source.substr(endPos, lineEnd - endPos);
std::regex linkRegex(
R"r(\s*"([^"]+)"\s*)r" // Find any quoted string as the link name -> match[1]
R"r((if\s+)r" // Begin optional condition -> match[2]
R"r((!)?\s*)r" // Optional ! -> match[3]
R"r(([_a-zA-Z0-9]+)?)r" // The condition -> match[4]
R"r()?\s*)r" // End optional condition -> match[2]
);
std::smatch linkMatch;
bool hasCondition = false;
std::string linkConditionExpression;
if (std::regex_match(linkStatement, linkMatch, linkRegex))
{
linkTarget = linkMatch[1].str();
hasCondition = !linkMatch[2].str().empty();
linkConditionExpression = linkMatch[4].str();
}
else
{
Log(Debug::Error) << "Shader " << templateName << " error: Expected a shader filename to link";
return false;
}
if (linkTarget.empty())
{
Log(Debug::Error) << "Shader " << templateName << " error: Empty link name";
return false;
}
if (hasCondition)
{
bool condition = !(linkConditionExpression.empty() || linkConditionExpression == "0");
if (linkMatch[3].str() == "!")
condition = !condition;
if (!condition)
2022-05-04 20:33:39 +00:00
linkTarget.clear();
}
source.replace(foundPos, lineEnd - foundPos, "");
return true;
}
bool parseDirectives(std::string& source, std::vector<std::string>& linkedShaderTemplateNames, const ShaderManager::DefineMap& defines, const ShaderManager::DefineMap& globalDefines, const std::string& templateName)
{
const char escapeCharacter = '$';
size_t foundPos = 0;
while ((foundPos = source.find(escapeCharacter, foundPos)) != std::string::npos)
{
size_t endPos = source.find_first_of(" \n\r()[].;,", foundPos);
if (endPos == std::string::npos)
{
Log(Debug::Error) << "Shader " << templateName << " error: Unexpected EOF";
return false;
}
std::string directive = source.substr(foundPos + 1, endPos - (foundPos + 1));
if (directive == "foreach")
{
if (!parseForeachDirective(source, templateName, foundPos))
return false;
}
else if (directive == "link")
{
std::string linkTarget;
if (!parseLinkDirective(source, linkTarget, templateName, foundPos))
return false;
if (!linkTarget.empty() && linkTarget != templateName)
linkedShaderTemplateNames.push_back(linkTarget);
}
else
{
Log(Debug::Error) << "Shader " << templateName << " error: Unknown shader directive: $" << directive;
return false;
}
}
return true;
}
bool parseDefines(std::string& source, const ShaderManager::DefineMap& defines,
const ShaderManager::DefineMap& globalDefines, const std::string& templateName)
2016-02-17 22:29:07 +00:00
{
const char escapeCharacter = '@';
size_t foundPos = 0;
std::vector<std::string> forIterators;
2016-02-17 22:29:07 +00:00
while ((foundPos = source.find(escapeCharacter)) != std::string::npos)
{
size_t endPos = source.find_first_of(" \n\r()[].;,", foundPos);
2016-02-17 22:29:07 +00:00
if (endPos == std::string::npos)
{
Log(Debug::Error) << "Shader " << templateName << " error: Unexpected EOF";
2016-02-17 22:29:07 +00:00
return false;
}
std::string define = source.substr(foundPos+1, endPos - (foundPos+1));
ShaderManager::DefineMap::const_iterator defineFound = defines.find(define);
ShaderManager::DefineMap::const_iterator globalDefineFound = globalDefines.find(define);
if (define == "foreach")
{
source.replace(foundPos, 1, "$");
size_t iterNameStart = endPos + 1;
size_t iterNameEnd = source.find_first_of(" \n\r()[].;,", iterNameStart);
if (iterNameEnd == std::string::npos)
{
Log(Debug::Error) << "Shader " << templateName << " error: Unexpected EOF";
return false;
}
forIterators.push_back(source.substr(iterNameStart, iterNameEnd - iterNameStart));
}
else if (define == "endforeach")
{
source.replace(foundPos, 1, "$");
if (forIterators.empty())
{
Log(Debug::Error) << "Shader " << templateName << " error: endforeach without foreach";
return false;
}
else
forIterators.pop_back();
}
else if (define == "link")
{
source.replace(foundPos, 1, "$");
}
else if (std::find(forIterators.begin(), forIterators.end(), define) != forIterators.end())
{
source.replace(foundPos, 1, "$");
}
else if (defineFound != defines.end())
2016-02-17 22:29:07 +00:00
{
source.replace(foundPos, endPos - foundPos, defineFound->second);
}
else if (globalDefineFound != globalDefines.end())
{
source.replace(foundPos, endPos - foundPos, globalDefineFound->second);
2016-02-17 22:29:07 +00:00
}
else
{
Log(Debug::Error) << "Shader " << templateName << " error: Undefined " << define;
return false;
2016-02-17 22:29:07 +00:00
}
}
return true;
}
Merge branch 'SHADER_HOT_RELOAD' into 'master' Shaders: Hot reload, togglable by lua debug command See merge request OpenMW/openmw!2238 (cherry picked from commit 4078f19c741685b7120c636108de7ded1ae6dbfd) 8d194a16 Shaders: rudimentary hot reloader on shaders 4e7c1c5b Added break when the operation failed 6b38d622 Added lua bindings to toggle hot reload (disabled by default) or to trigger a reload 31d41252 forgot memory include f78fa989 fixed include, cleaned comments and indentation fc8838c7 Renamed lua binding, and use action to avoid concurrency issue aa51d6de Missing chrono include ? 68d06989 Fixed cyclical included check b6d7293a Removed weird lines that I thought were necessary to please the compiler 9a475b0c fixed blank lines and missing breaks cdd95f78 replaced empty function body by default a1c8dc9d C++17 compat ? 7b78bf4b Fix files with different defines weren't added to the hot reload manager cc9d4364 includes now work when the same shader has different defines 15751c57 Lua debug api doc 3ab0a991 Hot reload done only once every 200 ms, no point in beeing faster df69fc76 Post processing shaders now use the same lua commands, no more launcher option... c71f3508 changed overview.rst of post processing 603b30e1 Added some variable names to make it clearer what their function was baadc06e Merge branch 'master' into 'SHADER_HOT_RELOAD' decfbc53 Fix threading issues b14cc673 adds missing decleration 16a4b571 adds missing include 166717d6 Makes sure threads are only stopped once ,and that they will be re-started 25c1f0ca Renamed variable to fix case issue
2022-08-21 09:08:27 +00:00
struct HotReloadManager
{
using KeysHolder = std::set<ShaderManager::MapKey>;
std::unordered_map<std::string, KeysHolder> mShaderFiles;
2022-09-09 08:13:47 +00:00
std::unordered_map<std::string, std::set<boost::filesystem::path>> templateIncludedFiles;
std::chrono::time_point<std::chrono::system_clock> mLastAutoRecompileTime;
Merge branch 'SHADER_HOT_RELOAD' into 'master' Shaders: Hot reload, togglable by lua debug command See merge request OpenMW/openmw!2238 (cherry picked from commit 4078f19c741685b7120c636108de7ded1ae6dbfd) 8d194a16 Shaders: rudimentary hot reloader on shaders 4e7c1c5b Added break when the operation failed 6b38d622 Added lua bindings to toggle hot reload (disabled by default) or to trigger a reload 31d41252 forgot memory include f78fa989 fixed include, cleaned comments and indentation fc8838c7 Renamed lua binding, and use action to avoid concurrency issue aa51d6de Missing chrono include ? 68d06989 Fixed cyclical included check b6d7293a Removed weird lines that I thought were necessary to please the compiler 9a475b0c fixed blank lines and missing breaks cdd95f78 replaced empty function body by default a1c8dc9d C++17 compat ? 7b78bf4b Fix files with different defines weren't added to the hot reload manager cc9d4364 includes now work when the same shader has different defines 15751c57 Lua debug api doc 3ab0a991 Hot reload done only once every 200 ms, no point in beeing faster df69fc76 Post processing shaders now use the same lua commands, no more launcher option... c71f3508 changed overview.rst of post processing 603b30e1 Added some variable names to make it clearer what their function was baadc06e Merge branch 'master' into 'SHADER_HOT_RELOAD' decfbc53 Fix threading issues b14cc673 adds missing decleration 16a4b571 adds missing include 166717d6 Makes sure threads are only stopped once ,and that they will be re-started 25c1f0ca Renamed variable to fix case issue
2022-08-21 09:08:27 +00:00
bool mHotReloadEnabled;
bool mTriggerReload;
HotReloadManager()
{
mTriggerReload = false;
mHotReloadEnabled = false;
2022-09-09 08:13:47 +00:00
mLastAutoRecompileTime = std::chrono::system_clock::now();
Merge branch 'SHADER_HOT_RELOAD' into 'master' Shaders: Hot reload, togglable by lua debug command See merge request OpenMW/openmw!2238 (cherry picked from commit 4078f19c741685b7120c636108de7ded1ae6dbfd) 8d194a16 Shaders: rudimentary hot reloader on shaders 4e7c1c5b Added break when the operation failed 6b38d622 Added lua bindings to toggle hot reload (disabled by default) or to trigger a reload 31d41252 forgot memory include f78fa989 fixed include, cleaned comments and indentation fc8838c7 Renamed lua binding, and use action to avoid concurrency issue aa51d6de Missing chrono include ? 68d06989 Fixed cyclical included check b6d7293a Removed weird lines that I thought were necessary to please the compiler 9a475b0c fixed blank lines and missing breaks cdd95f78 replaced empty function body by default a1c8dc9d C++17 compat ? 7b78bf4b Fix files with different defines weren't added to the hot reload manager cc9d4364 includes now work when the same shader has different defines 15751c57 Lua debug api doc 3ab0a991 Hot reload done only once every 200 ms, no point in beeing faster df69fc76 Post processing shaders now use the same lua commands, no more launcher option... c71f3508 changed overview.rst of post processing 603b30e1 Added some variable names to make it clearer what their function was baadc06e Merge branch 'master' into 'SHADER_HOT_RELOAD' decfbc53 Fix threading issues b14cc673 adds missing decleration 16a4b571 adds missing include 166717d6 Makes sure threads are only stopped once ,and that they will be re-started 25c1f0ca Renamed variable to fix case issue
2022-08-21 09:08:27 +00:00
}
void addShaderFiles(const std::string& templateName,const ShaderManager::DefineMap& defines )
{
2022-09-09 08:13:47 +00:00
const std::set<boost::filesystem::path>& shaderFiles = templateIncludedFiles[templateName];
for (const boost::filesystem::path& file : shaderFiles)
Merge branch 'SHADER_HOT_RELOAD' into 'master' Shaders: Hot reload, togglable by lua debug command See merge request OpenMW/openmw!2238 (cherry picked from commit 4078f19c741685b7120c636108de7ded1ae6dbfd) 8d194a16 Shaders: rudimentary hot reloader on shaders 4e7c1c5b Added break when the operation failed 6b38d622 Added lua bindings to toggle hot reload (disabled by default) or to trigger a reload 31d41252 forgot memory include f78fa989 fixed include, cleaned comments and indentation fc8838c7 Renamed lua binding, and use action to avoid concurrency issue aa51d6de Missing chrono include ? 68d06989 Fixed cyclical included check b6d7293a Removed weird lines that I thought were necessary to please the compiler 9a475b0c fixed blank lines and missing breaks cdd95f78 replaced empty function body by default a1c8dc9d C++17 compat ? 7b78bf4b Fix files with different defines weren't added to the hot reload manager cc9d4364 includes now work when the same shader has different defines 15751c57 Lua debug api doc 3ab0a991 Hot reload done only once every 200 ms, no point in beeing faster df69fc76 Post processing shaders now use the same lua commands, no more launcher option... c71f3508 changed overview.rst of post processing 603b30e1 Added some variable names to make it clearer what their function was baadc06e Merge branch 'master' into 'SHADER_HOT_RELOAD' decfbc53 Fix threading issues b14cc673 adds missing decleration 16a4b571 adds missing include 166717d6 Makes sure threads are only stopped once ,and that they will be re-started 25c1f0ca Renamed variable to fix case issue
2022-08-21 09:08:27 +00:00
{
mShaderFiles[file.string()].insert(std::make_pair(templateName, defines));
}
}
void update(ShaderManager& Manager,osgViewer::Viewer& viewer)
{
2022-09-09 08:13:47 +00:00
auto timeSinceLastCheckMillis = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - mLastAutoRecompileTime);
Merge branch 'SHADER_HOT_RELOAD' into 'master' Shaders: Hot reload, togglable by lua debug command See merge request OpenMW/openmw!2238 (cherry picked from commit 4078f19c741685b7120c636108de7ded1ae6dbfd) 8d194a16 Shaders: rudimentary hot reloader on shaders 4e7c1c5b Added break when the operation failed 6b38d622 Added lua bindings to toggle hot reload (disabled by default) or to trigger a reload 31d41252 forgot memory include f78fa989 fixed include, cleaned comments and indentation fc8838c7 Renamed lua binding, and use action to avoid concurrency issue aa51d6de Missing chrono include ? 68d06989 Fixed cyclical included check b6d7293a Removed weird lines that I thought were necessary to please the compiler 9a475b0c fixed blank lines and missing breaks cdd95f78 replaced empty function body by default a1c8dc9d C++17 compat ? 7b78bf4b Fix files with different defines weren't added to the hot reload manager cc9d4364 includes now work when the same shader has different defines 15751c57 Lua debug api doc 3ab0a991 Hot reload done only once every 200 ms, no point in beeing faster df69fc76 Post processing shaders now use the same lua commands, no more launcher option... c71f3508 changed overview.rst of post processing 603b30e1 Added some variable names to make it clearer what their function was baadc06e Merge branch 'master' into 'SHADER_HOT_RELOAD' decfbc53 Fix threading issues b14cc673 adds missing decleration 16a4b571 adds missing include 166717d6 Makes sure threads are only stopped once ,and that they will be re-started 25c1f0ca Renamed variable to fix case issue
2022-08-21 09:08:27 +00:00
if ((mHotReloadEnabled && timeSinceLastCheckMillis.count() > 200) || mTriggerReload == true)
{
reloadTouchedShaders(Manager, viewer);
}
mTriggerReload = false;
}
void reloadTouchedShaders(ShaderManager& Manager, osgViewer::Viewer& viewer)
{
bool threadsRunningToStop = false;
for (auto& [pathShaderToTest, shaderKeys]: mShaderFiles)
{
2022-09-09 08:13:47 +00:00
auto write_time = std::chrono::system_clock::from_time_t(boost::filesystem::last_write_time(pathShaderToTest));
Merge branch 'SHADER_HOT_RELOAD' into 'master' Shaders: Hot reload, togglable by lua debug command See merge request OpenMW/openmw!2238 (cherry picked from commit 4078f19c741685b7120c636108de7ded1ae6dbfd) 8d194a16 Shaders: rudimentary hot reloader on shaders 4e7c1c5b Added break when the operation failed 6b38d622 Added lua bindings to toggle hot reload (disabled by default) or to trigger a reload 31d41252 forgot memory include f78fa989 fixed include, cleaned comments and indentation fc8838c7 Renamed lua binding, and use action to avoid concurrency issue aa51d6de Missing chrono include ? 68d06989 Fixed cyclical included check b6d7293a Removed weird lines that I thought were necessary to please the compiler 9a475b0c fixed blank lines and missing breaks cdd95f78 replaced empty function body by default a1c8dc9d C++17 compat ? 7b78bf4b Fix files with different defines weren't added to the hot reload manager cc9d4364 includes now work when the same shader has different defines 15751c57 Lua debug api doc 3ab0a991 Hot reload done only once every 200 ms, no point in beeing faster df69fc76 Post processing shaders now use the same lua commands, no more launcher option... c71f3508 changed overview.rst of post processing 603b30e1 Added some variable names to make it clearer what their function was baadc06e Merge branch 'master' into 'SHADER_HOT_RELOAD' decfbc53 Fix threading issues b14cc673 adds missing decleration 16a4b571 adds missing include 166717d6 Makes sure threads are only stopped once ,and that they will be re-started 25c1f0ca Renamed variable to fix case issue
2022-08-21 09:08:27 +00:00
if (write_time.time_since_epoch() > mLastAutoRecompileTime.time_since_epoch())
{
if (!threadsRunningToStop)
{
threadsRunningToStop = viewer.areThreadsRunning();
if (threadsRunningToStop)
viewer.stopThreading();
}
for (const auto& [templateName, shaderDefines]: shaderKeys)
{
ShaderManager::ShaderMap::iterator shaderIt = Manager.mShaders.find(std::make_pair(templateName, shaderDefines));
ShaderManager::TemplateMap::iterator templateIt = Manager.mShaderTemplates.find(templateName); //Can't be Null, if we're here it means the template was added
std::string& shaderSource = templateIt->second;
2022-09-09 08:13:47 +00:00
std::set<boost::filesystem::path> insertedPaths;
boost::filesystem::path path = (boost::filesystem::path(Manager.mPath) / templateName);
boost::filesystem::ifstream stream;
Merge branch 'SHADER_HOT_RELOAD' into 'master' Shaders: Hot reload, togglable by lua debug command See merge request OpenMW/openmw!2238 (cherry picked from commit 4078f19c741685b7120c636108de7ded1ae6dbfd) 8d194a16 Shaders: rudimentary hot reloader on shaders 4e7c1c5b Added break when the operation failed 6b38d622 Added lua bindings to toggle hot reload (disabled by default) or to trigger a reload 31d41252 forgot memory include f78fa989 fixed include, cleaned comments and indentation fc8838c7 Renamed lua binding, and use action to avoid concurrency issue aa51d6de Missing chrono include ? 68d06989 Fixed cyclical included check b6d7293a Removed weird lines that I thought were necessary to please the compiler 9a475b0c fixed blank lines and missing breaks cdd95f78 replaced empty function body by default a1c8dc9d C++17 compat ? 7b78bf4b Fix files with different defines weren't added to the hot reload manager cc9d4364 includes now work when the same shader has different defines 15751c57 Lua debug api doc 3ab0a991 Hot reload done only once every 200 ms, no point in beeing faster df69fc76 Post processing shaders now use the same lua commands, no more launcher option... c71f3508 changed overview.rst of post processing 603b30e1 Added some variable names to make it clearer what their function was baadc06e Merge branch 'master' into 'SHADER_HOT_RELOAD' decfbc53 Fix threading issues b14cc673 adds missing decleration 16a4b571 adds missing include 166717d6 Makes sure threads are only stopped once ,and that they will be re-started 25c1f0ca Renamed variable to fix case issue
2022-08-21 09:08:27 +00:00
stream.open(path);
if (stream.fail())
{
Log(Debug::Error) << "Failed to open " << path.string();
}
std::stringstream buffer;
buffer << stream.rdbuf();
// parse includes
int fileNumber = 1;
std::string source = buffer.str();
if (!addLineDirectivesAfterConditionalBlocks(source)
2022-09-09 08:13:47 +00:00
|| !parseIncludes(boost::filesystem::path(Manager.mPath), source, templateName, fileNumber, {}, insertedPaths))
Merge branch 'SHADER_HOT_RELOAD' into 'master' Shaders: Hot reload, togglable by lua debug command See merge request OpenMW/openmw!2238 (cherry picked from commit 4078f19c741685b7120c636108de7ded1ae6dbfd) 8d194a16 Shaders: rudimentary hot reloader on shaders 4e7c1c5b Added break when the operation failed 6b38d622 Added lua bindings to toggle hot reload (disabled by default) or to trigger a reload 31d41252 forgot memory include f78fa989 fixed include, cleaned comments and indentation fc8838c7 Renamed lua binding, and use action to avoid concurrency issue aa51d6de Missing chrono include ? 68d06989 Fixed cyclical included check b6d7293a Removed weird lines that I thought were necessary to please the compiler 9a475b0c fixed blank lines and missing breaks cdd95f78 replaced empty function body by default a1c8dc9d C++17 compat ? 7b78bf4b Fix files with different defines weren't added to the hot reload manager cc9d4364 includes now work when the same shader has different defines 15751c57 Lua debug api doc 3ab0a991 Hot reload done only once every 200 ms, no point in beeing faster df69fc76 Post processing shaders now use the same lua commands, no more launcher option... c71f3508 changed overview.rst of post processing 603b30e1 Added some variable names to make it clearer what their function was baadc06e Merge branch 'master' into 'SHADER_HOT_RELOAD' decfbc53 Fix threading issues b14cc673 adds missing decleration 16a4b571 adds missing include 166717d6 Makes sure threads are only stopped once ,and that they will be re-started 25c1f0ca Renamed variable to fix case issue
2022-08-21 09:08:27 +00:00
{
break;
}
shaderSource = source;
std::vector<std::string> linkedShaderNames;
if (!Manager.createSourceFromTemplate(shaderSource, linkedShaderNames, templateName, shaderDefines))
{
break;
}
shaderIt->second->setShaderSource(shaderSource);
}
}
}
if (threadsRunningToStop)
viewer.startThreading();
2022-09-09 08:13:47 +00:00
mLastAutoRecompileTime = std::chrono::system_clock::now();
Merge branch 'SHADER_HOT_RELOAD' into 'master' Shaders: Hot reload, togglable by lua debug command See merge request OpenMW/openmw!2238 (cherry picked from commit 4078f19c741685b7120c636108de7ded1ae6dbfd) 8d194a16 Shaders: rudimentary hot reloader on shaders 4e7c1c5b Added break when the operation failed 6b38d622 Added lua bindings to toggle hot reload (disabled by default) or to trigger a reload 31d41252 forgot memory include f78fa989 fixed include, cleaned comments and indentation fc8838c7 Renamed lua binding, and use action to avoid concurrency issue aa51d6de Missing chrono include ? 68d06989 Fixed cyclical included check b6d7293a Removed weird lines that I thought were necessary to please the compiler 9a475b0c fixed blank lines and missing breaks cdd95f78 replaced empty function body by default a1c8dc9d C++17 compat ? 7b78bf4b Fix files with different defines weren't added to the hot reload manager cc9d4364 includes now work when the same shader has different defines 15751c57 Lua debug api doc 3ab0a991 Hot reload done only once every 200 ms, no point in beeing faster df69fc76 Post processing shaders now use the same lua commands, no more launcher option... c71f3508 changed overview.rst of post processing 603b30e1 Added some variable names to make it clearer what their function was baadc06e Merge branch 'master' into 'SHADER_HOT_RELOAD' decfbc53 Fix threading issues b14cc673 adds missing decleration 16a4b571 adds missing include 166717d6 Makes sure threads are only stopped once ,and that they will be re-started 25c1f0ca Renamed variable to fix case issue
2022-08-21 09:08:27 +00:00
}
};
osg::ref_ptr<osg::Shader> ShaderManager::getShader(const std::string &templateName, const ShaderManager::DefineMap &defines, osg::Shader::Type shaderType)
{
std::unique_lock<std::mutex> lock(mMutex);
// read the template if we haven't already
TemplateMap::iterator templateIt = mShaderTemplates.find(templateName);
2022-09-09 08:13:47 +00:00
std::set<boost::filesystem::path> insertedPaths;
Merge branch 'SHADER_HOT_RELOAD' into 'master' Shaders: Hot reload, togglable by lua debug command See merge request OpenMW/openmw!2238 (cherry picked from commit 4078f19c741685b7120c636108de7ded1ae6dbfd) 8d194a16 Shaders: rudimentary hot reloader on shaders 4e7c1c5b Added break when the operation failed 6b38d622 Added lua bindings to toggle hot reload (disabled by default) or to trigger a reload 31d41252 forgot memory include f78fa989 fixed include, cleaned comments and indentation fc8838c7 Renamed lua binding, and use action to avoid concurrency issue aa51d6de Missing chrono include ? 68d06989 Fixed cyclical included check b6d7293a Removed weird lines that I thought were necessary to please the compiler 9a475b0c fixed blank lines and missing breaks cdd95f78 replaced empty function body by default a1c8dc9d C++17 compat ? 7b78bf4b Fix files with different defines weren't added to the hot reload manager cc9d4364 includes now work when the same shader has different defines 15751c57 Lua debug api doc 3ab0a991 Hot reload done only once every 200 ms, no point in beeing faster df69fc76 Post processing shaders now use the same lua commands, no more launcher option... c71f3508 changed overview.rst of post processing 603b30e1 Added some variable names to make it clearer what their function was baadc06e Merge branch 'master' into 'SHADER_HOT_RELOAD' decfbc53 Fix threading issues b14cc673 adds missing decleration 16a4b571 adds missing include 166717d6 Makes sure threads are only stopped once ,and that they will be re-started 25c1f0ca Renamed variable to fix case issue
2022-08-21 09:08:27 +00:00
if (templateIt == mShaderTemplates.end())
{
2022-09-09 08:13:47 +00:00
boost::filesystem::path path = (boost::filesystem::path(mPath) / templateName);
boost::filesystem::ifstream stream;
stream.open(path);
if (stream.fail())
{
Log(Debug::Error) << "Failed to open " << path.string();
2018-10-09 06:21:12 +00:00
return nullptr;
}
std::stringstream buffer;
buffer << stream.rdbuf();
2016-02-17 22:29:07 +00:00
// parse includes
int fileNumber = 1;
2016-02-17 22:29:07 +00:00
std::string source = buffer.str();
if (!addLineDirectivesAfterConditionalBlocks(source)
2022-09-09 08:13:47 +00:00
|| !parseIncludes(boost::filesystem::path(mPath), source, templateName, fileNumber, {}, insertedPaths))
2018-10-09 06:21:12 +00:00
return nullptr;
Merge branch 'SHADER_HOT_RELOAD' into 'master' Shaders: Hot reload, togglable by lua debug command See merge request OpenMW/openmw!2238 (cherry picked from commit 4078f19c741685b7120c636108de7ded1ae6dbfd) 8d194a16 Shaders: rudimentary hot reloader on shaders 4e7c1c5b Added break when the operation failed 6b38d622 Added lua bindings to toggle hot reload (disabled by default) or to trigger a reload 31d41252 forgot memory include f78fa989 fixed include, cleaned comments and indentation fc8838c7 Renamed lua binding, and use action to avoid concurrency issue aa51d6de Missing chrono include ? 68d06989 Fixed cyclical included check b6d7293a Removed weird lines that I thought were necessary to please the compiler 9a475b0c fixed blank lines and missing breaks cdd95f78 replaced empty function body by default a1c8dc9d C++17 compat ? 7b78bf4b Fix files with different defines weren't added to the hot reload manager cc9d4364 includes now work when the same shader has different defines 15751c57 Lua debug api doc 3ab0a991 Hot reload done only once every 200 ms, no point in beeing faster df69fc76 Post processing shaders now use the same lua commands, no more launcher option... c71f3508 changed overview.rst of post processing 603b30e1 Added some variable names to make it clearer what their function was baadc06e Merge branch 'master' into 'SHADER_HOT_RELOAD' decfbc53 Fix threading issues b14cc673 adds missing decleration 16a4b571 adds missing include 166717d6 Makes sure threads are only stopped once ,and that they will be re-started 25c1f0ca Renamed variable to fix case issue
2022-08-21 09:08:27 +00:00
mHotReloadManager->templateIncludedFiles[templateName] = insertedPaths;
templateIt = mShaderTemplates.insert(std::make_pair(templateName, source)).first;
}
ShaderMap::iterator shaderIt = mShaders.find(std::make_pair(templateName, defines));
if (shaderIt == mShaders.end())
{
std::string shaderSource = templateIt->second;
std::vector<std::string> linkedShaderNames;
if (!createSourceFromTemplate(shaderSource, linkedShaderNames, templateName, defines))
2017-11-07 22:54:31 +00:00
{
// Add to the cache anyway to avoid logging the same error over and over.
mShaders.insert(std::make_pair(std::make_pair(templateName, defines), nullptr));
2018-10-09 06:21:12 +00:00
return nullptr;
2017-11-07 22:54:31 +00:00
}
osg::ref_ptr<osg::Shader> shader (new osg::Shader(shaderType));
shader->setShaderSource(shaderSource);
2021-06-06 01:21:03 +00:00
// Assign a unique prefix to allow the SharedStateManager to compare shaders efficiently.
// Append shader source filename for debugging.
static unsigned int counter = 0;
2021-06-06 01:21:03 +00:00
shader->setName(Misc::StringUtils::format("%u %s", counter++, templateName));
Merge branch 'SHADER_HOT_RELOAD' into 'master' Shaders: Hot reload, togglable by lua debug command See merge request OpenMW/openmw!2238 (cherry picked from commit 4078f19c741685b7120c636108de7ded1ae6dbfd) 8d194a16 Shaders: rudimentary hot reloader on shaders 4e7c1c5b Added break when the operation failed 6b38d622 Added lua bindings to toggle hot reload (disabled by default) or to trigger a reload 31d41252 forgot memory include f78fa989 fixed include, cleaned comments and indentation fc8838c7 Renamed lua binding, and use action to avoid concurrency issue aa51d6de Missing chrono include ? 68d06989 Fixed cyclical included check b6d7293a Removed weird lines that I thought were necessary to please the compiler 9a475b0c fixed blank lines and missing breaks cdd95f78 replaced empty function body by default a1c8dc9d C++17 compat ? 7b78bf4b Fix files with different defines weren't added to the hot reload manager cc9d4364 includes now work when the same shader has different defines 15751c57 Lua debug api doc 3ab0a991 Hot reload done only once every 200 ms, no point in beeing faster df69fc76 Post processing shaders now use the same lua commands, no more launcher option... c71f3508 changed overview.rst of post processing 603b30e1 Added some variable names to make it clearer what their function was baadc06e Merge branch 'master' into 'SHADER_HOT_RELOAD' decfbc53 Fix threading issues b14cc673 adds missing decleration 16a4b571 adds missing include 166717d6 Makes sure threads are only stopped once ,and that they will be re-started 25c1f0ca Renamed variable to fix case issue
2022-08-21 09:08:27 +00:00
mHotReloadManager->addShaderFiles(templateName, defines);
lock.unlock();
getLinkedShaders(shader, linkedShaderNames, defines);
lock.lock();
shaderIt = mShaders.insert(std::make_pair(std::make_pair(templateName, defines), shader)).first;
}
return shaderIt->second;
}
osg::ref_ptr<osg::Program> ShaderManager::getProgram(osg::ref_ptr<osg::Shader> vertexShader, osg::ref_ptr<osg::Shader> fragmentShader, const osg::Program* programTemplate)
2016-02-17 14:04:05 +00:00
{
2020-06-25 19:46:07 +00:00
std::lock_guard<std::mutex> lock(mMutex);
2016-02-17 14:04:05 +00:00
ProgramMap::iterator found = mPrograms.find(std::make_pair(vertexShader, fragmentShader));
if (found == mPrograms.end())
{
if (!programTemplate) programTemplate = mProgramTemplate;
osg::ref_ptr<osg::Program> program = programTemplate ? cloneProgram(programTemplate) : osg::ref_ptr<osg::Program>(new osg::Program);
2016-02-17 14:04:05 +00:00
program->addShader(vertexShader);
program->addShader(fragmentShader);
addLinkedShaders(vertexShader, program);
addLinkedShaders(fragmentShader, program);
2016-02-17 14:04:05 +00:00
found = mPrograms.insert(std::make_pair(std::make_pair(vertexShader, fragmentShader), program)).first;
}
return found->second;
}
osg::ref_ptr<osg::Program> ShaderManager::cloneProgram(const osg::Program* src)
{
osg::ref_ptr<osg::Program> program = static_cast<osg::Program*>(src->clone(osg::CopyOp::SHALLOW_COPY));
for (auto& [name, idx] : src->getUniformBlockBindingList())
program->addBindUniformBlock(name, idx);
return program;
}
ShaderManager::DefineMap ShaderManager::getGlobalDefines()
{
return DefineMap(mGlobalDefines);
}
void ShaderManager::setGlobalDefines(DefineMap & globalDefines)
{
mGlobalDefines = globalDefines;
for (const auto& [key, shader]: mShaders)
{
std::string templateId = key.first;
ShaderManager::DefineMap defines = key.second;
if (shader == nullptr)
// I'm not sure how to handle a shader that was already broken as there's no way to get a potential replacement to the nodes that need it.
continue;
std::string shaderSource = mShaderTemplates[templateId];
std::vector<std::string> linkedShaderNames;
if (!createSourceFromTemplate(shaderSource, linkedShaderNames, templateId, defines))
// We just broke the shader and there's no way to force existing objects back to fixed-function mode as we would when creating the shader.
// If we put a nullptr in the shader map, we just lose the ability to put a working one in later.
continue;
shader->setShaderSource(shaderSource);
getLinkedShaders(shader, linkedShaderNames, defines);
}
}
void ShaderManager::releaseGLObjects(osg::State *state)
{
2020-06-25 19:46:07 +00:00
std::lock_guard<std::mutex> lock(mMutex);
for (const auto& [_, shader] : mShaders)
{
if (shader != nullptr)
shader->releaseGLObjects(state);
}
for (const auto& [_, program] : mPrograms)
program->releaseGLObjects(state);
}
bool ShaderManager::createSourceFromTemplate(std::string& source, std::vector<std::string>& linkedShaderTemplateNames, const std::string& templateName, const ShaderManager::DefineMap& defines)
{
if (!parseDefines(source, defines, mGlobalDefines, templateName))
return false;
if (!parseDirectives(source, linkedShaderTemplateNames, defines, mGlobalDefines, templateName))
return false;
return true;
}
void ShaderManager::getLinkedShaders(osg::ref_ptr<osg::Shader> shader, const std::vector<std::string>& linkedShaderNames, const DefineMap& defines)
{
mLinkedShaders.erase(shader);
if (linkedShaderNames.empty())
return;
for (auto& linkedShaderName : linkedShaderNames)
{
auto linkedShader = getShader(linkedShaderName, defines, shader->getType());
if (linkedShader)
mLinkedShaders[shader].emplace_back(linkedShader);
}
}
void ShaderManager::addLinkedShaders(osg::ref_ptr<osg::Shader> shader, osg::ref_ptr<osg::Program> program)
{
auto linkedIt = mLinkedShaders.find(shader);
if (linkedIt != mLinkedShaders.end())
for (const auto& linkedShader : linkedIt->second)
program->addShader(linkedShader);
}
int ShaderManager::reserveGlobalTextureUnits(Slot slot)
2022-06-06 20:40:38 +00:00
{
int unit = mReservedTextureUnitsBySlot[static_cast<int>(slot)];
if (unit >= 0)
return unit;
2022-06-06 20:40:38 +00:00
{
// Texture units from `8 - numberOfShadowMaps` to `8` are used for shadows, so we skip them here.
// TODO: Maybe instead of fixed texture units use `reserveGlobalTextureUnits` for shadows as well.
static const int numberOfShadowMaps = Settings::Manager::getBool("enable shadows", "Shadows") ?
std::clamp(Settings::Manager::getInt("number of shadow maps", "Shadows"), 1, 8) :
0;
if (getAvailableTextureUnits() >= 8 && getAvailableTextureUnits() - 1 < 8)
2022-06-06 20:40:38 +00:00
mReservedTextureUnits = mMaxTextureUnits - (8 - numberOfShadowMaps);
}
if (getAvailableTextureUnits() < 2)
2022-06-06 20:40:38 +00:00
throw std::runtime_error("Can't reserve texture unit; no available units");
mReservedTextureUnits++;
unit = mMaxTextureUnits - mReservedTextureUnits;
mReservedTextureUnitsBySlot[static_cast<int>(slot)] = unit;
return unit;
2022-06-06 20:40:38 +00:00
}
Merge branch 'SHADER_HOT_RELOAD' into 'master' Shaders: Hot reload, togglable by lua debug command See merge request OpenMW/openmw!2238 (cherry picked from commit 4078f19c741685b7120c636108de7ded1ae6dbfd) 8d194a16 Shaders: rudimentary hot reloader on shaders 4e7c1c5b Added break when the operation failed 6b38d622 Added lua bindings to toggle hot reload (disabled by default) or to trigger a reload 31d41252 forgot memory include f78fa989 fixed include, cleaned comments and indentation fc8838c7 Renamed lua binding, and use action to avoid concurrency issue aa51d6de Missing chrono include ? 68d06989 Fixed cyclical included check b6d7293a Removed weird lines that I thought were necessary to please the compiler 9a475b0c fixed blank lines and missing breaks cdd95f78 replaced empty function body by default a1c8dc9d C++17 compat ? 7b78bf4b Fix files with different defines weren't added to the hot reload manager cc9d4364 includes now work when the same shader has different defines 15751c57 Lua debug api doc 3ab0a991 Hot reload done only once every 200 ms, no point in beeing faster df69fc76 Post processing shaders now use the same lua commands, no more launcher option... c71f3508 changed overview.rst of post processing 603b30e1 Added some variable names to make it clearer what their function was baadc06e Merge branch 'master' into 'SHADER_HOT_RELOAD' decfbc53 Fix threading issues b14cc673 adds missing decleration 16a4b571 adds missing include 166717d6 Makes sure threads are only stopped once ,and that they will be re-started 25c1f0ca Renamed variable to fix case issue
2022-08-21 09:08:27 +00:00
void ShaderManager::update(osgViewer::Viewer& viewer)
{
mHotReloadManager->update(*this, viewer);
}
void ShaderManager::setHotReloadEnabled(bool value)
{
mHotReloadManager->mHotReloadEnabled = value;
}
void ShaderManager::triggerShaderReload()
{
mHotReloadManager->mTriggerReload = true;
}
}