From 0c885db052dac59f0ea2a8c841fdb11e6136b1c8 Mon Sep 17 00:00:00 2001 From: iota97 Date: Mon, 18 May 2020 11:17:45 +0200 Subject: [PATCH] User chain support --- Core/Config.cpp | 40 ++++++++++++++++- Core/Config.h | 5 ++- Core/CwCheat.cpp | 4 +- Core/HLE/sceDisplay.cpp | 7 +-- GPU/Common/PostShader.cpp | 19 ++++++++ GPU/Common/PostShader.h | 2 + GPU/Common/PresentationCommon.cpp | 8 ++-- UI/GameSettingsScreen.cpp | 73 +++++++++++++++++++++---------- UI/GameSettingsScreen.h | 2 +- UI/MiscScreens.cpp | 6 +-- UI/MiscScreens.h | 3 +- UI/NativeApp.cpp | 1 + Windows/MainWindowMenu.cpp | 12 +++-- 13 files changed, 134 insertions(+), 48 deletions(-) diff --git a/Core/Config.cpp b/Core/Config.cpp index a3c7be90174e..ace856117590 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -805,7 +805,6 @@ static ConfigSetting graphicsSettings[] = { // Not really a graphics setting... ReportedConfigSetting("SplineBezierQuality", &g_Config.iSplineBezierQuality, 2, true, true), ReportedConfigSetting("HardwareTessellation", &g_Config.bHardwareTessellation, false, true, true), - ReportedConfigSetting("PostShader", &g_Config.sPostShaderName, "Off", true, true), ConfigSetting("TextureShader", &g_Config.sTextureShaderName, "Off", true, true), ReportedConfigSetting("MemBlockTransferGPU", &g_Config.bBlockTransferGPU, true, true, true), @@ -1254,6 +1253,14 @@ void Config::Load(const char *iniFileName, const char *controllerIniFilename) { mPostShaderSetting[it.first] = std::stof(it.second); } + auto postShaderChain = iniFile.GetOrCreateSection("PostShaderList")->ToMap(); + vPostShaderNames.clear(); + for (auto it : postShaderChain) { + vPostShaderNames.push_back(it.second); + } + if (vPostShaderNames.empty()) + vPostShaderNames.push_back("Off"); + // This caps the exponent 4 (so 16x.) if (iAnisotropyLevel > 4) { iAnisotropyLevel = 4; @@ -1385,6 +1392,13 @@ void Config::Save(const char *saveReason) { for (auto it = mPostShaderSetting.begin(), end = mPostShaderSetting.end(); it != end; ++it) { postShaderSetting->Set(it->first.c_str(), it->second); } + Section *postShaderChain = iniFile.GetOrCreateSection("PostShaderList"); + postShaderChain->Clear(); + for (size_t i = 0; i < vPostShaderNames.size(); ++i) { + char keyName[64]; + snprintf(keyName, sizeof(keyName), "PostShader%d", (int)i+1); + postShaderChain->Set(keyName, vPostShaderNames[i]); + } } Section *control = iniFile.GetOrCreateSection("Control"); @@ -1643,6 +1657,14 @@ bool Config::saveGameConfig(const std::string &pGameId, const std::string &title postShaderSetting->Set(it->first.c_str(), it->second); } + Section *postShaderChain = iniFile.GetOrCreateSection("PostShaderList"); + postShaderChain->Clear(); + for (size_t i = 0; i < vPostShaderNames.size(); ++i) { + char keyName[64]; + snprintf(keyName, sizeof(keyName), "PostShader%d", (int)i+1); + postShaderChain->Set(keyName, vPostShaderNames[i]); + } + KeyMap::SaveToIni(iniFile); iniFile.Save(fullIniFilePath); @@ -1667,6 +1689,14 @@ bool Config::loadGameConfig(const std::string &pGameId, const std::string &title mPostShaderSetting[it.first] = std::stof(it.second); } + auto postShaderChain = iniFile.GetOrCreateSection("PostShaderList")->ToMap(); + vPostShaderNames.clear(); + for (auto it : postShaderChain) { + vPostShaderNames.push_back(it.second); + } + if (vPostShaderNames.empty()) + vPostShaderNames.push_back("Off"); + IterateSettings(iniFile, [](Section *section, ConfigSetting *setting) { if (setting->perGame_) { setting->Get(section); @@ -1697,6 +1727,14 @@ void Config::unloadGameConfig() { mPostShaderSetting[it.first] = std::stof(it.second); } + auto postShaderChain = iniFile.GetOrCreateSection("PostShaderList")->ToMap(); + vPostShaderNames.clear(); + for (auto it : postShaderChain) { + vPostShaderNames.push_back(it.second); + } + if (vPostShaderNames.empty()) + vPostShaderNames.push_back("Off"); + LoadStandardControllerIni(); } } diff --git a/Core/Config.h b/Core/Config.h index 5a1a6b57b707..b999569edace 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -212,9 +212,10 @@ struct Config { bool bFragmentTestCache; int iSplineBezierQuality; // 0 = low , 1 = Intermediate , 2 = High bool bHardwareTessellation; - std::string sPostShaderName; // Off for off. - std::string sTextureShaderName; + + std::vector vPostShaderNames; // Off for chain end (only Off for no shader) std::map mPostShaderSetting; + std::string sTextureShaderName; bool bGfxDebugOutput; bool bGfxDebugSplitSubmit; int iInflightFrames; diff --git a/Core/CwCheat.cpp b/Core/CwCheat.cpp index 7ed008f886e4..38b70abd778b 100644 --- a/Core/CwCheat.cpp +++ b/Core/CwCheat.cpp @@ -950,7 +950,7 @@ void CWCheatEngine::ExecuteOp(const CheatOperation &op, const CheatCode &cheat, case CheatOp::PostShader: { - auto shaderChain = GetPostShaderChain(g_Config.sPostShaderName); + auto shaderChain = GetFullPostShadersChain(g_Config.vPostShaderNames); if (op.PostShaderUniform.shader < shaderChain.size()) { std::string shaderName = shaderChain[op.PostShaderUniform.shader]->section; if (shaderName != "Off") @@ -961,7 +961,7 @@ void CWCheatEngine::ExecuteOp(const CheatOperation &op, const CheatCode &cheat, case CheatOp::PostShaderFromMemory: { - auto shaderChain = GetPostShaderChain(g_Config.sPostShaderName); + auto shaderChain = GetFullPostShadersChain(g_Config.vPostShaderNames); if (Memory::IsValidAddress(op.addr) && op.PostShaderUniform.shader < shaderChain.size()) { union { float f; diff --git a/Core/HLE/sceDisplay.cpp b/Core/HLE/sceDisplay.cpp index 01c07a51822f..7d0b9e7b6043 100644 --- a/Core/HLE/sceDisplay.cpp +++ b/Core/HLE/sceDisplay.cpp @@ -751,7 +751,6 @@ void __DisplayFlip(int cyclesLate) { // But, let's flip at least once every 10 vblanks, to update fps, etc. const bool noRecentFlip = g_Config.iRenderingMode != FB_NON_BUFFERED_MODE && numVBlanksSinceFlip >= 10; // Also let's always flip for animated shaders. - const ShaderInfo *shaderInfo = g_Config.sPostShaderName == "Off" ? nullptr : GetPostShaderInfo(g_Config.sPostShaderName); bool postEffectRequiresFlip = false; bool duplicateFrames = g_Config.bRenderDuplicateFrames && g_Config.iFrameSkip == 0; @@ -764,11 +763,7 @@ void __DisplayFlip(int cyclesLate) { // postEffectRequiresFlip is not compatible with frameskip unthrottling, see #12325. if (g_Config.iRenderingMode != FB_NON_BUFFERED_MODE && !(unthrottleNeedsSkip && !FrameTimingThrottled())) { - if (shaderInfo) { - postEffectRequiresFlip = (shaderInfo->requires60fps || duplicateFrames); - } else { - postEffectRequiresFlip = duplicateFrames; - } + postEffectRequiresFlip = duplicateFrames || PostShaderChainRequires60FPS(GetFullPostShadersChain(g_Config.vPostShaderNames)); } const bool fbDirty = gpu->FramebufferDirty(); diff --git a/GPU/Common/PostShader.cpp b/GPU/Common/PostShader.cpp index 57eaf1f50dd7..d0d9ec8963e5 100644 --- a/GPU/Common/PostShader.cpp +++ b/GPU/Common/PostShader.cpp @@ -213,6 +213,25 @@ std::vector GetPostShaderChain(const std::string &name) { return backwards; } +std::vector GetFullPostShadersChain(const std::vector &names) { + std::vector fullChain; + for (auto shaderName : names) { + if (shaderName == "Off") + break; + auto shaderChain = GetPostShaderChain(shaderName); + fullChain.insert(fullChain.end(), shaderChain.begin(), shaderChain.end()); + } + return fullChain; +} + +bool PostShaderChainRequires60FPS(const std::vector &chain) { + for (auto shaderInfo : chain) { + if (shaderInfo->requires60fps) + return true; + } + return false; +} + const std::vector &GetAllPostShaderInfo() { return shaderInfo; } diff --git a/GPU/Common/PostShader.h b/GPU/Common/PostShader.h index 6febf0ee2d1e..3ad0d50485b4 100644 --- a/GPU/Common/PostShader.h +++ b/GPU/Common/PostShader.h @@ -83,6 +83,8 @@ void ReloadAllPostShaderInfo(); const ShaderInfo *GetPostShaderInfo(const std::string &name); std::vector GetPostShaderChain(const std::string &name); +std::vector GetFullPostShadersChain(const std::vector &names); +bool PostShaderChainRequires60FPS(const std::vector &chain); const std::vector &GetAllPostShaderInfo(); const TextureShaderInfo *GetTextureShaderInfo(const std::string &name); diff --git a/GPU/Common/PresentationCommon.cpp b/GPU/Common/PresentationCommon.cpp index d11bf72b9503..f2ce4721da0f 100644 --- a/GPU/Common/PresentationCommon.cpp +++ b/GPU/Common/PresentationCommon.cpp @@ -210,9 +210,9 @@ static std::string ReadShaderSrc(const std::string &filename) { // Note: called on resize and settings changes. bool PresentationCommon::UpdatePostShader() { std::vector shaderInfo; - if (g_Config.sPostShaderName != "Off") { + if (g_Config.vPostShaderNames[0] != "Off") { ReloadAllPostShaderInfo(); - shaderInfo = GetPostShaderChain(g_Config.sPostShaderName); + shaderInfo = GetFullPostShadersChain(g_Config.vPostShaderNames); } DestroyPostShader(); @@ -754,9 +754,9 @@ void PresentationCommon::CopyToOutput(OutputFlags flags, int uvRotation, float u void PresentationCommon::CalculateRenderResolution(int *width, int *height, bool *upscaling, bool *ssaa) { // Check if postprocessing shader is doing upscaling as it requires native resolution std::vector shaderInfo; - if (g_Config.sPostShaderName != "Off") { + if (g_Config.vPostShaderNames[0] != "Off") { ReloadAllPostShaderInfo(); - shaderInfo = GetPostShaderChain(g_Config.sPostShaderName); + shaderInfo = GetFullPostShadersChain(g_Config.vPostShaderNames); } bool firstIsUpscalingFilter = shaderInfo.empty() ? false : shaderInfo.front()->isUpscalingFilter; diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 60d2757f41fa..4fa553bc8b8e 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -74,6 +74,8 @@ #include "Windows/W32Util/ShellUtil.h" #endif +extern bool g_ShaderNameListChanged; + GameSettingsScreen::GameSettingsScreen(std::string gamePath, std::string gameID, bool editThenRestore) : UIDialogScreenWithGameBackground(gamePath), gameID_(gameID), enableReports_(false), editThenRestore_(editThenRestore) { lastVertical_ = UseVerticalLayout(); @@ -305,24 +307,51 @@ void GameSettingsScreen::CreateViews() { altSpeed2->SetZeroLabel(gr->T("Unlimited")); altSpeed2->SetNegativeDisable(gr->T("Disabled")); - graphicsSettings->Add(new ItemHeader(gr->T("Features"))); - postProcChoice_ = graphicsSettings->Add(new ChoiceWithValueDisplay(&g_Config.sPostShaderName, gr->T("Postprocessing Shader"), &PostShaderTranslateName)); - postProcChoice_->OnClick.Handle(this, &GameSettingsScreen::OnPostProcShader); - postProcChoice_->SetEnabledFunc([] { - return g_Config.iRenderingMode != FB_NON_BUFFERED_MODE; - }); + graphicsSettings->Add(new ItemHeader(gr->T("Postprocessing effect"))); + + std::vector alreadyAddedShader; + for (int i = 0; i < g_Config.vPostShaderNames.size() && i < ARRAY_SIZE(shaderNames_); ++i) { + // Vector pointer get invalidated on resize, cache name to have always a valid reference for drawing + shaderNames_[i] = g_Config.vPostShaderNames[i]; + postProcChoice_ = graphicsSettings->Add(new ChoiceWithValueDisplay(&shaderNames_[i], StringFromFormat("%s #%d", gr->T("Postprocessing Shader"), i + 1), &PostShaderTranslateName)); + postProcChoice_->OnClick.Add([=](EventParams &e) { + auto gr = GetI18NCategory("Graphics"); + auto procScreen = new PostProcScreen(gr->T("Postprocessing Shader"), i); + procScreen->OnChoice.Handle(this, &GameSettingsScreen::OnPostProcShaderChange); + if (e.v) + procScreen->SetPopupOrigin(e.v); + screenManager()->push(procScreen); + return UI::EVENT_DONE; + }); + postProcChoice_->SetEnabledFunc([] { + return g_Config.iRenderingMode != FB_NON_BUFFERED_MODE; + }); - auto shaderChain = GetPostShaderChain(g_Config.sPostShaderName); - for (auto shaderInfo : shaderChain) { - for (size_t i = 0; i < ARRAY_SIZE(shaderInfo->settings); ++i) { - auto &setting = shaderInfo->settings[i]; - if (!setting.name.empty()) { - auto &value = g_Config.mPostShaderSetting[StringFromFormat("%sSettingValue%d", shaderInfo->section.c_str(), i + 1)]; - graphicsSettings->Add(new PopupSliderChoiceFloat(&value, setting.minValue, setting.maxValue, ps->T(setting.name), setting.step, screenManager())); + auto shaderChain = GetPostShaderChain(g_Config.vPostShaderNames[i]); + for (auto shaderInfo : shaderChain) { + // Disable duplicated shader slider + bool duplicated = std::find(alreadyAddedShader.begin(), alreadyAddedShader.end(), shaderInfo->section) != alreadyAddedShader.end(); + alreadyAddedShader.push_back(shaderInfo->section); + for (size_t i = 0; i < ARRAY_SIZE(shaderInfo->settings); ++i) { + auto &setting = shaderInfo->settings[i]; + if (!setting.name.empty()) { + auto &value = g_Config.mPostShaderSetting[StringFromFormat("%sSettingValue%d", shaderInfo->section.c_str(), i + 1)]; + if (duplicated) { + auto sliderName = StringFromFormat("%s %s", ps->T(setting.name), ps->T("(duplicated setting, previous slider will be used)")); + PopupSliderChoiceFloat *settingValue = graphicsSettings->Add(new PopupSliderChoiceFloat(&value, setting.minValue, setting.maxValue, sliderName, setting.step, screenManager())); + settingValue->SetEnabled(false); + } else { + PopupSliderChoiceFloat *settingValue = graphicsSettings->Add(new PopupSliderChoiceFloat(&value, setting.minValue, setting.maxValue, ps->T(setting.name), setting.step, screenManager())); + settingValue->SetEnabledFunc([] { + return g_Config.iRenderingMode != FB_NON_BUFFERED_MODE; + }); + } + } } } } + graphicsSettings->Add(new ItemHeader(gr->T("Screen layout"))); #if !defined(MOBILE_DEVICE) graphicsSettings->Add(new CheckBox(&g_Config.bFullScreen, gr->T("FullScreen", "Full Screen")))->OnClick.Handle(this, &GameSettingsScreen::OnFullscreenChange); if (System_GetPropertyInt(SYSPROP_DISPLAY_COUNT) > 1) { @@ -1226,6 +1255,10 @@ void GameSettingsScreen::update() { RecreateViews(); lastVertical_ = vertical; } + if (g_ShaderNameListChanged) { + g_ShaderNameListChanged = false; + RecreateViews(); + } } void GameSettingsScreen::onFinish(DialogResult result) { @@ -1489,19 +1522,11 @@ UI::EventReturn GameSettingsScreen::OnLanguageChange(UI::EventParams &e) { return UI::EVENT_DONE; } -UI::EventReturn GameSettingsScreen::OnPostProcShader(UI::EventParams &e) { - auto gr = GetI18NCategory("Graphics"); - auto procScreen = new PostProcScreen(gr->T("Postprocessing Shader")); - procScreen->OnChoice.Handle(this, &GameSettingsScreen::OnPostProcShaderChange); - if (e.v) - procScreen->SetPopupOrigin(e.v); - screenManager()->push(procScreen); - return UI::EVENT_DONE; -} - UI::EventReturn GameSettingsScreen::OnPostProcShaderChange(UI::EventParams &e) { + g_Config.vPostShaderNames.erase(std::remove(g_Config.vPostShaderNames.begin(), g_Config.vPostShaderNames.end(), "Off"), g_Config.vPostShaderNames.end()); + g_Config.vPostShaderNames.push_back("Off"); + g_ShaderNameListChanged = true; NativeMessageReceived("gpu_resized", ""); - RecreateViews(); // Update setting name return UI::EVENT_DONE; } diff --git a/UI/GameSettingsScreen.h b/UI/GameSettingsScreen.h index 3b0859e0d060..00697f6f86f5 100644 --- a/UI/GameSettingsScreen.h +++ b/UI/GameSettingsScreen.h @@ -80,7 +80,6 @@ class GameSettingsScreen : public UIDialogScreenWithGameBackground { UI::EventReturn OnLanguage(UI::EventParams &e); UI::EventReturn OnLanguageChange(UI::EventParams &e); UI::EventReturn OnAutoFrameskip(UI::EventParams &e); - UI::EventReturn OnPostProcShader(UI::EventParams &e); UI::EventReturn OnPostProcShaderChange(UI::EventParams &e); UI::EventReturn OnTextureShader(UI::EventParams &e); UI::EventReturn OnTextureShaderChange(UI::EventParams &e); @@ -132,6 +131,7 @@ class GameSettingsScreen : public UIDialogScreenWithGameBackground { int prevInflightFrames_; bool enableReports_; bool tessHWEnable_; + std::string shaderNames_[256]; //edit the game-specific settings and restore the global settings after exiting bool editThenRestore_; diff --git a/UI/MiscScreens.cpp b/UI/MiscScreens.cpp index a5e29524832a..00b3f02b9e6b 100644 --- a/UI/MiscScreens.cpp +++ b/UI/MiscScreens.cpp @@ -301,7 +301,7 @@ void PromptScreen::TriggerFinish(DialogResult result) { UIDialogScreenWithBackground::TriggerFinish(result); } -PostProcScreen::PostProcScreen(const std::string &title) : ListPopupScreen(title) { +PostProcScreen::PostProcScreen(const std::string &title, int id) : ListPopupScreen(title), id_(id) { auto ps = GetI18NCategory("PostShaders"); ReloadAllPostShaderInfo(); shaders_ = GetAllPostShaderInfo(); @@ -310,7 +310,7 @@ PostProcScreen::PostProcScreen(const std::string &title) : ListPopupScreen(title for (int i = 0; i < (int)shaders_.size(); i++) { if (!shaders_[i].visible) continue; - if (shaders_[i].section == g_Config.sPostShaderName) + if (shaders_[i].section == g_Config.vPostShaderNames[id_]) selected = i; items.push_back(ps->T(shaders_[i].section.c_str(), shaders_[i].name.c_str())); } @@ -320,7 +320,7 @@ PostProcScreen::PostProcScreen(const std::string &title) : ListPopupScreen(title void PostProcScreen::OnCompleted(DialogResult result) { if (result != DR_OK) return; - g_Config.sPostShaderName = shaders_[listView_->GetSelected()].section; + g_Config.vPostShaderNames[id_] = shaders_[listView_->GetSelected()].section; } TextureShaderScreen::TextureShaderScreen(const std::string &title) : ListPopupScreen(title) { diff --git a/UI/MiscScreens.h b/UI/MiscScreens.h index b1c5881bc436..d920fc77fe80 100644 --- a/UI/MiscScreens.h +++ b/UI/MiscScreens.h @@ -105,12 +105,13 @@ class NewLanguageScreen : public ListPopupScreen { class PostProcScreen : public ListPopupScreen { public: - PostProcScreen(const std::string &title); + PostProcScreen(const std::string &title, int id); private: void OnCompleted(DialogResult result) override; bool ShowButtons() const override { return true; } std::vector shaders_; + int id_; }; class TextureShaderScreen : public ListPopupScreen { diff --git a/UI/NativeApp.cpp b/UI/NativeApp.cpp index ffd0051677d8..b783140809dc 100644 --- a/UI/NativeApp.cpp +++ b/UI/NativeApp.cpp @@ -148,6 +148,7 @@ std::string config_filename; // Really need to clean this mess of globals up... but instead I add more :P bool g_TakeScreenshot; +bool g_ShaderNameListChanged = false; static bool isOuya; static bool resized = false; static bool restarting = false; diff --git a/Windows/MainWindowMenu.cpp b/Windows/MainWindowMenu.cpp index 858a4e919fb4..8e5b83aeecec 100644 --- a/Windows/MainWindowMenu.cpp +++ b/Windows/MainWindowMenu.cpp @@ -47,6 +47,7 @@ #include "Core/Core.h" extern bool g_TakeScreenshot; +extern bool g_ShaderNameListChanged; namespace MainWindow { extern HINSTANCE hInst; @@ -154,7 +155,7 @@ namespace MainWindow { int item = ID_SHADERS_BASE + 1; for (size_t i = 0; i < availableShaders.size(); i++) - CheckMenuItem(menu, item++, ((g_Config.sPostShaderName == availableShaders[i]) ? MF_CHECKED : MF_UNCHECKED)); + CheckMenuItem(menu, item++, ((g_Config.vPostShaderNames[0] == availableShaders[i] && (g_Config.vPostShaderNames[0] == "Off" || g_Config.vPostShaderNames[1] == "Off")) ? MF_CHECKED : MF_UNCHECKED)); } bool CreateShadersSubmenu(HMENU menu) { @@ -188,7 +189,7 @@ namespace MainWindow { continue; int checkedStatus = MF_UNCHECKED; availableShaders.push_back(i->section); - if (g_Config.sPostShaderName == i->section) { + if (g_Config.vPostShaderNames[0] == i->section && (g_Config.vPostShaderNames[0] == "Off" || g_Config.vPostShaderNames[1] == "Off")) { checkedStatus = MF_CHECKED; } @@ -1064,8 +1065,11 @@ namespace MainWindow { // ID_SHADERS_BASE and an additional 1 off it. u32 index = (wParam - ID_SHADERS_BASE - 1); if (index < availableShaders.size()) { - g_Config.sPostShaderName = availableShaders[index]; - + g_Config.vPostShaderNames.clear(); + if (availableShaders[index] != "Off") + g_Config.vPostShaderNames.push_back(availableShaders[index]); + g_Config.vPostShaderNames.push_back("Off"); + g_ShaderNameListChanged = true; NativeMessageReceived("gpu_resized", ""); break; }