diff --git a/GPU/Common/PostShader.cpp b/GPU/Common/PostShader.cpp index a1b5ace7e4..66980d0739 100644 --- a/GPU/Common/PostShader.cpp +++ b/GPU/Common/PostShader.cpp @@ -36,8 +36,11 @@ static std::vector shaderInfo; // Additionally, scan the VFS assets. (TODO) void LoadPostShaderInfo(std::vector directories) { + std::vector notVisible; + shaderInfo.clear(); - ShaderInfo off; + ShaderInfo off{}; + off.visible = true; off.name = "Off"; off.section = "Off"; off.outputResolution = false; @@ -66,6 +69,14 @@ void LoadPostShaderInfo(std::vector directories) { off.settingStep4 = 0.01f; 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:"); @@ -102,6 +113,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, ""); @@ -148,15 +161,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. @@ -167,7 +185,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]; @@ -175,6 +193,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 9be8063d77..50b36d205d 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 @@ -63,7 +66,7 @@ struct ShaderInfo { float settingStep4; // 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; @@ -75,5 +78,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 4074e93806..58b954a17a 100644 --- a/GPU/Common/PresentationCommon.cpp +++ b/GPU/Common/PresentationCommon.cpp @@ -178,20 +178,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 31de1a4833..b5e1bb0eb0 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) {