From 37dd2fddc41ff3ebaab985da25d6f1c7ea011d3d Mon Sep 17 00:00:00 2001 From: collecting Date: Thu, 5 Feb 2026 02:57:28 -0500 Subject: [PATCH] fix/feat: Introduce CAS & Add Dynamic Slider Viewing for Toggled WAF's, and remove Android ASTC visibility on PC --- .../configuration/configure_graphics.cpp | 105 ++++--- src/citron/configuration/configure_graphics.h | 8 +- .../configure_graphics_advanced.cpp | 50 ++-- .../configuration/shared_translation.cpp | 90 +++--- src/citron/configuration/shared_translation.h | 6 +- src/citron/main.cpp | 29 +- src/common/settings.h | 256 ++++++++---------- src/common/settings_enums.h | 84 +++--- .../renderer_opengl/gl_blit_screen.cpp | 1 + .../renderer_opengl/present/fsr.cpp | 14 +- src/video_core/renderer_opengl/present/fsr.h | 3 +- .../renderer_opengl/present/layer.cpp | 19 +- .../renderer_vulkan/present/filters.cpp | 9 +- .../renderer_vulkan/present/fsr.cpp | 8 +- src/video_core/renderer_vulkan/present/fsr.h | 2 +- .../renderer_vulkan/present/layer.cpp | 18 +- .../present/window_adapt_pass.cpp | 9 +- .../renderer_vulkan/vk_blit_screen.cpp | 1 + 18 files changed, 388 insertions(+), 324 deletions(-) diff --git a/src/citron/configuration/configure_graphics.cpp b/src/citron/configuration/configure_graphics.cpp index 42ef5de66..7f4875417 100644 --- a/src/citron/configuration/configure_graphics.cpp +++ b/src/citron/configuration/configure_graphics.cpp @@ -31,6 +31,12 @@ #include #include +#include "citron/configuration/configuration_shared.h" +#include "citron/configuration/configure_graphics.h" +#include "citron/configuration/shared_widget.h" +#include "citron/qt_common.h" +#include "citron/uisettings.h" +#include "citron/vk_device_info.h" #include "common/common_types.h" #include "common/dynamic_library.h" #include "common/logging/log.h" @@ -38,12 +44,6 @@ #include "common/settings_enums.h" #include "core/core.h" #include "ui_configure_graphics.h" -#include "citron/configuration/configuration_shared.h" -#include "citron/configuration/configure_graphics.h" -#include "citron/configuration/shared_widget.h" -#include "citron/qt_common.h" -#include "citron/uisettings.h" -#include "citron/vk_device_info.h" static const std::vector default_present_modes{VK_PRESENT_MODE_IMMEDIATE_KHR, VK_PRESENT_MODE_FIFO_KHR}; @@ -276,6 +276,14 @@ void ConfigureGraphics::Setup(const ConfigurationShared::Builder& builder) { return builder.BuildWidget( setting, apply_funcs, ConfigurationShared::RequestType::ReverseSlider, true, 0.5f, nullptr, tr("%", "FSR sharpening percentage (e.g. 50%)")); + } else if (setting->Id() == Settings::values.cas_sharpening_slider.Id()) { + // CAS needs a 0.5 multiplier to show 0-100% (actually 0.0-0.5 internally if we + // follow FSR) Wait, CAS slider is 0-100 in settings.h. FSR is 0-200 internally? + // Actually FSR slider is 0-200 in settings.h. + // Let's check settings.h for CAS slider again. + return builder.BuildWidget(setting, apply_funcs, + ConfigurationShared::RequestType::Slider, true, 1.0f, + nullptr, tr("%")); } else { return builder.BuildWidget(setting, apply_funcs); } @@ -289,9 +297,20 @@ void ConfigureGraphics::Setup(const ConfigurationShared::Builder& builder) { continue; } - // Store reference to the FSR sharpness widget for later use if (setting->Id() == Settings::values.fsr_sharpening_slider.Id()) { fsr_sharpness_widget = widget; + } else if (setting->Id() == Settings::values.cas_sharpening_slider.Id()) { + cas_sharpness_widget = widget; + } else if (setting->Id() == Settings::values.lanczos_quality.Id()) { + lq_widget = widget; + } else if (setting->Id() == Settings::values.crt_scanline_strength.Id() || + setting->Id() == Settings::values.crt_curvature.Id() || + setting->Id() == Settings::values.crt_gamma.Id() || + setting->Id() == Settings::values.crt_bloom.Id() || + setting->Id() == Settings::values.crt_mask_type.Id() || + setting->Id() == Settings::values.crt_brightness.Id() || + setting->Id() == Settings::values.crt_alpha.Id()) { + crt_widgets.push_back(widget); } if (setting->Id() == Settings::values.renderer_backend.Id()) { @@ -372,39 +391,61 @@ void ConfigureGraphics::Setup(const ConfigurationShared::Builder& builder) { api_grid_layout->addWidget(widget); } - // Set up FSR sharpness slider conditional enabling - if (fsr_sharpness_widget) { - // Create a function to update the enabled state based on scaling filter - auto update_fsr_sharpness_enabled = [this]() { - if (fsr_sharpness_widget) { - const auto scaling_filter = Settings::values.scaling_filter.GetValue(); - const bool fsr2_selected = (scaling_filter == Settings::ScalingFilter::Fsr2); - fsr_sharpness_widget->setEnabled(!fsr2_selected); + // Set up Scaling Filter conditional visibility for sliders + QComboBox* scaling_filter_combobox = nullptr; + for (const auto& [id, widget] : hold_graphics) { + if (id == Settings::values.scaling_filter.Id()) { + scaling_filter_combobox = static_cast(widget)->combobox; + break; + } + } - // Grey out the widget when disabled + if (scaling_filter_combobox) { + // Create a function to update the enabled/visible state based on current UI selection + auto update_visibility = [this, scaling_filter_combobox, &builder]() { + const auto& translations = builder.ComboboxTranslations().at( + Settings::EnumMetadata::Index()); + const auto scaling_filter = static_cast( + translations.at(scaling_filter_combobox->currentIndex()).first); + + if (fsr_sharpness_widget) { + const bool fsr_selected = (scaling_filter == Settings::ScalingFilter::Fsr); + const bool fsr2_selected = (scaling_filter == Settings::ScalingFilter::Fsr2); + + // Visible only if FSR 1 or FSR 2 is selected + fsr_sharpness_widget->setVisible(fsr_selected || fsr2_selected); + + // FSR 2.0 doesn't use the FSR 1.0 sharpness slider but we allow it to be visible + // but disabled to show it's an FSR-related setting. + fsr_sharpness_widget->setEnabled(!fsr2_selected); if (fsr2_selected) { fsr_sharpness_widget->setStyleSheet(QStringLiteral("QWidget { color: gray; }")); } else { fsr_sharpness_widget->setStyleSheet(QStringLiteral("")); } } + + if (cas_sharpness_widget) { + cas_sharpness_widget->setVisible(scaling_filter == Settings::ScalingFilter::Cas); + } + + if (lq_widget) { + lq_widget->setVisible(scaling_filter == Settings::ScalingFilter::Lanczos); + } + + const bool crt_selected = (scaling_filter == Settings::ScalingFilter::CRTEasyMode || + scaling_filter == Settings::ScalingFilter::CRTRoyale); + for (auto* crt_widget : crt_widgets) { + crt_widget->setVisible(crt_selected); + } }; // Initial state - update_fsr_sharpness_enabled(); + update_visibility(); - // Connect to scaling filter changes - if (!Settings::IsConfiguringGlobal()) { - // Find the scaling filter widget and connect to its changes - for (const auto& [id, widget] : hold_graphics) { - if (id == Settings::values.scaling_filter.Id()) { - auto* config_widget = static_cast(widget); - QObject::connect(config_widget->combobox, QOverload::of(&QComboBox::activated), - [update_fsr_sharpness_enabled]() { update_fsr_sharpness_enabled(); }); - break; - } - } - } + // Connect to scaling filter changes (real-time update) + QObject::connect(scaling_filter_combobox, QOverload::of(&QComboBox::activated), + [update_visibility]() { update_visibility(); }); } // Background color is too specific to build into the new system, so we manage it here @@ -615,8 +656,10 @@ void ConfigureGraphics::SetTemplateStyleSheet(const QString& sheet) { // Replace all placeholders with the actual color values in #RRGGBB format // Use QStringLiteral() to satisfy Qt 6's explicit string constructor requirements final_style.replace(QStringLiteral("%%ACCENT_COLOR%%"), accent_color.name(QColor::HexRgb)); - final_style.replace(QStringLiteral("%%ACCENT_COLOR_HOVER%%"), accent_color_hover.name(QColor::HexRgb)); - final_style.replace(QStringLiteral("%%ACCENT_COLOR_PRESSED%%"), accent_color_pressed.name(QColor::HexRgb)); + final_style.replace(QStringLiteral("%%ACCENT_COLOR_HOVER%%"), + accent_color_hover.name(QColor::HexRgb)); + final_style.replace(QStringLiteral("%%ACCENT_COLOR_PRESSED%%"), + accent_color_pressed.name(QColor::HexRgb)); // Apply the processed stylesheet to this widget and all its children (like checkboxes) this->setStyleSheet(final_style); diff --git a/src/citron/configuration/configure_graphics.h b/src/citron/configuration/configure_graphics.h index cb519fb3a..9eb3a9ad7 100644 --- a/src/citron/configuration/configure_graphics.h +++ b/src/citron/configuration/configure_graphics.h @@ -14,11 +14,11 @@ #include #include #include +#include "citron/configuration/configuration_shared.h" #include "common/common_types.h" #include "common/settings_enums.h" #include "configuration/shared_translation.h" #include "vk_device_info.h" -#include "citron/configuration/configuration_shared.h" class QPushButton; class QEvent; @@ -47,7 +47,8 @@ class ConfigureGraphics : public ConfigurationShared::Tab { Q_OBJECT // This property allows the main UI file to pass its stylesheet to this widget - Q_PROPERTY(QString templateStyleSheet READ GetTemplateStyleSheet WRITE SetTemplateStyleSheet NOTIFY TemplateStyleSheetChanged) + Q_PROPERTY(QString templateStyleSheet READ GetTemplateStyleSheet WRITE SetTemplateStyleSheet + NOTIFY TemplateStyleSheetChanged) public: explicit ConfigureGraphics( @@ -125,6 +126,9 @@ private: QComboBox* aspect_ratio_combobox; QComboBox* resolution_combobox; QWidget* fsr_sharpness_widget; + QWidget* cas_sharpness_widget; + QWidget* lq_widget; + std::vector crt_widgets; // This variable will hold the raw stylesheet string QString m_template_style_sheet; diff --git a/src/citron/configuration/configure_graphics_advanced.cpp b/src/citron/configuration/configure_graphics_advanced.cpp index deb20b2bf..16b9ef9c1 100644 --- a/src/citron/configuration/configure_graphics_advanced.cpp +++ b/src/citron/configuration/configure_graphics_advanced.cpp @@ -2,21 +2,22 @@ // SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include "citron/configuration/configure_graphics_advanced.h" #include #include #include +#include "citron/configuration/configuration_shared.h" +#include "citron/configuration/configure_graphics_advanced.h" +#include "citron/configuration/shared_translation.h" +#include "citron/configuration/shared_widget.h" #include "common/settings.h" #include "core/core.h" #include "ui_configure_graphics_advanced.h" -#include "citron/configuration/configuration_shared.h" -#include "citron/configuration/shared_translation.h" -#include "citron/configuration/shared_widget.h" + ConfigureGraphicsAdvanced::ConfigureGraphicsAdvanced( const Core::System& system_, std::shared_ptr> group_, const ConfigurationShared::Builder& builder, QWidget* parent) -: Tab(group_, parent), ui{std::make_unique()}, system{system_} { + : Tab(group_, parent), ui{std::make_unique()}, system{system_} { ui->setupUi(this); @@ -36,27 +37,32 @@ void ConfigureGraphicsAdvanced::Setup(const ConfigurationShared::Builder& builde std::map hold{}; // A map will sort the data for us for (auto setting : - Settings::values.linkage.by_category[Settings::Category::RendererAdvanced]) { + Settings::values.linkage.by_category[Settings::Category::RendererAdvanced]) { +#ifndef ANDROID + if (setting->Id() == Settings::values.android_astc_mode.Id()) { + continue; + } +#endif ConfigurationShared::Widget* widget = builder.BuildWidget(setting, apply_funcs); - if (widget == nullptr) { - continue; - } - if (!widget->Valid()) { - widget->deleteLater(); - continue; - } - - hold.emplace(setting->Id(), widget); - - // Keep track of enable_compute_pipelines so we can display it when needed - if (setting->Id() == Settings::values.enable_compute_pipelines.Id()) { - checkbox_enable_compute_pipelines = widget; - } + if (widget == nullptr) { + continue; } - for (const auto& [id, widget] : hold) { - layout.addWidget(widget); + if (!widget->Valid()) { + widget->deleteLater(); + continue; } + + hold.emplace(setting->Id(), widget); + + // Keep track of enable_compute_pipelines so we can display it when needed + if (setting->Id() == Settings::values.enable_compute_pipelines.Id()) { + checkbox_enable_compute_pipelines = widget; + } + } + for (const auto& [id, widget] : hold) { + layout.addWidget(widget); + } } void ConfigureGraphicsAdvanced::ApplyConfiguration() { diff --git a/src/citron/configuration/shared_translation.cpp b/src/citron/configuration/shared_translation.cpp index 4d0a65cd1..2b427c8e0 100644 --- a/src/citron/configuration/shared_translation.cpp +++ b/src/citron/configuration/shared_translation.cpp @@ -10,11 +10,11 @@ #include #include #include +#include "citron/uisettings.h" #include "common/settings.h" #include "common/settings_enums.h" #include "common/settings_setting.h" #include "common/time_zone.h" -#include "citron/uisettings.h" namespace ConfigurationShared { @@ -130,30 +130,42 @@ std::unique_ptr InitializeTranslations(QWidget* parent) { "much more VRAM and bandwidth.\n" "Options lower than 1X can cause rendering issues.")); INSERT(Settings, scaling_filter, tr("Window Adapting Filter:"), QStringLiteral()); - INSERT(Settings, fsr_sharpening_slider, tr("FSR Sharpness:"), + INSERT(Settings, fsr_sharpening_slider, tr("FSR Sharpness"), tr("Determines how sharpened the image will look while using FSR's dynamic contrast.")); - INSERT(Settings, lanczos_quality, tr("Lanczos Quality:"), tr("The quality of the Lanczos filter. Higher is sharper but more expensive.")); + INSERT(Settings, cas_sharpening_slider, tr("CAS Sharpness"), + tr("Determines the level of sharpening applied by the Contrast Adaptive Sharpening " + "(CAS) filter.")); + INSERT(Settings, lanczos_quality, tr("Lanczos Quality:"), + tr("The quality of the Lanczos filter. Higher is sharper but more expensive.")); INSERT(Settings, fsr2_quality_mode, tr("FSR 2.0 Quality Mode:"), - tr("Selects the quality mode for FSR 2.0 upscaling. Quality provides better image quality, Performance provides better performance.")); + tr("Selects the quality mode for FSR 2.0 upscaling. Quality provides better image " + "quality, Performance provides better performance.")); INSERT(Settings, crt_scanline_strength, tr("CRT Scanline Strength:"), - tr("Controls the intensity of scanlines. Higher values create more pronounced horizontal lines.")); + tr("Controls the intensity of scanlines. Higher values create more pronounced " + "horizontal lines.")); INSERT(Settings, crt_curvature, tr("CRT Curvature:"), tr("Applies barrel distortion to simulate the curved screen of a CRT monitor.")); INSERT(Settings, crt_gamma, tr("CRT Gamma:"), - tr("Adjusts the gamma correction curve. Higher values brighten the image, lower values darken it.")); + tr("Adjusts the gamma correction curve. Higher values brighten the image, lower values " + "darken it.")); INSERT(Settings, crt_bloom, tr("CRT Bloom:"), tr("Controls the glow effect around bright areas, simulating phosphor persistence.")); INSERT(Settings, crt_mask_type, tr("CRT Mask Type:"), - tr("Selects the phosphor mask pattern: None, Aperture Grille (vertical stripes), or Shadow Mask (triangular pattern).")); + tr("Selects the phosphor mask pattern: None, Aperture Grille (vertical stripes), or " + "Shadow Mask (triangular pattern).")); INSERT(Settings, crt_brightness, tr("CRT Brightness:"), - tr("Adjusts overall brightness of the CRT effect. Use to compensate for darkening from other effects.")); + tr("Adjusts overall brightness of the CRT effect. Use to compensate for darkening from " + "other effects.")); INSERT(Settings, crt_alpha, tr("CRT Alpha:"), - tr("Controls transparency of the CRT effect. Lower values make the effect more transparent.")); + tr("Controls transparency of the CRT effect. Lower values make the effect more " + "transparent.")); - INSERT(Settings, frame_skipping, tr("Frame Skipping:"), - tr("Skips frames to maintain performance when the system cannot keep up with the target frame rate.")); - INSERT(Settings, frame_skipping_mode, tr("Frame Skipping Mode:"), - tr("Adaptive mode skips frames based on performance, while Fixed mode skips a specific number of frames.")); + INSERT(Settings, frame_skipping, tr("Frame Skipping:"), + tr("Skips frames to maintain performance when the system cannot keep up with the target " + "frame rate.")); + INSERT(Settings, frame_skipping_mode, tr("Frame Skipping Mode:"), + tr("Adaptive mode skips frames based on performance, while Fixed mode skips a specific " + "number of frames.")); INSERT(Settings, anti_aliasing, tr("Anti-Aliasing Method:"), tr("The anti-aliasing method to use.\nSMAA offers the best quality.\nFXAA has a " "lower performance impact and can produce a better and more stable picture under " @@ -202,10 +214,11 @@ std::unique_ptr InitializeTranslations(QWidget* parent) { INSERT(Settings, vram_limit_mb, tr("VRAM Limit (MB):"), tr("Sets the maximum VRAM usage limit in megabytes. Set to 0 for auto-detection " "(80% of available VRAM). Recommended: 6144 for 8GB GPUs, 4096 for 6GB GPUs.")); - INSERT(Settings, gc_aggressiveness, tr("GC Aggressiveness:"), - tr("Controls how aggressively the emulator evicts unused textures and buffers from VRAM.\n" - "Off: Disable automatic cleanup (not recommended, may cause crashes).\n" - "Light: Gentle cleanup, keeps more textures cached (recommended).")); + INSERT( + Settings, gc_aggressiveness, tr("GC Aggressiveness:"), + tr("Controls how aggressively the emulator evicts unused textures and buffers from VRAM.\n" + "Off: Disable automatic cleanup (not recommended, may cause crashes).\n" + "Light: Gentle cleanup, keeps more textures cached (recommended).")); INSERT(Settings, texture_eviction_frames, tr("Texture Eviction Frames:"), tr("Number of frames a texture must be unused before it can be evicted. " "Lower values free VRAM faster but may cause more texture reloading.")); @@ -271,16 +284,18 @@ std::unique_ptr InitializeTranslations(QWidget* parent) { "unlocked.")); INSERT(Settings, barrier_feedback_loops, tr("Barrier feedback loops"), tr("Improves rendering of transparency effects in specific games.")); - INSERT(Settings, extended_dynamic_state, tr("Extended Dynamic State:"), - tr("Selects the level of Vulkan Extended Dynamic State support.\n" - "EDS3: Enables all Extended Dynamic State features (recommended).\n" - "EDS2: Enables EDS1 and EDS2 features only.\n" - "EDS1: Enables basic Extended Dynamic State features only.\n" - "Disabled: Disables all Extended Dynamic State features (may reduce compatibility).")); - INSERT(Settings, use_conditional_rendering, tr("Use conditional rendering"), - tr("Enables conditional rendering based on query results.\n" - "Disabling this can fix flickering objects in some games but may impact performance.\n" - "Try disabling if you see objects appearing and disappearing rapidly.")); + INSERT( + Settings, extended_dynamic_state, tr("Extended Dynamic State:"), + tr("Selects the level of Vulkan Extended Dynamic State support.\n" + "EDS3: Enables all Extended Dynamic State features (recommended).\n" + "EDS2: Enables EDS1 and EDS2 features only.\n" + "EDS1: Enables basic Extended Dynamic State features only.\n" + "Disabled: Disables all Extended Dynamic State features (may reduce compatibility).")); + INSERT( + Settings, use_conditional_rendering, tr("Use conditional rendering"), + tr("Enables conditional rendering based on query results.\n" + "Disabling this can fix flickering objects in some games but may impact performance.\n" + "Try disabling if you see objects appearing and disappearing rapidly.")); // Renderer (Debug) @@ -477,6 +492,7 @@ std::unique_ptr ComboboxEnumeration(QWidget* parent) { PAIR(ScalingFilter, Fsr2, tr("AMD FidelityFX™️ Super Resolution 2.0")), PAIR(ScalingFilter, CRTEasyMode, tr("CRT EasyMode")), PAIR(ScalingFilter, CRTRoyale, tr("CRT Royale")), + PAIR(ScalingFilter, Cas, tr("CAS (Contrast Adaptive Sharpening)")), }}); translations->insert({Settings::EnumMetadata::Index(), { @@ -493,16 +509,16 @@ std::unique_ptr ComboboxEnumeration(QWidget* parent) { PAIR(FSR2QualityMode, UltraPerformance, tr("Ultra Performance")), }}); - translations->insert({Settings::EnumMetadata::Index(), - { - PAIR(FrameSkipping, Disabled, tr("Disabled")), - PAIR(FrameSkipping, Enabled, tr("Enabled")), - }}); - translations->insert({Settings::EnumMetadata::Index(), - { - PAIR(FrameSkippingMode, Adaptive, tr("Adaptive")), - PAIR(FrameSkippingMode, Fixed, tr("Fixed")), - }}); + translations->insert({Settings::EnumMetadata::Index(), + { + PAIR(FrameSkipping, Disabled, tr("Disabled")), + PAIR(FrameSkipping, Enabled, tr("Enabled")), + }}); + translations->insert({Settings::EnumMetadata::Index(), + { + PAIR(FrameSkippingMode, Adaptive, tr("Adaptive")), + PAIR(FrameSkippingMode, Fixed, tr("Fixed")), + }}); translations->insert({Settings::EnumMetadata::Index(), { PAIR(AspectRatio, R16_9, tr("Default (16:9)")), diff --git a/src/citron/configuration/shared_translation.h b/src/citron/configuration/shared_translation.h index 71ec60f88..c03629d79 100644 --- a/src/citron/configuration/shared_translation.h +++ b/src/citron/configuration/shared_translation.h @@ -39,17 +39,17 @@ static const std::map scaling_filter_texts_map {Settings::ScalingFilter::Bicubic, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Bicubic"))}, {Settings::ScalingFilter::Gaussian, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Gaussian"))}, - {Settings::ScalingFilter::Lanczos, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Lanczos"))}, + {Settings::ScalingFilter::Lanczos, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Lanczos"))}, {Settings::ScalingFilter::ScaleForce, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "ScaleForce"))}, - {Settings::ScalingFilter::ScaleFx, - QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "ScaleFX"))}, + {Settings::ScalingFilter::ScaleFx, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "ScaleFX"))}, {Settings::ScalingFilter::Fsr, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "FSR"))}, {Settings::ScalingFilter::Fsr2, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "FSR 2.0"))}, {Settings::ScalingFilter::CRTEasyMode, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "CRT EasyMode"))}, {Settings::ScalingFilter::CRTRoyale, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "CRT Royale"))}, + {Settings::ScalingFilter::Cas, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "CAS"))}, }; static const std::map use_docked_mode_texts_map = { diff --git a/src/citron/main.cpp b/src/citron/main.cpp index 80ccfa406..2e6ea942e 100644 --- a/src/citron/main.cpp +++ b/src/citron/main.cpp @@ -5710,8 +5710,22 @@ void GMainWindow::UpdateAPIText() { void GMainWindow::UpdateFilterText() { const auto filter = Settings::values.scaling_filter.GetValue(); const auto filter_text = ConfigurationShared::scaling_filter_texts_map.find(filter)->second; - filter_status_button->setText(filter == Settings::ScalingFilter::Fsr ? tr("FSR") - : filter_text.toUpper()); + QString label; + switch (filter) { + case Settings::ScalingFilter::Fsr: + label = tr("FSR"); + break; + case Settings::ScalingFilter::Fsr2: + label = tr("FSR2"); + break; + case Settings::ScalingFilter::Cas: + label = tr("CAS"); + break; + default: + label = filter_text.toUpper(); + break; + } + filter_status_button->setText(label); } void GMainWindow::UpdateAAText() { @@ -6512,7 +6526,6 @@ void GMainWindow::CheckForUpdatesAutomatically() { void GMainWindow::RegisterAutoloaderContents() { autoloader_provider->ClearAllEntries(); - const auto& disabled_addons = Settings::values.disabled_addons; const auto sdmc_path = Common::FS::GetCitronPath(Common::FS::CitronPath::SDMCDir); const auto autoloader_root = sdmc_path / "autoloader"; @@ -6526,17 +6539,13 @@ void GMainWindow::RegisterAutoloaderContents() { if (!title_dir_entry.is_directory()) continue; - u64 title_id_val = 0; try { - title_id_val = std::stoull(title_dir_entry.path().filename().string(), nullptr, 16); + [[maybe_unused]] auto val = + std::stoull(title_dir_entry.path().filename().string(), nullptr, 16); } catch (const std::invalid_argument&) { continue; } - const auto it = disabled_addons.find(title_id_val); - const auto& disabled_for_game = - (it != disabled_addons.end()) ? it->second : std::vector{}; - const auto process_content_type = [&](const std::filesystem::path& content_path) { if (!Common::FS::IsDir(content_path)) return; @@ -6546,7 +6555,7 @@ void GMainWindow::RegisterAutoloaderContents() { continue; const std::string mod_name = mod_dir_entry.path().filename().string(); - // Citron: We do NOT skip disabled content here. + // We do NOT skip disabled content here. // If we skip it here, it doesn't show up in the UI (Properties -> Add-ons), // making it impossible for the user to re-enable it. // The PatchManager (core/file_sys/patch_manager.cpp) handles the actual enforcement diff --git a/src/common/settings.h b/src/common/settings.h index 122154499..3bd91a73e 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -353,72 +353,47 @@ struct Values { Specialization::Percentage, true, true}; + SwitchableSetting cas_sharpening_slider{linkage, + 50, + 0, + 100, + "cas_sharpening_slider", + Category::Renderer, + Specialization::Scalar | + Specialization::Percentage, + true, + true}; // CRT Shader Settings (only active when CRT filter is selected) - SwitchableSetting crt_scanline_strength{linkage, - 1.0f, // 100/100 = 1.0 (range 0-200, actual 0.0-2.0) - 0.0f, - 2.0f, - "crt_scanline_strength", - Category::Renderer, - Specialization::Scalar, - true, - true}; - SwitchableSetting crt_curvature{linkage, - 0.0f, - 0.0f, - 1.0f, - "crt_curvature", - Category::Renderer, - Specialization::Scalar, - true, - true}; - SwitchableSetting crt_gamma{linkage, - 1.0f, // 100 maps to 1.0 (range 1-300, actual 1.0-3.0) - 1.0f, - 3.0f, - "crt_gamma", - Category::Renderer, - Specialization::Scalar, - true, - true}; - SwitchableSetting crt_bloom{linkage, - 0.33f, // 33/100 = 0.33 (range 0-100, actual 0.0-1.0) - 0.0f, - 1.0f, - "crt_bloom", - Category::Renderer, - Specialization::Scalar, - true, - true}; - SwitchableSetting crt_mask_type{linkage, - 1, // Already correct - 0, - 2, - "crt_mask_type", - Category::Renderer, - Specialization::Scalar, - true, - true}; // 0=none, 1=aperture, 2=shadow - SwitchableSetting crt_brightness{linkage, - 1.0f, // Default brightness (1.0 = no change) - 0.0f, - 2.0f, - "crt_brightness", - Category::Renderer, - Specialization::Scalar, - true, - true}; - SwitchableSetting crt_alpha{linkage, - 1.0f, // Default alpha (1.0 = fully opaque) - 0.0f, - 1.0f, - "crt_alpha", - Category::Renderer, - Specialization::Scalar, - true, - true}; - + SwitchableSetting crt_scanline_strength{ + linkage, + 1.0f, // 100/100 = 1.0 (range 0-200, actual 0.0-2.0) + 0.0f, 2.0f, "crt_scanline_strength", Category::Renderer, Specialization::Scalar, + true, true}; + SwitchableSetting crt_curvature{ + linkage, 0.0f, 0.0f, 1.0f, "crt_curvature", Category::Renderer, Specialization::Scalar, + true, true}; + SwitchableSetting crt_gamma{ + linkage, + 1.0f, // 100 maps to 1.0 (range 1-300, actual 1.0-3.0) + 1.0f, 3.0f, "crt_gamma", Category::Renderer, Specialization::Scalar, true, true}; + SwitchableSetting crt_bloom{ + linkage, + 0.33f, // 33/100 = 0.33 (range 0-100, actual 0.0-1.0) + 0.0f, 1.0f, "crt_bloom", Category::Renderer, Specialization::Scalar, true, true}; + SwitchableSetting crt_mask_type{ + linkage, + 1, // Already correct + 0, 2, "crt_mask_type", Category::Renderer, Specialization::Scalar, + true, true}; // 0=none, 1=aperture, 2=shadow + SwitchableSetting crt_brightness{ + linkage, + 1.0f, // Default brightness (1.0 = no change) + 0.0f, 2.0f, "crt_brightness", Category::Renderer, Specialization::Scalar, true, true}; + SwitchableSetting crt_alpha{ + linkage, + 1.0f, // Default alpha (1.0 = fully opaque) + 0.0f, 1.0f, "crt_alpha", Category::Renderer, Specialization::Scalar, true, true}; SwitchableSetting lanczos_quality{linkage, 3, // Default value @@ -430,37 +405,38 @@ struct Values { true, true}; - SwitchableSetting fsr2_quality_mode{linkage, - FSR2QualityMode::Quality, // Quality by default - FSR2QualityMode::Quality, // Min value - FSR2QualityMode::UltraPerformance, // Max value - "fsr2_quality_mode", - Category::Renderer, - Specialization::Default, - true, - true}; + SwitchableSetting fsr2_quality_mode{ + linkage, + FSR2QualityMode::Quality, // Quality by default + FSR2QualityMode::Quality, // Min value + FSR2QualityMode::UltraPerformance, // Max value + "fsr2_quality_mode", + Category::Renderer, + Specialization::Default, + true, + true}; + SwitchableSetting frame_skipping{ + linkage, + FrameSkipping::Disabled, // Disabled by default + FrameSkipping::Disabled, + FrameSkipping::Enabled, + "frame_skipping", + Category::Renderer, + Specialization::Default, + true, + true}; - - SwitchableSetting frame_skipping{linkage, - FrameSkipping::Disabled, // Disabled by default - FrameSkipping::Disabled, - FrameSkipping::Enabled, - "frame_skipping", - Category::Renderer, - Specialization::Default, - true, - true}; - - SwitchableSetting frame_skipping_mode{linkage, - FrameSkippingMode::Adaptive, // Adaptive by default - FrameSkippingMode::Adaptive, - FrameSkippingMode::Fixed, - "frame_skipping_mode", - Category::Renderer, - Specialization::Default, - true, - true}; + SwitchableSetting frame_skipping_mode{ + linkage, + FrameSkippingMode::Adaptive, // Adaptive by default + FrameSkippingMode::Adaptive, + FrameSkippingMode::Fixed, + "frame_skipping_mode", + Category::Renderer, + Specialization::Default, + true, + true}; SwitchableSetting bg_red{ linkage, 0, "bg_red", Category::Renderer, Specialization::Default, true, true}; @@ -520,55 +496,54 @@ struct Values { // GC aggressiveness level for texture/buffer cache eviction SwitchableSetting gc_aggressiveness{linkage, - GCAggressiveness::Light, - GCAggressiveness::Off, - GCAggressiveness::Light, - "gc_aggressiveness", - Category::RendererAdvanced, - Specialization::Default, - true, - true}; + GCAggressiveness::Light, + GCAggressiveness::Off, + GCAggressiveness::Light, + "gc_aggressiveness", + Category::RendererAdvanced, + Specialization::Default, + true, + true}; // Number of frames before unused textures are evicted (default 2) SwitchableSetting texture_eviction_frames{linkage, - 2, // default: 2 frames - 1, // min: 1 frame - 60, // max: 60 frames (1 second at 60fps) - "texture_eviction_frames", - Category::RendererAdvanced, - Specialization::Default, - true, - true}; - - // Number of frames before unused buffers are evicted (default 5) - SwitchableSetting buffer_eviction_frames{linkage, - 5, // default: 5 frames - 1, // min: 1 frame - 120, // max: 120 frames (2 seconds at 60fps) - "buffer_eviction_frames", + 2, // default: 2 frames + 1, // min: 1 frame + 60, // max: 60 frames (1 second at 60fps) + "texture_eviction_frames", Category::RendererAdvanced, Specialization::Default, true, true}; + // Number of frames before unused buffers are evicted (default 5) + SwitchableSetting buffer_eviction_frames{linkage, + 5, // default: 5 frames + 1, // min: 1 frame + 120, // max: 120 frames (2 seconds at 60fps) + "buffer_eviction_frames", + Category::RendererAdvanced, + Specialization::Default, + true, + true}; + // Enable sparse texture priority eviction (evict large unmapped pages first) - SwitchableSetting sparse_texture_priority_eviction{linkage, false, - "sparse_texture_priority_eviction", - Category::RendererAdvanced}; + SwitchableSetting sparse_texture_priority_eviction{ + linkage, false, "sparse_texture_priority_eviction", Category::RendererAdvanced}; // Enable VRAM usage logging for debugging SwitchableSetting log_vram_usage{linkage, false, "log_vram_usage", - Category::RendererAdvanced}; + Category::RendererAdvanced}; // FIXED: Android Adreno 740 native ASTC eviction // Controls texture cache eviction strategy on Android devices with native ASTC support // Auto = detect based on GPU, Native = use compressed size, Decompress = use decompressed size SwitchableSetting android_astc_mode{linkage, - AndroidAstcMode::Auto, - AndroidAstcMode::Auto, - AndroidAstcMode::Decompress, - "android_astc_mode", - Category::RendererAdvanced}; + AndroidAstcMode::Auto, + AndroidAstcMode::Auto, + AndroidAstcMode::Decompress, + "android_astc_mode", + Category::RendererAdvanced}; SwitchableSetting async_presentation{linkage, #ifdef ANDROID @@ -605,12 +580,13 @@ struct Values { Category::RendererAdvanced}; SwitchableSetting barrier_feedback_loops{linkage, true, "barrier_feedback_loops", Category::RendererAdvanced}; - SwitchableSetting extended_dynamic_state{linkage, - ExtendedDynamicState::EDS3, - ExtendedDynamicState::Disabled, - ExtendedDynamicState::EDS3, - "extended_dynamic_state", - Category::RendererAdvanced}; + SwitchableSetting extended_dynamic_state{ + linkage, + ExtendedDynamicState::EDS3, + ExtendedDynamicState::Disabled, + ExtendedDynamicState::EDS3, + "extended_dynamic_state", + Category::RendererAdvanced}; SwitchableSetting use_conditional_rendering{linkage, true, "use_conditional_rendering", Category::RendererAdvanced}; @@ -676,7 +652,9 @@ struct Values { true}; // Linux - Setting is_wayland_platform{linkage, false, "is_wayland_platform", Category::Miscellaneous, Specialization::Default, false}; + Setting is_wayland_platform{ + linkage, false, "is_wayland_platform", Category::Miscellaneous, Specialization::Default, + false}; SwitchableSetting enable_gamemode{linkage, true, "enable_gamemode", Category::Linux}; // Controls @@ -805,11 +783,12 @@ struct Values { Setting web_api_url{linkage, "api.ynet-fun.xyz", "web_api_url", Category::WebService}; Setting citron_username{linkage, std::string(), "citron_username", - Category::WebService}; + Category::WebService}; Setting citron_token{linkage, std::string(), "citron_token", Category::WebService}; // Updater - Setting enable_auto_update_check{linkage, true, "enable_auto_update_check", Category::WebService}; + Setting enable_auto_update_check{linkage, true, "enable_auto_update_check", + Category::WebService}; // Add-Ons std::map> disabled_addons; @@ -823,9 +802,12 @@ struct Values { // This stores the external path used for Intelligent Mirroring sync std::map mirrored_save_paths; - Setting global_custom_save_path_enabled{linkage, false, "global_custom_save_path_enabled", Category::DataStorage}; - Setting global_custom_save_path{linkage, std::string(), "global_custom_save_path", Category::DataStorage}; - Setting backup_saves_to_nand{linkage, false, "backup_saves_to_nand", Category::DataStorage}; + Setting global_custom_save_path_enabled{linkage, false, "global_custom_save_path_enabled", + Category::DataStorage}; + Setting global_custom_save_path{linkage, std::string(), "global_custom_save_path", + Category::DataStorage}; + Setting backup_saves_to_nand{linkage, false, "backup_saves_to_nand", + Category::DataStorage}; }; extern Values values; diff --git a/src/common/settings_enums.h b/src/common/settings_enums.h index 000d1e8c0..93e0c1360 100644 --- a/src/common/settings_enums.h +++ b/src/common/settings_enums.h @@ -91,8 +91,8 @@ template <> inline std::vector> EnumMetadata::Canonicalizations() { return { - {"auto", AudioEngine::Auto}, {"cubeb", AudioEngine::Cubeb}, {"sdl2", AudioEngine::Sdl2}, - {"openal", AudioEngine::OpenAL}, {"null", AudioEngine::Null}, {"oboe", AudioEngine::Oboe}, + {"auto", AudioEngine::Auto}, {"cubeb", AudioEngine::Cubeb}, {"sdl2", AudioEngine::Sdl2}, + {"openal", AudioEngine::OpenAL}, {"null", AudioEngine::Null}, {"oboe", AudioEngine::Oboe}, }; } @@ -110,8 +110,7 @@ enum class AudioMode : u32 { }; template <> -inline std::vector> -EnumMetadata::Canonicalizations() { +inline std::vector> EnumMetadata::Canonicalizations() { return { {"Mono", AudioMode::Mono}, {"Stereo", AudioMode::Stereo}, @@ -146,8 +145,7 @@ enum class Language : u32 { }; template <> -inline std::vector> -EnumMetadata::Canonicalizations() { +inline std::vector> EnumMetadata::Canonicalizations() { return { {"Japanese", Language::Japanese}, {"EnglishAmerican", Language::EnglishAmerican}, @@ -186,15 +184,10 @@ enum class Region : u32 { }; template <> -inline std::vector> -EnumMetadata::Canonicalizations() { +inline std::vector> EnumMetadata::Canonicalizations() { return { - {"Japan", Region::Japan}, - {"Usa", Region::Usa}, - {"Europe", Region::Europe}, - {"Australia", Region::Australia}, - {"China", Region::China}, - {"Korea", Region::Korea}, + {"Japan", Region::Japan}, {"Usa", Region::Usa}, {"Europe", Region::Europe}, + {"Australia", Region::Australia}, {"China", Region::China}, {"Korea", Region::Korea}, {"Taiwan", Region::Taiwan}, }; } @@ -254,8 +247,7 @@ enum class TimeZone : u32 { }; template <> -inline std::vector> -EnumMetadata::Canonicalizations() { +inline std::vector> EnumMetadata::Canonicalizations() { return { {"Auto", TimeZone::Auto}, {"Default", TimeZone::Default}, @@ -388,8 +380,7 @@ enum class VSyncMode : u32 { }; template <> -inline std::vector> -EnumMetadata::Canonicalizations() { +inline std::vector> EnumMetadata::Canonicalizations() { return { {"Immediate", VSyncMode::Immediate}, {"Mailbox", VSyncMode::Mailbox}, @@ -543,12 +534,9 @@ template <> inline std::vector> EnumMetadata::Canonicalizations() { return { - {"Memory_4Gb", MemoryLayout::Memory_4Gb}, - {"Memory_6Gb", MemoryLayout::Memory_6Gb}, - {"Memory_8Gb", MemoryLayout::Memory_8Gb}, - {"Memory_10Gb", MemoryLayout::Memory_10Gb}, - {"Memory_12Gb", MemoryLayout::Memory_12Gb}, - {"Memory_14Gb", MemoryLayout::Memory_14Gb}, + {"Memory_4Gb", MemoryLayout::Memory_4Gb}, {"Memory_6Gb", MemoryLayout::Memory_6Gb}, + {"Memory_8Gb", MemoryLayout::Memory_8Gb}, {"Memory_10Gb", MemoryLayout::Memory_10Gb}, + {"Memory_12Gb", MemoryLayout::Memory_12Gb}, {"Memory_14Gb", MemoryLayout::Memory_14Gb}, {"Memory_16Gb", MemoryLayout::Memory_16Gb}, }; } @@ -625,9 +613,9 @@ enum class ResolutionSetup : s32 { Res1_2X = 0, Res3_4X = 1, Res1X = 2, - Res5_4X = 11, // 1.25X + Res5_4X = 11, // 1.25X Res3_2X = 3, - Res7_4X = 12, // 1.75X + Res7_4X = 12, // 1.75X Res2X = 4, Res3X = 5, Res4X = 6, @@ -641,20 +629,13 @@ template <> inline std::vector> EnumMetadata::Canonicalizations() { return { - {"Res1_4X", ResolutionSetup::Res1_4X}, - {"Res1_2X", ResolutionSetup::Res1_2X}, - {"Res3_4X", ResolutionSetup::Res3_4X}, - {"Res1X", ResolutionSetup::Res1X}, - {"Res5_4X", ResolutionSetup::Res5_4X}, - {"Res3_2X", ResolutionSetup::Res3_2X}, - {"Res7_4X", ResolutionSetup::Res7_4X}, - {"Res2X", ResolutionSetup::Res2X}, - {"Res3X", ResolutionSetup::Res3X}, - {"Res4X", ResolutionSetup::Res4X}, - {"Res5X", ResolutionSetup::Res5X}, - {"Res6X", ResolutionSetup::Res6X}, - {"Res7X", ResolutionSetup::Res7X}, - {"Res8X", ResolutionSetup::Res8X}, + {"Res1_4X", ResolutionSetup::Res1_4X}, {"Res1_2X", ResolutionSetup::Res1_2X}, + {"Res3_4X", ResolutionSetup::Res3_4X}, {"Res1X", ResolutionSetup::Res1X}, + {"Res5_4X", ResolutionSetup::Res5_4X}, {"Res3_2X", ResolutionSetup::Res3_2X}, + {"Res7_4X", ResolutionSetup::Res7_4X}, {"Res2X", ResolutionSetup::Res2X}, + {"Res3X", ResolutionSetup::Res3X}, {"Res4X", ResolutionSetup::Res4X}, + {"Res5X", ResolutionSetup::Res5X}, {"Res6X", ResolutionSetup::Res6X}, + {"Res7X", ResolutionSetup::Res7X}, {"Res8X", ResolutionSetup::Res8X}, }; } @@ -675,7 +656,8 @@ enum class ScalingFilter : u32 { Fsr2 = 8, CRTEasyMode = 9, CRTRoyale = 10, - MaxEnum = 11, + Cas = 11, + MaxEnum = 12, }; template <> @@ -693,6 +675,7 @@ EnumMetadata::Canonicalizations() { {"Fsr2", ScalingFilter::Fsr2}, {"CRTEasyMode", ScalingFilter::CRTEasyMode}, {"CRTRoyale", ScalingFilter::CRTRoyale}, + {"Cas", ScalingFilter::Cas}, {"MaxEnum", ScalingFilter::MaxEnum}, }; } @@ -714,10 +697,8 @@ template <> inline std::vector> EnumMetadata::Canonicalizations() { return { - {"None", AntiAliasing::None}, - {"Fxaa", AntiAliasing::Fxaa}, - {"Smaa", AntiAliasing::Smaa}, - {"Taa", AntiAliasing::Taa}, + {"None", AntiAliasing::None}, {"Fxaa", AntiAliasing::Fxaa}, + {"Smaa", AntiAliasing::Smaa}, {"Taa", AntiAliasing::Taa}, {"MaxEnum", AntiAliasing::MaxEnum}, }; } @@ -805,12 +786,9 @@ template <> inline std::vector> EnumMetadata::Canonicalizations() { return { - {"R16_9", AspectRatio::R16_9}, - {"R4_3", AspectRatio::R4_3}, - {"R21_9", AspectRatio::R21_9}, - {"R16_10", AspectRatio::R16_10}, - {"R32_9", AspectRatio::R32_9}, - {"Stretch", AspectRatio::Stretch}, + {"R16_9", AspectRatio::R16_9}, {"R4_3", AspectRatio::R4_3}, + {"R21_9", AspectRatio::R21_9}, {"R16_10", AspectRatio::R16_10}, + {"R32_9", AspectRatio::R32_9}, {"Stretch", AspectRatio::Stretch}, }; } @@ -882,8 +860,8 @@ inline u32 EnumMetadata::Index() { // FIXED: VRAM leak prevention - GC aggressiveness levels enum class GCAggressiveness : u32 { - Off = 0, // Disable automatic GC (not recommended) - Light = 1, // Light GC - gentle eviction of old textures/buffers + Off = 0, // Disable automatic GC (not recommended) + Light = 1, // Light GC - gentle eviction of old textures/buffers }; template <> diff --git a/src/video_core/renderer_opengl/gl_blit_screen.cpp b/src/video_core/renderer_opengl/gl_blit_screen.cpp index d0d03835c..4b75e177a 100644 --- a/src/video_core/renderer_opengl/gl_blit_screen.cpp +++ b/src/video_core/renderer_opengl/gl_blit_screen.cpp @@ -95,6 +95,7 @@ void BlitScreen::CreateWindowAdapt() { break; case Settings::ScalingFilter::Fsr: case Settings::ScalingFilter::Fsr2: + case Settings::ScalingFilter::Cas: case Settings::ScalingFilter::Bilinear: default: window_adapt = MakeBilinear(device); diff --git a/src/video_core/renderer_opengl/present/fsr.cpp b/src/video_core/renderer_opengl/present/fsr.cpp index b764aadae..fcb40a2b1 100644 --- a/src/video_core/renderer_opengl/present/fsr.cpp +++ b/src/video_core/renderer_opengl/present/fsr.cpp @@ -49,11 +49,12 @@ FSR::FSR(u32 output_width_, u32 output_height_) : width(output_width_), height(o FSR::~FSR() = default; GLuint FSR::Draw(ProgramManager& program_manager, GLuint texture, u32 input_image_width, - u32 input_image_height, const Common::Rectangle& crop_rect) { - const f32 input_width = static_cast(input_image_width); - const f32 input_height = static_cast(input_image_height); - const f32 output_width = static_cast(width); - const f32 output_height = static_cast(height); + u32 input_image_height, const Common::Rectangle& crop_rect, + float sharpening) { + const float input_width = static_cast(input_image_width); + const float input_height = static_cast(input_image_height); + const float output_width = static_cast(width); + const float output_height = static_cast(height); const f32 viewport_width = (crop_rect.right - crop_rect.left) * input_width; const f32 viewport_x = crop_rect.left * input_width; const f32 viewport_height = (crop_rect.bottom - crop_rect.top) * input_height; @@ -66,9 +67,6 @@ GLuint FSR::Draw(ProgramManager& program_manager, GLuint texture, u32 input_imag easu_con.data() + 12, viewport_width, viewport_height, input_width, input_height, output_width, output_height, viewport_x, viewport_y); - const float sharpening = - static_cast(Settings::values.fsr_sharpening_slider.GetValue()) / 100.0f; - FsrRcasCon(rcas_con.data(), sharpening); glProgramUniform4uiv(easu_frag.handle, 0, sizeof(easu_con), easu_con.data()); diff --git a/src/video_core/renderer_opengl/present/fsr.h b/src/video_core/renderer_opengl/present/fsr.h index 606935a01..6cf47cdd7 100644 --- a/src/video_core/renderer_opengl/present/fsr.h +++ b/src/video_core/renderer_opengl/present/fsr.h @@ -20,7 +20,8 @@ public: ~FSR(); GLuint Draw(ProgramManager& program_manager, GLuint texture, u32 input_image_width, - u32 input_image_height, const Common::Rectangle& crop_rect); + u32 input_image_height, const Common::Rectangle& crop_rect, + float sharpening); bool NeedsRecreation(const Common::Rectangle& screen); diff --git a/src/video_core/renderer_opengl/present/layer.cpp b/src/video_core/renderer_opengl/present/layer.cpp index d9efdb219..bed7f8c02 100644 --- a/src/video_core/renderer_opengl/present/layer.cpp +++ b/src/video_core/renderer_opengl/present/layer.cpp @@ -65,8 +65,8 @@ GLuint Layer::ConfigureDraw(std::array& out_matrix, break; case Settings::AntiAliasing::Taa: CreateTAA(); - texture = taa->Draw(program_manager, info.display_texture, - GL_NONE, GL_NONE, GL_NONE, 0); // TODO: Add proper motion vectors + texture = taa->Draw(program_manager, info.display_texture, GL_NONE, GL_NONE, GL_NONE, + 0); // TODO: Add proper motion vectors break; default: break; @@ -75,12 +75,23 @@ GLuint Layer::ConfigureDraw(std::array& out_matrix, glDisablei(GL_SCISSOR_TEST, 0); - if (filters.get_scaling_filter() == Settings::ScalingFilter::Fsr) { + if (filters.get_scaling_filter() == Settings::ScalingFilter::Fsr || + filters.get_scaling_filter() == Settings::ScalingFilter::Cas) { if (!fsr || fsr->NeedsRecreation(layout.screen)) { fsr = std::make_unique(layout.screen.GetWidth(), layout.screen.GetHeight()); } - texture = fsr->Draw(program_manager, texture, info.scaled_width, info.scaled_height, crop); + float sharpening = 0.0f; + if (filters.get_scaling_filter() == Settings::ScalingFilter::Fsr) { + sharpening = + static_cast(Settings::values.fsr_sharpening_slider.GetValue()) / 100.0f; + } else if (filters.get_scaling_filter() == Settings::ScalingFilter::Cas) { + sharpening = + static_cast(Settings::values.cas_sharpening_slider.GetValue()) / 100.0f; + } + + texture = fsr->Draw(program_manager, texture, info.scaled_width, info.scaled_height, crop, + sharpening); crop = {0, 0, 1, 1}; } if (filters.get_scaling_filter() == Settings::ScalingFilter::Fsr2) { diff --git a/src/video_core/renderer_vulkan/present/filters.cpp b/src/video_core/renderer_vulkan/present/filters.cpp index 673b1ea8a..3ea9ebb05 100644 --- a/src/video_core/renderer_vulkan/present/filters.cpp +++ b/src/video_core/renderer_vulkan/present/filters.cpp @@ -5,14 +5,16 @@ #include "common/common_types.h" #include "video_core/host_shaders/present_bicubic_frag_spv.h" -#include "video_core/host_shaders/present_lanczos_frag_spv.h" #include "video_core/host_shaders/present_gaussian_frag_spv.h" +#include "video_core/host_shaders/present_lanczos_frag_spv.h" +#include "video_core/host_shaders/vulkan_crt_easymode_frag_spv.h" +#include "video_core/host_shaders/vulkan_fidelityfx_fsr_rcas_fp16_frag_spv.h" +#include "video_core/host_shaders/vulkan_fidelityfx_fsr_rcas_fp32_frag_spv.h" #include "video_core/host_shaders/vulkan_present_frag_spv.h" #include "video_core/host_shaders/vulkan_present_scaleforce_fp16_frag_spv.h" #include "video_core/host_shaders/vulkan_present_scaleforce_fp32_frag_spv.h" #include "video_core/host_shaders/vulkan_present_scalefx_fp16_frag_spv.h" #include "video_core/host_shaders/vulkan_present_scalefx_fp32_frag_spv.h" -#include "video_core/host_shaders/vulkan_crt_easymode_frag_spv.h" #include "video_core/renderer_vulkan/present/filters.h" #include "video_core/renderer_vulkan/present/util.h" #include "video_core/renderer_vulkan/vk_shader_util.h" @@ -72,7 +74,8 @@ std::unique_ptr MakeScaleFx(const Device& device, VkFormat fram } std::unique_ptr MakeLanczos(const Device& device, VkFormat frame_format) { - return std::make_unique(device, frame_format, CreateNearestNeighborSampler(device), + return std::make_unique(device, frame_format, + CreateNearestNeighborSampler(device), BuildShader(device, PRESENT_LANCZOS_FRAG_SPV)); } diff --git a/src/video_core/renderer_vulkan/present/fsr.cpp b/src/video_core/renderer_vulkan/present/fsr.cpp index 3f708be70..db2b33f8c 100644 --- a/src/video_core/renderer_vulkan/present/fsr.cpp +++ b/src/video_core/renderer_vulkan/present/fsr.cpp @@ -24,8 +24,8 @@ using PushConstants = std::array; FSR::FSR(const Device& device, MemoryAllocator& memory_allocator, size_t image_count, VkExtent2D extent) - : m_device{device}, m_memory_allocator{memory_allocator}, - m_image_count{image_count}, m_extent{extent} { + : m_device{device}, m_memory_allocator{memory_allocator}, m_image_count{image_count}, + m_extent{extent} { CreateImages(); CreateRenderPasses(); @@ -157,7 +157,7 @@ void FSR::UploadImages(Scheduler& scheduler) { VkImageView FSR::Draw(Scheduler& scheduler, size_t image_index, VkImage source_image, VkImageView source_image_view, VkExtent2D input_image_extent, - const Common::Rectangle& crop_rect) { + const Common::Rectangle& crop_rect, float sharpening) { Images& images = m_dynamic_images[image_index]; VkImage easu_image = *images.images[Easu]; @@ -188,8 +188,6 @@ VkImageView FSR::Draw(Scheduler& scheduler, size_t image_index, VkImage source_i input_image_height, output_image_width, output_image_height, viewport_x, viewport_y); - const float sharpening = - static_cast(Settings::values.fsr_sharpening_slider.GetValue()) / 100.0f; FsrRcasCon(rcas_con.data(), sharpening); UploadImages(scheduler); diff --git a/src/video_core/renderer_vulkan/present/fsr.h b/src/video_core/renderer_vulkan/present/fsr.h index 8602e8146..bdc635250 100644 --- a/src/video_core/renderer_vulkan/present/fsr.h +++ b/src/video_core/renderer_vulkan/present/fsr.h @@ -18,7 +18,7 @@ public: VkExtent2D extent); VkImageView Draw(Scheduler& scheduler, size_t image_index, VkImage source_image, VkImageView source_image_view, VkExtent2D input_image_extent, - const Common::Rectangle& crop_rect); + const Common::Rectangle& crop_rect, float sharpening); private: void CreateImages(); diff --git a/src/video_core/renderer_vulkan/present/layer.cpp b/src/video_core/renderer_vulkan/present/layer.cpp index 2228da7b4..31132700c 100644 --- a/src/video_core/renderer_vulkan/present/layer.cpp +++ b/src/video_core/renderer_vulkan/present/layer.cpp @@ -57,7 +57,8 @@ Layer::Layer(const Device& device_, MemoryAllocator& memory_allocator_, Schedule device_memory(device_memory_), filters(filters_), image_count(image_count_) { CreateDescriptorPool(); CreateDescriptorSets(layout); - if (filters.get_scaling_filter() == Settings::ScalingFilter::Fsr) { + if (filters.get_scaling_filter() == Settings::ScalingFilter::Fsr || + filters.get_scaling_filter() == Settings::ScalingFilter::Cas) { CreateFSR(output_size); } if (filters.get_scaling_filter() == Settings::ScalingFilter::Fsr2) { @@ -109,8 +110,16 @@ void Layer::ConfigureDraw(PresentPushConstants* out_push_constants, }; if (fsr) { + float sharpening = 0.0f; + if (filters.get_scaling_filter() == Settings::ScalingFilter::Fsr) { + sharpening = + static_cast(Settings::values.fsr_sharpening_slider.GetValue()) / 100.0f; + } else if (filters.get_scaling_filter() == Settings::ScalingFilter::Cas) { + sharpening = + static_cast(Settings::values.cas_sharpening_slider.GetValue()) / 100.0f; + } source_image_view = fsr->Draw(scheduler, image_index, source_image, source_image_view, - render_extent, crop_rect); + render_extent, crop_rect, sharpening); crop_rect = {0, 0, 1, 1}; } if (fsr2) { @@ -257,7 +266,8 @@ void Layer::UpdateDescriptorSet(VkImageView image_view, VkSampler sampler, size_ const VkDescriptorImageInfo image_info{ .sampler = sampler, .imageView = image_view, - .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, // Correct layout for texture sampling + .imageLayout = + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, // Correct layout for texture sampling }; const VkWriteDescriptorSet sampler_write{ @@ -294,7 +304,7 @@ void Layer::UpdateRawImage(const Tegra::FramebufferConfig& framebuffer, size_t i Tegra::Texture::UnswizzleTexture( mapped_span.subspan(image_offset, linear_size), std::span(host_ptr, tiled_size), bytes_per_pixel, framebuffer.width, framebuffer.height, 1, block_height_log2, 0); - buffer.Flush(); // Ensure host writes are visible before the GPU copy. + buffer.Flush(); // Ensure host writes are visible before the GPU copy. } const VkBufferImageCopy copy{ diff --git a/src/video_core/renderer_vulkan/present/window_adapt_pass.cpp b/src/video_core/renderer_vulkan/present/window_adapt_pass.cpp index 2f576b997..232844413 100644 --- a/src/video_core/renderer_vulkan/present/window_adapt_pass.cpp +++ b/src/video_core/renderer_vulkan/present/window_adapt_pass.cpp @@ -2,8 +2,10 @@ // SPDX-FileCopyrightText: Copyright 2026 citron Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include "common/settings.h" #include "core/frontend/framebuffer_layout.h" #include "video_core/framebuffer_config.h" +#include "video_core/fsr.h" #include "video_core/host_shaders/vulkan_present_vert_spv.h" #include "video_core/renderer_vulkan/present/layer.h" #include "video_core/renderer_vulkan/present/present_push_constants.h" @@ -13,7 +15,6 @@ #include "video_core/renderer_vulkan/vk_shader_util.h" #include "video_core/vulkan_common/vulkan_device.h" #include "video_core/vulkan_common/vulkan_memory_allocator.h" -#include "common/settings.h" namespace Vulkan { @@ -93,8 +94,9 @@ void WindowAdaptPass::Draw(RasterizerVulkan& rasterizer, Scheduler& scheduler, s cmdbuf.ClearAttachments({clear_attachment}, {clear_rect}); const auto current_scaling_filter = Settings::values.scaling_filter.GetValue(); - const bool is_crt_enabled = current_scaling_filter == Settings::ScalingFilter::CRTEasyMode || - current_scaling_filter == Settings::ScalingFilter::CRTRoyale; + const bool is_crt_enabled = + current_scaling_filter == Settings::ScalingFilter::CRTEasyMode || + current_scaling_filter == Settings::ScalingFilter::CRTRoyale; for (size_t i = 0; i < layer_count; i++) { cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, graphics_pipelines[i]); @@ -139,6 +141,7 @@ void WindowAdaptPass::Draw(RasterizerVulkan& rasterizer, Scheduler& scheduler, s cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, graphics_pipeline_layout, 0, descriptor_sets[i], {}); + cmdbuf.Draw(4, 1, 0, 0); } diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.cpp b/src/video_core/renderer_vulkan/vk_blit_screen.cpp index d59da892c..7291c6435 100644 --- a/src/video_core/renderer_vulkan/vk_blit_screen.cpp +++ b/src/video_core/renderer_vulkan/vk_blit_screen.cpp @@ -55,6 +55,7 @@ void BlitScreen::SetWindowAdaptPass() { case Settings::ScalingFilter::CRTRoyale: window_adapt = MakeCRT(device, swapchain_view_format); break; + case Settings::ScalingFilter::Cas: case Settings::ScalingFilter::Fsr: case Settings::ScalingFilter::Fsr2: case Settings::ScalingFilter::Bilinear: