diff --git a/GPU/Common/PostShader.cpp b/GPU/Common/PostShader.cpp index df30f76df7..780a65f033 100644 --- a/GPU/Common/PostShader.cpp +++ b/GPU/Common/PostShader.cpp @@ -36,6 +36,8 @@ static std::vector shaderInfo; // Additionally, scan the VFS assets. (TODO) void LoadPostShaderInfo(std::vector directories) { + std::vector notVisible; + shaderInfo.clear(); ShaderInfo off; off.name = "Off"; @@ -46,6 +48,14 @@ void LoadPostShaderInfo(std::vector directories) { off.requires60fps = false; shaderInfo.push_back(off); + auto appendShader = [&](const ShaderInfo &info) { + auto beginErase = std::remove(shaderInfo.begin(), shaderInfo.end(), info.name); + if (beginErase != shaderInfo.end()) { + shaderInfo.erase(beginErase, shaderInfo.end()); + } + shaderInfo.push_back(info); + }; + for (size_t d = 0; d < directories.size(); d++) { std::vector fileInfo; getFilesInDir(directories[d].c_str(), &fileInfo, "ini:"); @@ -82,6 +92,8 @@ void LoadPostShaderInfo(std::vector directories) { std::string temp; info.section = section.name(); section.Get("Name", &info.name, section.name().c_str()); + section.Get("Parent", &info.parent, ""); + section.Get("Visible", &info.visible, true); section.Get("Fragment", &temp, ""); info.fragmentShaderFile = path + "/" + temp; section.Get("Vertex", &temp, ""); @@ -99,15 +111,20 @@ void LoadPostShaderInfo(std::vector directories) { continue; } - auto beginErase = std::find(shaderInfo.begin(), shaderInfo.end(), info.name); - if (beginErase != shaderInfo.end()) { - shaderInfo.erase(beginErase, shaderInfo.end()); + if (info.visible) { + appendShader(info); + } else { + notVisible.push_back(info); } - shaderInfo.push_back(info); } } } } + + // We always want the not visible ones at the end. Makes menus easier. + for (const auto &info : notVisible) { + appendShader(info); + } } // Scans the directories for shader ini files and collects info about all the shaders found. @@ -118,7 +135,7 @@ void ReloadAllPostShaderInfo() { LoadPostShaderInfo(directories); } -const ShaderInfo *GetPostShaderInfo(std::string name) { +const ShaderInfo *GetPostShaderInfo(const std::string &name) { for (size_t i = 0; i < shaderInfo.size(); i++) { if (shaderInfo[i].section == name) return &shaderInfo[i]; @@ -126,6 +143,25 @@ const ShaderInfo *GetPostShaderInfo(std::string name) { return nullptr; } +std::vector GetPostShaderChain(const std::string &name) { + std::vector backwards; + const ShaderInfo *shaderInfo = GetPostShaderInfo(name); + while (shaderInfo) { + backwards.push_back(shaderInfo); + + if (!shaderInfo->parent.empty() && shaderInfo->parent != "Off") { + shaderInfo = GetPostShaderInfo(shaderInfo->parent); + } else { + shaderInfo = nullptr; + } + } + + if (!backwards.empty()) + std::reverse(backwards.begin(), backwards.end()); + // Not backwards anymore. + return backwards; +} + const std::vector &GetAllPostShaderInfo() { return shaderInfo; } diff --git a/GPU/Common/PostShader.h b/GPU/Common/PostShader.h index f848e14802..62740a9569 100644 --- a/GPU/Common/PostShader.h +++ b/GPU/Common/PostShader.h @@ -28,10 +28,13 @@ struct ShaderInfo { std::string iniFile; // which ini file was this definition in? So we can write settings back later std::string section; // ini file section. This is saved. std::string name; // Fancy display name. + std::string parent; // Parent shader ini section name. std::string fragmentShaderFile; std::string vertexShaderFile; + // Show this shader in lists (i.e. not just for chaining.) + bool visible; // Run at output instead of input resolution bool outputResolution; // Use x1 rendering res + nearest screen scaling filter @@ -42,7 +45,7 @@ struct ShaderInfo { bool requires60fps; // TODO: Add support for all kinds of fun options like mapping the depth buffer, - // SRGB texture reads, multiple shaders chained, etc. + // SRGB texture reads, etc. bool operator == (const std::string &other) { return name == other; @@ -54,5 +57,6 @@ struct ShaderInfo { void ReloadAllPostShaderInfo(); -const ShaderInfo *GetPostShaderInfo(std::string name); +const ShaderInfo *GetPostShaderInfo(const std::string &name); +std::vector GetPostShaderChain(const std::string &name); const std::vector &GetAllPostShaderInfo(); diff --git a/GPU/Common/PresentationCommon.cpp b/GPU/Common/PresentationCommon.cpp index 2787ca9604..1ee9acee6a 100644 --- a/GPU/Common/PresentationCommon.cpp +++ b/GPU/Common/PresentationCommon.cpp @@ -173,20 +173,22 @@ static std::string ReadShaderSrc(const std::string &filename) { // Note: called on resize and settings changes. bool PresentationCommon::UpdatePostShader() { - const ShaderInfo *shaderInfo = nullptr; + std::vector shaderInfo; if (g_Config.sPostShaderName != "Off") { ReloadAllPostShaderInfo(); - shaderInfo = GetPostShaderInfo(g_Config.sPostShaderName); + shaderInfo = GetPostShaderChain(g_Config.sPostShaderName); } DestroyPostShader(); - if (shaderInfo == nullptr) + if (shaderInfo.empty()) return false; - bool pipeline = BuildPostShader(shaderInfo, nullptr); - if (!pipeline) { - DestroyPostShader(); - return false; + for (int i = 0; i < shaderInfo.size(); ++i) { + const ShaderInfo *next = i + 1 < shaderInfo.size() ? shaderInfo[i + 1] : nullptr; + if (!BuildPostShader(shaderInfo[i], next)) { + DestroyPostShader(); + return false; + } } usePostShader_ = true; diff --git a/UI/MiscScreens.cpp b/UI/MiscScreens.cpp index 27fadc85fd..7795ffc65e 100644 --- a/UI/MiscScreens.cpp +++ b/UI/MiscScreens.cpp @@ -306,6 +306,8 @@ PostProcScreen::PostProcScreen(const std::string &title) : ListPopupScreen(title std::vector items; int selected = -1; for (int i = 0; i < (int)shaders_.size(); i++) { + if (!shaders_[i].visible) + continue; if (shaders_[i].section == g_Config.sPostShaderName) selected = i; items.push_back(ps->T(shaders_[i].section.c_str(), shaders_[i].name.c_str())); diff --git a/Windows/MainWindowMenu.cpp b/Windows/MainWindowMenu.cpp index 978a73db5b..f80d80de53 100644 --- a/Windows/MainWindowMenu.cpp +++ b/Windows/MainWindowMenu.cpp @@ -181,6 +181,8 @@ namespace MainWindow { availableShaders.clear(); for (auto i = info.begin(); i != info.end(); ++i) { + if (!i->visible) + continue; int checkedStatus = MF_UNCHECKED; availableShaders.push_back(i->section); if (g_Config.sPostShaderName == i->section) {