fix/feat: Introduce CAS & Add Dynamic Slider Viewing for Toggled WAF's, and remove Android ASTC visibility on PC

This commit is contained in:
collecting
2026-02-05 02:57:28 -05:00
parent 9443737034
commit 37dd2fddc4
18 changed files with 388 additions and 324 deletions

View File

@@ -31,6 +31,12 @@
#include <qgridlayout.h>
#include <vulkan/vulkan_core.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"
#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<VkPresentModeKHR> 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<ConfigurationShared::Widget*>(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<Settings::ScalingFilter>::Index());
const auto scaling_filter = static_cast<Settings::ScalingFilter>(
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<ConfigurationShared::Widget*>(widget);
QObject::connect(config_widget->combobox, QOverload<int>::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<int>::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);

View File

@@ -14,11 +14,11 @@
#include <QWidget>
#include <qobjectdefs.h>
#include <vulkan/vulkan_core.h>
#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<QWidget*> crt_widgets;
// This variable will hold the raw stylesheet string
QString m_template_style_sheet;

View File

@@ -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 <vector>
#include <QLabel>
#include <qnamespace.h>
#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<std::vector<ConfigurationShared::Tab*>> group_,
const ConfigurationShared::Builder& builder, QWidget* parent)
: Tab(group_, parent), ui{std::make_unique<Ui::ConfigureGraphicsAdvanced>()}, system{system_} {
: Tab(group_, parent), ui{std::make_unique<Ui::ConfigureGraphicsAdvanced>()}, system{system_} {
ui->setupUi(this);
@@ -36,27 +37,32 @@ void ConfigureGraphicsAdvanced::Setup(const ConfigurationShared::Builder& builde
std::map<u32, QWidget*> 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() {

View File

@@ -10,11 +10,11 @@
#include <utility>
#include <QCoreApplication>
#include <QWidget>
#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<TranslationMap> 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<TranslationMap> 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<TranslationMap> 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<ComboboxTranslationMap> 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<Settings::AntiAliasing>::Index(),
{
@@ -493,16 +509,16 @@ std::unique_ptr<ComboboxTranslationMap> ComboboxEnumeration(QWidget* parent) {
PAIR(FSR2QualityMode, UltraPerformance, tr("Ultra Performance")),
}});
translations->insert({Settings::EnumMetadata<Settings::FrameSkipping>::Index(),
{
PAIR(FrameSkipping, Disabled, tr("Disabled")),
PAIR(FrameSkipping, Enabled, tr("Enabled")),
}});
translations->insert({Settings::EnumMetadata<Settings::FrameSkippingMode>::Index(),
{
PAIR(FrameSkippingMode, Adaptive, tr("Adaptive")),
PAIR(FrameSkippingMode, Fixed, tr("Fixed")),
}});
translations->insert({Settings::EnumMetadata<Settings::FrameSkipping>::Index(),
{
PAIR(FrameSkipping, Disabled, tr("Disabled")),
PAIR(FrameSkipping, Enabled, tr("Enabled")),
}});
translations->insert({Settings::EnumMetadata<Settings::FrameSkippingMode>::Index(),
{
PAIR(FrameSkippingMode, Adaptive, tr("Adaptive")),
PAIR(FrameSkippingMode, Fixed, tr("Fixed")),
}});
translations->insert({Settings::EnumMetadata<Settings::AspectRatio>::Index(),
{
PAIR(AspectRatio, R16_9, tr("Default (16:9)")),

View File

@@ -39,17 +39,17 @@ static const std::map<Settings::ScalingFilter, QString> 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<Settings::ConsoleMode, QString> use_docked_mode_texts_map = {

View File

@@ -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<std::string>{};
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

View File

@@ -353,72 +353,47 @@ struct Values {
Specialization::Percentage,
true,
true};
SwitchableSetting<int, true> 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<float, true> 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<float, true> crt_curvature{linkage,
0.0f,
0.0f,
1.0f,
"crt_curvature",
Category::Renderer,
Specialization::Scalar,
true,
true};
SwitchableSetting<float, true> 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<float, true> 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<int, true> 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<float, true> crt_brightness{linkage,
1.0f, // Default brightness (1.0 = no change)
0.0f,
2.0f,
"crt_brightness",
Category::Renderer,
Specialization::Scalar,
true,
true};
SwitchableSetting<float, true> crt_alpha{linkage,
1.0f, // Default alpha (1.0 = fully opaque)
0.0f,
1.0f,
"crt_alpha",
Category::Renderer,
Specialization::Scalar,
true,
true};
SwitchableSetting<float, true> 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<float, true> crt_curvature{
linkage, 0.0f, 0.0f, 1.0f, "crt_curvature", Category::Renderer, Specialization::Scalar,
true, true};
SwitchableSetting<float, true> 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<float, true> 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<int, true> 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<float, true> crt_brightness{
linkage,
1.0f, // Default brightness (1.0 = no change)
0.0f, 2.0f, "crt_brightness", Category::Renderer, Specialization::Scalar, true, true};
SwitchableSetting<float, true> crt_alpha{
linkage,
1.0f, // Default alpha (1.0 = fully opaque)
0.0f, 1.0f, "crt_alpha", Category::Renderer, Specialization::Scalar, true, true};
SwitchableSetting<int, true> lanczos_quality{linkage,
3, // Default value
@@ -430,37 +405,38 @@ struct Values {
true,
true};
SwitchableSetting<FSR2QualityMode, true> 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<FSR2QualityMode, true> 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<FrameSkipping, true> frame_skipping{
linkage,
FrameSkipping::Disabled, // Disabled by default
FrameSkipping::Disabled,
FrameSkipping::Enabled,
"frame_skipping",
Category::Renderer,
Specialization::Default,
true,
true};
SwitchableSetting<FrameSkipping, true> frame_skipping{linkage,
FrameSkipping::Disabled, // Disabled by default
FrameSkipping::Disabled,
FrameSkipping::Enabled,
"frame_skipping",
Category::Renderer,
Specialization::Default,
true,
true};
SwitchableSetting<FrameSkippingMode, true> frame_skipping_mode{linkage,
FrameSkippingMode::Adaptive, // Adaptive by default
FrameSkippingMode::Adaptive,
FrameSkippingMode::Fixed,
"frame_skipping_mode",
Category::Renderer,
Specialization::Default,
true,
true};
SwitchableSetting<FrameSkippingMode, true> frame_skipping_mode{
linkage,
FrameSkippingMode::Adaptive, // Adaptive by default
FrameSkippingMode::Adaptive,
FrameSkippingMode::Fixed,
"frame_skipping_mode",
Category::Renderer,
Specialization::Default,
true,
true};
SwitchableSetting<u8, false> 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<GCAggressiveness, true> 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<u32, true> 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<u32, true> 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<u32, true> 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<bool> sparse_texture_priority_eviction{linkage, false,
"sparse_texture_priority_eviction",
Category::RendererAdvanced};
SwitchableSetting<bool> sparse_texture_priority_eviction{
linkage, false, "sparse_texture_priority_eviction", Category::RendererAdvanced};
// Enable VRAM usage logging for debugging
SwitchableSetting<bool> 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<AndroidAstcMode, true> 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<bool> async_presentation{linkage,
#ifdef ANDROID
@@ -605,12 +580,13 @@ struct Values {
Category::RendererAdvanced};
SwitchableSetting<bool> barrier_feedback_loops{linkage, true, "barrier_feedback_loops",
Category::RendererAdvanced};
SwitchableSetting<ExtendedDynamicState, true> extended_dynamic_state{linkage,
ExtendedDynamicState::EDS3,
ExtendedDynamicState::Disabled,
ExtendedDynamicState::EDS3,
"extended_dynamic_state",
Category::RendererAdvanced};
SwitchableSetting<ExtendedDynamicState, true> extended_dynamic_state{
linkage,
ExtendedDynamicState::EDS3,
ExtendedDynamicState::Disabled,
ExtendedDynamicState::EDS3,
"extended_dynamic_state",
Category::RendererAdvanced};
SwitchableSetting<bool> use_conditional_rendering{linkage, true, "use_conditional_rendering",
Category::RendererAdvanced};
@@ -676,7 +652,9 @@ struct Values {
true};
// Linux
Setting<bool, false> is_wayland_platform{linkage, false, "is_wayland_platform", Category::Miscellaneous, Specialization::Default, false};
Setting<bool, false> is_wayland_platform{
linkage, false, "is_wayland_platform", Category::Miscellaneous, Specialization::Default,
false};
SwitchableSetting<bool> enable_gamemode{linkage, true, "enable_gamemode", Category::Linux};
// Controls
@@ -805,11 +783,12 @@ struct Values {
Setting<std::string> web_api_url{linkage, "api.ynet-fun.xyz", "web_api_url",
Category::WebService};
Setting<std::string> citron_username{linkage, std::string(), "citron_username",
Category::WebService};
Category::WebService};
Setting<std::string> citron_token{linkage, std::string(), "citron_token", Category::WebService};
// Updater
Setting<bool> enable_auto_update_check{linkage, true, "enable_auto_update_check", Category::WebService};
Setting<bool> enable_auto_update_check{linkage, true, "enable_auto_update_check",
Category::WebService};
// Add-Ons
std::map<u64, std::vector<std::string>> disabled_addons;
@@ -823,9 +802,12 @@ struct Values {
// This stores the external path used for Intelligent Mirroring sync
std::map<u64, std::string> mirrored_save_paths;
Setting<bool> global_custom_save_path_enabled{linkage, false, "global_custom_save_path_enabled", Category::DataStorage};
Setting<std::string> global_custom_save_path{linkage, std::string(), "global_custom_save_path", Category::DataStorage};
Setting<bool> backup_saves_to_nand{linkage, false, "backup_saves_to_nand", Category::DataStorage};
Setting<bool> global_custom_save_path_enabled{linkage, false, "global_custom_save_path_enabled",
Category::DataStorage};
Setting<std::string> global_custom_save_path{linkage, std::string(), "global_custom_save_path",
Category::DataStorage};
Setting<bool> backup_saves_to_nand{linkage, false, "backup_saves_to_nand",
Category::DataStorage};
};
extern Values values;

View File

@@ -91,8 +91,8 @@ template <>
inline std::vector<std::pair<std::string, AudioEngine>>
EnumMetadata<AudioEngine>::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<std::pair<std::string, AudioMode>>
EnumMetadata<AudioMode>::Canonicalizations() {
inline std::vector<std::pair<std::string, AudioMode>> EnumMetadata<AudioMode>::Canonicalizations() {
return {
{"Mono", AudioMode::Mono},
{"Stereo", AudioMode::Stereo},
@@ -146,8 +145,7 @@ enum class Language : u32 {
};
template <>
inline std::vector<std::pair<std::string, Language>>
EnumMetadata<Language>::Canonicalizations() {
inline std::vector<std::pair<std::string, Language>> EnumMetadata<Language>::Canonicalizations() {
return {
{"Japanese", Language::Japanese},
{"EnglishAmerican", Language::EnglishAmerican},
@@ -186,15 +184,10 @@ enum class Region : u32 {
};
template <>
inline std::vector<std::pair<std::string, Region>>
EnumMetadata<Region>::Canonicalizations() {
inline std::vector<std::pair<std::string, Region>> EnumMetadata<Region>::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<std::pair<std::string, TimeZone>>
EnumMetadata<TimeZone>::Canonicalizations() {
inline std::vector<std::pair<std::string, TimeZone>> EnumMetadata<TimeZone>::Canonicalizations() {
return {
{"Auto", TimeZone::Auto},
{"Default", TimeZone::Default},
@@ -388,8 +380,7 @@ enum class VSyncMode : u32 {
};
template <>
inline std::vector<std::pair<std::string, VSyncMode>>
EnumMetadata<VSyncMode>::Canonicalizations() {
inline std::vector<std::pair<std::string, VSyncMode>> EnumMetadata<VSyncMode>::Canonicalizations() {
return {
{"Immediate", VSyncMode::Immediate},
{"Mailbox", VSyncMode::Mailbox},
@@ -543,12 +534,9 @@ template <>
inline std::vector<std::pair<std::string, MemoryLayout>>
EnumMetadata<MemoryLayout>::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<std::pair<std::string, ResolutionSetup>>
EnumMetadata<ResolutionSetup>::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<ScalingFilter>::Canonicalizations() {
{"Fsr2", ScalingFilter::Fsr2},
{"CRTEasyMode", ScalingFilter::CRTEasyMode},
{"CRTRoyale", ScalingFilter::CRTRoyale},
{"Cas", ScalingFilter::Cas},
{"MaxEnum", ScalingFilter::MaxEnum},
};
}
@@ -714,10 +697,8 @@ template <>
inline std::vector<std::pair<std::string, AntiAliasing>>
EnumMetadata<AntiAliasing>::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<std::pair<std::string, AspectRatio>>
EnumMetadata<AspectRatio>::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<ExtendedDynamicState>::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 <>

View File

@@ -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);

View File

@@ -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<f32>& crop_rect) {
const f32 input_width = static_cast<f32>(input_image_width);
const f32 input_height = static_cast<f32>(input_image_height);
const f32 output_width = static_cast<f32>(width);
const f32 output_height = static_cast<f32>(height);
u32 input_image_height, const Common::Rectangle<float>& crop_rect,
float sharpening) {
const float input_width = static_cast<float>(input_image_width);
const float input_height = static_cast<float>(input_image_height);
const float output_width = static_cast<float>(width);
const float output_height = static_cast<float>(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<float>(Settings::values.fsr_sharpening_slider.GetValue()) / 100.0f;
FsrRcasCon(rcas_con.data(), sharpening);
glProgramUniform4uiv(easu_frag.handle, 0, sizeof(easu_con), easu_con.data());

View File

@@ -20,7 +20,8 @@ public:
~FSR();
GLuint Draw(ProgramManager& program_manager, GLuint texture, u32 input_image_width,
u32 input_image_height, const Common::Rectangle<f32>& crop_rect);
u32 input_image_height, const Common::Rectangle<float>& crop_rect,
float sharpening);
bool NeedsRecreation(const Common::Rectangle<u32>& screen);

View File

@@ -65,8 +65,8 @@ GLuint Layer::ConfigureDraw(std::array<GLfloat, 3 * 2>& 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<GLfloat, 3 * 2>& 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<FSR>(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<float>(Settings::values.fsr_sharpening_slider.GetValue()) / 100.0f;
} else if (filters.get_scaling_filter() == Settings::ScalingFilter::Cas) {
sharpening =
static_cast<float>(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) {

View File

@@ -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<WindowAdaptPass> MakeScaleFx(const Device& device, VkFormat fram
}
std::unique_ptr<WindowAdaptPass> MakeLanczos(const Device& device, VkFormat frame_format) {
return std::make_unique<WindowAdaptPass>(device, frame_format, CreateNearestNeighborSampler(device),
return std::make_unique<WindowAdaptPass>(device, frame_format,
CreateNearestNeighborSampler(device),
BuildShader(device, PRESENT_LANCZOS_FRAG_SPV));
}

View File

@@ -24,8 +24,8 @@ using PushConstants = std::array<u32, 4 * 4>;
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<f32>& crop_rect) {
const Common::Rectangle<f32>& 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<float>(Settings::values.fsr_sharpening_slider.GetValue()) / 100.0f;
FsrRcasCon(rcas_con.data(), sharpening);
UploadImages(scheduler);

View File

@@ -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<f32>& crop_rect);
const Common::Rectangle<f32>& crop_rect, float sharpening);
private:
void CreateImages();

View File

@@ -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<float>(Settings::values.fsr_sharpening_slider.GetValue()) / 100.0f;
} else if (filters.get_scaling_filter() == Settings::ScalingFilter::Cas) {
sharpening =
static_cast<float>(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{

View File

@@ -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);
}

View File

@@ -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: