diff --git a/CMakeModules/GenerateSettingKeys.cmake b/CMakeModules/GenerateSettingKeys.cmake index fa353f12c..439e3802e 100644 --- a/CMakeModules/GenerateSettingKeys.cmake +++ b/CMakeModules/GenerateSettingKeys.cmake @@ -47,6 +47,8 @@ foreach(KEY IN ITEMS "turbo_limit" "texture_filter" "antialiasing_filter" + "output_scaling" + "fsr_sharpness" "texture_sampling" "delay_game_render_thread_us" "layout_option" diff --git a/src/citra_qt/configuration/config.cpp b/src/citra_qt/configuration/config.cpp index 74c4b75f6..9996c6d16 100644 --- a/src/citra_qt/configuration/config.cpp +++ b/src/citra_qt/configuration/config.cpp @@ -718,6 +718,8 @@ void QtConfig::ReadRendererValues() { ReadGlobalSetting(Settings::values.texture_filter); ReadGlobalSetting(Settings::values.antialiasing_filter); + ReadGlobalSetting(Settings::values.output_scaling); + ReadGlobalSetting(Settings::values.fsr_sharpness); ReadGlobalSetting(Settings::values.texture_sampling); ReadGlobalSetting(Settings::values.delay_game_render_thread_us); @@ -1263,6 +1265,8 @@ void QtConfig::SaveRendererValues() { WriteGlobalSetting(Settings::values.texture_filter); WriteGlobalSetting(Settings::values.antialiasing_filter); + WriteGlobalSetting(Settings::values.output_scaling); + WriteGlobalSetting(Settings::values.fsr_sharpness); WriteGlobalSetting(Settings::values.texture_sampling); WriteGlobalSetting(Settings::values.delay_game_render_thread_us); diff --git a/src/citra_qt/configuration/configure_enhancements.cpp b/src/citra_qt/configuration/configure_enhancements.cpp index bd7961736..9cfb6476f 100644 --- a/src/citra_qt/configuration/configure_enhancements.cpp +++ b/src/citra_qt/configuration/configure_enhancements.cpp @@ -27,6 +27,8 @@ ConfigureEnhancements::ConfigureEnhancements(QWidget* parent) updateShaders(static_cast(currentIndex)); }); + connect(ui->fsr_sharpness_slider, &QSlider::valueChanged, this, + &ConfigureEnhancements::SetFSRSharpnessIndicatorText); ui->toggle_preload_textures->setEnabled(ui->toggle_custom_textures->isChecked()); ui->toggle_async_custom_loading->setEnabled(ui->toggle_custom_textures->isChecked()); connect(ui->toggle_custom_textures, &QCheckBox::toggled, this, [this] { @@ -35,12 +37,18 @@ ConfigureEnhancements::ConfigureEnhancements(QWidget* parent) if (!ui->toggle_preload_textures->isEnabled()) ui->toggle_preload_textures->setChecked(false); }); + connect(ui->output_scaling_combobox, &QComboBox::currentIndexChanged, this, &ConfigureEnhancements::SetFSRSharpnessEnabled); } ConfigureEnhancements::~ConfigureEnhancements() = default; void ConfigureEnhancements::SetConfiguration() { + const s32 volume = + static_cast(Settings::values.fsr_sharpness.GetValue() * 100); + ui->fsr_sharpness_slider->setValue(volume); + SetFSRSharpnessIndicatorText(ui->fsr_sharpness_slider->sliderPosition()); + if (!Settings::IsConfiguringGlobal()) { ConfigurationShared::SetPerGameSetting(ui->resolution_factor_combobox, &Settings::values.resolution_factor); @@ -52,6 +60,10 @@ void ConfigureEnhancements::SetConfiguration() { &Settings::values.antialiasing_filter); ConfigurationShared::SetHighlight(ui->widget_antialiasing_filter, !Settings::values.antialiasing_filter.UsingGlobal()); + ConfigurationShared::SetPerGameSetting(ui->output_scaling_combobox, + &Settings::values.output_scaling); + ConfigurationShared::SetHighlight(ui->widget_output_scaling, + !Settings::values.output_scaling.UsingGlobal()); } else { ui->resolution_factor_combobox->setCurrentIndex( Settings::values.resolution_factor.GetValue()); @@ -59,8 +71,10 @@ void ConfigureEnhancements::SetConfiguration() { static_cast(Settings::values.texture_filter.GetValue())); ui->antialiasing_filter_combobox->setCurrentIndex( static_cast(Settings::values.antialiasing_filter.GetValue())); + ui->output_scaling_combobox->setCurrentIndex( + static_cast(Settings::values.output_scaling.GetValue())); } - + ui->fsr_sharpness_slider->setEnabled(ui->output_scaling_combobox->currentIndex() == 3); ui->render_3d_combobox->setCurrentIndex( static_cast(Settings::values.render_3d.GetValue())); ui->swap_eyes_3d->setChecked(Settings::values.swap_eyes_3d.GetValue()); @@ -68,7 +82,6 @@ void ConfigureEnhancements::SetConfiguration() { ui->mono_rendering_eye->setCurrentIndex( static_cast(Settings::values.mono_render_option.GetValue())); updateShaders(Settings::values.render_3d.GetValue()); - ui->toggle_linear_filter->setChecked(Settings::values.filter_mode.GetValue()); ui->use_integer_scaling->setChecked(Settings::values.use_integer_scaling.GetValue()); ui->toggle_dump_textures->setChecked(Settings::values.dump_textures.GetValue()); ui->toggle_custom_textures->setChecked(Settings::values.custom_textures.GetValue()); @@ -77,6 +90,13 @@ void ConfigureEnhancements::SetConfiguration() { ui->disable_right_eye_render->setChecked(Settings::values.disable_right_eye_render.GetValue()); } +void ConfigureEnhancements::SetFSRSharpnessIndicatorText(int percentage) { + ui->fsr_sharpness_indicator->setText(tr("%1%", "FSR Sharpness (e.g. 50%)").arg(percentage)); +} + +void ConfigureEnhancements::SetFSRSharpnessEnabled(int output) { + ui->fsr_sharpness_slider->setEnabled(output == 3); +} void ConfigureEnhancements::updateShaders(Settings::StereoRenderOption stereo_option) { ui->shader_combobox->clear(); ui->shader_combobox->setEnabled(true); @@ -132,14 +152,14 @@ void ConfigureEnhancements::ApplyConfiguration() { } Settings::values.disable_right_eye_render = ui->disable_right_eye_render->isChecked(); - ConfigurationShared::ApplyPerGameSetting(&Settings::values.filter_mode, - ui->toggle_linear_filter, linear_filter); ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_integer_scaling, ui->use_integer_scaling, use_integer_scaling); ConfigurationShared::ApplyPerGameSetting(&Settings::values.texture_filter, ui->texture_filter_combobox); ConfigurationShared::ApplyPerGameSetting(&Settings::values.antialiasing_filter, ui->antialiasing_filter_combobox); + ConfigurationShared::ApplyPerGameSetting(&Settings::values.output_scaling, + ui->output_scaling_combobox); ConfigurationShared::ApplyPerGameSetting(&Settings::values.dump_textures, ui->toggle_dump_textures, dump_textures); ConfigurationShared::ApplyPerGameSetting(&Settings::values.custom_textures, @@ -159,7 +179,7 @@ void ConfigureEnhancements::SetupPerGameUI() { ui->widget_resolution->setEnabled(Settings::values.resolution_factor.UsingGlobal()); ui->widget_texture_filter->setEnabled(Settings::values.texture_filter.UsingGlobal()); ui->widget_antialiasing_filter->setEnabled(Settings::values.antialiasing_filter.UsingGlobal()); - ui->toggle_linear_filter->setEnabled(Settings::values.filter_mode.UsingGlobal()); + ui->widget_output_scaling->setEnabled(Settings::values.output_scaling.UsingGlobal()); ui->use_integer_scaling->setEnabled(Settings::values.use_integer_scaling.UsingGlobal()); ui->toggle_dump_textures->setEnabled(Settings::values.dump_textures.UsingGlobal()); ui->toggle_custom_textures->setEnabled(Settings::values.custom_textures.UsingGlobal()); @@ -177,8 +197,6 @@ void ConfigureEnhancements::SetupPerGameUI() { ui->widget_shader->setVisible(false); - ConfigurationShared::SetColoredTristate(ui->toggle_linear_filter, Settings::values.filter_mode, - linear_filter); ConfigurationShared::SetColoredTristate( ui->use_integer_scaling, Settings::values.use_integer_scaling, use_integer_scaling); ConfigurationShared::SetColoredTristate(ui->toggle_dump_textures, @@ -205,4 +223,8 @@ void ConfigureEnhancements::SetupPerGameUI() { ConfigurationShared::SetColoredComboBox( ui->antialiasing_filter_combobox, ui->widget_antialiasing_filter, static_cast(Settings::values.antialiasing_filter.GetValue(true))); + + ConfigurationShared::SetColoredComboBox( + ui->output_scaling_combobox, ui->widget_output_scaling, + static_cast(Settings::values.output_scaling.GetValue(true))); } diff --git a/src/citra_qt/configuration/configure_enhancements.h b/src/citra_qt/configuration/configure_enhancements.h index 70d6a6673..4cb8b2a0f 100644 --- a/src/citra_qt/configuration/configure_enhancements.h +++ b/src/citra_qt/configuration/configure_enhancements.h @@ -36,7 +36,8 @@ public: private: void updateShaders(Settings::StereoRenderOption stereo_option); void updateTextureFilter(int index); - + void SetFSRSharpnessIndicatorText(int percentage); + void SetFSRSharpnessEnabled(int output); std::unique_ptr ui; ConfigurationShared::CheckState linear_filter; ConfigurationShared::CheckState use_integer_scaling; diff --git a/src/citra_qt/configuration/configure_enhancements.ui b/src/citra_qt/configuration/configure_enhancements.ui index 09470fd96..d13a020ea 100644 --- a/src/citra_qt/configuration/configure_enhancements.ui +++ b/src/citra_qt/configuration/configure_enhancements.ui @@ -121,10 +121,184 @@ - - - Enable Linear Filtering + + + true + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Output Scaling + + + + + + + + Nearest + + + + + Bilinear + + + + + Adaptive + + + + + AMD FidelityFX Super Resolution 1 + + + + + Sharp Bilinear + + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + FSR Sharpness + + + + + + + Qt::Orientation::Horizontal + + + QSizePolicy::Policy::Preferred + + + + 30 + 20 + + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 0 + 0 + + + + 100 + + + 5 + + + Qt::Orientation::Horizontal + + + + + + + + 0 + 0 + + + + + 32 + 0 + + + + 0 % + + + Qt::AlignmentFlag::AlignCenter + + + + + + + @@ -457,7 +631,6 @@ resolution_factor_combobox - toggle_linear_filter shader_combobox texture_filter_combobox antialiasing_filter_combobox diff --git a/src/common/settings.cpp b/src/common/settings.cpp index 8ceed00fa..bfce92801 100644 --- a/src/common/settings.cpp +++ b/src/common/settings.cpp @@ -69,6 +69,23 @@ std::string_view GetAntialiasingFilterName(AntiAliasingFilter filter) { return "Invalid"; } } + +std::string_view GetOutputScalingName(OutputScaling scaling) { + switch (scaling) { + case OutputScaling::Nearest: + return "Nearest"; + case OutputScaling::Bilinear: + return "Bilinear"; + case OutputScaling::Adaptive: + return "Adaptive"; + case OutputScaling::FSR: + return "AMD FidelityFX Super Resolution 1"; + case OutputScaling::SharpBilinear: + return "Sharp Bilinear"; + default: + return "Invalid"; + } +} std::string_view GetTextureSamplingName(TextureSampling sampling) { switch (sampling) { case TextureSampling::GameControlled: @@ -116,6 +133,7 @@ void LogSettings() { log_setting("Renderer_FilterMode", values.filter_mode.GetValue()); log_setting("Renderer_TextureFilter", GetTextureFilterName(values.texture_filter.GetValue())); log_setting("Renderer_AntialiasingFilter", GetAntialiasingFilterName(values.antialiasing_filter.GetValue())); + log_setting("Renderer_OutputScaling", GetOutputScalingName(values.output_scaling.GetValue())); log_setting("Renderer_TextureSampling", GetTextureSamplingName(values.texture_sampling.GetValue())); log_setting("Renderer_DelayGameRenderThreasUs", values.delay_game_render_thread_us.GetValue()); @@ -227,6 +245,8 @@ void RestoreGlobalState(bool is_powered_on) { values.frame_limit.SetGlobal(true); values.texture_filter.SetGlobal(true); values.antialiasing_filter.SetGlobal(true); + values.output_scaling.SetGlobal(true); + values.fsr_sharpness.SetGlobal(true); values.texture_sampling.SetGlobal(true); values.delay_game_render_thread_us.SetGlobal(true); values.layout_option.SetGlobal(true); diff --git a/src/common/settings.h b/src/common/settings.h index 915719e38..0e9c91e96 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -118,6 +118,14 @@ enum class AntiAliasingFilter : u32 { SMAA = 2, }; +enum class OutputScaling : u32 { + Nearest = 0, + Bilinear = 1, + Adaptive = 2, + FSR = 3, + SharpBilinear = 4, +}; + enum class TextureSampling : u32 { GameControlled = 0, NearestNeighbor = 1, @@ -545,6 +553,8 @@ struct Values { SwitchableSetting turbo_limit{200, 0, 1000, Keys::turbo_limit}; SwitchableSetting texture_filter{TextureFilter::NoFilter, Keys::texture_filter}; SwitchableSetting antialiasing_filter{AntiAliasingFilter::None, Keys::antialiasing_filter}; + SwitchableSetting output_scaling{OutputScaling::Adaptive, Keys::output_scaling}; + SwitchableSetting fsr_sharpness{0.8f, 0.f, 1.f, Keys::fsr_sharpness}; SwitchableSetting texture_sampling{TextureSampling::GameControlled, Keys::texture_sampling}; SwitchableSetting delay_game_render_thread_us{0, 0, 16000, diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index b21f75691..7461d144a 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp @@ -664,12 +664,8 @@ void RendererOpenGL::DrawSingleScreen(const ScreenInfo& screen_info, float scree // Texture Width and Height when correctly rotated to landscape bool isDownsampling = false; - int scalingMode; //0 is Nearest Neighbor, 1 is Gamma Corrected Bilinear, 2 is High Quality Scaling (Upsampling via Gamma Corrected Bilinear, Downsampling is Gamma Corrected Area Sampling) - if (Settings::values.filter_mode.GetValue()){ - scalingMode = 2; - } else { - scalingMode = 0; - } + int scalingMode; //0 is Nearest Neighbor, 1 is Gamma Corrected Bilinear, 2 is Adaptive (Bilinear/Area), 3 is FSR, 4 is Sharp Bilinear + scalingMode = static_cast(Settings::values.output_scaling.GetValue()); int antialiasingMode = static_cast(Settings::values.antialiasing_filter.GetValue()); //0 is none, 1 is FXAA, 2 is SMAA if (orientation == Layout::DisplayOrientation::Landscape || orientation == Layout::DisplayOrientation::LandscapeFlipped) { if (textureWidth > screenWidth){ @@ -918,7 +914,7 @@ void RendererOpenGL::DrawSingleScreen(const ScreenInfo& screen_info, float scree glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(rotate_vertices), rotate_vertices.data()); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } - if (scalingMode == 2){ + if (scalingMode >= 2){ if (isDownsampling){ //Output state.draw.read_framebuffer = originalReadFramebuffer; @@ -1047,7 +1043,8 @@ void RendererOpenGL::DrawSingleScreenStereo(const ScreenInfo& screen_info_l, } const u32 scale_factor = GetResolutionScaleFactor(); - const GLuint sampler = samplers[Settings::values.filter_mode.GetValue()].handle; + int scalingMode = static_cast(Settings::values.output_scaling.GetValue()); + const GLuint sampler = samplers[scalingMode > 0 ? 1 : 0].handle; glUniform4f(uniform_i_resolution, static_cast(screen_info_l.texture.width * scale_factor), static_cast(screen_info_l.texture.height * scale_factor), diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index 4fe029938..6d53e4612 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp @@ -418,8 +418,8 @@ void RendererVulkan::PrepareTextureDraw(TextureInfo framebufferTexture, vk::Fram } -void RendererVulkan::PrepareDraw(Frame* frame, const Layout::FramebufferLayout& layout, std::vector screenids) { - const auto sampler = present_samplers[Settings::values.filter_mode.GetValue()]; +void RendererVulkan::PrepareDraw(Frame* frame, const Layout::FramebufferLayout& layout, std::vector screenids, int filterMode) { + const auto sampler = present_samplers[filterMode]; const auto present_set = present_heap.Commit(); for (u32 i = 0; i < screenids.size(); i++) { update_queue.AddImageSampler(present_set, i, 0, screen_infos[screenids[i]].image_view, @@ -1099,7 +1099,7 @@ void RendererVulkan::DrawSingleScreen(u32 screen_id, float screenLeft, float scr const ScreenInfo& screen_info = screen_infos[screen_id]; const auto& texcoords = screen_info.texcoords; std::vector screenids = {screen_id}; - PrepareDraw(currentFrame, currentFramebufferLayout, screenids); + PrepareDraw(currentFrame, currentFramebufferLayout, screenids, 1); // Apply the initial default opacity value; Needed to avoid flickering if (applyingOpacity){ @@ -1125,12 +1125,8 @@ void RendererVulkan::DrawSingleScreen(u32 screen_id, float screenLeft, float scr // Texture Width and Height when correctly rotated to landscape bool isDownsampling = false; - int scalingMode; //0 is Nearest Neighbor, 1 is Gamma Corrected Bilinear, 2 is High Quality Scaling (Upsampling via Gamma Corrected Bilinear, Downsampling is Gamma Corrected Area Sampling) - if (Settings::values.filter_mode.GetValue()){ - scalingMode = 2; - } else { - scalingMode = 0; - } + int scalingMode; //0 is Nearest Neighbor, 1 is Gamma Corrected Bilinear, 2 is Adaptive (Bilinear/Area), 3 is FSR, 4 is Sharp Bilinear + scalingMode = static_cast(Settings::values.output_scaling.GetValue()); int antialiasingMode = static_cast(Settings::values.antialiasing_filter.GetValue()); //0 is none, 1 is FXAA, 2 is SMAA if (orientation == Layout::DisplayOrientation::Landscape || orientation == Layout::DisplayOrientation::LandscapeFlipped) { if (textureWidth > screenWidth){ @@ -1278,7 +1274,7 @@ void RendererVulkan::DrawSingleScreenStereo(u32 screen_id_l, u32 screen_id_r, fl const ScreenInfo& screen_info_l = screen_infos[screen_id_l]; const auto& texcoords = screen_info_l.texcoords; std::vector screenids = {screen_id_l, screen_id_r}; - PrepareDraw(currentFrame, currentFramebufferLayout, screenids); + PrepareDraw(currentFrame, currentFramebufferLayout, screenids, 1); // Apply the initial default opacity value; Needed to avoid flickering if (applyingOpacity){ diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.h b/src/video_core/renderer_vulkan/renderer_vulkan.h index 111bdfa04..66e3578e3 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.h +++ b/src/video_core/renderer_vulkan/renderer_vulkan.h @@ -98,7 +98,7 @@ private: void RenderScreenshot(); void RenderScreenshotWithStagingCopy(); bool TryRenderScreenshotWithHostMemory(); - void PrepareDraw(Frame* frame, const Layout::FramebufferLayout& layout, std::vector screenids); + void PrepareDraw(Frame* frame, const Layout::FramebufferLayout& layout, std::vector screenids, int filterMode); void PrepareTextureDraw(TextureInfo framebufferTexture, vk::Framebuffer framebuffer, vk::Pipeline shaderPipeline, std::vector texturesToSample, int filterMode); void RenderToWindow(PresentWindow& window, const Layout::FramebufferLayout& layout, bool flipped);