diff --git a/Core/Config.cpp b/Core/Config.cpp index 4096e3ca4194..f16c03e5386e 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -1190,6 +1190,12 @@ void Config::Load(const char *iniFileName, const char *controllerIniFilename) { } } + auto postShaderSetting = iniFile.GetOrCreateSection("PostShaderSetting")->ToMap(); + mPostShaderSetting.clear(); + for (auto it : postShaderSetting) { + mPostShaderSetting[it.first] = std::stof(it.second); + } + // This caps the exponent 4 (so 16x.) if (iAnisotropyLevel > 4) { iAnisotropyLevel = 4; @@ -1301,6 +1307,14 @@ void Config::Save(const char *saveReason) { pinnedPaths->Set(keyName, vPinnedPaths[i]); } + if (!bGameSpecific) { + IniFile::Section *postShaderSetting = iniFile.GetOrCreateSection("PostShaderSetting"); + postShaderSetting->Clear(); + for (auto it = mPostShaderSetting.begin(), end = mPostShaderSetting.end(); it != end; ++it) { + postShaderSetting->Set(it->first.c_str(), it->second); + } + } + IniFile::Section *control = iniFile.GetOrCreateSection("Control"); control->Delete("DPadRadius"); @@ -1551,6 +1565,12 @@ bool Config::saveGameConfig(const std::string &pGameId, const std::string &title } }); + IniFile::Section *postShaderSetting = iniFile.GetOrCreateSection("PostShaderSetting"); + postShaderSetting->Clear(); + for (auto it = mPostShaderSetting.begin(), end = mPostShaderSetting.end(); it != end; ++it) { + postShaderSetting->Set(it->first.c_str(), it->second); + } + KeyMap::SaveToIni(iniFile); iniFile.Save(fullIniFilePath); @@ -1569,6 +1589,12 @@ bool Config::loadGameConfig(const std::string &pGameId, const std::string &title IniFile iniFile; iniFile.Load(iniFileNameFull); + auto postShaderSetting = iniFile.GetOrCreateSection("PostShaderSetting")->ToMap(); + mPostShaderSetting.clear(); + for (auto it : postShaderSetting) { + mPostShaderSetting[it.first] = std::stof(it.second); + } + IterateSettings(iniFile, [](IniFile::Section *section, ConfigSetting *setting) { if (setting->perGame_) { setting->Get(section); @@ -1593,6 +1619,12 @@ void Config::unloadGameConfig() { } }); + auto postShaderSetting = iniFile.GetOrCreateSection("PostShaderSetting")->ToMap(); + mPostShaderSetting.clear(); + for (auto it : postShaderSetting) { + mPostShaderSetting[it.first] = std::stof(it.second); + } + LoadStandardControllerIni(); } } diff --git a/Core/Config.h b/Core/Config.h index ebc2cfbaf628..2b1437d3b47a 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -205,6 +205,7 @@ struct Config { int iSplineBezierQuality; // 0 = low , 1 = Intermediate , 2 = High bool bHardwareTessellation; std::string sPostShaderName; // Off for off. + std::map mPostShaderSetting; bool bGfxDebugOutput; bool bGfxDebugSplitSubmit; int iInflightFrames; diff --git a/GPU/Common/PostShader.cpp b/GPU/Common/PostShader.cpp index df30f76df793..a1b5ace7e4d4 100644 --- a/GPU/Common/PostShader.cpp +++ b/GPU/Common/PostShader.cpp @@ -44,6 +44,26 @@ void LoadPostShaderInfo(std::vector directories) { off.isUpscalingFilter = false; off.SSAAFilterLevel = 0; off.requires60fps = false; + off.settingName1 = ""; + off.settingValue1 = 0.0f; + off.minSettingValue1 = -1.0f; + off.maxSettingValue1 = 1.0f; + off.settingStep1 = 0.01f; + off.settingName2 = ""; + off.settingValue2 = 0.0f; + off.minSettingValue2 = -1.0f; + off.maxSettingValue2 = 1.0f; + off.settingStep2 = 0.01f; + off.settingName3 = ""; + off.settingValue3 = 0.0f; + off.minSettingValue3 = -1.0f; + off.maxSettingValue3 = 1.0f; + off.settingStep3 = 0.01f; + off.settingName4 = ""; + off.settingValue4 = 0.0f; + off.minSettingValue4 = -1.0f; + off.maxSettingValue4 = 1.0f; + off.settingStep4 = 0.01f; shaderInfo.push_back(off); for (size_t d = 0; d < directories.size(); d++) { @@ -90,6 +110,35 @@ void LoadPostShaderInfo(std::vector directories) { section.Get("Upscaling", &info.isUpscalingFilter, false); section.Get("SSAA", &info.SSAAFilterLevel, 0); section.Get("60fps", &info.requires60fps, false); + section.Get("SettingName1", &info.settingName1, ""); + section.Get("SettingDefaultValue1", &info.settingValue1, 0.0f); + section.Get("SettingMinValue1", &info.minSettingValue1, -1.0f); + section.Get("SettingMaxValue1", &info.maxSettingValue1, 1.0f); + section.Get("SettingStep1", &info.settingStep1, 0.01f); + section.Get("SettingName2", &info.settingName2, ""); + section.Get("SettingDefaultValue2", &info.settingValue2, 0.0f); + section.Get("SettingMinValue2", &info.minSettingValue2, -1.0f); + section.Get("SettingMaxValue2", &info.maxSettingValue2, 1.0f); + section.Get("SettingStep2", &info.settingStep2, 0.01f); + section.Get("SettingName3", &info.settingName3, ""); + section.Get("SettingDefaultValue3", &info.settingValue3, 0.0f); + section.Get("SettingMinValue3", &info.minSettingValue3, -1.0f); + section.Get("SettingMaxValue3", &info.maxSettingValue3, 1.0f); + section.Get("SettingStep3", &info.settingStep3, 0.01f); + section.Get("SettingName4", &info.settingName4, ""); + section.Get("SettingDefaultValue4", &info.settingValue4, 0.0f); + section.Get("SettingMinValue4", &info.minSettingValue4, -1.0f); + section.Get("SettingMaxValue4", &info.maxSettingValue4, 1.0f); + section.Get("SettingStep4", &info.settingStep4, 0.01f); + + if (g_Config.mPostShaderSetting.find(info.section + "SettingValue1") == g_Config.mPostShaderSetting.end()) + g_Config.mPostShaderSetting.insert(std::pair(info.section + "SettingValue1", info.settingValue1)); + if (g_Config.mPostShaderSetting.find(info.section + "SettingValue2") == g_Config.mPostShaderSetting.end()) + g_Config.mPostShaderSetting.insert(std::pair(info.section + "SettingValue2", info.settingValue2)); + if (g_Config.mPostShaderSetting.find(info.section + "SettingValue3") == g_Config.mPostShaderSetting.end()) + g_Config.mPostShaderSetting.insert(std::pair(info.section + "SettingValue3", info.settingValue3)); + if (g_Config.mPostShaderSetting.find(info.section + "SettingValue4") == g_Config.mPostShaderSetting.end()) + g_Config.mPostShaderSetting.insert(std::pair(info.section + "SettingValue4", info.settingValue4)); // Let's ignore shaders we can't support. TODO: Not a very good check if (gl_extensions.IsGLES && !gl_extensions.GLES3) { diff --git a/GPU/Common/PostShader.h b/GPU/Common/PostShader.h index f848e14802f4..9be8063d7738 100644 --- a/GPU/Common/PostShader.h +++ b/GPU/Common/PostShader.h @@ -41,6 +41,27 @@ struct ShaderInfo { // Force constant/max refresh for animated filters bool requires60fps; + std::string settingName1; + float settingValue1; + float maxSettingValue1; + float minSettingValue1; + float settingStep1; + std::string settingName2; + float settingValue2; + float maxSettingValue2; + float minSettingValue2; + float settingStep2; + std::string settingName3; + float settingValue3; + float maxSettingValue3; + float minSettingValue3; + float settingStep3; + std::string settingName4; + float settingValue4; + float maxSettingValue4; + float minSettingValue4; + float settingStep4; + // TODO: Add support for all kinds of fun options like mapping the depth buffer, // SRGB texture reads, multiple shaders chained, etc. diff --git a/GPU/Common/PresentationCommon.cpp b/GPU/Common/PresentationCommon.cpp index 43c22bcbb018..85ad7e0baedb 100644 --- a/GPU/Common/PresentationCommon.cpp +++ b/GPU/Common/PresentationCommon.cpp @@ -164,6 +164,11 @@ void PresentationCommon::CalculatePostShaderUniforms(int bufferWidth, int buffer // The shader translator tacks this onto our shaders, if we don't set it they render garbage. uniforms->gl_HalfPixel[0] = u_pixel_delta * 0.5f; uniforms->gl_HalfPixel[1] = v_pixel_delta * 0.5f; + + uniforms->setting[0] = g_Config.mPostShaderSetting[g_Config.sPostShaderName + "SettingValue1"];; + uniforms->setting[1] = g_Config.mPostShaderSetting[g_Config.sPostShaderName + "SettingValue2"]; + uniforms->setting[2] = g_Config.mPostShaderSetting[g_Config.sPostShaderName + "SettingValue3"]; + uniforms->setting[3] = g_Config.mPostShaderSetting[g_Config.sPostShaderName + "SettingValue4"]; } static std::string ReadShaderSrc(const std::string &filename) { @@ -214,7 +219,8 @@ bool PresentationCommon::UpdatePostShader() { { "u_texelDelta", 1, 1, Draw::UniformType::FLOAT2, offsetof(PostShaderUniforms, texelDelta) }, { "u_pixelDelta", 2, 2, Draw::UniformType::FLOAT2, offsetof(PostShaderUniforms, pixelDelta) }, { "u_time", 3, 3, Draw::UniformType::FLOAT4, offsetof(PostShaderUniforms, time) }, - { "u_video", 4, 4, Draw::UniformType::FLOAT1, offsetof(PostShaderUniforms, video) }, + { "u_setting", 4, 4, Draw::UniformType::FLOAT4, offsetof(PostShaderUniforms, setting) }, + { "u_video", 5, 5, Draw::UniformType::FLOAT1, offsetof(PostShaderUniforms, video) }, } }; Draw::Pipeline *pipeline = CreatePipeline({ vs, fs }, true, &postShaderDesc); if (!pipeline) diff --git a/GPU/Common/PresentationCommon.h b/GPU/Common/PresentationCommon.h index 967a6b0f2b36..7744d9b1e075 100644 --- a/GPU/Common/PresentationCommon.h +++ b/GPU/Common/PresentationCommon.h @@ -31,6 +31,7 @@ struct CardboardSettings { struct PostShaderUniforms { float texelDelta[2]; float pixelDelta[2]; float time[4]; + float setting[4]; float video; float pad[3]; // Used on Direct3D9. float gl_HalfPixel[4]; diff --git a/GPU/Common/ShaderTranslation.cpp b/GPU/Common/ShaderTranslation.cpp index 7f42a7b2b706..192e59f1860b 100644 --- a/GPU/Common/ShaderTranslation.cpp +++ b/GPU/Common/ShaderTranslation.cpp @@ -86,6 +86,7 @@ cbuffer data : register(b0) { float2 u_texelDelta; float2 u_pixelDelta; float4 u_time; + float4 u_setting; float u_video; }; )"; @@ -101,6 +102,7 @@ layout (std140, set = 0, binding = 0) uniform Data { vec2 u_texelDelta; vec2 u_pixelDelta; vec4 u_time; + vec4 u_setting; float u_video; }; )"; @@ -110,7 +112,8 @@ float4 gl_HalfPixel : register(c0); float2 u_texelDelta : register(c1); float2 u_pixelDelta : register(c2); float4 u_time : register(c3); -float u_video : register(c4); +float4 u_setting : register(c4); +float u_video : register(c5); )"; // SPIRV-Cross' HLSL output has some deficiencies we need to work around. diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index b8486e6cbe5f..5429fb08eff8 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -290,6 +290,24 @@ void GameSettingsScreen::CreateViews() { return g_Config.iRenderingMode != FB_NON_BUFFERED_MODE; }); + const ShaderInfo *shaderInfo = GetPostShaderInfo(g_Config.sPostShaderName); + if (shaderInfo && !shaderInfo->settingName1.empty()) { + auto &value = g_Config.mPostShaderSetting[g_Config.sPostShaderName + "SettingValue1"]; + graphicsSettings->Add(new PopupSliderChoiceFloat(&value, shaderInfo->minSettingValue1, shaderInfo->maxSettingValue1, shaderInfo->settingName1, shaderInfo->settingStep1, screenManager())); + } + if (shaderInfo && !shaderInfo->settingName2.empty()) { + auto &value = g_Config.mPostShaderSetting[g_Config.sPostShaderName + "SettingValue2"]; + graphicsSettings->Add(new PopupSliderChoiceFloat(&value, shaderInfo->minSettingValue2, shaderInfo->maxSettingValue2, shaderInfo->settingName2, shaderInfo->settingStep2, screenManager())); + } + if (shaderInfo && !shaderInfo->settingName3.empty()) { + auto &value = g_Config.mPostShaderSetting[g_Config.sPostShaderName + "SettingValue3"]; + graphicsSettings->Add(new PopupSliderChoiceFloat(&value, shaderInfo->minSettingValue3, shaderInfo->maxSettingValue3, shaderInfo->settingName3, shaderInfo->settingStep3, screenManager())); + } + if (shaderInfo && !shaderInfo->settingName4.empty()) { + auto &value = g_Config.mPostShaderSetting[g_Config.sPostShaderName + "SettingValue4"]; + graphicsSettings->Add(new PopupSliderChoiceFloat(&value, shaderInfo->minSettingValue4, shaderInfo->maxSettingValue4, shaderInfo->settingName4, shaderInfo->settingStep4, screenManager())); + } + #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) { @@ -1413,12 +1431,13 @@ UI::EventReturn GameSettingsScreen::OnPostProcShader(UI::EventParams &e) { UI::EventReturn GameSettingsScreen::OnPostProcShaderChange(UI::EventParams &e) { NativeMessageReceived("gpu_resized", ""); + RecreateViews(); // Update setting name return UI::EVENT_DONE; } UI::EventReturn GameSettingsScreen::OnDeveloperTools(UI::EventParams &e) { -screenManager()->push(new DeveloperToolsScreen()); -return UI::EVENT_DONE; + screenManager()->push(new DeveloperToolsScreen()); + return UI::EVENT_DONE; } UI::EventReturn GameSettingsScreen::OnRemoteISO(UI::EventParams &e) { diff --git a/assets/shaders/bloom.fsh b/assets/shaders/bloom.fsh index c2450c270930..e0636297a24a 100644 --- a/assets/shaders/bloom.fsh +++ b/assets/shaders/bloom.fsh @@ -10,8 +10,7 @@ precision mediump int; uniform sampler2D sampler0; varying vec2 v_texcoord0; -float amount = 0.60; // suitable range = 0.00 - 1.00 -float power = 0.5; // suitable range = 0.0 - 1.0 +uniform vec4 u_setting; void main() { @@ -21,9 +20,9 @@ void main() for(int i= -3 ;i < 3; i++) { - sum += texture2D(sampler0, v_texcoord0 + vec2(-1, i)*0.004) * amount; - sum += texture2D(sampler0, v_texcoord0 + vec2(0, i)*0.004) * amount; - sum += texture2D(sampler0, v_texcoord0 + vec2(1, i)*0.004) * amount; + sum += texture2D(sampler0, v_texcoord0 + vec2(-1, i)*0.004) * u_setting.x; + sum += texture2D(sampler0, v_texcoord0 + vec2(0, i)*0.004) * u_setting.x; + sum += texture2D(sampler0, v_texcoord0 + vec2(1, i)*0.004) * u_setting.x; } if (color.r < 0.3 && color.g < 0.3 && color.b < 0.3) @@ -42,7 +41,7 @@ void main() } } - bloom = mix(color, bloom, power); + bloom = mix(color, bloom, u_setting.y); gl_FragColor.rgb = bloom; gl_FragColor.a = 1.0; } diff --git a/assets/shaders/cartoon.fsh b/assets/shaders/cartoon.fsh index 3c7be597a042..de8c0a07fde5 100644 --- a/assets/shaders/cartoon.fsh +++ b/assets/shaders/cartoon.fsh @@ -10,7 +10,7 @@ precision mediump float; precision mediump int; #endif -const float bb = 0.5; // effects black border sensitivity; from 0.0 to 1.0 +uniform vec4 u_setting; uniform sampler2D sampler0; @@ -39,7 +39,7 @@ void main() float d2=dot(abs(c20-c02),dt); float hl=dot(abs(c01-c21),dt); float vl=dot(abs(c10-c12),dt); - float d = bb*(d1+d2+hl+vl)/(dot(c11,dt)+0.15); + float d = u_setting.x*(d1+d2+hl+vl)/(dot(c11,dt)+0.15); float lc = 4.0*length(c11); float f = fract(lc); f*=f; diff --git a/assets/shaders/colorcorrection.fsh b/assets/shaders/colorcorrection.fsh new file mode 100644 index 000000000000..cf62884f5aa5 --- /dev/null +++ b/assets/shaders/colorcorrection.fsh @@ -0,0 +1,20 @@ +// Color correction + +#ifdef GL_ES +precision mediump float; +precision mediump int; +#endif + +uniform sampler2D sampler0; +varying vec2 v_texcoord0; + +uniform vec4 u_setting; + +void main() +{ + vec3 rgb = texture2D( sampler0, v_texcoord0 ).xyz; + rgb = vec3(mix(vec3(dot(rgb, vec3(0.299, 0.587, 0.114))), rgb, u_setting.y)); + rgb = (rgb-0.5)*u_setting.z+0.5+u_setting.x-1.0; + gl_FragColor.rgb = pow(rgb, vec3(1.0/u_setting.w)); + gl_FragColor.a = 1.0; +} diff --git a/assets/shaders/defaultshaders.ini b/assets/shaders/defaultshaders.ini index f000589e5baf..2fe8c9499bcb 100644 --- a/assets/shaders/defaultshaders.ini +++ b/assets/shaders/defaultshaders.ini @@ -32,10 +32,23 @@ Vertex=fxaa.vsh Name=Bloom Fragment=bloom.fsh Vertex=fxaa.vsh +SettingName1=Amount +SettingDefaultValue1=0.6 +SettingMaxValue1=1.0 +SettingMinValue1=0.0 +SettingName2=Power +SettingDefaultValue2=0.5 +SettingMaxValue2=1.0 +SettingMinValue2=0.0 [Sharpen] Name=Sharpen Fragment=sharpen.fsh Vertex=fxaa.vsh +SettingName1=Amount +SettingDefaultValue1=1.5 +SettingMaxValue1=3.0 +SettingMinValue1=1.0 +SettingStep1=0.1 [InverseColors] Name=Inverse Colors Author=Henrik @@ -46,10 +59,24 @@ Name=Scanlines (CRT) Fragment=scanlines.fsh Vertex=fxaa.vsh OutputResolution=True +SettingName1=Amount +SettingDefaultValue1=1.0 +SettingMaxValue1=1.0 +SettingMinValue1=0.0 +SettingStep1=0.1 +SettingName2=Intensity +SettingDefaultValue2=0.5 +SettingMaxValue2=1.0 +SettingMinValue2=0.0 +SettingStep2=0.05 [Cartoon] Name=Cartoon Fragment=cartoon.fsh Vertex=cartoon.vsh +SettingName1=Black border +SettingDefaultValue1=0.5 +SettingMaxValue1=1.0 +SettingMinValue1=0.0 [4xHqGLSL] Name=4xHqGLSL Upscaler Fragment=4xhqglsl.fsh @@ -93,3 +120,28 @@ Fragment=GaussianDownscale.fsh Vertex=fxaa.vsh OutputResolution=True SSAA=2 +[ColorCorrection] +Name=Color correction +Fragment=colorcorrection.fsh +Vertex=fxaa.vsh +SettingName1=Brightness +SettingDefaultValue1=1.0 +SettingMaxValue1=2.0 +SettingMinValue1=0.1 +SettingStep1=0.05 +SettingName2=Saturation +SettingDefaultValue2=1.0 +SettingMaxValue2=2.0 +SettingMinValue2=0.0 +SettingStep2=0.1 +SettingName3=Constrast +SettingDefaultValue3=1.0 +SettingMaxValue3=3.0 +SettingMinValue3=0.1 +SettingStep3=0.1 +SettingName4=Gamma +SettingDefaultValue4=1.0 +SettingMaxValue4=2.0 +SettingMinValue4=0.1 +SettingStep4=0.05 + diff --git a/assets/shaders/scanlines.fsh b/assets/shaders/scanlines.fsh index 77a839a37bac..ac568b14a98f 100644 --- a/assets/shaders/scanlines.fsh +++ b/assets/shaders/scanlines.fsh @@ -8,13 +8,12 @@ precision mediump int; uniform sampler2D sampler0; varying vec2 v_texcoord0; -float amount = 1.0; // suitable range = 0.0 - 1.0 -float intensity = 0.5; // suitable range = 0.0 - 1.0 +uniform vec4 u_setting; void main() { - float pos0 = ((v_texcoord0.y + 1.0) * 170.0*amount); - float pos1 = cos((fract( pos0 ) - 0.5)*3.1415926*intensity)*1.5; + float pos0 = ((v_texcoord0.y + 1.0) * 170.0*u_setting.x); + float pos1 = cos((fract( pos0 ) - 0.5)*3.1415926*u_setting.y)*1.5; vec4 rgb = texture2D( sampler0, v_texcoord0 ); // slight contrast curve diff --git a/assets/shaders/sharpen.fsh b/assets/shaders/sharpen.fsh index d5ad04de549b..3c528c760215 100644 --- a/assets/shaders/sharpen.fsh +++ b/assets/shaders/sharpen.fsh @@ -8,12 +8,12 @@ precision mediump int; uniform sampler2D sampler0; varying vec2 v_texcoord0; -float amount = 1.5; +uniform vec4 u_setting; void main() { vec3 color = texture2D(sampler0, v_texcoord0.xy).xyz; - color -= texture2D(sampler0, v_texcoord0.xy+0.0001).xyz*7.0*amount; - color += texture2D(sampler0, v_texcoord0.xy-0.0001).xyz*7.0*amount; + color -= texture2D(sampler0, v_texcoord0.xy+0.0001).xyz*7.0*u_setting.x; + color += texture2D(sampler0, v_texcoord0.xy-0.0001).xyz*7.0*u_setting.x; gl_FragColor.rgb = color; }