From 3a657fe33c4d1bb060a3a67e00d2334c40dde541 Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Tue, 29 Jul 2014 11:34:57 -0500 Subject: [PATCH 1/6] Add TryParseVector to StringUtil. Adds a nice way to have options be in a vector for results --- Source/Core/Common/StringUtil.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/Source/Core/Common/StringUtil.h b/Source/Core/Common/StringUtil.h index 50d270e732..8e9e9315af 100644 --- a/Source/Core/Common/StringUtil.h +++ b/Source/Core/Common/StringUtil.h @@ -75,6 +75,23 @@ static bool TryParse(const std::string &str, N *const output) return false; } +template +bool TryParseVector(const std::string& str, std::vector* output, const char delimiter = ',') +{ + output->clear(); + std::istringstream buffer(str); + std::string variable; + + while (std::getline(buffer, variable, delimiter)) + { + N tmp = 0; + if (!TryParse(variable, &tmp)) + return false; + output->push_back(tmp); + } + return true; +} + // TODO: kill this bool AsciiToHex(const std::string& _szValue, u32& result); From 6bdc32c54aa19b8b61b19a4b11167ba329667b0a Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Tue, 29 Jul 2014 11:47:56 -0500 Subject: [PATCH 2/6] Add the VideoCommon PostProcessing class. This class loads all the common PP shader configuration options and passes those options through to a inherited class that OpenGL or D3D will have. Makes it so all the common code for PP shaders is in VideoCommon instead of duplicating the code across each backend. --- Source/Core/Common/IniFile.cpp | 6 +- Source/Core/Common/IniFile.h | 5 + Source/Core/DolphinWX/VideoConfigDiag.cpp | 5 + Source/Core/DolphinWX/VideoConfigDiag.h | 13 + .../Core/VideoBackends/OGL/PostProcessing.cpp | 94 +++++- .../Core/VideoBackends/OGL/PostProcessing.h | 32 +- Source/Core/VideoCommon/CMakeLists.txt | 1 + Source/Core/VideoCommon/PostProcessing.cpp | 304 ++++++++++++++++++ Source/Core/VideoCommon/PostProcessing.h | 104 ++++++ Source/Core/VideoCommon/RenderBase.cpp | 2 + Source/Core/VideoCommon/RenderBase.h | 4 + Source/Core/VideoCommon/VideoCommon.vcxproj | 4 +- .../VideoCommon/VideoCommon.vcxproj.filters | 8 +- 13 files changed, 555 insertions(+), 27 deletions(-) create mode 100644 Source/Core/VideoCommon/PostProcessing.cpp create mode 100644 Source/Core/VideoCommon/PostProcessing.h diff --git a/Source/Core/Common/IniFile.cpp b/Source/Core/Common/IniFile.cpp index da9d99e250..f3ea5751ba 100644 --- a/Source/Core/Common/IniFile.cpp +++ b/Source/Core/Common/IniFile.cpp @@ -19,9 +19,7 @@ #include "Common/IniFile.h" #include "Common/StringUtil.h" -namespace { - -void ParseLine(const std::string& line, std::string* keyOut, std::string* valueOut) +void IniFile::ParseLine(const std::string& line, std::string* keyOut, std::string* valueOut) { if (line[0] == '#') return; @@ -40,8 +38,6 @@ void ParseLine(const std::string& line, std::string* keyOut, std::string* valueO } } -} - const std::string& IniFile::NULL_STRING = ""; void IniFile::Section::Set(const std::string& key, const std::string& newValue) diff --git a/Source/Core/Common/IniFile.h b/Source/Core/Common/IniFile.h index 3ff7e39794..1e62b5c7f7 100644 --- a/Source/Core/Common/IniFile.h +++ b/Source/Core/Common/IniFile.h @@ -116,6 +116,11 @@ public: Section* GetOrCreateSection(const std::string& section); + // This function is related to parsing data from lines of INI files + // It's used outside of IniFile, which is why it is exposed publicly + // In particular it is used in PostProcessing for its configuration + static void ParseLine(const std::string& line, std::string* keyOut, std::string* valueOut); + private: std::list
sections; diff --git a/Source/Core/DolphinWX/VideoConfigDiag.cpp b/Source/Core/DolphinWX/VideoConfigDiag.cpp index 565827fc22..13f3dad9b4 100644 --- a/Source/Core/DolphinWX/VideoConfigDiag.cpp +++ b/Source/Core/DolphinWX/VideoConfigDiag.cpp @@ -415,6 +415,11 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string &title, con else choice_ppshader->SetStringSelection(StrToWxStr(vconfig.sPostProcessingShader)); + // Should the configuration button be loaded by default? + PostProcessingShaderConfiguration postprocessing_shader; + postprocessing_shader.LoadShader(vconfig.sPostProcessingShader); + button_config_pp->Enable(postprocessing_shader.HasOptions()); + choice_ppshader->Bind(wxEVT_CHOICE, &VideoConfigDiag::Event_PPShader, this); szr_enh->Add(new wxStaticText(page_enh, -1, _("Post-Processing Effect:")), 1, wxALIGN_CENTER_VERTICAL, 0); diff --git a/Source/Core/DolphinWX/VideoConfigDiag.h b/Source/Core/DolphinWX/VideoConfigDiag.h index ab574cd2fe..6802f0be84 100644 --- a/Source/Core/DolphinWX/VideoConfigDiag.h +++ b/Source/Core/DolphinWX/VideoConfigDiag.h @@ -142,6 +142,19 @@ protected: else vconfig.sPostProcessingShader.clear(); + // Should we enable the configuration button? + PostProcessingShaderConfiguration postprocessing_shader; + postprocessing_shader.LoadShader(vconfig.sPostProcessingShader); + button_config_pp->Enable(postprocessing_shader.HasOptions()); + + ev.Skip(); + } + + void Event_ConfigurePPShader(wxCommandEvent &ev) + { + PostProcessingConfigDiag dialog(this, vconfig.sPostProcessingShader); + dialog.ShowModal(); + ev.Skip(); } diff --git a/Source/Core/VideoBackends/OGL/PostProcessing.cpp b/Source/Core/VideoBackends/OGL/PostProcessing.cpp index e885d63a56..06a15b07cc 100644 --- a/Source/Core/VideoBackends/OGL/PostProcessing.cpp +++ b/Source/Core/VideoBackends/OGL/PostProcessing.cpp @@ -40,14 +40,13 @@ static char s_vertex_shader[] = void Init() { - s_currentShader = ""; - s_enable = 0; - s_width = 0; - s_height = 0; + m_enable = false; + m_width = 0; + m_height = 0; - glGenFramebuffers(1, &s_fbo); - glGenTextures(1, &s_texture); - glBindTexture(GL_TEXTURE_2D, s_texture); + glGenFramebuffers(1, &m_fbo); + glGenTextures(1, &m_texture); + glBindTexture(GL_TEXTURE_2D, m_texture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); // disable mipmaps glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); @@ -59,7 +58,7 @@ void Init() void Shutdown() { - s_shader.Destroy(); + m_shader.Destroy(); glDeleteFramebuffers(1, &s_fbo); glDeleteTextures(1, &s_texture); @@ -84,6 +83,9 @@ void BlitToScreen() s_shader.Bind(); + glUniform4f(m_uniform_resolution, (float)m_width, (float)m_height, 1.0f/(float)m_width, 1.0f/(float)m_height); + glUniform1ui(m_uniform_time, (GLuint)m_timer.GetTimeElapsed()); + glUniform4f(s_uniform_resolution, (float)s_width, (float)s_height, 1.0f/(float)s_width, 1.0f/(float)s_height); glActiveTexture(GL_TEXTURE0+9); @@ -145,10 +147,82 @@ void ApplyShader() } // read uniform locations - s_uniform_resolution = glGetUniformLocation(s_shader.glprogid, "resolution"); + m_uniform_resolution = glGetUniformLocation(m_shader.glprogid, "resolution"); + m_uniform_time = glGetUniformLocation(m_shader.glprogid, "time"); + + for (const auto& it : m_options) + { + std::string glsl_name = "option_" + it.first; + m_uniform_bindings[it.first] = glGetUniformLocation(m_shader.glprogid, glsl_name.c_str()); + } // successful - s_enable = true; + m_enable = true; +} + +void OpenGLPostProcessing::CreateHeader() +{ + m_glsl_header = + // Required variables + // Shouldn't be accessed directly by the PP shader + // Texture sampler + "SAMPLER_BINDING(8) uniform sampler2D samp8;\n" + "SAMPLER_BINDING(9) uniform sampler2D samp9;\n" + + // Output variable + "out float4 ocol0;\n" + // Input coordinates + "in float2 uv0;\n" + // Resolution + "uniform float4 resolution;\n" + // Time + "uniform uint time;\n" + + // Interfacing functions + "float4 Sample()\n" + "{\n" + "\treturn texture(samp9, uv0);\n" + "}\n" + + "float4 SampleLocation(float2 location)\n" + "{\n" + "\treturn texture(samp9, location);\n" + "}\n" + + "#define SampleOffset(offset) textureOffset(samp9, uv0, offset)\n" + + "float4 SampleFontLocation(float2 location)\n" + "{\n" + "\treturn texture(samp8, location);\n" + "}\n" + + "float2 GetResolution()\n" + "{\n" + "\treturn resolution.xy;\n" + "}\n" + + "float2 GetInvResolution()\n" + "{\n" + "\treturn resolution.zw;\n" + "}\n" + + "float2 GetCoordinates()\n" + "{\n" + "\treturn uv0;\n" + "}\n" + + "uint GetTime()\n" + "{\n" + "\treturn time;\n" + "}\n" + + "void SetOutput(float4 color)\n" + "{\n" + "\tocol0 = color;\n" + "}\n" + + "#define GetOption(x) (option_#x)\n" + "#define OptionEnabled(x) (option_#x != 0)\n"; } } // namespace diff --git a/Source/Core/VideoBackends/OGL/PostProcessing.h b/Source/Core/VideoBackends/OGL/PostProcessing.h index 1a6f015bbc..4f2fb87250 100644 --- a/Source/Core/VideoBackends/OGL/PostProcessing.h +++ b/Source/Core/VideoBackends/OGL/PostProcessing.h @@ -4,26 +4,38 @@ #pragma once +#include +#include + #include "VideoBackends/OGL/GLUtil.h" #include "VideoCommon/VideoCommon.h" namespace OGL { -namespace PostProcessing +class OpenGLPostProcessing : public PostProcessingShaderImplementation { +public: + OpenGLPostProcessing(); + ~OpenGLPostProcessing(); -void Init(); -void Shutdown(); + void BindTargetFramebuffer() override; + void BlitToScreen() override; + void Update(u32 width, u32 height) override; + void ApplyShader() override; -void BindTargetFramebuffer(); -void BlitToScreen(); -void Update(u32 width, u32 height); +private: + GLuint m_fbo; + GLuint m_texture; + SHADER m_shader; + GLuint m_uniform_resolution; + GLuint m_uniform_time; + std::string m_glsl_header; -void ReloadShader(); + std::unordered_map m_uniform_bindings; -void ApplyShader(); - -} // namespace + void CreateHeader(); + std::string LoadShaderOptions(const std::string& code); +}; } // namespace diff --git a/Source/Core/VideoCommon/CMakeLists.txt b/Source/Core/VideoCommon/CMakeLists.txt index 844184210d..ef71208943 100644 --- a/Source/Core/VideoCommon/CMakeLists.txt +++ b/Source/Core/VideoCommon/CMakeLists.txt @@ -18,6 +18,7 @@ set(SRCS BPFunctions.cpp PixelEngine.cpp PixelShaderGen.cpp PixelShaderManager.cpp + PostProcessing.cpp RenderBase.cpp Statistics.cpp TextureCacheBase.cpp diff --git a/Source/Core/VideoCommon/PostProcessing.cpp b/Source/Core/VideoCommon/PostProcessing.cpp new file mode 100644 index 0000000000..019001da15 --- /dev/null +++ b/Source/Core/VideoCommon/PostProcessing.cpp @@ -0,0 +1,304 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include + +#include "Common/CommonPaths.h" +#include "Common/FileUtil.h" +#include "Common/IniFile.h" +#include "Common/StringUtil.h" + +#include "VideoCommon/PostProcessing.h" +#include "VideoCommon/VideoConfig.h" + + +PostProcessingShaderImplementation::PostProcessingShaderImplementation() +{ + m_timer.Start(); +} + +PostProcessingShaderImplementation::~PostProcessingShaderImplementation() +{ + m_timer.Stop(); +} + +std::string PostProcessingShaderConfiguration::LoadShader(std::string shader) +{ + // Load the shader from the configuration if there isn't one sent to us. + if (shader == "") + shader = g_ActiveConfig.sPostProcessingShader; + m_current_shader = shader; + + // loading shader code + std::string code; + std::string path = File::GetUserPath(D_SHADERS_IDX) + shader + ".glsl"; + + if (!File::Exists(path)) + { + // Fallback to shared user dir + path = File::GetSysDirectory() + SHADERS_DIR DIR_SEP + shader + ".glsl"; + } + + if (!File::ReadFileToString(path, code)) + { + ERROR_LOG(VIDEO, "Post-processing shader not found: %s", path.c_str()); + return ""; + } + + LoadOptions(code); + LoadOptionsConfiguration(); + + return code; +} + +void PostProcessingShaderConfiguration::LoadOptions(const std::string& code) +{ + const std::string config_start_delimiter = "[configuration]"; + const std::string config_end_delimiter = "[/configuration]"; + size_t configuration_start = code.find(config_start_delimiter); + size_t configuration_end = code.find(config_end_delimiter); + + m_options.clear(); + m_any_options_dirty = true; + + if (configuration_start == std::string::npos || + configuration_end == std::string::npos) + { + // Issue loading configuration or there isn't one. + return; + } + + std::string configuration_string = code.substr(configuration_start + config_start_delimiter.size(), + configuration_end - configuration_start - config_start_delimiter.size()); + + std::istringstream in(configuration_string); + + struct GLSLStringOption + { + std::string m_type; + std::vector> m_options; + }; + + std::vector option_strings; + GLSLStringOption* current_strings = nullptr; + while (!in.eof()) + { + std::string line; + + if (std::getline(in, line)) + { +#ifndef _WIN32 + // Check for CRLF eol and convert it to LF + if (!line.empty() && line.at(line.size()-1) == '\r') + { + line.erase(line.size()-1); + } +#endif + + if (line.size() > 0) + { + if (line[0] == '[') + { + size_t endpos = line.find("]"); + + if (endpos != std::string::npos) + { + // New section! + std::string sub = line.substr(1, endpos - 1); + option_strings.push_back({ sub }); + current_strings = &option_strings.back(); + } + } + else + { + if (current_strings) + { + std::string key, value; + IniFile::ParseLine(line, &key, &value); + + if (!(key == "" && value == "")) + current_strings->m_options.push_back(std::make_pair(key, value)); + } + } + } + } + } + + for (const auto& it : option_strings) + { + ConfigurationOption option; + option.m_dirty = true; + + if (it.m_type == "OptionBool") + option.m_type = ConfigurationOption::OptionType::OPTION_BOOL; + else if (it.m_type == "OptionRangeFloat") + option.m_type = ConfigurationOption::OptionType::OPTION_FLOAT; + else if (it.m_type == "OptionRangeInteger") + option.m_type = ConfigurationOption::OptionType::OPTION_INTEGER; + + for (const auto& string_option : it.m_options) + { + if (string_option.first == "GUIName") + { + option.m_gui_name = string_option.second; + } + else if (string_option.first == "OptionName") + { + option.m_option_name = string_option.second; + } + else if (string_option.first == "DependentOption") + { + option.m_dependent_option = string_option.second; + } + else if (string_option.first == "MinValue" || + string_option.first == "MaxValue" || + string_option.first == "DefaultValue" || + string_option.first == "StepAmount") + { + std::vector* output_integer = nullptr; + std::vector* output_float = nullptr; + + if (string_option.first == "MinValue") + { + output_integer = &option.m_integer_min_values; + output_float = &option.m_float_min_values; + } + else if (string_option.first == "MaxValue") + { + output_integer = &option.m_integer_max_values; + output_float = &option.m_float_max_values; + } + else if (string_option.first == "DefaultValue") + { + output_integer = &option.m_integer_values; + output_float = &option.m_float_values; + } + else if (string_option.first == "StepAmount") + { + output_integer = &option.m_integer_step_values; + output_float = &option.m_float_step_values; + } + + if (option.m_type == ConfigurationOption::OptionType::OPTION_BOOL) + { + TryParse(string_option.second, &option.m_bool_value); + } + else if (option.m_type == ConfigurationOption::OptionType::OPTION_INTEGER) + { + TryParseVector(string_option.second, output_integer); + if (output_integer->size() > 4) + output_integer->erase(output_integer->begin() + 4, output_integer->end()); + } + else if (option.m_type == ConfigurationOption::OptionType::OPTION_FLOAT) + { + TryParseVector(string_option.second, output_float); + if (output_float->size() > 4) + output_float->erase(output_float->begin() + 4, output_float->end()); + } + } + } + m_options[option.m_option_name] = option; + } +} + +void PostProcessingShaderConfiguration::LoadOptionsConfiguration() +{ + IniFile ini; + ini.Load(File::GetUserPath(F_DOLPHINCONFIG_IDX)); + std::string section = m_current_shader + "-options"; + + for (auto& it : m_options) + { + switch (it.second.m_type) + { + case ConfigurationOption::OptionType::OPTION_BOOL: + ini.GetOrCreateSection(section)->Get(it.second.m_option_name, &it.second.m_bool_value, it.second.m_bool_value); + break; + case ConfigurationOption::OptionType::OPTION_INTEGER: + { + std::string value; + ini.GetOrCreateSection(section)->Get(it.second.m_option_name, &value); + if (value != "") + TryParseVector(value, &it.second.m_integer_values); + } + break; + case ConfigurationOption::OptionType::OPTION_FLOAT: + { + std::string value; + ini.GetOrCreateSection(section)->Get(it.second.m_option_name, &value); + if (value != "") + TryParseVector(value, &it.second.m_float_values); + } + break; + } + } +} + +void PostProcessingShaderConfiguration::SaveOptionsConfiguration() +{ + IniFile ini; + ini.Load(File::GetUserPath(F_DOLPHINCONFIG_IDX)); + std::string section = m_current_shader + "-options"; + + for (auto& it : m_options) + { + switch (it.second.m_type) + { + case ConfigurationOption::OptionType::OPTION_BOOL: + { + ini.GetOrCreateSection(section)->Set(it.second.m_option_name, it.second.m_bool_value); + } + break; + case ConfigurationOption::OptionType::OPTION_INTEGER: + { + std::string value = ""; + for (size_t i = 0; i < it.second.m_integer_values.size(); ++i) + value += StringFromFormat("%d%s", it.second.m_integer_values[i], i == (it.second.m_integer_values.size() - 1) ? "": ", "); + ini.GetOrCreateSection(section)->Set(it.second.m_option_name, value); + } + break; + case ConfigurationOption::OptionType::OPTION_FLOAT: + { + std::string value = ""; + for (size_t i = 0; i < it.second.m_float_values.size(); ++i) + value += StringFromFormat("%f%s", it.second.m_float_values[i], i == (it.second.m_float_values.size() - 1) ? "": ", "); + ini.GetOrCreateSection(section)->Set(it.second.m_option_name, value); + } + break; + } + } + ini.Save(File::GetUserPath(F_DOLPHINCONFIG_IDX)); +} + +void PostProcessingShaderConfiguration::ReloadShader() +{ + m_current_shader = ""; +} + +void PostProcessingShaderConfiguration::SetOptionf(std::string option, int index, float value) +{ + auto it = m_options.find(option); + + it->second.m_float_values[index] = value; + it->second.m_dirty = true; + m_any_options_dirty = true; +} + +void PostProcessingShaderConfiguration::SetOptioni(std::string option, int index, s32 value) +{ + auto it = m_options.find(option); + + it->second.m_integer_values[index] = value; + it->second.m_dirty = true; + m_any_options_dirty = true; +} + +void PostProcessingShaderConfiguration::SetOptionb(std::string option, bool value) +{ + auto it = m_options.find(option); + + it->second.m_bool_value = value; + it->second.m_dirty = true; + m_any_options_dirty = true; +} diff --git a/Source/Core/VideoCommon/PostProcessing.h b/Source/Core/VideoCommon/PostProcessing.h new file mode 100644 index 0000000000..0f539dbb05 --- /dev/null +++ b/Source/Core/VideoCommon/PostProcessing.h @@ -0,0 +1,104 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include +#include +#include + +#include "Common/StringUtil.h" +#include "Common/Timer.h" + +class PostProcessingShaderConfiguration +{ +public: + struct ConfigurationOption + { + enum OptionType + { + OPTION_BOOL = 0, + OPTION_FLOAT, + OPTION_INTEGER, + }; + + bool m_bool_value; + + std::vector m_float_values; + std::vector m_integer_values; + + std::vector m_float_min_values; + std::vector m_integer_min_values; + + std::vector m_float_max_values; + std::vector m_integer_max_values; + + std::vector m_float_step_values; + std::vector m_integer_step_values; + + OptionType m_type; + + std::string m_gui_name; + std::string m_option_name; + std::string m_dependent_option; + bool m_dirty; + }; + + typedef std::map ConfigMap; + + PostProcessingShaderConfiguration() : m_current_shader("") {} + virtual ~PostProcessingShaderConfiguration() {} + + // Loads the configuration with a shader + // If the argument is "" the class will load the shader from the g_activeConfig option. + // Returns the loaded shader source from file + std::string LoadShader(std::string shader = ""); + void SaveOptionsConfiguration(); + void ReloadShader(); + std::string GetShader() { return m_current_shader; } + + bool IsDirty() { return m_any_options_dirty; } + void SetDirty(bool dirty) { m_any_options_dirty = dirty; } + + bool HasOptions() { return m_options.size() > 0; } + ConfigMap& GetOptions() { return m_options; } + const ConfigurationOption& GetOption(const std::string& option) { return m_options[option]; } + + // For updating option's values + void SetOptionf(std::string option, int index, float value); + void SetOptioni(std::string option, int index, s32 value); + void SetOptionb(std::string option, bool value); + +private: + bool m_any_options_dirty; + std::string m_current_shader; + ConfigMap m_options; + + void LoadOptions(const std::string& code); + void LoadOptionsConfiguration(); +}; + +class PostProcessingShaderImplementation +{ +public: + PostProcessingShaderImplementation(); + virtual ~PostProcessingShaderImplementation(); + + PostProcessingShaderConfiguration* GetConfig() { return &m_config; } + + // Should be implemented by the backends for backend specific code + virtual void BindTargetFramebuffer() = 0; + virtual void BlitToScreen() = 0; + virtual void Update(u32 width, u32 height) = 0; + virtual void ApplyShader() = 0; + +protected: + bool m_enable; + u32 m_width; + u32 m_height; + // Timer for determining our time value + Common::Timer m_timer; + + PostProcessingShaderConfiguration m_config; +}; diff --git a/Source/Core/VideoCommon/RenderBase.cpp b/Source/Core/VideoCommon/RenderBase.cpp index 4ba52d09fe..07b4f8bccb 100644 --- a/Source/Core/VideoCommon/RenderBase.cpp +++ b/Source/Core/VideoCommon/RenderBase.cpp @@ -59,6 +59,8 @@ int Renderer::s_target_height; int Renderer::s_backbuffer_width; int Renderer::s_backbuffer_height; +PostProcessingShaderImplementation* Renderer::m_post_processor; + TargetRectangle Renderer::target_rc; int Renderer::s_LastEFBScale; diff --git a/Source/Core/VideoCommon/RenderBase.h b/Source/Core/VideoCommon/RenderBase.h index 8707219d82..3ed767b348 100644 --- a/Source/Core/VideoCommon/RenderBase.h +++ b/Source/Core/VideoCommon/RenderBase.h @@ -115,6 +115,8 @@ public: static PEControl::PixelFormat GetPrevPixelFormat() { return prev_efb_format; } static void StorePixelFormat(PEControl::PixelFormat new_format) { prev_efb_format = new_format; } + PostProcessingShaderImplementation* GetPostProcessor() { return m_post_processor; } + protected: static void CalculateTargetScale(int x, int y, int &scaledX, int &scaledY); @@ -153,6 +155,8 @@ protected: FPSCounter m_fps_counter; + static PostProcessingShaderImplementation* m_post_processor; + private: static PEControl::PixelFormat prev_efb_format; static unsigned int efb_scale_numeratorX; diff --git a/Source/Core/VideoCommon/VideoCommon.vcxproj b/Source/Core/VideoCommon/VideoCommon.vcxproj index a7e8d7d23b..f00e031cc3 100644 --- a/Source/Core/VideoCommon/VideoCommon.vcxproj +++ b/Source/Core/VideoCommon/VideoCommon.vcxproj @@ -56,6 +56,7 @@ + @@ -105,6 +106,7 @@ + @@ -148,4 +150,4 @@ - \ No newline at end of file + diff --git a/Source/Core/VideoCommon/VideoCommon.vcxproj.filters b/Source/Core/VideoCommon/VideoCommon.vcxproj.filters index cf8611b719..85f6424c24 100644 --- a/Source/Core/VideoCommon/VideoCommon.vcxproj.filters +++ b/Source/Core/VideoCommon/VideoCommon.vcxproj.filters @@ -107,6 +107,9 @@ Util + + Util + Util @@ -234,6 +237,9 @@ Util + + Util + Util @@ -266,4 +272,4 @@ - \ No newline at end of file + From b8a21b37446e80b2c6a249933babe9acae9e618e Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Tue, 29 Jul 2014 11:52:34 -0500 Subject: [PATCH 3/6] Add the PostProcessing class object to RenderBase in VideoCommon. Backends will initialize this variable with their own inherited PostProcessing class object. --- Source/Core/VideoCommon/RenderBase.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Source/Core/VideoCommon/RenderBase.h b/Source/Core/VideoCommon/RenderBase.h index 3ed767b348..fc20752a50 100644 --- a/Source/Core/VideoCommon/RenderBase.h +++ b/Source/Core/VideoCommon/RenderBase.h @@ -24,6 +24,8 @@ #include "VideoCommon/NativeVertexFormat.h" #include "VideoCommon/VideoCommon.h" +class PostProcessingShaderImplementation; + // TODO: Move these out of here. extern int frameCount; extern int OSDChoice; From cced3b4a18b5116a715bb2bfc40f3f6c47165640 Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Tue, 29 Jul 2014 11:57:02 -0500 Subject: [PATCH 4/6] Change OpenGL's post processing to use the new VideoCommon PP object. Let's OpenGL's PostProcessing namespace be changed to a class inheriting from VideoCommon's PostProcessing class. --- .../Core/VideoBackends/OGL/PostProcessing.cpp | 202 ++++++++++++------ .../Core/VideoBackends/OGL/PostProcessing.h | 2 + Source/Core/VideoBackends/OGL/Render.cpp | 13 +- Source/Core/VideoBackends/OGL/main.cpp | 2 - 4 files changed, 148 insertions(+), 71 deletions(-) diff --git a/Source/Core/VideoBackends/OGL/PostProcessing.cpp b/Source/Core/VideoBackends/OGL/PostProcessing.cpp index 06a15b07cc..dee133ed03 100644 --- a/Source/Core/VideoBackends/OGL/PostProcessing.cpp +++ b/Source/Core/VideoBackends/OGL/PostProcessing.cpp @@ -4,6 +4,7 @@ #include "Common/CommonPaths.h" #include "Common/FileUtil.h" +#include "Common/StringUtil.h" #include "VideoBackends/OGL/FramebufferManager.h" #include "VideoBackends/OGL/GLUtil.h" @@ -16,20 +17,6 @@ namespace OGL { -namespace PostProcessing -{ - -static std::string s_currentShader; -static SHADER s_shader; -static bool s_enable; - -static u32 s_width; -static u32 s_height; -static GLuint s_fbo; -static GLuint s_texture; - -static GLuint s_uniform_resolution; - static char s_vertex_shader[] = "out vec2 uv0;\n" "void main(void) {\n" @@ -38,7 +25,7 @@ static char s_vertex_shader[] = " uv0 = rawpos;\n" "}\n"; -void Init() +OpenGLPostProcessing::OpenGLPostProcessing() { m_enable = false; m_width = 0; @@ -51,98 +38,151 @@ void Init() glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); - glBindFramebuffer(GL_FRAMEBUFFER, s_fbo); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, s_texture, 0); + glBindFramebuffer(GL_FRAMEBUFFER, m_fbo); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_texture, 0); FramebufferManager::SetFramebuffer(0); + + CreateHeader(); } -void Shutdown() +OpenGLPostProcessing::~OpenGLPostProcessing() { m_shader.Destroy(); - glDeleteFramebuffers(1, &s_fbo); - glDeleteTextures(1, &s_texture); + glDeleteFramebuffers(1, &m_fbo); + glDeleteTextures(1, &m_texture); } -void ReloadShader() +void OpenGLPostProcessing::BindTargetFramebuffer() { - s_currentShader = ""; + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_enable ? m_fbo : 0); } -void BindTargetFramebuffer () +void OpenGLPostProcessing::BlitToScreen() { - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, s_enable ? s_fbo : 0); -} - -void BlitToScreen() -{ - if (!s_enable) return; + if (!m_enable) return; glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); - glViewport(0, 0, s_width, s_height); + glViewport(0, 0, m_width, m_height); - s_shader.Bind(); + m_shader.Bind(); glUniform4f(m_uniform_resolution, (float)m_width, (float)m_height, 1.0f/(float)m_width, 1.0f/(float)m_height); glUniform1ui(m_uniform_time, (GLuint)m_timer.GetTimeElapsed()); - glUniform4f(s_uniform_resolution, (float)s_width, (float)s_height, 1.0f/(float)s_width, 1.0f/(float)s_height); + if (m_config.IsDirty()) + { + for (auto& it : m_config.GetOptions()) + { + if (it.second.m_dirty) + { + switch (it.second.m_type) + { + case PostProcessingShaderConfiguration::ConfigurationOption::OptionType::OPTION_BOOL: + glUniform1i(m_uniform_bindings[it.first], it.second.m_bool_value); + break; + case PostProcessingShaderConfiguration::ConfigurationOption::OptionType::OPTION_INTEGER: + switch (it.second.m_integer_values.size()) + { + case 1: + glUniform1i(m_uniform_bindings[it.first], it.second.m_integer_values[0]); + break; + case 2: + glUniform2i(m_uniform_bindings[it.first], + it.second.m_integer_values[0], + it.second.m_integer_values[1]); + break; + case 3: + glUniform3i(m_uniform_bindings[it.first], + it.second.m_integer_values[0], + it.second.m_integer_values[1], + it.second.m_integer_values[2]); + break; + case 4: + glUniform4i(m_uniform_bindings[it.first], + it.second.m_integer_values[0], + it.second.m_integer_values[1], + it.second.m_integer_values[2], + it.second.m_integer_values[3]); + break; + } + break; + case PostProcessingShaderConfiguration::ConfigurationOption::OptionType::OPTION_FLOAT: + switch (it.second.m_float_values.size()) + { + case 1: + glUniform1f(m_uniform_bindings[it.first], it.second.m_float_values[0]); + break; + case 2: + glUniform2f(m_uniform_bindings[it.first], + it.second.m_float_values[0], + it.second.m_float_values[1]); + break; + case 3: + glUniform3f(m_uniform_bindings[it.first], + it.second.m_float_values[0], + it.second.m_float_values[1], + it.second.m_float_values[2]); + break; + case 4: + glUniform4f(m_uniform_bindings[it.first], + it.second.m_float_values[0], + it.second.m_float_values[1], + it.second.m_float_values[2], + it.second.m_float_values[3]); + break; + } + break; + } + it.second.m_dirty = false; + } + } + m_config.SetDirty(false); + } glActiveTexture(GL_TEXTURE0+9); - glBindTexture(GL_TEXTURE_2D, s_texture); + glBindTexture(GL_TEXTURE_2D, m_texture); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - -/* glBindFramebuffer(GL_READ_FRAMEBUFFER, s_fbo); - - glBlitFramebuffer(rc.left, rc.bottom, rc.right, rc.top, - rc.left, rc.bottom, rc.right, rc.top, - GL_COLOR_BUFFER_BIT, GL_NEAREST);*/ } -void Update ( u32 width, u32 height ) +void OpenGLPostProcessing::Update(u32 width, u32 height) { ApplyShader(); - if (s_enable && (width != s_width || height != s_height)) { - s_width = width; - s_height = height; + if (m_enable && (width != m_width || height != m_height)) + { + m_width = width; + m_height = height; // alloc texture for framebuffer glActiveTexture(GL_TEXTURE0+9); - glBindTexture(GL_TEXTURE_2D, s_texture); + glBindTexture(GL_TEXTURE_2D, m_texture); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); } } -void ApplyShader() +void OpenGLPostProcessing::ApplyShader() { // shader didn't changed - if (s_currentShader == g_ActiveConfig.sPostProcessingShader) return; - s_currentShader = g_ActiveConfig.sPostProcessingShader; - s_enable = false; - s_shader.Destroy(); + if (m_config.GetShader() == g_ActiveConfig.sPostProcessingShader) return; + + m_enable = false; + m_shader.Destroy(); + m_uniform_bindings.clear(); // shader disabled if (g_ActiveConfig.sPostProcessingShader == "") return; // so need to compile shader + std::string code = m_config.LoadShader(); - // loading shader code - std::string code; - std::string path = File::GetUserPath(D_SHADERS_IDX) + g_ActiveConfig.sPostProcessingShader + ".glsl"; - if (!File::Exists(path)) - { - // Fallback to shared user dir - path = File::GetSysDirectory() + SHADERS_DIR DIR_SEP + g_ActiveConfig.sPostProcessingShader + ".glsl"; - } - if (!File::ReadFileToString(path, code)) { - ERROR_LOG(VIDEO, "Post-processing shader not found: %s", path.c_str()); - return; - } + if (code == "") return; + + code = LoadShaderOptions(code); // and compile it - if (!ProgramShaderCache::CompileShader(s_shader, s_vertex_shader, code.c_str())) { - ERROR_LOG(VIDEO, "Failed to compile post-processing shader %s", s_currentShader.c_str()); + if (!ProgramShaderCache::CompileShader(m_shader, s_vertex_shader, code.c_str())) { + ERROR_LOG(VIDEO, "Failed to compile post-processing shader %s", m_config.GetShader().c_str()); return; } @@ -150,7 +190,7 @@ void ApplyShader() m_uniform_resolution = glGetUniformLocation(m_shader.glprogid, "resolution"); m_uniform_time = glGetUniformLocation(m_shader.glprogid, "time"); - for (const auto& it : m_options) + for (const auto& it : m_config.GetOptions()) { std::string glsl_name = "option_" + it.first; m_uniform_bindings[it.first] = glGetUniformLocation(m_shader.glprogid, glsl_name.c_str()); @@ -225,6 +265,38 @@ void OpenGLPostProcessing::CreateHeader() "#define OptionEnabled(x) (option_#x != 0)\n"; } -} // namespace +std::string OpenGLPostProcessing::LoadShaderOptions(const std::string& code) +{ + std::string glsl_options = ""; + m_uniform_bindings.clear(); + + for (const auto& it : m_config.GetOptions()) + { + if (it.second.m_type == PostProcessingShaderConfiguration::ConfigurationOption::OptionType::OPTION_BOOL) + { + glsl_options += StringFromFormat("uniform int option_%s;\n", it.first.c_str()); + } + else if (it.second.m_type == PostProcessingShaderConfiguration::ConfigurationOption::OptionType::OPTION_INTEGER) + { + u32 count = it.second.m_integer_values.size(); + if (count == 1) + glsl_options += StringFromFormat("uniform int option_%s;\n", it.first.c_str()); + else + glsl_options += StringFromFormat("uniform int%d option_%s;\n", count, it.first.c_str()); + } + else if (it.second.m_type == PostProcessingShaderConfiguration::ConfigurationOption::OptionType::OPTION_FLOAT) + { + u32 count = it.second.m_float_values.size(); + if (count == 1) + glsl_options += StringFromFormat("uniform float option_%s;\n", it.first.c_str()); + else + glsl_options += StringFromFormat("uniform float%d option_%s;\n", count, it.first.c_str()); + } + + m_uniform_bindings[it.first] = 0; + } + + return m_glsl_header + glsl_options + code; +} } // namespace OGL diff --git a/Source/Core/VideoBackends/OGL/PostProcessing.h b/Source/Core/VideoBackends/OGL/PostProcessing.h index 4f2fb87250..6aa93cc9a5 100644 --- a/Source/Core/VideoBackends/OGL/PostProcessing.h +++ b/Source/Core/VideoBackends/OGL/PostProcessing.h @@ -8,6 +8,8 @@ #include #include "VideoBackends/OGL/GLUtil.h" + +#include "VideoCommon/PostProcessing.h" #include "VideoCommon/VideoCommon.h" namespace OGL diff --git a/Source/Core/VideoBackends/OGL/Render.cpp b/Source/Core/VideoBackends/OGL/Render.cpp index a3bba96fd1..d6881171e7 100644 --- a/Source/Core/VideoBackends/OGL/Render.cpp +++ b/Source/Core/VideoBackends/OGL/Render.cpp @@ -641,6 +641,9 @@ void Renderer::Shutdown() delete s_pfont; s_pfont = nullptr; s_ShowEFBCopyRegions.Destroy(); + + delete m_post_processor; + m_post_processor = nullptr; } void Renderer::Init() @@ -649,6 +652,8 @@ void Renderer::Init() g_framebuffer_manager = new FramebufferManager(s_target_width, s_target_height, s_MSAASamples); + m_post_processor = new OpenGLPostProcessing(); + s_pfont = new RasterFont(); ProgramShaderCache::CompileShader(s_ShowEFBCopyRegions, @@ -1331,7 +1336,7 @@ void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbHeight,const EFBRectangl ResetAPIState(); - PostProcessing::Update(s_backbuffer_width, s_backbuffer_height); + m_post_processor->Update(s_backbuffer_width, s_backbuffer_height); UpdateDrawRectangle(s_backbuffer_width, s_backbuffer_height); TargetRectangle flipped_trc = GetTargetRectangle(); @@ -1354,7 +1359,7 @@ void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbHeight,const EFBRectangl if (g_ActiveConfig.bUseXFB) { // Render to the real/postprocessing buffer now. - PostProcessing::BindTargetFramebuffer(); + m_post_processor->BindTargetFramebuffer(); // draw each xfb source glBindFramebuffer(GL_READ_FRAMEBUFFER, FramebufferManager::GetXFBFramebuffer()); @@ -1413,7 +1418,7 @@ void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbHeight,const EFBRectangl FramebufferManager::ResolveAndGetRenderTarget(rc); // Render to the real/postprocessing buffer now. (resolve have changed this in msaa mode) - PostProcessing::BindTargetFramebuffer(); + m_post_processor->BindTargetFramebuffer(); // always the non-msaa fbo GLuint fb = s_MSAASamples>1?FramebufferManager::GetResolvedFramebuffer():FramebufferManager::GetEFBFramebuffer(); @@ -1424,7 +1429,7 @@ void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbHeight,const EFBRectangl GL_COLOR_BUFFER_BIT, GL_LINEAR); } - PostProcessing::BlitToScreen(); + m_post_processor->BlitToScreen(); glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); diff --git a/Source/Core/VideoBackends/OGL/main.cpp b/Source/Core/VideoBackends/OGL/main.cpp index 44febec4a9..c23abad7a6 100644 --- a/Source/Core/VideoBackends/OGL/main.cpp +++ b/Source/Core/VideoBackends/OGL/main.cpp @@ -210,7 +210,6 @@ void VideoBackend::Video_Prepare() VertexShaderManager::Init(); PixelShaderManager::Init(); ProgramShaderCache::Init(); - PostProcessing::Init(); g_texture_cache = new TextureCache(); g_sampler_cache = new SamplerCache(); Renderer::Init(); @@ -250,7 +249,6 @@ void VideoBackend::Video_Cleanup() { g_sampler_cache = nullptr; delete g_texture_cache; g_texture_cache = nullptr; - PostProcessing::Shutdown(); ProgramShaderCache::Shutdown(); VertexShaderManager::Shutdown(); PixelShaderManager::Shutdown(); From 32fe37d8349d42f5863e7bad832b5e4a2bd9b5ef Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Tue, 29 Jul 2014 12:08:57 -0500 Subject: [PATCH 5/6] Change all the post processing shaders to the new system. Removes the README.txt file in favour of a new wiki page I'm going to generate. --- Data/Sys/Shaders/16bit.glsl | 13 ++--- Data/Sys/Shaders/32bit.glsl | 13 ++--- Data/Sys/Shaders/FXAA.glsl | 54 +++++++++----------- Data/Sys/Shaders/README.txt | 18 ------- Data/Sys/Shaders/acidmetal.glsl | 9 +--- Data/Sys/Shaders/acidtrip.glsl | 9 +--- Data/Sys/Shaders/acidtrip2.glsl | 13 ++--- Data/Sys/Shaders/asciiart.glsl | 55 +++++++++------------ Data/Sys/Shaders/auto_toon.glsl | 21 +++----- Data/Sys/Shaders/auto_toon2.glsl | 22 +++------ Data/Sys/Shaders/bad_bloom.glsl | 51 +++++++++---------- Data/Sys/Shaders/brighten.glsl | 7 +-- Data/Sys/Shaders/chrismas.glsl | 9 +--- Data/Sys/Shaders/cool1.glsl | 9 +--- Data/Sys/Shaders/darkerbrighter.glsl | 19 +++---- Data/Sys/Shaders/emboss.glsl | 25 ++++------ Data/Sys/Shaders/fire.glsl | 9 +--- Data/Sys/Shaders/fire2.glsl | 9 +--- Data/Sys/Shaders/firewater.glsl | 15 ++---- Data/Sys/Shaders/grayscale.glsl | 9 +--- Data/Sys/Shaders/grayscale2.glsl | 9 +--- Data/Sys/Shaders/invert.glsl | 7 +-- Data/Sys/Shaders/invert_blue.glsl | 7 +-- Data/Sys/Shaders/invertedoutline.glsl | 13 ++--- Data/Sys/Shaders/mad_world.glsl | 19 +++---- Data/Sys/Shaders/nightvision.glsl | 9 +--- Data/Sys/Shaders/nightvision2.glsl | 31 +++++------- Data/Sys/Shaders/nightvision2scanlines.glsl | 35 ++++++------- Data/Sys/Shaders/posterize.glsl | 9 +--- Data/Sys/Shaders/posterize2.glsl | 9 +--- Data/Sys/Shaders/primarycolors.glsl | 9 +--- Data/Sys/Shaders/sepia.glsl | 9 +--- Data/Sys/Shaders/sketchy.glsl | 21 +++----- Data/Sys/Shaders/spookey1.glsl | 9 +--- Data/Sys/Shaders/spookey2.glsl | 9 +--- Data/Sys/Shaders/stereoscopic.glsl | 23 +++------ Data/Sys/Shaders/stereoscopic2.glsl | 15 ++---- Data/Sys/Shaders/sunset.glsl | 9 +--- Data/Sys/Shaders/swap_RGB_BGR.glsl | 7 +-- Data/Sys/Shaders/swap_RGB_BRG.glsl | 7 +-- Data/Sys/Shaders/swap_RGB_GBR.glsl | 7 +-- Data/Sys/Shaders/swap_RGB_GRB.glsl | 7 +-- Data/Sys/Shaders/swap_RGB_RBG.glsl | 7 +-- Data/Sys/Shaders/toxic.glsl | 9 +--- 44 files changed, 206 insertions(+), 479 deletions(-) delete mode 100644 Data/Sys/Shaders/README.txt diff --git a/Data/Sys/Shaders/16bit.glsl b/Data/Sys/Shaders/16bit.glsl index edff1d5e3c..fd13d3469e 100644 --- a/Data/Sys/Shaders/16bit.glsl +++ b/Data/Sys/Shaders/16bit.glsl @@ -1,10 +1,3 @@ -SAMPLER_BINDING(9) uniform sampler2D samp9; - -out vec4 ocol0; -in vec2 uv0; - -uniform vec4 resolution; - void main() { //Change this number to increase the pixel size. @@ -14,9 +7,9 @@ void main() float green = 0.0; float blue = 0.0; - vec2 pos = floor(uv0 * resolution.xy / pixelSize) * pixelSize * resolution.zw; + float2 pos = floor(GetCoordinates() * GetResolution() / pixelSize) * pixelSize * GetInvResolution(); - vec4 c0 = texture(samp9, pos); + float4 c0 = SampleLocation(pos); if (c0.r < 0.1) red = 0.1; @@ -57,5 +50,5 @@ void main() else green = 1.0; - ocol0 = vec4(red, green, blue, c0.a); + SetOutput(float4(red, green, blue, c0.a)); } diff --git a/Data/Sys/Shaders/32bit.glsl b/Data/Sys/Shaders/32bit.glsl index ed8fb890c5..d0e43db2ce 100644 --- a/Data/Sys/Shaders/32bit.glsl +++ b/Data/Sys/Shaders/32bit.glsl @@ -1,10 +1,3 @@ -SAMPLER_BINDING(9) uniform sampler2D samp9; - -out vec4 ocol0; -in vec2 uv0; - -uniform vec4 resolution; - void main() { //Change this number to increase the pixel size. @@ -14,9 +7,9 @@ void main() float green = 0.0; float blue = 0.0; - vec2 pos = floor(uv0 * resolution.xy / pixelSize) * pixelSize * resolution.zw; + float2 pos = floor(GetCoordinates() * GetResolution() / pixelSize) * pixelSize * GetInvResolution(); - vec4 c0 = texture(samp9, pos); + float4 c0 = SampleLocation(pos); if (c0.r < 0.06) red = 0.06; @@ -82,5 +75,5 @@ void main() else green = 1.0; - ocol0 = vec4(red, green, blue, c0.a); + SetOutput(float4(red, green, blue, c0.a)); } diff --git a/Data/Sys/Shaders/FXAA.glsl b/Data/Sys/Shaders/FXAA.glsl index 60d072cdaa..897bd30e62 100644 --- a/Data/Sys/Shaders/FXAA.glsl +++ b/Data/Sys/Shaders/FXAA.glsl @@ -12,26 +12,20 @@ // 0. You just DO WHAT THE FUCK YOU WANT TO. -SAMPLER_BINDING(9) uniform sampler2D samp9; - -out vec4 ocol0; -in vec2 uv0; - -uniform vec4 resolution; #define FXAA_REDUCE_MIN (1.0/ 128.0) #define FXAA_REDUCE_MUL (1.0 / 8.0) #define FXAA_SPAN_MAX 8.0 - -vec4 applyFXAA(vec2 fragCoord, sampler2D tex) + +float4 applyFXAA(float2 fragCoord) { - vec4 color; - vec2 inverseVP = resolution.zw; - vec3 rgbNW = texture(tex, (fragCoord + vec2(-1.0, -1.0)) * inverseVP).xyz; - vec3 rgbNE = texture(tex, (fragCoord + vec2(1.0, -1.0)) * inverseVP).xyz; - vec3 rgbSW = texture(tex, (fragCoord + vec2(-1.0, 1.0)) * inverseVP).xyz; - vec3 rgbSE = texture(tex, (fragCoord + vec2(1.0, 1.0)) * inverseVP).xyz; - vec3 rgbM = texture(tex, fragCoord * inverseVP).xyz; - vec3 luma = vec3(0.299, 0.587, 0.114); + float4 color; + float2 inverseVP = GetInvResolution(); + float3 rgbNW = SampleLocation((fragCoord + float2(-1.0, -1.0)) * inverseVP).xyz; + float3 rgbNE = SampleLocation((fragCoord + float2(1.0, -1.0)) * inverseVP).xyz; + float3 rgbSW = SampleLocation((fragCoord + float2(-1.0, 1.0)) * inverseVP).xyz; + float3 rgbSE = SampleLocation((fragCoord + float2(1.0, 1.0)) * inverseVP).xyz; + float3 rgbM = SampleLocation(fragCoord * inverseVP).xyz; + float3 luma = float3(0.299, 0.587, 0.114); float lumaNW = dot(rgbNW, luma); float lumaNE = dot(rgbNE, luma); float lumaSW = dot(rgbSW, luma); @@ -39,8 +33,8 @@ vec4 applyFXAA(vec2 fragCoord, sampler2D tex) float lumaM = dot(rgbM, luma); float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE))); float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE))); - - vec2 dir; + + float2 dir; dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE)); dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE)); @@ -48,26 +42,26 @@ vec4 applyFXAA(vec2 fragCoord, sampler2D tex) (0.25 * FXAA_REDUCE_MUL), FXAA_REDUCE_MIN); float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce); - dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX), - max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX), + dir = min(float2(FXAA_SPAN_MAX, FXAA_SPAN_MAX), + max(float2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX), dir * rcpDirMin)) * inverseVP; - vec3 rgbA = 0.5 * ( - texture(tex, fragCoord * inverseVP + dir * (1.0 / 3.0 - 0.5)).xyz + - texture(tex, fragCoord * inverseVP + dir * (2.0 / 3.0 - 0.5)).xyz); - vec3 rgbB = rgbA * 0.5 + 0.25 * ( - texture(tex, fragCoord * inverseVP + dir * -0.5).xyz + - texture(tex, fragCoord * inverseVP + dir * 0.5).xyz); - + float3 rgbA = 0.5 * ( + SampleLocation(fragCoord * inverseVP + dir * (1.0 / 3.0 - 0.5)).xyz + + SampleLocation(fragCoord * inverseVP + dir * (2.0 / 3.0 - 0.5)).xyz); + float3 rgbB = rgbA * 0.5 + 0.25 * ( + SampleLocation(fragCoord * inverseVP + dir * -0.5).xyz + + SampleLocation(fragCoord * inverseVP + dir * 0.5).xyz); + float lumaB = dot(rgbB, luma); if ((lumaB < lumaMin) || (lumaB > lumaMax)) - color = vec4(rgbA, 1.0); + color = float4(rgbA, 1.0); else - color = vec4(rgbB, 1.0); + color = float4(rgbB, 1.0); return color; } void main() { - ocol0 = applyFXAA(uv0 * resolution.xy, samp9); + SetOutput(applyFXAA(GetCoordinates() * GetResolution())); } diff --git a/Data/Sys/Shaders/README.txt b/Data/Sys/Shaders/README.txt deleted file mode 100644 index acb7d22615..0000000000 --- a/Data/Sys/Shaders/README.txt +++ /dev/null @@ -1,18 +0,0 @@ -//dummy shader: -SAMPLER_BINDING(9) uniform sampler2D samp9; - -out vec4 ocol0; -in vec2 uv0; - -void main() -{ - ocol0 = texture(samp9, uv0); -} - -/* -And now that's over with, the contents of this readme file! -For best results, turn Wordwrap formatting on... -The shaders shown in the dropdown box in the video plugin configuration window are kept in the directory named User/Data/Shaders. They are linked in to the dolphin source from the repository at . See for more details on the way shaders work. - -This file will hopefully hold more content in future... -*/ diff --git a/Data/Sys/Shaders/acidmetal.glsl b/Data/Sys/Shaders/acidmetal.glsl index 6e976f0093..6ea8891f6a 100644 --- a/Data/Sys/Shaders/acidmetal.glsl +++ b/Data/Sys/Shaders/acidmetal.glsl @@ -1,11 +1,6 @@ -SAMPLER_BINDING(9) uniform sampler2D samp9; - -out vec4 ocol0; -in vec2 uv0; - void main() { - vec4 c0 = texture(samp9, uv0); + float4 c0 = Sample(); float red = 0.0; float blue = 0.0; @@ -17,5 +12,5 @@ void main() float green = max(c0.r + c0.b, c0.g); - ocol0 = vec4(red, green, blue, 1.0); + SetOutput(float4(red, green, blue, 1.0)); } diff --git a/Data/Sys/Shaders/acidtrip.glsl b/Data/Sys/Shaders/acidtrip.glsl index 172e281b52..8722e621f1 100644 --- a/Data/Sys/Shaders/acidtrip.glsl +++ b/Data/Sys/Shaders/acidtrip.glsl @@ -1,11 +1,4 @@ -SAMPLER_BINDING(9) uniform sampler2D samp9; - -out vec4 ocol0; -in vec2 uv0; - -uniform vec4 resolution; - void main() { - ocol0 = (texture(samp9, uv0+resolution.zw) - texture(samp9, uv0-resolution.zw)) * 8.0; + SetOutput((SampleOffset(int2(1, 1)) - SampleOffset(int2(-1, -1))) * 8.0); } diff --git a/Data/Sys/Shaders/acidtrip2.glsl b/Data/Sys/Shaders/acidtrip2.glsl index 332de035f6..054fe17173 100644 --- a/Data/Sys/Shaders/acidtrip2.glsl +++ b/Data/Sys/Shaders/acidtrip2.glsl @@ -1,13 +1,6 @@ -SAMPLER_BINDING(9) uniform sampler2D samp9; - -out vec4 ocol0; -in vec2 uv0; - -uniform vec4 resolution; - void main() { - vec4 a = texture(samp9, uv0+resolution.zw); - vec4 b = texture(samp9, uv0-resolution.zw); - ocol0 = ( a*a*1.3 - b ) * 8.0; + float4 a = SampleOffset(int2( 1, 1)); + float4 b = SampleOffset(int2(-1, -1)); + SetOutput(( a*a*1.3 - b ) * 8.0); } diff --git a/Data/Sys/Shaders/asciiart.glsl b/Data/Sys/Shaders/asciiart.glsl index 089d216839..52fec3da6d 100644 --- a/Data/Sys/Shaders/asciiart.glsl +++ b/Data/Sys/Shaders/asciiart.glsl @@ -1,48 +1,39 @@ -// textures -SAMPLER_BINDING(8) uniform sampler2D samp8; -SAMPLER_BINDING(9) uniform sampler2D samp9; - const int char_width = 8; const int char_height = 13; const int char_count = 95; const int char_pixels = char_width*char_height; -const vec2 char_dim = vec2(char_width, char_height); -const vec2 font_scale = vec2(1.0/float(char_width)/float(char_count), 1.0/float(char_height)); - -out vec4 ocol0; -in vec2 uv0; - -uniform vec4 resolution; +const float2 char_dim = float2(char_width, char_height); +const float2 font_scale = float2(1.0/float(char_width)/float(char_count), 1.0/float(char_height)); void main() { - vec2 char_pos = floor(uv0*resolution.xy/char_dim); - vec2 pixel_offset = floor(uv0*resolution.xy) - char_pos*char_dim; + float2 char_pos = floor(GetCoordinates()*GetResolution()/char_dim); + float2 pixel_offset = floor(GetCoordinates()*GetResolution()) - char_pos*char_dim; // just a big number float mindiff = float(char_width*char_height) * 100.0; float minc = 0.0; - vec4 mina = vec4(0.0, 0.0, 0.0, 0.0); - vec4 minb = vec4(0.0, 0.0, 0.0, 0.0); + float4 mina = float4(0.0, 0.0, 0.0, 0.0); + float4 minb = float4(0.0, 0.0, 0.0, 0.0); for (int i=0; i 0.9) green = c0.r / 3.0; - ocol0 = vec4(red, green, blue, 1.0); + SetOutput(float4(red, green, blue, 1.0)); } diff --git a/Data/Sys/Shaders/fire2.glsl b/Data/Sys/Shaders/fire2.glsl index 2ca04ec529..4b116f9871 100644 --- a/Data/Sys/Shaders/fire2.glsl +++ b/Data/Sys/Shaders/fire2.glsl @@ -1,11 +1,6 @@ -SAMPLER_BINDING(9) uniform sampler2D samp9; - -out vec4 ocol0; -in vec2 uv0; - void main() { - vec4 c0 = texture(samp9, uv0); + float4 c0 = Sample(); float red = 0.0; float green = 0.0; float blue = 0.0; @@ -14,5 +9,5 @@ void main() red = c0.r + (c0.g / 2.0) + (c0.b / 3.0); green = c0.r / 3.0; - ocol0 = vec4(red, green, blue, 1.0); + SetOutput(float4(red, green, blue, 1.0)); } diff --git a/Data/Sys/Shaders/firewater.glsl b/Data/Sys/Shaders/firewater.glsl index 20cf927bc9..32b9be3d5d 100644 --- a/Data/Sys/Shaders/firewater.glsl +++ b/Data/Sys/Shaders/firewater.glsl @@ -1,15 +1,8 @@ -SAMPLER_BINDING(9) uniform sampler2D samp9; - -out vec4 ocol0; -in vec2 uv0; - -uniform vec4 resolution; - void main() { - float4 c0 = texture(samp9, uv0); - float4 c1 = texture(samp9, uv0 + float2(1,1)*resolution.zw); - float4 c2 = texture(samp9, uv0 + float2(-1,-1)*resolution.zw); + float4 c0 = Sample(); + float4 c1 = SampleOffset(int2( 1, 1)); + float4 c2 = SampleOffset(int2(-1, -1)); float red = c0.r; float green = c0.g; float blue = c0.b; @@ -18,5 +11,5 @@ void main() red = c0.r - c1.b; blue = c0.b - c2.r + (c0.g - c0.r); - ocol0 = float4(red, 0.0, blue, alpha); + SetOutput(float4(red, 0.0, blue, alpha)); } diff --git a/Data/Sys/Shaders/grayscale.glsl b/Data/Sys/Shaders/grayscale.glsl index 1c3658f00f..a7a211ce4a 100644 --- a/Data/Sys/Shaders/grayscale.glsl +++ b/Data/Sys/Shaders/grayscale.glsl @@ -1,11 +1,6 @@ -SAMPLER_BINDING(9) uniform sampler2D samp9; - -out vec4 ocol0; -in vec2 uv0; - void main() { - vec4 c0 = texture(samp9, uv0); + float4 c0 = Sample(); float avg = (c0.r + c0.g + c0.b) / 3.0; - ocol0 = vec4(avg, avg, avg, c0.a); + SetOutput(float4(avg, avg, avg, c0.a)); } diff --git a/Data/Sys/Shaders/grayscale2.glsl b/Data/Sys/Shaders/grayscale2.glsl index 7e8f09e064..98cb1f8838 100644 --- a/Data/Sys/Shaders/grayscale2.glsl +++ b/Data/Sys/Shaders/grayscale2.glsl @@ -1,12 +1,7 @@ -SAMPLER_BINDING(9) uniform sampler2D samp9; - -out vec4 ocol0; -in vec2 uv0; - void main() { - vec4 c0 = texture(samp9, uv0); + float4 c0 = Sample(); // Info: http://www.oreillynet.com/cs/user/view/cs_msg/8691 float avg = (0.222 * c0.r) + (0.707 * c0.g) + (0.071 * c0.b); - ocol0 = vec4(avg, avg, avg, c0.a); + SetOutput(float4(avg, avg, avg, c0.a)); } diff --git a/Data/Sys/Shaders/invert.glsl b/Data/Sys/Shaders/invert.glsl index 01e840c6e6..46cf142c84 100644 --- a/Data/Sys/Shaders/invert.glsl +++ b/Data/Sys/Shaders/invert.glsl @@ -1,9 +1,4 @@ -SAMPLER_BINDING(9) uniform sampler2D samp9; - -out vec4 ocol0; -in vec2 uv0; - void main() { - ocol0 = vec4(1.0, 1.0, 1.0, 1.0) - texture(samp9, uv0); + SetOutput(float4(1.0, 1.0, 1.0, 1.0) - Sample()); } diff --git a/Data/Sys/Shaders/invert_blue.glsl b/Data/Sys/Shaders/invert_blue.glsl index 081027ff75..75602ea2a6 100644 --- a/Data/Sys/Shaders/invert_blue.glsl +++ b/Data/Sys/Shaders/invert_blue.glsl @@ -1,9 +1,4 @@ -SAMPLER_BINDING(9) uniform sampler2D samp9; - -out vec4 ocol0; -in vec2 uv0; - void main() { - ocol0 = vec4(0.0, 0.0, 0.7, 1.0) - texture(samp9, uv0); + SetOutput(float4(0.0, 0.0, 0.7, 1.0) - Sample()); } diff --git a/Data/Sys/Shaders/invertedoutline.glsl b/Data/Sys/Shaders/invertedoutline.glsl index b5b29731b9..fa1cb0f9bd 100644 --- a/Data/Sys/Shaders/invertedoutline.glsl +++ b/Data/Sys/Shaders/invertedoutline.glsl @@ -1,14 +1,7 @@ -SAMPLER_BINDING(9) uniform sampler2D samp9; - -out vec4 ocol0; -in vec2 uv0; - -uniform vec4 resolution; - void main() { - float4 c0 = texture(samp9, uv0); - float4 c1 = texture(samp9, uv0 + float2(5,5)*resolution.zw); + float4 c0 = Sample(); + float4 c1 = SampleOffset(int2(5, 5)); - ocol0 = c0 - c1; + SetOutput(c0 - c1); } diff --git a/Data/Sys/Shaders/mad_world.glsl b/Data/Sys/Shaders/mad_world.glsl index 1aff5223a2..8d596541a1 100644 --- a/Data/Sys/Shaders/mad_world.glsl +++ b/Data/Sys/Shaders/mad_world.glsl @@ -1,26 +1,19 @@ -SAMPLER_BINDING(9) uniform sampler2D samp9; - -out vec4 ocol0; -in vec2 uv0; - -uniform vec4 resolution; - void main() { - float4 emboss = (texture(samp9, uv0+resolution.zw) - texture(samp9, uv0-resolution.zw))*2.0; - emboss -= (texture(samp9, uv0+float2(1,-1)*resolution.zw).rgba - texture(samp9, uv0+float2(-1,1)*resolution.zw).rgba); - float4 color = texture(samp9, uv0).rgba; + float4 emboss = (SampleLocation(GetCoordinates()+GetInvResolution()) - SampleLocation(GetCoordinates()-GetInvResolution()))*2.0; + emboss -= (SampleLocation(GetCoordinates()+float2(1,-1)*GetInvResolution()).rgba - SampleLocation(GetCoordinates()+float2(-1,1)*GetInvResolution()).rgba); + float4 color = Sample(); if (color.r > 0.8 && color.b + color.b < 0.2) { - ocol0 = float4(1,0,0,0); + SetOutput(float4(1,0,0,0)); } else { color += emboss; if (dot(color.rgb, float3(0.3, 0.5, 0.2)) > 0.5) - ocol0 = float4(1,1,1,1); + SetOutput(float4(1,1,1,1)); else - ocol0 = float4(0,0,0,0); + SetOutput(float4(0,0,0,0)); } } diff --git a/Data/Sys/Shaders/nightvision.glsl b/Data/Sys/Shaders/nightvision.glsl index 0756b81812..9039b4bbdb 100644 --- a/Data/Sys/Shaders/nightvision.glsl +++ b/Data/Sys/Shaders/nightvision.glsl @@ -1,15 +1,10 @@ -SAMPLER_BINDING(9) uniform sampler2D samp9; - -out vec4 ocol0; -in vec2 uv0; - void main() { - float4 c0 = texture(samp9, uv0).rgba; + float4 c0 = Sample(); float green = c0.g; if (c0.g < 0.50) green = c0.r + c0.b; - ocol0 = float4(0.0, green, 0.0, 1.0); + SetOutput(float4(0.0, green, 0.0, 1.0)); } diff --git a/Data/Sys/Shaders/nightvision2.glsl b/Data/Sys/Shaders/nightvision2.glsl index cec3e82d72..c3e6a25462 100644 --- a/Data/Sys/Shaders/nightvision2.glsl +++ b/Data/Sys/Shaders/nightvision2.glsl @@ -1,27 +1,20 @@ -SAMPLER_BINDING(9) uniform sampler2D samp9; - -out vec4 ocol0; -in vec2 uv0; - -uniform vec4 resolution; - void main() { //variables float internalresolution = 1278.0; - float4 c0 = texture(samp9, uv0).rgba; + float4 c0 = Sample(); //blur float4 blurtotal = float4(0.0, 0.0, 0.0, 0.0); float blursize = 1.5; - blurtotal += texture(samp9, uv0 + float2(-blursize, -blursize) * resolution.zw); - blurtotal += texture(samp9, uv0 + float2(-blursize, blursize) * resolution.zw); - blurtotal += texture(samp9, uv0 + float2( blursize, -blursize) * resolution.zw); - blurtotal += texture(samp9, uv0 + float2( blursize, blursize) * resolution.zw); - blurtotal += texture(samp9, uv0 + float2(-blursize, 0.0) * resolution.zw); - blurtotal += texture(samp9, uv0 + float2( blursize, 0.0) * resolution.zw); - blurtotal += texture(samp9, uv0 + float2( 0.0, -blursize) * resolution.zw); - blurtotal += texture(samp9, uv0 + float2( 0.0, blursize) * resolution.zw); + blurtotal += SampleLocation(GetCoordinates() + float2(-blursize, -blursize) * GetInvResolution()); + blurtotal += SampleLocation(GetCoordinates() + float2(-blursize, blursize) * GetInvResolution()); + blurtotal += SampleLocation(GetCoordinates() + float2( blursize, -blursize) * GetInvResolution()); + blurtotal += SampleLocation(GetCoordinates() + float2( blursize, blursize) * GetInvResolution()); + blurtotal += SampleLocation(GetCoordinates() + float2(-blursize, 0.0) * GetInvResolution()); + blurtotal += SampleLocation(GetCoordinates() + float2( blursize, 0.0) * GetInvResolution()); + blurtotal += SampleLocation(GetCoordinates() + float2( 0.0, -blursize) * GetInvResolution()); + blurtotal += SampleLocation(GetCoordinates() + float2( 0.0, blursize) * GetInvResolution()); blurtotal *= 0.125; c0 = blurtotal; @@ -32,8 +25,8 @@ void main() grey = grey * 0.5 + 0.7; // darken edges - float x = uv0.x * resolution.x; - float y = uv0.y * resolution.y; + float x = GetCoordinates().x * GetResolution().x; + float y = GetCoordinates().y * GetResolution().y; if (x > internalresolution/2.0) x = internalresolution-x; if (y > internalresolution/2.0) @@ -65,5 +58,5 @@ void main() grey -= y / 200.0; // output - ocol0 = float4(0.0, grey, 0.0, 1.0); + SetOutput(float4(0.0, grey, 0.0, 1.0)); } diff --git a/Data/Sys/Shaders/nightvision2scanlines.glsl b/Data/Sys/Shaders/nightvision2scanlines.glsl index 7006429314..d2f7eda2ea 100644 --- a/Data/Sys/Shaders/nightvision2scanlines.glsl +++ b/Data/Sys/Shaders/nightvision2scanlines.glsl @@ -1,27 +1,20 @@ -SAMPLER_BINDING(9) uniform sampler2D samp9; - -out vec4 ocol0; -in vec2 uv0; - -uniform vec4 resolution; - void main() { //variables float internalresolution = 1278.0; - float4 c0 = texture(samp9, uv0).rgba; + float4 c0 = Sample(); //blur float4 blurtotal = float4(0.0, 0.0, 0.0, 0.0); float blursize = 1.5; - blurtotal += texture(samp9, uv0 + float2(-blursize, -blursize)*resolution.zw); - blurtotal += texture(samp9, uv0 + float2(-blursize, blursize)*resolution.zw); - blurtotal += texture(samp9, uv0 + float2( blursize, -blursize)*resolution.zw); - blurtotal += texture(samp9, uv0 + float2( blursize, blursize)*resolution.zw); - blurtotal += texture(samp9, uv0 + float2(-blursize, 0.0)*resolution.zw); - blurtotal += texture(samp9, uv0 + float2( blursize, 0.0)*resolution.zw); - blurtotal += texture(samp9, uv0 + float2( 0.0, -blursize)*resolution.zw); - blurtotal += texture(samp9, uv0 + float2( 0.0, blursize)*resolution.zw); + blurtotal += SampleLocation(GetCoordinates() + float2(-blursize, -blursize)*GetInvResolution()); + blurtotal += SampleLocation(GetCoordinates() + float2(-blursize, blursize)*GetInvResolution()); + blurtotal += SampleLocation(GetCoordinates() + float2( blursize, -blursize)*GetInvResolution()); + blurtotal += SampleLocation(GetCoordinates() + float2( blursize, blursize)*GetInvResolution()); + blurtotal += SampleLocation(GetCoordinates() + float2(-blursize, 0.0)*GetInvResolution()); + blurtotal += SampleLocation(GetCoordinates() + float2( blursize, 0.0)*GetInvResolution()); + blurtotal += SampleLocation(GetCoordinates() + float2( 0.0, -blursize)*GetInvResolution()); + blurtotal += SampleLocation(GetCoordinates() + float2( 0.0, blursize)*GetInvResolution()); blurtotal *= 0.125; c0 = blurtotal; @@ -31,14 +24,14 @@ void main() // brighten and apply horizontal scanlines // This would have been much simpler if I could get the stupid modulo (%) to work // If anyone who is more well versed in Cg knows how to do this it'd be slightly more efficient - // float lineIntensity = ((uv0[1] % 9) - 4) / 40; - float vPos = uv0.y*resolution.y / 9.0; + // float lineIntensity = ((GetCoordinates()[1] % 9) - 4) / 40; + float vPos = GetCoordinates().y*GetResolution().y / 9.0; float lineIntensity = (((vPos - floor(vPos)) * 9.0) - 4.0) / 40.0; grey = grey * 0.5 + 0.7 + lineIntensity; // darken edges - float x = uv0.x * resolution.x; - float y = uv0.y * resolution.y; + float x = GetCoordinates().x * GetResolution().x; + float y = GetCoordinates().y * GetResolution().y; if (x > internalresolution/2.0) x = internalresolution-x; @@ -74,5 +67,5 @@ void main() grey -= y / 200.0; // output - ocol0 = float4(0.0, grey, 0.0, 1.0); + SetOutput(float4(0.0, grey, 0.0, 1.0)); } diff --git a/Data/Sys/Shaders/posterize.glsl b/Data/Sys/Shaders/posterize.glsl index 6b41c8332f..dba7e59ee3 100644 --- a/Data/Sys/Shaders/posterize.glsl +++ b/Data/Sys/Shaders/posterize.glsl @@ -1,11 +1,6 @@ -SAMPLER_BINDING(9) uniform sampler2D samp9; - -out vec4 ocol0; -in vec2 uv0; - void main() { - float4 c0 = texture(samp9, uv0).rgba; + float4 c0 = Sample(); float red = 0.0; float green = 0.0; float blue = 0.0; @@ -19,5 +14,5 @@ void main() if (c0.b > 0.25) blue = c0.b; - ocol0 = float4(red, green, blue, 1.0); + SetOutput(float4(red, green, blue, 1.0)); } diff --git a/Data/Sys/Shaders/posterize2.glsl b/Data/Sys/Shaders/posterize2.glsl index 782bf32d9d..2000b0f726 100644 --- a/Data/Sys/Shaders/posterize2.glsl +++ b/Data/Sys/Shaders/posterize2.glsl @@ -1,8 +1,3 @@ -SAMPLER_BINDING(9) uniform sampler2D samp9; - -out vec4 ocol0; -in vec2 uv0; - float bound(float color) { if (color < 0.35) @@ -18,6 +13,6 @@ float bound(float color) void main() { - float4 c0 = texture(samp9, uv0); - ocol0 = float4(bound(c0.r), bound(c0.g), bound(c0.b), c0.a); + float4 c0 = Sample(); + SetOutput(float4(bound(c0.r), bound(c0.g), bound(c0.b), c0.a)); } diff --git a/Data/Sys/Shaders/primarycolors.glsl b/Data/Sys/Shaders/primarycolors.glsl index ee62fc46f5..fb82fd4236 100644 --- a/Data/Sys/Shaders/primarycolors.glsl +++ b/Data/Sys/Shaders/primarycolors.glsl @@ -1,11 +1,6 @@ -SAMPLER_BINDING(9) uniform sampler2D samp9; - -out vec4 ocol0; -in vec2 uv0; - void main() { - vec4 c0 = texture(samp9, uv0); + float4 c0 = Sample(); float red = c0.r; float blue = c0.b; float green = c0.g; @@ -78,5 +73,5 @@ void main() green = 0.05; } } - ocol0 = vec4(red, green, blue, c0.a); + SetOutput(float4(red, green, blue, c0.a)); } diff --git a/Data/Sys/Shaders/sepia.glsl b/Data/Sys/Shaders/sepia.glsl index 77d2414908..55985553f6 100644 --- a/Data/Sys/Shaders/sepia.glsl +++ b/Data/Sys/Shaders/sepia.glsl @@ -1,11 +1,6 @@ -SAMPLER_BINDING(9) uniform sampler2D samp9; - -out vec4 ocol0; -in vec2 uv0; - void main() { - vec4 c0 = texture(samp9, uv0); + float4 c0 = Sample(); // Same coefficients as grayscale2 at this point float avg = (0.222 * c0.r) + (0.707 * c0.g) + (0.071 * c0.b); @@ -14,5 +9,5 @@ void main() // Not sure about these coefficients, they just seem to produce the proper yellow float green=avg*.75; float blue=avg*.5; - ocol0 = vec4(red, green, blue, c0.a); + SetOutput(float4(red, green, blue, c0.a)); } diff --git a/Data/Sys/Shaders/sketchy.glsl b/Data/Sys/Shaders/sketchy.glsl index 024593f719..fd6f5832bd 100644 --- a/Data/Sys/Shaders/sketchy.glsl +++ b/Data/Sys/Shaders/sketchy.glsl @@ -1,24 +1,17 @@ -SAMPLER_BINDING(9) uniform sampler2D samp9; - -out vec4 ocol0; -in vec2 uv0; - -uniform vec4 resolution; - void main() { - float4 c0 = texture(samp9, uv0).rgba; + float4 c0 = Sample(); float4 tmp = float4(0.0, 0.0, 0.0, 0.0); - tmp += c0 - texture(samp9, uv0 + float2(2.0, 2.0)*resolution.zw).rgba; - tmp += c0 - texture(samp9, uv0 - float2(2.0, 2.0)*resolution.zw).rgba; - tmp += c0 - texture(samp9, uv0 + float2(2.0, -2.0)*resolution.zw).rgba; - tmp += c0 - texture(samp9, uv0 - float2(2.0, -2.0)*resolution.zw).rgba; + tmp += c0 - SampleOffset(int2( 2, 2)); + tmp += c0 - SampleOffset(int2(-2, -2)); + tmp += c0 - SampleOffset(int2( 2, -2)); + tmp += c0 - SampleOffset(int2(-2, 2)); float grey = ((0.222 * tmp.r) + (0.707 * tmp.g) + (0.071 * tmp.b)); // get rid of the bottom line, as it is incorrect. - if (uv0.y*resolution.y < 163.0) + if (GetCoordinates().y*GetResolution().y < 163.0) tmp = float4(1.0, 1.0, 1.0, 1.0); c0 = c0 + 1.0 - grey * 7.0; - ocol0 = float4(c0.r, c0.g, c0.b, 1.0); + SetOutput(float4(c0.r, c0.g, c0.b, 1.0)); } diff --git a/Data/Sys/Shaders/spookey1.glsl b/Data/Sys/Shaders/spookey1.glsl index 249e2d06dc..9801dcf965 100644 --- a/Data/Sys/Shaders/spookey1.glsl +++ b/Data/Sys/Shaders/spookey1.glsl @@ -1,11 +1,6 @@ -SAMPLER_BINDING(9) uniform sampler2D samp9; - -out vec4 ocol0; -in vec2 uv0; - void main() { - vec4 c0 = texture(samp9, uv0); + float4 c0 = Sample(); float red = 0.0; float blue = 0.0; @@ -19,5 +14,5 @@ void main() blue = c0.r + c0.b; } - ocol0 = vec4(red, 0.0, blue, 1.0); + SetOutput(float4(red, 0.0, blue, 1.0)); } diff --git a/Data/Sys/Shaders/spookey2.glsl b/Data/Sys/Shaders/spookey2.glsl index 34299ccc1d..77a68ff168 100644 --- a/Data/Sys/Shaders/spookey2.glsl +++ b/Data/Sys/Shaders/spookey2.glsl @@ -1,11 +1,6 @@ -SAMPLER_BINDING(9) uniform sampler2D samp9; - -out vec4 ocol0; -in vec2 uv0; - void main() { - vec4 c0 = texture(samp9, uv0); + float4 c0 = Sample(); float red = 0.0; float green = 0.0; float blue = 0.0; @@ -21,5 +16,5 @@ void main() green = c0.r + c0.b; } - ocol0 = vec4(red, green, blue, 1.0); + SetOutput(float4(red, green, blue, 1.0)); } diff --git a/Data/Sys/Shaders/stereoscopic.glsl b/Data/Sys/Shaders/stereoscopic.glsl index 7c97313c8f..0c49b55f32 100644 --- a/Data/Sys/Shaders/stereoscopic.glsl +++ b/Data/Sys/Shaders/stereoscopic.glsl @@ -1,31 +1,24 @@ // Omega's 3D Stereoscopic filtering // TODO: Need depth info! -SAMPLER_BINDING(9) uniform sampler2D samp9; - -out vec4 ocol0; -in vec2 uv0; - -uniform vec4 resolution; - void main() { // Source Color - float4 c0 = texture(samp9, uv0).rgba; - float sep = 5.0; - float red = c0.r; - float green = c0.g; - float blue = c0.b; + float4 c0 = Sample(); + const int sep = 5; + float red = c0.r; + float green = c0.g; + float blue = c0.b; // Left Eye (Red) - float4 c1 = texture(samp9, uv0 + float2(sep,0.0)*resolution.zw).rgba; + float4 c1 = SampleOffset(int2(sep, 0)); red = max(c0.r, c1.r); // Right Eye (Cyan) - float4 c2 = texture(samp9, uv0 + float2(-sep,0.0)*resolution.zw).rgba; + float4 c2 = SampleOffset(int2(-sep, 0)); float cyan = (c2.g + c2.b) / 2.0; green = max(c0.g, cyan); blue = max(c0.b, cyan); - ocol0 = float4(red, green, blue, c0.a); + SetOutput(float4(red, green, blue, c0.a)); } diff --git a/Data/Sys/Shaders/stereoscopic2.glsl b/Data/Sys/Shaders/stereoscopic2.glsl index 4fb8f5df11..1784a988bf 100644 --- a/Data/Sys/Shaders/stereoscopic2.glsl +++ b/Data/Sys/Shaders/stereoscopic2.glsl @@ -1,31 +1,24 @@ // Omega's 3D Stereoscopic filtering (Amber/Blue) // TODO: Need depth info! -SAMPLER_BINDING(9) uniform sampler2D samp9; - -out vec4 ocol0; -in vec2 uv0; - -uniform vec4 resolution; - void main() { // Source Color - float4 c0 = texture(samp9, uv0).rgba; + float4 c0 = Sample(); float sep = 5.0; float red = c0.r; float green = c0.g; float blue = c0.b; // Left Eye (Amber) - float4 c2 = texture(samp9, uv0 + float2(sep,0.0)*resolution.zw).rgba; + float4 c2 = SampleLocation(GetCoordinates() + float2(sep,0.0)*GetInvResolution()).rgba; float amber = (c2.r + c2.g) / 2.0; red = max(c0.r, amber); green = max(c0.g, amber); // Right Eye (Blue) - float4 c1 = texture(samp9, uv0 + float2(-sep,0.0)*resolution.zw).rgba; + float4 c1 = SampleLocation(GetCoordinates() + float2(-sep,0.0)*GetInvResolution()).rgba; blue = max(c0.b, c1.b); - ocol0 = float4(red, green, blue, c0.a); + SetOutput(float4(red, green, blue, c0.a)); } diff --git a/Data/Sys/Shaders/sunset.glsl b/Data/Sys/Shaders/sunset.glsl index b2a793c84d..000d32f7c6 100644 --- a/Data/Sys/Shaders/sunset.glsl +++ b/Data/Sys/Shaders/sunset.glsl @@ -1,10 +1,5 @@ -SAMPLER_BINDING(9) uniform sampler2D samp9; - -out vec4 ocol0; -in vec2 uv0; - void main() { - vec4 c0 = texture(samp9, uv0); - ocol0 = vec4(c0.r * 1.5, c0.g, c0.b * 0.5, c0.a); + float4 c0 = Sample(); + SetOutput(float4(c0.r * 1.5, c0.g, c0.b * 0.5, c0.a)); } diff --git a/Data/Sys/Shaders/swap_RGB_BGR.glsl b/Data/Sys/Shaders/swap_RGB_BGR.glsl index 69c8461451..c71292f9e3 100644 --- a/Data/Sys/Shaders/swap_RGB_BGR.glsl +++ b/Data/Sys/Shaders/swap_RGB_BGR.glsl @@ -1,9 +1,4 @@ -SAMPLER_BINDING(9) uniform sampler2D samp9; - -out vec4 ocol0; -in vec2 uv0; - void main() { - ocol0 = texture(samp9, uv0).bgra; + SetOutput(Sample().bgra); } diff --git a/Data/Sys/Shaders/swap_RGB_BRG.glsl b/Data/Sys/Shaders/swap_RGB_BRG.glsl index a9ec859b9f..3b2738423f 100644 --- a/Data/Sys/Shaders/swap_RGB_BRG.glsl +++ b/Data/Sys/Shaders/swap_RGB_BRG.glsl @@ -1,9 +1,4 @@ -SAMPLER_BINDING(9) uniform sampler2D samp9; - -out vec4 ocol0; -in vec2 uv0; - void main() { - ocol0 = texture(samp9, uv0).brga; + SetOutput(Sample().brga); } diff --git a/Data/Sys/Shaders/swap_RGB_GBR.glsl b/Data/Sys/Shaders/swap_RGB_GBR.glsl index bde5b51766..5dc1951a6d 100644 --- a/Data/Sys/Shaders/swap_RGB_GBR.glsl +++ b/Data/Sys/Shaders/swap_RGB_GBR.glsl @@ -1,9 +1,4 @@ -SAMPLER_BINDING(9) uniform sampler2D samp9; - -out vec4 ocol0; -in vec2 uv0; - void main() { - ocol0 = texture(samp9, uv0).gbra; + SetOutput(Sample()); } diff --git a/Data/Sys/Shaders/swap_RGB_GRB.glsl b/Data/Sys/Shaders/swap_RGB_GRB.glsl index 19cd3b0e41..5dc1951a6d 100644 --- a/Data/Sys/Shaders/swap_RGB_GRB.glsl +++ b/Data/Sys/Shaders/swap_RGB_GRB.glsl @@ -1,9 +1,4 @@ -SAMPLER_BINDING(9) uniform sampler2D samp9; - -out vec4 ocol0; -in vec2 uv0; - void main() { - ocol0 = texture(samp9, uv0).grba; + SetOutput(Sample()); } diff --git a/Data/Sys/Shaders/swap_RGB_RBG.glsl b/Data/Sys/Shaders/swap_RGB_RBG.glsl index c003436fff..77cc11e0c6 100644 --- a/Data/Sys/Shaders/swap_RGB_RBG.glsl +++ b/Data/Sys/Shaders/swap_RGB_RBG.glsl @@ -1,9 +1,4 @@ -SAMPLER_BINDING(9) uniform sampler2D samp9; - -out vec4 ocol0; -in vec2 uv0; - void main() { - ocol0 = texture(samp9, uv0).rbga; + SetOutput(Sample().rbga); } diff --git a/Data/Sys/Shaders/toxic.glsl b/Data/Sys/Shaders/toxic.glsl index ab31e4c5f1..1aa38c5e07 100644 --- a/Data/Sys/Shaders/toxic.glsl +++ b/Data/Sys/Shaders/toxic.glsl @@ -1,11 +1,6 @@ -SAMPLER_BINDING(9) uniform sampler2D samp9; - -out vec4 ocol0; -in vec2 uv0; - void main() { - vec4 c0 = texture(samp9, uv0); + float4 c0 = Sample(); float red = 0.0; float green = 0.0; float blue = 0.0; @@ -21,5 +16,5 @@ void main() green = c0.r + c0.b; } - ocol0 = vec4(red, green, blue, 1.0); + SetOutput(float4(red, green, blue, 1.0)); } From 287758f15d07cb6e0c19d861d8134124361d2d30 Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Tue, 29 Jul 2014 12:14:25 -0500 Subject: [PATCH 6/6] Add the configuration dialog for post processing configuration options. Only enables the config button when the shader options available to it --- Source/Core/DolphinWX/CMakeLists.txt | 1 + Source/Core/DolphinWX/DolphinWX.vcxproj | 4 +- .../Core/DolphinWX/DolphinWX.vcxproj.filters | 8 +- .../DolphinWX/PostProcessingConfigDiag.cpp | 316 ++++++++++++++++++ .../Core/DolphinWX/PostProcessingConfigDiag.h | 106 ++++++ Source/Core/DolphinWX/VideoConfigDiag.cpp | 13 +- Source/Core/DolphinWX/VideoConfigDiag.h | 9 + 7 files changed, 454 insertions(+), 3 deletions(-) create mode 100644 Source/Core/DolphinWX/PostProcessingConfigDiag.cpp create mode 100644 Source/Core/DolphinWX/PostProcessingConfigDiag.h diff --git a/Source/Core/DolphinWX/CMakeLists.txt b/Source/Core/DolphinWX/CMakeLists.txt index 302a27df28..613041de50 100644 --- a/Source/Core/DolphinWX/CMakeLists.txt +++ b/Source/Core/DolphinWX/CMakeLists.txt @@ -62,6 +62,7 @@ set(GUI_SRCS MemoryCards/WiiSaveCrypted.cpp NetWindow.cpp PatchAddEdit.cpp + PostProcessingConfigDiag.cpp SoftwareVideoConfigDialog.cpp TASInputDlg.cpp VideoConfigDiag.cpp diff --git a/Source/Core/DolphinWX/DolphinWX.vcxproj b/Source/Core/DolphinWX/DolphinWX.vcxproj index e62e2f2e43..52a13521ce 100644 --- a/Source/Core/DolphinWX/DolphinWX.vcxproj +++ b/Source/Core/DolphinWX/DolphinWX.vcxproj @@ -97,6 +97,7 @@ + @@ -144,6 +145,7 @@ + @@ -228,4 +230,4 @@ - \ No newline at end of file + diff --git a/Source/Core/DolphinWX/DolphinWX.vcxproj.filters b/Source/Core/DolphinWX/DolphinWX.vcxproj.filters index b9910845a8..59be1c3188 100644 --- a/Source/Core/DolphinWX/DolphinWX.vcxproj.filters +++ b/Source/Core/DolphinWX/DolphinWX.vcxproj.filters @@ -93,6 +93,9 @@ GUI\Video + + GUI\Video + GUI\Video @@ -217,6 +220,9 @@ GUI\Video + + GUI\Video + GUI\Video @@ -296,4 +302,4 @@ Resources - \ No newline at end of file + diff --git a/Source/Core/DolphinWX/PostProcessingConfigDiag.cpp b/Source/Core/DolphinWX/PostProcessingConfigDiag.cpp new file mode 100644 index 0000000000..031c19f19d --- /dev/null +++ b/Source/Core/DolphinWX/PostProcessingConfigDiag.cpp @@ -0,0 +1,316 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "Common/StringUtil.h" + +#include "DolphinWX/PostProcessingConfigDiag.h" + +#include "VideoCommon/RenderBase.h" + +PostProcessingConfigDiag::PostProcessingConfigDiag(wxWindow* parent, const std::string& shader) + : wxDialog(parent, -1, + wxString::Format(_("Post Processing Shader Configuration"))), + m_shader(shader) +{ + // Depending on if we are running already, either use the one from the videobackend + // or generate our own. + if (g_renderer && g_renderer->GetPostProcessor()) + { + m_post_processor = g_renderer->GetPostProcessor()->GetConfig(); + } + else + { + m_post_processor = new PostProcessingShaderConfiguration(); + m_post_processor->LoadShader(m_shader); + } + + // Create our UI classes + const PostProcessingShaderConfiguration::ConfigMap& config_map = m_post_processor->GetOptions(); + for (const auto& it : config_map) + { + if (it.second.m_type == PostProcessingShaderConfiguration::ConfigurationOption::OptionType::OPTION_BOOL) + { + ConfigGrouping* group = new ConfigGrouping(ConfigGrouping::WidgetType::TYPE_TOGGLE, + it.second.m_gui_name, it.first, it.second.m_dependent_option, + &it.second); + m_config_map[it.first] = group; + } + else + { + ConfigGrouping* group = new ConfigGrouping(ConfigGrouping::WidgetType::TYPE_SLIDER, + it.second.m_gui_name, it.first, it.second.m_dependent_option, + &it.second); + m_config_map[it.first] = group; + } + } + + // Arrange our vectors based on dependency + for (const auto& it : m_config_map) + { + const std::string parent_name = it.second->GetParent(); + if (parent_name.size()) + { + // Since it depends on a different object, push it to a parent's object + m_config_map[parent_name]->AddChild(m_config_map[it.first]); + } + else + { + // It doesn't have a child, just push it to the vector + m_config_groups.push_back(m_config_map[it.first]); + } + } + + // Generate our UI + wxNotebook* const notebook = new wxNotebook(this, -1); + wxPanel* const page_general = new wxPanel(notebook, -1); + wxFlexGridSizer* const szr_general = new wxFlexGridSizer(2, 5, 5); + + // Now let's actually populate our window with our information + bool add_general_page = false; + for (const auto& it : m_config_groups) + { + if (it->HasChildren()) + { + // Options with children get their own tab + wxPanel* const page_option = new wxPanel(notebook, -1); + wxFlexGridSizer* const szr_option = new wxFlexGridSizer(2, 10, 5); + it->GenerateUI(this, page_option, szr_option); + + // Add all the children + for (const auto& child : it->GetChildren()) + { + child->GenerateUI(this, page_option, szr_option); + } + page_option->SetSizerAndFit(szr_option); + notebook->AddPage(page_option, _(it->GetGUIName())); + } + else + { + // Options with no children go in to the general tab + if (!add_general_page) + { + // Make it so it doesn't show up if there aren't any options without children. + add_general_page = true; + } + it->GenerateUI(this, page_general, szr_general); + } + } + + if (add_general_page) + { + page_general->SetSizerAndFit(szr_general); + notebook->InsertPage(0, page_general, _("General")); + } + + // Close Button + wxButton* const btn_close = new wxButton(this, wxID_OK, _("Close")); + btn_close->Bind(wxEVT_BUTTON, &PostProcessingConfigDiag::Event_ClickClose, this); + + Bind(wxEVT_CLOSE_WINDOW, &PostProcessingConfigDiag::Event_Close, this); + + wxBoxSizer* const szr_main = new wxBoxSizer(wxVERTICAL); + szr_main->Add(notebook, 1, wxEXPAND | wxALL, 5); + szr_main->Add(btn_close, 0, wxALIGN_RIGHT | wxRIGHT | wxBOTTOM, 5); + + SetSizerAndFit(szr_main); + Center(); + SetFocus(); + + UpdateWindowUI(); +} + +PostProcessingConfigDiag::~PostProcessingConfigDiag() +{ + m_post_processor->SaveOptionsConfiguration(); + if (g_renderer && g_renderer->GetPostProcessor()) + m_post_processor = nullptr; + else + delete m_post_processor; +} + +void PostProcessingConfigDiag::ConfigGrouping::GenerateUI(PostProcessingConfigDiag* dialog, wxWindow* parent, wxFlexGridSizer* sizer) +{ + if (m_type == WidgetType::TYPE_TOGGLE) + { + m_option_checkbox = new wxCheckBox(parent, wxID_ANY, _(m_gui_name)); + m_option_checkbox->SetValue(m_config_option->m_bool_value); + m_option_checkbox->Bind(wxEVT_CHECKBOX, &PostProcessingConfigDiag::Event_CheckBox, + dialog, wxID_ANY, wxID_ANY, new UserEventData(m_option)); + + sizer->Add(m_option_checkbox); + sizer->AddStretchSpacer(); + } + else + { + size_t vector_size = 0; + if (m_config_option->m_type == PostProcessingShaderConfiguration::ConfigurationOption::OptionType::OPTION_INTEGER) + vector_size = m_config_option->m_integer_values.size(); + else + vector_size = m_config_option->m_float_values.size(); + + wxFlexGridSizer* const szr_values = new wxFlexGridSizer(vector_size + 1, 0, 0); + wxStaticText* const option_static_text = new wxStaticText(parent, wxID_ANY, _(m_gui_name)); + sizer->Add(option_static_text); + + for (size_t i = 0; i < vector_size; ++i) + { + // wxSlider uses a signed integer for it's minimum and maximum values + // This won't work for floats. + // Let's determine how many steps we can take and use that instead. + int steps = 0; + int current_value = 0; + std::string string_value; + if (m_config_option->m_type == PostProcessingShaderConfiguration::ConfigurationOption::OptionType::OPTION_INTEGER) + { + // Find out our range by taking the max subtracting the minimum. + double range = m_config_option->m_integer_max_values[i] - m_config_option->m_integer_min_values[i]; + + // How many steps we have is the range divided by the step interval configured. + // This may not be 100% spot on accurate since developers can have odd stepping intervals set. + // Round up so if it is outside our range, then set it to the minimum or maximum + steps = ceil(range / (double)m_config_option->m_integer_step_values[i]); + + // Default value is just the currently set value here + current_value = m_config_option->m_integer_values[i]; + string_value = std::to_string(m_config_option->m_integer_values[i]); + } + else + { + // Same as above but with floats + float range = m_config_option->m_float_max_values[i] - m_config_option->m_float_min_values[i]; + steps = ceil(range / m_config_option->m_float_step_values[i]); + + // We need to convert our default float value from a float to the nearest step value range + current_value = (m_config_option->m_float_values[i] / m_config_option->m_float_step_values[i]); + string_value = std::to_string(m_config_option->m_float_values[i]); + } + + wxSlider* slider = new wxSlider(parent, wxID_ANY, current_value, 0, steps, + wxDefaultPosition, wxSize(200, -1), wxSL_HORIZONTAL | wxSL_BOTTOM); + wxTextCtrl* text_ctrl = new wxTextCtrl(parent, wxID_ANY, string_value); + + // Disable the textctrl, it's only there to show the absolute value from the slider + text_ctrl->Enable(false); + + // wxWidget takes over the pointer provided to it in the event handler. + // This won't be a memory leak, it'll be destroyed on dialog close. + slider->Bind(wxEVT_SLIDER, &PostProcessingConfigDiag::Event_Slider, + dialog, wxID_ANY, wxID_ANY, new UserEventData(m_option)); + + m_option_sliders.push_back(slider); + m_option_text_ctrls.push_back(text_ctrl); + } + + if (vector_size == 1) + { + szr_values->Add(m_option_sliders[0], wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL)); + szr_values->Add(m_option_text_ctrls[0]); + + sizer->Add(szr_values); + } + else + { + wxFlexGridSizer* const szr_inside = new wxFlexGridSizer(2, 0, 0); + for (size_t i = 0; i < vector_size; ++i) + { + szr_inside->Add(m_option_sliders[i], wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL)); + szr_inside->Add(m_option_text_ctrls[i]); + } + + szr_values->Add(szr_inside); + sizer->Add(szr_values); + } + } +} + +void PostProcessingConfigDiag::ConfigGrouping::EnableDependentChildren(bool enable) +{ + // Enable or disable all the children + for (auto& it : m_children) + { + if (it->m_type == ConfigGrouping::WidgetType::TYPE_TOGGLE) + { + it->m_option_checkbox->Enable(enable); + } + else + { + for (auto& slider : it->m_option_sliders) + slider->Enable(enable); + } + // Set this objects children as well + it->EnableDependentChildren(enable); + } +} + +void PostProcessingConfigDiag::Event_CheckBox(wxCommandEvent &ev) +{ + UserEventData* config_option = (UserEventData*)ev.GetEventUserData(); + ConfigGrouping* config = m_config_map[config_option->GetData()]; + + m_post_processor->SetOptionb(config->GetOption(), ev.IsChecked()); + + config->EnableDependentChildren(ev.IsChecked()); + + ev.Skip(); +} + +void PostProcessingConfigDiag::Event_Slider(wxCommandEvent &ev) +{ + UserEventData* config_option = (UserEventData*)ev.GetEventUserData(); + ConfigGrouping* config = m_config_map[config_option->GetData()]; + + const auto& option_data = m_post_processor->GetOption(config->GetOption()); + + size_t vector_size = 0; + if (option_data.m_type == PostProcessingShaderConfiguration::ConfigurationOption::OptionType::OPTION_INTEGER) + vector_size = option_data.m_integer_values.size(); + else + vector_size = option_data.m_float_values.size(); + + for (size_t i = 0; i < vector_size; ++i) + { + // Got to do this garbage again. + // Convert current step in to the real range value + int current_step = config->GetSliderValue(i); + std::string string_value; + if (option_data.m_type == PostProcessingShaderConfiguration::ConfigurationOption::OptionType::OPTION_INTEGER) + { + s32 value = option_data.m_integer_step_values[i] * current_step + option_data.m_integer_min_values[i]; + m_post_processor->SetOptioni(config->GetOption(), i, value); + string_value = std::to_string(value); + + } + else + { + float value = option_data.m_float_step_values[i] * current_step + option_data.m_float_min_values[i]; + m_post_processor->SetOptionf(config->GetOption(), i, value); + string_value = std::to_string(value); + } + // Update the text box to include the new value + config->SetSliderText(i, string_value); + } + ev.Skip(); +} + +void PostProcessingConfigDiag::Event_ClickClose(wxCommandEvent&) +{ + Close(); +} + +void PostProcessingConfigDiag::Event_Close(wxCloseEvent& ev) +{ + EndModal(wxID_OK); +} + diff --git a/Source/Core/DolphinWX/PostProcessingConfigDiag.h b/Source/Core/DolphinWX/PostProcessingConfigDiag.h new file mode 100644 index 0000000000..dabf44468b --- /dev/null +++ b/Source/Core/DolphinWX/PostProcessingConfigDiag.h @@ -0,0 +1,106 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "VideoCommon/PostProcessing.h" + +class PostProcessingConfigDiag : public wxDialog +{ +public: + PostProcessingConfigDiag(wxWindow* parent, const std::string& shader); + ~PostProcessingConfigDiag(); + +private: + + // This is literally the stupidest thing ever + // wxWidgets takes ownership of any pointer given to a event handler + // Instead of passing them a pointer to a std::string, we wrap around it here. + class UserEventData : public wxObject + { + public: + UserEventData(const std::string& data) : m_data(data) {} + const std::string& GetData() { return m_data; } + private: + const std::string m_data; + }; + + class ConfigGrouping + { + public: + enum WidgetType + { + TYPE_TOGGLE, + TYPE_SLIDER, + }; + + ConfigGrouping(WidgetType type, const std::string& gui_name, + const std::string& option_name, const std::string& parent, + const PostProcessingShaderConfiguration::ConfigurationOption* config_option) + : m_type(type), m_gui_name(gui_name), + m_option(option_name), m_parent(parent), + m_config_option(config_option) {} + + void AddChild(ConfigGrouping* child) { m_children.push_back(child); } + bool HasChildren() { return m_children.size() != 0; } + std::vector& GetChildren() { return m_children; } + + // Gets the string that is shown in the UI for the option + const std::string& GetGUIName() { return m_gui_name; } + // Gets the option name for use in the shader + // Also is a unique identifier for the option's configuration + const std::string& GetOption() { return m_option; } + // Gets the option name of the parent of this option + const std::string& GetParent() { return m_parent; } + + void GenerateUI(PostProcessingConfigDiag* dialog, wxWindow* parent, wxFlexGridSizer* sizer); + + void EnableDependentChildren(bool enable); + + int GetSliderValue(const int index) { return m_option_sliders[index]->GetValue(); } + void SetSliderText(const int index, const std::string& text) { m_option_text_ctrls[index]->SetValue(text); } + + private: + const WidgetType m_type; + const std::string m_gui_name; + const std::string m_option; + const std::string m_parent; + const PostProcessingShaderConfiguration::ConfigurationOption* m_config_option; + + // For TYPE_TOGGLE + wxCheckBox* m_option_checkbox; + + // For TYPE_SLIDER + // Can have up to 4 + std::vector m_option_sliders; + std::vector m_option_text_ctrls; + + std::vector m_children; + }; + + // WX UI things + void Event_Close(wxCloseEvent&); + void Event_ClickClose(wxCommandEvent&); + void Event_Slider(wxCommandEvent &ev); + void Event_CheckBox(wxCommandEvent &ev); + + const std::string& m_shader; + PostProcessingShaderConfiguration* m_post_processor; + + std::map m_config_map; + std::vector m_config_groups; +}; + diff --git a/Source/Core/DolphinWX/VideoConfigDiag.cpp b/Source/Core/DolphinWX/VideoConfigDiag.cpp index 13f3dad9b4..0bd5a8ccff 100644 --- a/Source/Core/DolphinWX/VideoConfigDiag.cpp +++ b/Source/Core/DolphinWX/VideoConfigDiag.cpp @@ -1,3 +1,7 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + #include #include #include @@ -32,6 +36,7 @@ #include "DolphinWX/VideoConfigDiag.h" #include "DolphinWX/WxUtils.h" #include "VideoBackends/OGL/main.h" +#include "VideoCommon/PostProcessing.h" #include "VideoCommon/VideoBackendBase.h" #include "VideoCommon/VideoConfig.h" @@ -401,10 +406,13 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string &title, con // postproc shader if (vconfig.backend_info.PPShaders.size()) { + wxFlexGridSizer* const szr_pp = new wxFlexGridSizer(3, 5, 5); wxChoice *const choice_ppshader = new wxChoice(page_enh, -1); RegisterControl(choice_ppshader, wxGetTranslation(ppshader_desc)); choice_ppshader->AppendString(_("(off)")); + button_config_pp = new wxButton(page_enh, wxID_ANY, _("Config")); + for (const std::string& shader : vconfig.backend_info.PPShaders) { choice_ppshader->AppendString(StrToWxStr(shader)); @@ -421,9 +429,12 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string &title, con button_config_pp->Enable(postprocessing_shader.HasOptions()); choice_ppshader->Bind(wxEVT_CHOICE, &VideoConfigDiag::Event_PPShader, this); + button_config_pp->Bind(wxEVT_BUTTON, &VideoConfigDiag::Event_ConfigurePPShader, this); szr_enh->Add(new wxStaticText(page_enh, -1, _("Post-Processing Effect:")), 1, wxALIGN_CENTER_VERTICAL, 0); - szr_enh->Add(choice_ppshader); + szr_pp->Add(choice_ppshader); + szr_pp->Add(button_config_pp); + szr_enh->Add(szr_pp); } // Scaled copy, PL, Bilinear filter diff --git a/Source/Core/DolphinWX/VideoConfigDiag.h b/Source/Core/DolphinWX/VideoConfigDiag.h index 6802f0be84..261fa2f6ec 100644 --- a/Source/Core/DolphinWX/VideoConfigDiag.h +++ b/Source/Core/DolphinWX/VideoConfigDiag.h @@ -1,9 +1,14 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + #pragma once #include #include #include #include +#include #include #include #include @@ -22,7 +27,9 @@ #include "Core/ConfigManager.h" #include "Core/Core.h" #include "Core/CoreParameter.h" +#include "DolphinWX/PostProcessingConfigDiag.h" #include "DolphinWX/WxUtils.h" +#include "VideoCommon/PostProcessing.h" #include "VideoCommon/VideoBackendBase.h" #include "VideoCommon/VideoConfig.h" @@ -201,6 +208,8 @@ protected: wxStaticText* text_aamode; SettingChoice* choice_aamode; + wxButton* button_config_pp; + SettingCheckBox* borderless_fullscreen; SettingRadioButton* efbcopy_texture;